diff --git a/frontend/src/component/App.tsx b/frontend/src/component/App.tsx index d5b4f9162a..993faa9c12 100644 --- a/frontend/src/component/App.tsx +++ b/frontend/src/component/App.tsx @@ -19,6 +19,7 @@ import { useStyles } from './App.styles'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useProjects from '../hooks/api/getters/useProjects/useProjects'; import { useLastViewedProject } from '../hooks/useLastViewedProject'; +import Maintenance from './maintenance/Maintenance'; const InitialRedirect = () => { const { lastViewed } = useLastViewedProject(); @@ -57,7 +58,7 @@ export const App = () => { const hasFetchedAuth = Boolean(authDetails || user); const { classes: styles } = useStyles(); - const { isOss } = useUiConfig(); + const { isOss, uiConfig } = useUiConfig(); const availableRoutes = isOss() ? routes.filter(route => !route.enterprise) @@ -73,6 +74,12 @@ export const App = () => { show={} elseShow={ <> + } + />
diff --git a/frontend/src/component/maintenance/Maintenance.tsx b/frontend/src/component/maintenance/Maintenance.tsx new file mode 100644 index 0000000000..2fbc0337aa --- /dev/null +++ b/frontend/src/component/maintenance/Maintenance.tsx @@ -0,0 +1,35 @@ +import { styled } from '@mui/material'; +import { ErrorOutlineRounded } from '@mui/icons-material'; + +const StyledErrorRoundedIcon = styled(ErrorOutlineRounded)(({ theme }) => ({ + height: '20px', + width: '20px', + marginRight: theme.spacing(1), +})); + +const StyledDiv = styled('div')(({ theme }) => ({ + display: 'flex', + fontSize: theme.fontSizes.smallBody, + justifyContent: 'center', + alignItems: 'center', + color: theme.palette.error.main, + backgroundColor: theme.palette.error.light, + height: '65px', + borderBottom: `1px solid ${theme.palette.error.border}`, + whiteSpace: 'pre-wrap', +})); + +const Maintenance = () => { + return ( + + + Maintenance Mode! +

+ Any changes you make during maintenance mode will not be saved. + We apologize for any inconvenience this may cause. +

+
+ ); +}; + +export default Maintenance; diff --git a/frontend/src/hooks/api/getters/useAuth/useAuthEndpoint.ts b/frontend/src/hooks/api/getters/useAuth/useAuthEndpoint.ts index 3e7cb15bb2..ca8abfc5f5 100644 --- a/frontend/src/hooks/api/getters/useAuth/useAuthEndpoint.ts +++ b/frontend/src/hooks/api/getters/useAuth/useAuthEndpoint.ts @@ -42,7 +42,7 @@ export interface IAuthSplash { [key: string]: boolean; } -interface IUseAuthEndpointOutput { +export interface IUseAuthEndpointOutput { data?: AuthEndpointResponse; refetchAuth: () => void; loading: boolean; diff --git a/frontend/src/hooks/api/getters/useAuth/useAuthPermissions.ts b/frontend/src/hooks/api/getters/useAuth/useAuthPermissions.ts index ab35cbb1d3..084a113034 100644 --- a/frontend/src/hooks/api/getters/useAuth/useAuthPermissions.ts +++ b/frontend/src/hooks/api/getters/useAuth/useAuthPermissions.ts @@ -1,5 +1,7 @@ import { IPermission } from 'interfaces/user'; -import { useAuthEndpoint } from './useAuthEndpoint'; +import { IUseAuthEndpointOutput, useAuthEndpoint } from './useAuthEndpoint'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { IUiConfig } from 'interfaces/uiConfig'; interface IUseAuthPermissionsOutput { permissions?: IPermission[]; @@ -8,13 +10,23 @@ interface IUseAuthPermissionsOutput { error?: Error; } -export const useAuthPermissions = (): IUseAuthPermissionsOutput => { - const auth = useAuthEndpoint(); - const permissions = - auth.data && 'permissions' in auth.data +const getPermissions = ( + auth: IUseAuthEndpointOutput, + uiConfig: IUiConfig +): IPermission[] | undefined => { + let permissions = + auth.data && 'permissions' in auth.data && !uiConfig?.flags?.maintenance ? auth.data.permissions : undefined; + return permissions; +}; + +export const useAuthPermissions = (): IUseAuthPermissionsOutput => { + const auth = useAuthEndpoint(); + const { uiConfig } = useUiConfig(); + const permissions = getPermissions(auth, uiConfig); + return { permissions, refetchPermissions: auth.refetchAuth, diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index c088e22d66..4592776ade 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -44,6 +44,7 @@ export interface IFlags { variantsPerEnvironment?: boolean; favorites?: boolean; networkView?: boolean; + maintenance?: boolean; } export interface IVersionInfo { diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index e30a0f219d..a58f8af3f4 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -74,6 +74,7 @@ exports[`should create default config 1`] = ` "embedProxy": true, "embedProxyFrontend": true, "favorites": false, + "maintenance": false, "networkView": false, "proxyReturnAllToggles": false, "responseTimeWithAppName": false, @@ -89,6 +90,7 @@ exports[`should create default config 1`] = ` "embedProxy": true, "embedProxyFrontend": true, "favorites": false, + "maintenance": false, "networkView": false, "proxyReturnAllToggles": false, "responseTimeWithAppName": false, diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index d4d697a5a0..66b215f1d6 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -38,6 +38,10 @@ export const defaultExperimentalOptions = { process.env.UNLEASH_EXPERIMENTAL_FAVORITES, false, ), + maintenance: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_MAINTENANCE, + false, + ), networkView: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_NETWORK_VIEW, false, @@ -59,6 +63,7 @@ export interface IExperimentalOptions { variantsPerEnvironment?: boolean; favorites?: boolean; networkView?: boolean; + maintenance?: boolean; }; externalResolver: IExternalFlagResolver; } diff --git a/src/server-dev.ts b/src/server-dev.ts index 1d4bbdf880..5116842781 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -42,6 +42,7 @@ process.nextTick(async () => { changeRequests: true, favorites: true, variantsPerEnvironment: true, + maintenance: false, }, }, authentication: {