From 1fc39ade336641cf7f314803ad2080dbc297af75 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 11 Nov 2025 14:37:32 +0100 Subject: [PATCH] chore: allow custom messages in maintenance mode banner (UI) (#10961) Updates the maintenance mode banner to accept string variants, allowing for custom maintenance mode messages. Because the banner is almost the same as the existing banner component we have, we can simplify the impl and just reuse the existing banner instead. The one difference is that the maintenance mode banner used to be taller. However, after talking to UX, we agreed that the banner should be the same size, anyway. image --- frontend/src/component/App.tsx | 2 +- .../maintenance/MaintenanceBanner.tsx | 42 +++---------------- .../useMaintenanceBannerMessage.test.ts | 27 ++++++++++++ .../useMaintenanceBannerMessage.ts | 19 +++++++++ 4 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 frontend/src/component/maintenance/useMaintenanceBannerMessage.test.ts create mode 100644 frontend/src/component/maintenance/useMaintenanceBannerMessage.ts diff --git a/frontend/src/component/App.tsx b/frontend/src/component/App.tsx index abf9ae1be3..b8c6658c53 100644 --- a/frontend/src/component/App.tsx +++ b/frontend/src/component/App.tsx @@ -14,7 +14,7 @@ import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser'; import { SplashPageRedirect } from 'component/splash/SplashPageRedirect/SplashPageRedirect'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; -import MaintenanceBanner from './maintenance/MaintenanceBanner.tsx'; +import { MaintenanceBanner } from './maintenance/MaintenanceBanner.tsx'; import { styled } from '@mui/material'; import { InitialRedirect, useLastViewedPage } from './InitialRedirect.tsx'; import { InternalBanners } from './banners/internalBanners/InternalBanners.tsx'; diff --git a/frontend/src/component/maintenance/MaintenanceBanner.tsx b/frontend/src/component/maintenance/MaintenanceBanner.tsx index 48662431e6..39bb081725 100644 --- a/frontend/src/component/maintenance/MaintenanceBanner.tsx +++ b/frontend/src/component/maintenance/MaintenanceBanner.tsx @@ -1,39 +1,7 @@ -import { styled } from '@mui/material'; -import ErrorOutlineRounded from '@mui/icons-material/ErrorOutlineRounded'; -import { Sticky } from 'component/common/Sticky/Sticky'; +import { Banner } from 'component/banners/Banner/Banner'; +import { useMaintenanceBannerMessage } from './useMaintenanceBannerMessage.ts'; -const StyledErrorRoundedIcon = styled(ErrorOutlineRounded)(({ theme }) => ({ - color: theme.palette.error.main, - height: '20px', - width: '20px', - marginRight: theme.spacing(1), -})); - -const StyledDiv = styled(Sticky)(({ theme }) => ({ - display: 'flex', - fontSize: theme.fontSizes.smallBody, - justifyContent: 'center', - alignItems: 'center', - color: theme.palette.error.contrastText, - backgroundColor: theme.palette.error.light, - height: '65px', - borderBottom: `1px solid ${theme.palette.error.border}`, - whiteSpace: 'pre-wrap', - zIndex: theme.zIndex.sticky - 100, -})); - -const MaintenanceBanner = () => { - return ( - - - Maintenance Mode! -

- During maintenance mode, any changes made will not be saved and - you may receive an error. We apologize for any inconvenience - this may cause. -

-
- ); +export const MaintenanceBanner = () => { + const message = useMaintenanceBannerMessage(); + return ; }; - -export default MaintenanceBanner; diff --git a/frontend/src/component/maintenance/useMaintenanceBannerMessage.test.ts b/frontend/src/component/maintenance/useMaintenanceBannerMessage.test.ts new file mode 100644 index 0000000000..0d6071fb16 --- /dev/null +++ b/frontend/src/component/maintenance/useMaintenanceBannerMessage.test.ts @@ -0,0 +1,27 @@ +import { renderHook, waitFor } from '@testing-library/react'; +import { useMaintenanceBannerMessage } from './useMaintenanceBannerMessage.ts'; +import { testServerRoute, testServerSetup } from 'utils/testServer.ts'; +import { PayloadType, type Variant } from 'utils/variants.ts'; + +const server = testServerSetup(); +const setupApi = (maintenanceMode?: boolean | Variant) => { + testServerRoute(server, '/api/admin/ui-config', { + flags: { + maintenanceMode, + }, + }); +}; + +test('Returns custom string if variant has string payload', async () => { + setupApi({ + name: 'Variant', + enabled: true, + payload: { + type: PayloadType.STRING, + value: '**Custom** message', + }, + }); + const { result } = renderHook(() => useMaintenanceBannerMessage()); + + await waitFor(() => expect(result.current).toBe('**Custom** message')); +}); diff --git a/frontend/src/component/maintenance/useMaintenanceBannerMessage.ts b/frontend/src/component/maintenance/useMaintenanceBannerMessage.ts new file mode 100644 index 0000000000..cdef1f0c29 --- /dev/null +++ b/frontend/src/component/maintenance/useMaintenanceBannerMessage.ts @@ -0,0 +1,19 @@ +import { useUiFlag } from 'hooks/useUiFlag'; +import { useVariant } from 'hooks/useVariant'; +import { PayloadType, type Variant } from 'utils/variants'; + +export const defaultMessage = + '**Maintenance mode!** During maintenance mode, any changes made will not be saved and you may receive an error. We apologize for any inconvenience this may cause.'; + +export const useMaintenanceBannerMessage = (): string => { + const flag = useUiFlag('maintenanceMode'); + const variantValue = useVariant(flag as Variant); + if (typeof flag === 'boolean') { + return defaultMessage; + } + + if (flag?.payload?.type === PayloadType.STRING) { + return variantValue || defaultMessage; + } + return defaultMessage; +};