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

feat: command bar admin menu improvements (#9689)

This commit is contained in:
David Leek 2025-04-03 10:23:45 +02:00 committed by GitHub
parent 6432262be5
commit b9a7c0cda6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 103 additions and 47 deletions

View File

@ -1,16 +1,19 @@
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { adminRoutes } from './oldAdminRoutes';
import { adminRoutes as oldAdminRoutes } from './oldAdminRoutes';
import { adminRoutes } from './adminRoutes';
import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus';
import { filterAdminRoutes } from './filterAdminRoutes';
import { filterByConfig, mapRouteLink } from 'component/common/util';
import { useUiFlag } from 'hooks/useUiFlag';
export const useAdminRoutes = () => {
const newAdminUIEnabled = useUiFlag('adminNavUI');
const { uiConfig, isPro, isEnterprise } = useUiConfig();
const { isBilling } = useInstanceStatus();
const routes = [...adminRoutes];
const routes = newAdminUIEnabled ? [...adminRoutes] : [...oldAdminRoutes];
if (uiConfig.flags.UNLEASH_CLOUD) {
const adminBillingMenuItem = adminRoutes.findIndex(
const adminBillingMenuItem = routes.findIndex(
(route) => route.title === 'Billing & invoices',
);
routes[adminBillingMenuItem] = {

View File

@ -0,0 +1,22 @@
import { IconRenderer } from 'component/layout/MainLayout/NavigationSidebar/IconRenderer';
import InsightsIcon from '@mui/icons-material/Insights';
import PlaygroundIcon from '@mui/icons-material/AutoFixNormal';
import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
export const ButtonItemIcon = ({
path,
}: {
path: string;
}) => {
if (path === '/projects') {
return <ProjectIcon />;
}
if (path === '/playground') {
return <PlaygroundIcon />;
}
if (path === '/insights') {
return <InsightsIcon />;
}
return <IconRenderer path={path} />;
};

View File

@ -18,7 +18,6 @@ import {
type CommandResultGroupItem,
} from './RecentlyVisited/CommandResultGroup';
import { CommandPageSuggestions } from './CommandPageSuggestions';
import { useRoutes } from 'component/layout/MainLayout/NavigationSidebar/useRoutes';
import { useAsyncDebounce } from 'react-table';
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import {
@ -31,6 +30,7 @@ import { CommandSearchPages } from './CommandSearchPages';
import { CommandBarFeedback } from './CommandBarFeedback';
import { RecentlyVisitedRecorder } from './RecentlyVisitedRecorder';
import { ScreenReaderOnly } from 'component/common/ScreenReaderOnly/ScreenReaderOnly';
import { useCommandBarRoutes } from './useCommandBarRoutes';
export const CommandResultsPaper = styled(Paper)(({ theme }) => ({
position: 'absolute',
@ -101,12 +101,6 @@ const StyledClose = styled(Close)(({ theme }) => ({
fontSize: theme.typography.body1.fontSize,
}));
interface IPageRouteInfo {
path: string;
route: string;
title: string;
}
export const CommandBar = () => {
const { trackEvent } = usePlausibleTracker();
const searchInputRef = useRef<HTMLInputElement>(null);
@ -124,19 +118,7 @@ export const CommandBar = () => {
useState<CommandQueryCounter>({ query: '', count: 0 });
const [hasNoResults, setHasNoResults] = useState(false);
const [value, setValue] = useState<string>('');
const { routes } = useRoutes();
const allRoutes: Record<string, IPageRouteInfo> = {};
for (const route of [
...routes.mainNavRoutes,
...routes.adminRoutes,
...routes.primaryRoutes,
]) {
allRoutes[route.path] = {
path: route.path,
route: route.route,
title: route.title,
};
}
const { allRoutes } = useCommandBarRoutes();
const hideSuggestions = () => {
setShowSuggestions(false);
@ -159,7 +141,7 @@ export const CommandBar = () => {
setSearchedProjects(mappedProjects);
const filteredPages = Object.values(allRoutes).filter((route) =>
route.title.toLowerCase().includes(query.toLowerCase()),
route.searchText.toLowerCase().includes(query.toLowerCase()),
);
const mappedPages = filteredPages.map((page) => ({
name: page.title,

View File

@ -9,7 +9,7 @@ import {
type CommandResultGroupItem,
} from './RecentlyVisited/CommandResultGroup';
import { ListItemButton } from '@mui/material';
import { IconRenderer } from 'component/layout/MainLayout/NavigationSidebar/IconRenderer';
import { ButtonItemIcon } from './ButtonItemIcon';
export const CommandSearchPages = ({
items,
@ -50,7 +50,7 @@ export const CommandSearchPages = ({
sx={listItemButtonStyle}
>
<StyledListItemIcon>
<IconRenderer path={item.link} />
<ButtonItemIcon path={item.link} />
</StyledListItemIcon>
<StyledListItemText>
<StyledButtonTypography color='textPrimary'>

View File

@ -10,14 +10,12 @@ import {
import { Link } from 'react-router-dom';
import type { Theme } from '@mui/material/styles/createTheme';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { IconRenderer } from 'component/layout/MainLayout/NavigationSidebar/IconRenderer';
import InsightsIcon from '@mui/icons-material/Insights';
import PlaygroundIcon from '@mui/icons-material/AutoFixNormal';
import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { Children } from 'react';
import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
import { ButtonItemIcon } from '../ButtonItemIcon';
export const listItemButtonStyle = (theme: Theme) => ({
border: `1px solid transparent`,
@ -48,24 +46,6 @@ export interface CommandResultGroupItem {
description?: string | null;
}
const ButtonItemIcon = ({
path,
}: {
path: string;
}) => {
if (path === '/projects') {
return <ProjectIcon />;
}
if (path === '/playground') {
return <PlaygroundIcon />;
}
if (path === '/insights') {
return <InsightsIcon />;
}
return <IconRenderer path={path} />;
};
export const RecentlyVisitedPathButton = ({
keyName,
path,

View File

@ -0,0 +1,55 @@
import { adminGroups } from 'component/admin/adminRoutes';
import { useRoutes } from 'component/layout/MainLayout/NavigationSidebar/useRoutes';
import { useUiFlag } from 'hooks/useUiFlag';
import type { INavigationMenuItem } from 'interfaces/route';
import { useMemo } from 'react';
interface IPageRouteInfo {
path: string;
route: string;
title: string;
searchText: string;
}
export const useCommandBarRoutes = () => {
const newAdminUIEnabled = useUiFlag('adminNavUI');
const { routes } = useRoutes();
const getSearchText = (route: INavigationMenuItem, title: string) => {
if (route.group && adminGroups[route.group]) {
return `${title} ${route.path} ${route.group} ${adminGroups[route.group]}`;
}
return `${title} ${route.path}`;
};
const getRouteTitle = (route: INavigationMenuItem) => {
if (route.path === '/admin') {
return 'Admin settings';
}
return route.title;
};
return useMemo(() => {
const allRoutes: Record<string, IPageRouteInfo> = {};
for (const route of [
...routes.mainNavRoutes,
...routes.adminRoutes,
...routes.primaryRoutes,
]) {
const title = getRouteTitle(route);
allRoutes[route.path] = {
path: route.path,
route: route.route,
title: title,
searchText: newAdminUIEnabled
? getSearchText(route, title)
: title,
};
}
return {
allRoutes,
newAdminUIEnabled,
};
}, [routes]);
};

View File

@ -13,7 +13,9 @@ import UsersIcon from '@mui/icons-material/GroupOutlined';
import ServiceAccountIcon from '@mui/icons-material/Computer';
import GroupsIcon from '@mui/icons-material/GroupsOutlined';
import RoleIcon from '@mui/icons-material/AdminPanelSettingsOutlined';
import SettingsIcon from '@mui/icons-material/Settings';
import SearchIcon from '@mui/icons-material/Search';
import InsightsIcon from '@mui/icons-material/Insights';
import ApiAccessIcon from '@mui/icons-material/KeyOutlined';
import SingleSignOnIcon from '@mui/icons-material/AssignmentOutlined';
import NetworkIcon from '@mui/icons-material/HubOutlined';
@ -39,6 +41,7 @@ const icons: Record<
typeof SvgIcon | FC<ComponentProps<typeof SvgIcon>>
> = {
'/search': SearchIcon,
'/insights': InsightsIcon,
'/applications': ApplicationsIcon,
'/context': ContextFieldsIcon,
'/feature-toggle-type': FlagTypesIcon,
@ -47,13 +50,24 @@ const icons: Record<
'/strategies': CustomStrategiesIcon,
'/tag-types': TagTypesIcon,
'/environments': EnvironmentsIcon,
'/admin': SettingsIcon,
'/admin/users': UsersIcon,
'/admin/service-accounts': ServiceAccountIcon,
'/admin/groups': GroupsIcon,
'/admin/roles': RoleIcon,
'/admin/roles/project-roles': RoleIcon,
'/admin/api': ApiAccessIcon,
'/admin/auth': SingleSignOnIcon,
'/admin/auth/saml': SingleSignOnIcon,
'/admin/auth/scim': SingleSignOnIcon,
'/admin/auth/password': SingleSignOnIcon,
'/admin/auth/google': SingleSignOnIcon,
'/admin/network': NetworkIcon,
'/admin/network/traffic': NetworkIcon,
'/admin/network/data-usage': NetworkIcon,
'/admin/network/frontend-data-usage': NetworkIcon,
'/admin/network/connected-edges': NetworkIcon,
'/admin/network/backend-connections': NetworkIcon,
'/admin/maintenance': MaintenanceIcon,
'/admin/banners': BannersIcon,
'/admin/instance': InstanceStatsIcon,