1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-31 01:16:01 +02:00

feat: rework navigation sidebar admin section (#9556)

This commit is contained in:
David Leek 2025-03-18 10:35:06 +01:00 committed by GitHub
parent bf34ac18fc
commit 35ed2dabf3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 104 additions and 29 deletions

View File

@ -1,5 +1,6 @@
import { forwardRef, type ReactNode } from 'react'; import { forwardRef, type ReactNode } from 'react';
import { Box, Grid, styled, useMediaQuery, useTheme } from '@mui/material'; import { Box, Grid, styled, useMediaQuery, useTheme } from '@mui/material';
import { useLocation } from 'react-router-dom';
import Header from 'component/menu/Header/Header'; import Header from 'component/menu/Header/Header';
import Footer from 'component/menu/Footer/Footer'; import Footer from 'component/menu/Footer/Footer';
import Proclamation from 'component/common/Proclamation/Proclamation'; import Proclamation from 'component/common/Proclamation/Proclamation';
@ -17,6 +18,7 @@ import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
import { NavigationSidebar } from './NavigationSidebar/NavigationSidebar'; import { NavigationSidebar } from './NavigationSidebar/NavigationSidebar';
import { EventTimelineProvider } from 'component/events/EventTimeline/EventTimelineProvider'; import { EventTimelineProvider } from 'component/events/EventTimeline/EventTimelineProvider';
import { NewInUnleash } from './NavigationSidebar/NewInUnleash/NewInUnleash'; import { NewInUnleash } from './NavigationSidebar/NewInUnleash/NewInUnleash';
import { useUiFlag } from 'hooks/useUiFlag';
interface IMainLayoutProps { interface IMainLayoutProps {
children: ReactNode; children: ReactNode;
@ -90,7 +92,9 @@ const MainLayoutContentContainer = styled('main')(({ theme }) => ({
export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>( export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
({ children }, ref) => { ({ children }, ref) => {
const newAdminUIEnabled = useUiFlag('adminNavUI');
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
const location = useLocation();
const projectId = useOptionalPathParam('projectId'); const projectId = useOptionalPathParam('projectId');
const { isChangeRequestConfiguredInAnyEnv } = useChangeRequestsEnabled( const { isChangeRequestConfiguredInAnyEnv } = useChangeRequestsEnabled(
projectId || '', projectId || '',
@ -98,6 +102,10 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
const theme = useTheme(); const theme = useTheme();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('lg')); const isSmallScreen = useMediaQuery(theme.breakpoints.down('lg'));
const showOnlyAdminMenu =
newAdminUIEnabled && location.pathname.indexOf('/admin') === 0;
const showRegularNavigationSideBar =
!isSmallScreen && !showOnlyAdminMenu;
return ( return (
<EventTimelineProvider> <EventTimelineProvider>
@ -119,7 +127,7 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
})} })}
> >
<ConditionallyRender <ConditionallyRender
condition={!isSmallScreen} condition={showRegularNavigationSideBar}
show={ show={
<NavigationSidebar <NavigationSidebar
NewInUnleash={NewInUnleash} NewInUnleash={NewInUnleash}

View File

@ -2,6 +2,7 @@ import type React from 'react';
import { type FC, useCallback } from 'react'; import { type FC, useCallback } from 'react';
import type { INavigationMenuItem } from 'interfaces/route'; import type { INavigationMenuItem } from 'interfaces/route';
import type { NavigationMode } from './NavigationMode'; import type { NavigationMode } from './NavigationMode';
import { ShowAdmin } from './ShowHide';
import { import {
ExternalFullListItem, ExternalFullListItem,
FullListItem, FullListItem,
@ -9,6 +10,7 @@ import {
SignOutItem, SignOutItem,
} from './ListItems'; } from './ListItems';
import { Box, List, styled, Tooltip, Typography } from '@mui/material'; import { Box, List, styled, Tooltip, Typography } from '@mui/material';
import { useUiFlag } from 'hooks/useUiFlag';
import { IconRenderer } from './IconRenderer'; import { IconRenderer } from './IconRenderer';
import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge'; import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
@ -22,8 +24,9 @@ import AccordionSummary from '@mui/material/AccordionSummary';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import FlagIcon from '@mui/icons-material/OutlinedFlag'; import FlagIcon from '@mui/icons-material/OutlinedFlag';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon'; import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
import SettingsIcon from '@mui/icons-material/Settings';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
const StyledBadgeContainer = styled('div')(({ theme }) => ({ const StyledBadgeContainer = styled('div')(({ theme }) => ({
paddingLeft: theme.spacing(2), paddingLeft: theme.spacing(2),
@ -251,6 +254,81 @@ export const SecondaryNavigation: FC<{
); );
}; };
export const AdminSettingsNavigation: FC<{
onClick: (activeItem: string) => void;
onSetFullMode: () => void;
expanded: boolean;
routes: INavigationMenuItem[];
onExpandChange: (expanded: boolean) => void;
activeItem: string;
mode: NavigationMode;
}> = ({
onClick,
onSetFullMode,
expanded,
routes,
onExpandChange,
activeItem,
mode,
}) => {
const newAdminUIEnabled = useUiFlag('adminNavUI');
if (newAdminUIEnabled) {
return <AdminSettingsLink mode={mode} onClick={onClick} />;
}
return (
<>
{mode === 'full' && (
<SecondaryNavigation
expanded={expanded}
onExpandChange={(expand) => {
onExpandChange(expand);
}}
mode={mode}
title='Admin'
>
<SecondaryNavigationList
routes={routes}
mode={mode}
onClick={onClick}
activeItem={activeItem}
/>
</SecondaryNavigation>
)}
{mode === 'mini' && (
<ShowAdmin
onChange={() => {
onExpandChange(true);
onSetFullMode();
}}
/>
)}
</>
);
};
export const AdminSettingsLink: FC<{
mode: NavigationMode;
onClick: (activeItem: string) => void;
}> = ({ mode, onClick }) => {
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
return (
<Box>
<List>
<DynamicListItem
href='/admin'
text='Admin settings'
onClick={() => onClick('/admin')}
>
<SettingsIcon />
</DynamicListItem>
</List>
</Box>
);
};
export const RecentProjectsNavigation: FC<{ export const RecentProjectsNavigation: FC<{
mode: NavigationMode; mode: NavigationMode;
projectId: string; projectId: string;

View File

@ -1,7 +1,7 @@
import { Box, styled } from '@mui/material'; import { Box, styled } from '@mui/material';
import { type FC, useState, useEffect } from 'react'; import { type FC, useState, useEffect } from 'react';
import { useNavigationMode } from './useNavigationMode'; import { useNavigationMode } from './useNavigationMode';
import { ShowAdmin, ShowHide } from './ShowHide'; import { ShowHide } from './ShowHide';
import { useRoutes } from './useRoutes'; import { useRoutes } from './useRoutes';
import { useExpanded } from './useExpanded'; import { useExpanded } from './useExpanded';
import { import {
@ -11,7 +11,9 @@ import {
RecentProjectsNavigation, RecentProjectsNavigation,
SecondaryNavigation, SecondaryNavigation,
SecondaryNavigationList, SecondaryNavigationList,
AdminSettingsNavigation,
} from './NavigationList'; } from './NavigationList';
import { FullListItem, MiniListItem } from './ListItems';
import { useInitialPathname } from './useInitialPathname'; import { useInitialPathname } from './useInitialPathname';
import { useLastViewedProject } from 'hooks/useLastViewedProject'; import { useLastViewedProject } from 'hooks/useLastViewedProject';
import { useLastViewedFlags } from 'hooks/useLastViewedFlags'; import { useLastViewedFlags } from 'hooks/useLastViewedFlags';
@ -115,6 +117,7 @@ export const NavigationSidebar: FC<{ NewInUnleash?: typeof NewInUnleash }> = ({
const { lastViewed: lastViewedFlags } = useLastViewedFlags(); const { lastViewed: lastViewedFlags } = useLastViewedFlags();
const showRecentFlags = mode === 'full' && lastViewedFlags.length > 0; const showRecentFlags = mode === 'full' && lastViewedFlags.length > 0;
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
useEffect(() => { useEffect(() => {
setActiveItem(initialPathname); setActiveItem(initialPathname);
@ -178,32 +181,18 @@ export const NavigationSidebar: FC<{ NewInUnleash?: typeof NewInUnleash }> = ({
activeItem={activeItem} activeItem={activeItem}
/> />
</SecondaryNavigation> </SecondaryNavigation>
{mode === 'full' && (
<SecondaryNavigation
expanded={expanded.includes('admin')}
onExpandChange={(expand) => {
changeExpanded('admin', expand);
}}
mode={mode}
title='Admin'
>
<SecondaryNavigationList
routes={routes.adminRoutes}
mode={mode}
onClick={setActiveItem}
activeItem={activeItem}
/>
</SecondaryNavigation>
)}
{mode === 'mini' && ( <AdminSettingsNavigation
<ShowAdmin onClick={setActiveItem}
onChange={() => { mode={mode}
changeExpanded('admin', true); onSetFullMode={() => setMode('full')}
setMode('full'); activeItem={activeItem}
}} onExpandChange={(expand) => {
/> changeExpanded('admin', expand);
)} }}
expanded={expanded.includes('admin')}
routes={routes.adminRoutes}
/>
{showRecentProject && ( {showRecentProject && (
<RecentProjectsNavigation <RecentProjectsNavigation

View File

@ -58,7 +58,7 @@ process.nextTick(async () => {
filterExistingFlagNames: true, filterExistingFlagNames: true,
teamsIntegrationChangeRequests: true, teamsIntegrationChangeRequests: true,
simplifyDisableFeature: true, simplifyDisableFeature: true,
adminNavUI: true, adminNavUI: false,
}, },
}, },
authentication: { authentication: {