From c50459a5a149c958efb31147e8b2155c3e46b2cb Mon Sep 17 00:00:00 2001 From: Oleksandr Dubenko Date: Thu, 5 Dec 2024 11:31:02 +0100 Subject: [PATCH] frontend Sidebar: Move "isSelected" logic outside individual items Change logic that determines if the item is selected to the parent component. This allows for better memoization of individual items. Signed-off-by: Oleksandr Dubenko --- frontend/src/components/Sidebar/Sidebar.tsx | 45 ++++++++++++++++--- .../src/components/Sidebar/SidebarItem.tsx | 33 ++------------ 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/frontend/src/components/Sidebar/Sidebar.tsx b/frontend/src/components/Sidebar/Sidebar.tsx index 529db8ab55..d4a5586859 100644 --- a/frontend/src/components/Sidebar/Sidebar.tsx +++ b/frontend/src/components/Sidebar/Sidebar.tsx @@ -1,5 +1,5 @@ import { InlineIcon } from '@iconify/react'; -import { Button } from '@mui/material'; +import { Button, selectClasses } from '@mui/material'; import Box from '@mui/material/Box'; import Drawer from '@mui/material/Drawer'; import Grid from '@mui/material/Grid'; @@ -17,7 +17,7 @@ import { ActionButton } from '../common'; import CreateButton from '../common/Resource/CreateButton'; import NavigationTabs from './NavigationTabs'; import prepareRoutes from './prepareRoutes'; -import SidebarItem from './SidebarItem'; +import SidebarItem, { SidebarItemProps } from './SidebarItem'; import { DefaultSidebars, setSidebarSelected, @@ -153,6 +153,34 @@ const DefaultLinkArea = memo((props: { sidebarName: string; isOpen: boolean }) = ); }); +/** + * Checks if item or any sub items are selected + */ +function getIsSelected(item: SidebarItemProps, selectedName?: string | null): boolean { + if (!selectedName) return false; + return ( + item.name === selectedName || Boolean(item.subList?.find(it => getIsSelected(it, selectedName))) + ); +} + +/** + * Updates the isSelected field of an item + */ +function updateItemSelected( + item: SidebarItemProps, + selectedName?: string | null +): SidebarItemProps { + const isSelected = getIsSelected(item, selectedName); + if (isSelected === false) return item; + return { + ...item, + isSelected: isSelected, + subList: item.subList + ? item.subList.map(it => updateItemSelected(it, selectedName)) + : item.subList, + }; +} + export default function Sidebar() { const { t, i18n } = useTranslation(['glossary', 'translation']); @@ -177,7 +205,7 @@ export default function Sidebar() { return prepareRoutes(t, sidebar.selected.sidebar || ''); }, [ cluster, - sidebar.selected, + sidebar.selected.sidebar, sidebar.entries, sidebar.filters, i18n.language, @@ -195,13 +223,18 @@ export default function Sidebar() { [sidebar.selected.sidebar, isOpen] ); + const processedItems = useMemo( + () => items.map(item => updateItemSelected(item, sidebar.selected.item)), + [items, sidebar.selected.item] + ); + if (sidebar.selected.sidebar === null || !sidebar?.isVisible) { return null; } return ( ( { search, useClusterURL = false, subList = [], - selectedName, + isSelected, hasParent = false, icon, fullWidth = true, @@ -61,31 +61,6 @@ const SidebarItem = memo((props: SidebarItemProps) => { fullURL = createRouteURL(routeName); } - const isSelected = React.useMemo(() => { - if (name === selectedName) { - return true; - } - - let subListToCheck = [...subList]; - for (let i = 0; i < subListToCheck.length; i++) { - const subItem = subListToCheck[i]; - if (subItem.name === selectedName) { - return true; - } - - if (!!subItem.subList) { - subListToCheck = subListToCheck.concat(subItem.subList); - } - } - return false; - }, [subList, name, selectedName]); - - function shouldExpand() { - return isSelected || !!subList.find(item => item.name === selectedName); - } - - const expanded = subList.length > 0 && shouldExpand(); - return hide ? null : ( { padding: 0, }} > - + { {subList.map((item: SidebarItemProps) => (