From a01aa7e3555b28ac91185e423e39f5ae9a509cbf Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 3 Aug 2023 09:01:49 +0200 Subject: [PATCH] Update admin menu (#4389) ## About the changes - add divider - reorder items - add flag for project https://linear.app/unleash/project/[high][s][none]-improved-menu-aefaca264034 Closes https://linear.app/unleash/issue/1-1101/improved-menu-enterprise --- frontend/src/component/menu/Header/Header.tsx | 37 +++++++++------- .../Header/NavigationMenu/NavigationMenu.tsx | 24 ++++++++--- frontend/src/component/menu/routes.ts | 42 ++++++++++++++----- frontend/src/interfaces/route.ts | 1 + frontend/src/interfaces/uiConfig.ts | 1 + .../__snapshots__/create-config.test.ts.snap | 2 + src/lib/types/experimental.ts | 8 +++- src/server-dev.ts | 1 + 8 files changed, 84 insertions(+), 32 deletions(-) diff --git a/frontend/src/component/menu/Header/Header.tsx b/frontend/src/component/menu/Header/Header.tsx index ae0eb48a47..967edd1569 100644 --- a/frontend/src/component/menu/Header/Header.tsx +++ b/frontend/src/component/menu/Header/Header.tsx @@ -123,6 +123,7 @@ const Header: VFC = () => { const { uiConfig, isOss, isPro, isEnterprise } = useUiConfig(); const smallScreen = useMediaQuery(theme.breakpoints.down('md')); const [openDrawer, setOpenDrawer] = useState(false); + const showApiAccessInConfigure = !uiConfig?.flags?.frontendNavigationUpdate; const toggleDrawer = () => setOpenDrawer(prev => !prev); const onAdminClose = () => setAdminRef(null); @@ -141,23 +142,31 @@ const Header: VFC = () => { const filteredMainRoutes = { mainNavRoutes: getCondensedRoutes(routes.mainNavRoutes) - .concat([ - { - path: '/admin/api', - title: 'API access', - menu: {}, - }, - ]) + .concat( + showApiAccessInConfigure + ? [ + { + path: '/admin/api', + title: 'API access', + menu: {}, + }, + ] + : [] + ) .filter(filterByConfig(uiConfig)) .map(mapRouteLink), mobileRoutes: getCondensedRoutes(routes.mobileRoutes) - .concat([ - { - path: '/admin/api', - title: 'API access', - menu: {}, - }, - ]) + .concat( + showApiAccessInConfigure + ? [ + { + path: '/admin/api', + title: 'API access', + menu: {}, + }, + ] + : [] + ) .filter(filterByConfig(uiConfig)) .map(mapRouteLink), adminRoutes: adminMenuRoutes diff --git a/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx b/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx index da2cae8a30..d2dc3cee48 100644 --- a/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx +++ b/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx @@ -1,4 +1,8 @@ +import { Divider } from '@mui/material'; import { Menu, MenuItem, styled } from '@mui/material'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { Fragment } from 'react'; import { Link } from 'react-router-dom'; interface INavigationMenuProps { @@ -38,6 +42,9 @@ export const NavigationMenu = ({ anchorEl, style, }: INavigationMenuProps) => { + const { uiConfig } = useUiConfig(); + const showDividers = uiConfig?.flags?.frontendNavigationUpdate; + return ( - {options.map(option => { - return ( + {options.map((option, i) => ( + + } + /> {option.title} - ); - })} + + ))} ); }; diff --git a/frontend/src/component/menu/routes.ts b/frontend/src/component/menu/routes.ts index fd100c8382..1ca59d362b 100644 --- a/frontend/src/component/menu/routes.ts +++ b/frontend/src/component/menu/routes.ts @@ -457,69 +457,89 @@ export const adminMenuRoutes: INavigationMenuItem[] = [ path: '/admin/users', title: 'Users', menu: { adminSettings: true }, + group: 'users', }, { path: '/admin/service-accounts', title: 'Service accounts', menu: { adminSettings: true, mode: ['enterprise'] }, + group: 'users', }, { path: '/admin/groups', title: 'Groups', menu: { adminSettings: true, mode: ['enterprise'] }, flag: UG, + group: 'users', }, { path: '/admin/roles/*', title: 'Roles', menu: { adminSettings: true, mode: ['enterprise'] }, + group: 'users', + }, + { + path: '/admin/api', + title: 'API access', + flag: 'frontendNavigationUpdate', + menu: { adminSettings: true }, + group: 'access', }, { path: '/admin/cors', title: 'CORS origins', flag: 'embedProxyFrontend', menu: { adminSettings: true }, + group: 'access', }, { path: '/admin/auth', title: 'Single sign-on', menu: { adminSettings: true }, - }, - { - path: '/admin/instance', - title: 'Instance stats', - menu: { adminSettings: true }, + group: 'access', }, { path: '/admin/network/*', title: 'Network', menu: { adminSettings: true, mode: ['pro', 'enterprise'] }, configFlag: 'networkViewEnabled', + group: 'instance', }, { path: '/admin/maintenance', title: 'Maintenance', menu: { adminSettings: true }, + group: 'instance', }, { - path: '/admin/admin-invoices', - title: 'Billing & invoices', - menu: { adminSettings: true, mode: ['pro'] }, + path: '/admin/instance', + title: 'Instance stats', + menu: { adminSettings: true }, + group: 'instance', }, { path: '/admin/instance-privacy', title: 'Instance privacy', menu: { adminSettings: true }, + group: 'instance', }, { - path: '/history', - title: 'Event log', - menu: { adminSettings: true }, + path: '/admin/admin-invoices', + title: 'Billing & invoices', + menu: { adminSettings: true, mode: ['pro'] }, + group: 'instance', }, { path: '/admin/logins', title: 'Login history', menu: { adminSettings: true, mode: ['enterprise'] }, + group: 'log', + }, + { + path: '/history', + title: 'Event log', + menu: { adminSettings: true }, + group: 'log', }, ]; diff --git a/frontend/src/interfaces/route.ts b/frontend/src/interfaces/route.ts index a860eb8c67..a5dde225b5 100644 --- a/frontend/src/interfaces/route.ts +++ b/frontend/src/interfaces/route.ts @@ -22,6 +22,7 @@ export interface INavigationMenuItem { menu: IRouteMenu; flag?: keyof IFlags; configFlag?: keyof IUiConfig; + group?: string; } interface IRouteMenu { diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index eea3f36acc..6e46f14795 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -54,6 +54,7 @@ export interface IFlags { strategyVariant?: boolean; newProjectLayout?: boolean; configurableFeatureTypeLifetimes?: boolean; + frontendNavigationUpdate?: 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 29b8064581..7145659d35 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -79,6 +79,7 @@ exports[`should create default config 1`] = ` "emitPotentiallyStaleEvents": false, "featuresExportImport": true, "filterInvalidClientMetrics": false, + "frontendNavigationUpdate": false, "googleAuthEnabled": false, "maintenanceMode": false, "messageBanner": { @@ -113,6 +114,7 @@ exports[`should create default config 1`] = ` "emitPotentiallyStaleEvents": false, "featuresExportImport": true, "filterInvalidClientMetrics": false, + "frontendNavigationUpdate": false, "googleAuthEnabled": false, "maintenanceMode": false, "messageBanner": { diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 0c7bc97704..166c81cadf 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -26,7 +26,8 @@ export type IFlagKey = | 'slackAppAddon' | 'emitPotentiallyStaleEvents' | 'configurableFeatureTypeLifetimes' - | 'filterInvalidClientMetrics'; + | 'filterInvalidClientMetrics' + | 'frontendNavigationUpdate'; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; @@ -115,7 +116,6 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_EMIT_POTENTIALLY_STALE_EVENTS, false, ), - configurableFeatureTypeLifetimes: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_CONFIGURABLE_FEATURE_TYPE_LIFETIMES, false, @@ -124,6 +124,10 @@ const flags: IFlags = { process.env.FILTER_INVALID_CLIENT_METRICS, false, ), + frontendNavigationUpdate: parseEnvVarBoolean( + process.env.UNLEASH_NAVIGATION_UPDATE, + false, + ), }; export const defaultExperimentalOptions: IExperimentalOptions = { diff --git a/src/server-dev.ts b/src/server-dev.ts index c6533fd133..539c1b0ea5 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -42,6 +42,7 @@ process.nextTick(async () => { emitPotentiallyStaleEvents: true, slackAppAddon: true, configurableFeatureTypeLifetimes: true, + frontendNavigationUpdate: true, }, }, authentication: {