From a26cf932a12c4b1979742c2fc067dfcfa3466be9 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Wed, 7 Feb 2024 11:46:12 +0000 Subject: [PATCH 1/4] chore(devcontainer): upgrade node to 20 --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3d1ae9dd..6bf43202 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,7 +8,7 @@ "version": "latest" }, "ghcr.io/devcontainers/features/node:1": { - "version": 16 + "version": 20 }, "ghcr.io/devcontainers/features/common-utils:1": { "username": "vscode", From 6ec58723912b2cd1949007894ec7dcb9220f4994 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Wed, 7 Feb 2024 11:47:44 +0000 Subject: [PATCH 2/4] feat: add DISABLE_NOTIFICATIONS_PAGE feature flag --- packages/backend/src/config/app.js | 1 + .../src/graphql/queries/get-config.ee.js | 7 ++- packages/docs/pages/advanced/configuration.md | 57 ++++++++++--------- packages/web/src/components/Layout/index.tsx | 12 ++-- 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/packages/backend/src/config/app.js b/packages/backend/src/config/app.js index dd3a7c58..de3f5f9f 100644 --- a/packages/backend/src/config/app.js +++ b/packages/backend/src/config/app.js @@ -88,6 +88,7 @@ const appConfig = { licenseKey: process.env.LICENSE_KEY, sentryDsn: process.env.SENTRY_DSN, CI: process.env.CI === 'true', + disableNotificationsPage: process.env.DISABLE_NOTIFICATIONS_PAGE === 'true', }; if (!appConfig.encryptionKey) { diff --git a/packages/backend/src/graphql/queries/get-config.ee.js b/packages/backend/src/graphql/queries/get-config.ee.js index 4844be88..cb4091a0 100644 --- a/packages/backend/src/graphql/queries/get-config.ee.js +++ b/packages/backend/src/graphql/queries/get-config.ee.js @@ -1,6 +1,11 @@ +import appConfig from '../../config/app.js'; import { hasValidLicense } from '../../helpers/license.ee.js'; import Config from '../../models/config.js'; +const defaultConfig = { + disableNotificationsPage: appConfig.disableNotificationsPage, +}; + const getConfig = async (_parent, params) => { if (!(await hasValidLicense())) return {}; @@ -18,7 +23,7 @@ const getConfig = async (_parent, params) => { computedConfig[key] = value?.data; return computedConfig; - }, {}); + }, defaultConfig); }; export default getConfig; diff --git a/packages/docs/pages/advanced/configuration.md b/packages/docs/pages/advanced/configuration.md index 9befd08f..e971f059 100644 --- a/packages/docs/pages/advanced/configuration.md +++ b/packages/docs/pages/advanced/configuration.md @@ -14,31 +14,32 @@ The default values for some environment variables might be different in our deve Please be careful with the `ENCRYPTION_KEY` and `WEBHOOK_SECRET_KEY` environment variables. They are used to encrypt your credentials from third-party services and verify webhook requests. If you change them, your existing connections and flows will not continue to work. ::: -| Variable Name | Type | Default Value | Description | -| --------------------------- | ------- | ------------------ | ---------------------------------------------------------------------------------------------------- | -| `HOST` | string | `localhost` | HTTP Host | -| `PROTOCOL` | string | `http` | HTTP Protocol | -| `PORT` | string | `3000` | HTTP Port | -| `APP_ENV` | string | `production` | Automatisch Environment | -| `WEB_APP_URL` | string | | Can be used to override connection URLs and CORS URL | -| `WEBHOOK_URL` | string | | Can be used to override webhook URL | -| `LOG_LEVEL` | string | `info` | Can be used to configure log level such as `error`, `warn`, `info`, `http`, `debug` | -| `POSTGRES_DATABASE` | string | `automatisch` | Database Name | -| `POSTGRES_SCHEMA` | string | `public` | Database Schema | -| `POSTGRES_PORT` | number | `5432` | Database Port | -| `POSTGRES_ENABLE_SSL` | boolean | `false` | Enable/Disable SSL for the database | -| `POSTGRES_HOST` | string | `postgres` | Database Host | -| `POSTGRES_USERNAME` | string | `automatisch_user` | Database User | -| `POSTGRES_PASSWORD` | string | | Password of Database User | -| `ENCRYPTION_KEY` | string | | Encryption Key to store credentials | -| `WEBHOOK_SECRET_KEY` | string | | Webhook Secret Key to verify webhook requests | -| `APP_SECRET_KEY` | string | | Secret Key to authenticate the user | -| `REDIS_HOST` | string | `redis` | Redis Host | -| `REDIS_PORT` | number | `6379` | Redis Port | -| `REDIS_USERNAME` | string | | Redis Username | -| `REDIS_PASSWORD` | string | | Redis Password | -| `REDIS_TLS` | boolean | `false` | Redis TLS | -| `TELEMETRY_ENABLED` | boolean | `true` | Enable/Disable Telemetry | -| `ENABLE_BULLMQ_DASHBOARD` | boolean | `false` | Enable BullMQ Dashboard | -| `BULLMQ_DASHBOARD_USERNAME` | string | | Username to login BullMQ Dashboard | -| `BULLMQ_DASHBOARD_PASSWORD` | string | | Password to login BullMQ Dashboard | +| Variable Name | Type | Default Value | Description | +| ---------------------------- | ------- | ------------------ | ----------------------------------------------------------------------------------- | +| `HOST` | string | `localhost` | HTTP Host | +| `PROTOCOL` | string | `http` | HTTP Protocol | +| `PORT` | string | `3000` | HTTP Port | +| `APP_ENV` | string | `production` | Automatisch Environment | +| `WEB_APP_URL` | string | | Can be used to override connection URLs and CORS URL | +| `WEBHOOK_URL` | string | | Can be used to override webhook URL | +| `LOG_LEVEL` | string | `info` | Can be used to configure log level such as `error`, `warn`, `info`, `http`, `debug` | +| `POSTGRES_DATABASE` | string | `automatisch` | Database Name | +| `POSTGRES_SCHEMA` | string | `public` | Database Schema | +| `POSTGRES_PORT` | number | `5432` | Database Port | +| `POSTGRES_ENABLE_SSL` | boolean | `false` | Enable/Disable SSL for the database | +| `POSTGRES_HOST` | string | `postgres` | Database Host | +| `POSTGRES_USERNAME` | string | `automatisch_user` | Database User | +| `POSTGRES_PASSWORD` | string | | Password of Database User | +| `ENCRYPTION_KEY` | string | | Encryption Key to store credentials | +| `WEBHOOK_SECRET_KEY` | string | | Webhook Secret Key to verify webhook requests | +| `APP_SECRET_KEY` | string | | Secret Key to authenticate the user | +| `REDIS_HOST` | string | `redis` | Redis Host | +| `REDIS_PORT` | number | `6379` | Redis Port | +| `REDIS_USERNAME` | string | | Redis Username | +| `REDIS_PASSWORD` | string | | Redis Password | +| `REDIS_TLS` | boolean | `false` | Redis TLS | +| `TELEMETRY_ENABLED` | boolean | `true` | Enable/Disable Telemetry | +| `ENABLE_BULLMQ_DASHBOARD` | boolean | `false` | Enable BullMQ Dashboard | +| `BULLMQ_DASHBOARD_USERNAME` | string | | Username to login BullMQ Dashboard | +| `BULLMQ_DASHBOARD_PASSWORD` | string | | Password to login BullMQ Dashboard | +| `DISABLE_NOTIFICATIONS_PAGE` | boolean | `false` | Enable/Disable notifications page | diff --git a/packages/web/src/components/Layout/index.tsx b/packages/web/src/components/Layout/index.tsx index e9499d54..1ea91a15 100644 --- a/packages/web/src/components/Layout/index.tsx +++ b/packages/web/src/components/Layout/index.tsx @@ -12,7 +12,7 @@ import * as URLS from 'config/urls'; import useVersion from 'hooks/useVersion'; import AppBar from 'components/AppBar'; import Drawer from 'components/Drawer'; -import useAutomatischInfo from 'hooks/useAutomatischInfo'; +import useConfig from 'hooks/useConfig'; type PublicLayoutProps = { children: React.ReactNode; @@ -40,17 +40,17 @@ const drawerLinks = [ ]; type GenerateDrawerBottomLinksOptions = { - isMation: boolean; + disableNotificationsPage: boolean; loading: boolean; notificationBadgeContent: number; }; const generateDrawerBottomLinks = ({ - isMation, + disableNotificationsPage, loading, notificationBadgeContent = 0, }: GenerateDrawerBottomLinksOptions) => { - if (loading || isMation) { + if (loading || disableNotificationsPage) { return []; } @@ -68,7 +68,7 @@ export default function PublicLayout({ children, }: PublicLayoutProps): React.ReactElement { const version = useVersion(); - const { isMation, loading } = useAutomatischInfo(); + const { config, loading } = useConfig(['disableNotificationsPage']); const theme = useTheme(); const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg')); const [isDrawerOpen, setDrawerOpen] = React.useState(!matchSmallScreens); @@ -79,7 +79,7 @@ export default function PublicLayout({ const drawerBottomLinks = generateDrawerBottomLinks({ notificationBadgeContent: version.newVersionCount, loading, - isMation, + disableNotificationsPage: config?.disableNotificationsPage as boolean, }); return ( From e6b806616f5e3f2ee7364fb35164b988c651be00 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Wed, 7 Feb 2024 11:48:03 +0000 Subject: [PATCH 3/4] feat: add DISABLE_FAVICON feature flag --- packages/backend/src/config/app.js | 1 + .../src/graphql/queries/get-config.ee.js | 1 + packages/docs/pages/advanced/configuration.md | 1 + .../public/{favicon.ico => browser-tab.ico} | Bin packages/web/public/index.html | 1 - packages/web/public/manifest.json | 7 ------ .../src/components/MetadataProvider/index.tsx | 21 ++++++++++++++++++ 7 files changed, 24 insertions(+), 8 deletions(-) rename packages/web/public/{favicon.ico => browser-tab.ico} (100%) diff --git a/packages/backend/src/config/app.js b/packages/backend/src/config/app.js index de3f5f9f..20a2765f 100644 --- a/packages/backend/src/config/app.js +++ b/packages/backend/src/config/app.js @@ -89,6 +89,7 @@ const appConfig = { sentryDsn: process.env.SENTRY_DSN, CI: process.env.CI === 'true', disableNotificationsPage: process.env.DISABLE_NOTIFICATIONS_PAGE === 'true', + disableFavicon: process.env.DISABLE_FAVICON === 'true', }; if (!appConfig.encryptionKey) { diff --git a/packages/backend/src/graphql/queries/get-config.ee.js b/packages/backend/src/graphql/queries/get-config.ee.js index cb4091a0..e3c76053 100644 --- a/packages/backend/src/graphql/queries/get-config.ee.js +++ b/packages/backend/src/graphql/queries/get-config.ee.js @@ -4,6 +4,7 @@ import Config from '../../models/config.js'; const defaultConfig = { disableNotificationsPage: appConfig.disableNotificationsPage, + disableFavicon: appConfig.disableFavicon, }; const getConfig = async (_parent, params) => { diff --git a/packages/docs/pages/advanced/configuration.md b/packages/docs/pages/advanced/configuration.md index e971f059..a6635034 100644 --- a/packages/docs/pages/advanced/configuration.md +++ b/packages/docs/pages/advanced/configuration.md @@ -43,3 +43,4 @@ Please be careful with the `ENCRYPTION_KEY` and `WEBHOOK_SECRET_KEY` environment | `BULLMQ_DASHBOARD_USERNAME` | string | | Username to login BullMQ Dashboard | | `BULLMQ_DASHBOARD_PASSWORD` | string | | Password to login BullMQ Dashboard | | `DISABLE_NOTIFICATIONS_PAGE` | boolean | `false` | Enable/Disable notifications page | +| `DISABLE_FAVICON` | boolean | `false` | Enable/Disable favicon | diff --git a/packages/web/public/favicon.ico b/packages/web/public/browser-tab.ico similarity index 100% rename from packages/web/public/favicon.ico rename to packages/web/public/browser-tab.ico diff --git a/packages/web/public/index.html b/packages/web/public/index.html index 6663f427..e253ac47 100644 --- a/packages/web/public/index.html +++ b/packages/web/public/index.html @@ -2,7 +2,6 @@ - { + const existingFaviconElement = document.querySelector( + "link[rel~='icon']" + ) as HTMLLinkElement | null; + + if (config?.disableFavicon === true) { + existingFaviconElement?.remove(); + } + + if (config?.disableFavicon === false) { + if (existingFaviconElement) { + existingFaviconElement.href = '/browser-tab.ico'; + } else { + const newFaviconElement = document.createElement('link'); + newFaviconElement.rel = 'icon'; + document.head.appendChild(newFaviconElement); + newFaviconElement.href = '/browser-tab.ico'; + } + } + }, [config?.disableFavicon]); + return <>{children}; }; From 9d42fd929373025a8a2da7f8fc226ecdcc38cedd Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Wed, 7 Feb 2024 13:11:57 +0000 Subject: [PATCH 4/4] test(queries/get-config): incorporate feature flags cover disableNotificationsPage and disableFavicon feature flags --- .../src/graphql/queries/get-config.ee.js | 10 +++--- .../src/graphql/queries/get-config.ee.test.js | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/graphql/queries/get-config.ee.js b/packages/backend/src/graphql/queries/get-config.ee.js index e3c76053..b20216bc 100644 --- a/packages/backend/src/graphql/queries/get-config.ee.js +++ b/packages/backend/src/graphql/queries/get-config.ee.js @@ -2,14 +2,14 @@ import appConfig from '../../config/app.js'; import { hasValidLicense } from '../../helpers/license.ee.js'; import Config from '../../models/config.js'; -const defaultConfig = { - disableNotificationsPage: appConfig.disableNotificationsPage, - disableFavicon: appConfig.disableFavicon, -}; - const getConfig = async (_parent, params) => { if (!(await hasValidLicense())) return {}; + const defaultConfig = { + disableNotificationsPage: appConfig.disableNotificationsPage, + disableFavicon: appConfig.disableFavicon, + }; + const configQuery = Config.query(); if (Array.isArray(params.keys)) { diff --git a/packages/backend/src/graphql/queries/get-config.ee.test.js b/packages/backend/src/graphql/queries/get-config.ee.test.js index dd82e532..74a438e6 100644 --- a/packages/backend/src/graphql/queries/get-config.ee.test.js +++ b/packages/backend/src/graphql/queries/get-config.ee.test.js @@ -2,6 +2,7 @@ import { vi, describe, it, expect, beforeEach } from 'vitest'; import request from 'supertest'; import app from '../../app'; import { createConfig } from '../../../test/factories/config'; +import appConfig from '../../config/app'; import * as license from '../../helpers/license.ee'; describe('graphQL getConfig query', () => { @@ -56,6 +57,8 @@ describe('graphQL getConfig query', () => { [configOne.key]: configOne.value.data, [configTwo.key]: configTwo.value.data, [configThree.key]: configThree.value.data, + disableNotificationsPage: false, + disableFavicon: false, }, }, }; @@ -82,6 +85,38 @@ describe('graphQL getConfig query', () => { getConfig: { [configOne.key]: configOne.value.data, [configTwo.key]: configTwo.value.data, + disableNotificationsPage: false, + disableFavicon: false, + }, + }, + }; + + expect(response.body).toEqual(expectedResponsePayload); + }); + }); + + describe('and with different defaults', () => { + beforeEach(async () => { + vi.spyOn(appConfig, 'disableNotificationsPage', 'get').mockReturnValue( + true + ); + vi.spyOn(appConfig, 'disableFavicon', 'get').mockReturnValue(true); + }); + + it('should return custom config', async () => { + const response = await request(app) + .post('/graphql') + .send({ query }) + .expect(200); + + const expectedResponsePayload = { + data: { + getConfig: { + [configOne.key]: configOne.value.data, + [configTwo.key]: configTwo.value.data, + [configThree.key]: configThree.value.data, + disableNotificationsPage: true, + disableFavicon: true, }, }, };