diff --git a/ui/apps/pmm/package.json b/ui/apps/pmm/package.json index f31704f721a..052d0070cf1 100644 --- a/ui/apps/pmm/package.json +++ b/ui/apps/pmm/package.json @@ -26,7 +26,7 @@ "@mui/icons-material": "^7.3.7", "@mui/material": "^7.3.7", "@mui/x-date-pickers": "^7.5.0", - "@percona/percona-ui": "1.0.16", + "@percona/percona-ui": "1.0.17", "@pmm/shared": "*", "@reactour/tour": "^3.8.0", "@tanstack/react-query": "^5.45.1", diff --git a/ui/apps/pmm/src/components/sidebar/Sidebar.tsx b/ui/apps/pmm/src/components/sidebar/Sidebar.tsx index 7a8acb7ddef..dce37aa6727 100644 --- a/ui/apps/pmm/src/components/sidebar/Sidebar.tsx +++ b/ui/apps/pmm/src/components/sidebar/Sidebar.tsx @@ -2,7 +2,7 @@ import { FC, useCallback, useEffect, useState } from 'react'; import { useNavigation } from 'contexts/navigation'; import { NavigationHeading } from './nav-heading'; import { Drawer } from './drawer'; -import { NavItem } from './nav-item'; +import { SidebarNavItem } from './nav-item'; import List from '@mui/material/List'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; @@ -69,7 +69,7 @@ export const Sidebar: FC = () => { ]} > {navTree.map((item) => ( - ({ @@ -16,71 +13,33 @@ export const getStyles = ( ? { mr: level > 0 ? 1 : 0, } - : { - py: 1.5, - }, + : {}, navItemRootCollapsible: { borderTopLeftRadius: 0, borderBottomLeftRadius: 0, }, - listItemButton: { - px: 2, - height: 48, - borderRadius: 50, - justifyContent: drawerOpen ? undefined : 'center', - - [`.${typographyClasses.root}`]: { - fontWeight: 600, - }, - - [`&, .${listItemIconClasses.root}`]: { - color: active ? theme.palette.primary.main : theme.palette.text.primary, - }, - }, - listItemButtonCollapsible: { - backgroundColor: active - ? theme.components?.MuiListItemButton?.styleOverrides?.selected - : 'initial', - }, listCollapsible: level === 0 ? { - pl: 4, + pl: 4.75, pb: 2, } : level === 1 ? { - ml: 2.5, - pl: '11px', - pb: 2, + ml: 3.5, + pl: 1, borderLeft: 1, borderColor: theme.palette.divider, } : {}, - listItemIcon: { - minWidth: 'auto', - }, listItemDivider: { px: drawerOpen ? 2 : 1, }, divider: { flex: 1, }, - text: { - pl: 2, - - [`&:hover .${listItemTextClasses.secondary}`]: { - color: 'inherit', - }, - - [`.${listItemTextClasses.secondary}`]: { - ...theme.typography.helperText, - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - overflow: 'hidden', - - color: active ? 'inherit' : theme.palette.text.disabled, - }, + listItemButton: { + px: 2, }, textOnly: { m: 0, diff --git a/ui/apps/pmm/src/components/sidebar/nav-item/NavItem.test.tsx b/ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.test.tsx similarity index 88% rename from ui/apps/pmm/src/components/sidebar/nav-item/NavItem.test.tsx rename to ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.test.tsx index 56a068776a8..875deb49373 100644 --- a/ui/apps/pmm/src/components/sidebar/nav-item/NavItem.test.tsx +++ b/ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.test.tsx @@ -1,10 +1,11 @@ import { fireEvent, render, screen } from '@testing-library/react'; import { wrapWithRouter } from 'utils/testUtils'; -import NavItem from './NavItem'; -import { NavItemProps } from './NavItem.types'; +import SidebarNavItem from './SidebarNavItem'; +import { NavItemProps } from './SidebarNavItem.types'; import { NavItem as NavTreeItem } from 'types/navigation.types'; import { collapseClasses } from '@mui/material/Collapse'; import { MemoryRouterProps } from 'react-router-dom'; +import { ThemeContextProvider, pmmThemeOptions } from '@percona/percona-ui'; const TEST_NAV_TREE: NavTreeItem = { id: 'level-0', @@ -44,19 +45,21 @@ const renderNavItem = ({ activeItem?: NavTreeItem; } = {}) => render( - wrapWithRouter( - , - routerProps - ) + + {wrapWithRouter( + , + routerProps + )} + ); -describe('NavItem', () => { +describe('SidebarNavItem', () => { it('inner levels are closed by default', () => { renderNavItem(); @@ -157,14 +160,14 @@ describe('NavItem', () => { }, ], }; - renderNavItem({ + const { container } = renderNavItem({ activeItem: item, props: { item }, }); fireEvent.click(screen.getByTestId('navitem-with-badge-toggle')); - expect(screen.getByTestId('navitem-dot')).toBeInTheDocument(); + expect(container.querySelector('.MuiBadge-dot')).toBeInTheDocument(); }); it('renders divider if item has type "menu-divider"', () => { diff --git a/ui/apps/pmm/src/components/sidebar/nav-item/NavItem.tsx b/ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.tsx similarity index 72% rename from ui/apps/pmm/src/components/sidebar/nav-item/NavItem.tsx rename to ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.tsx index 2cc2ad840a4..41142a8b4f7 100644 --- a/ui/apps/pmm/src/components/sidebar/nav-item/NavItem.tsx +++ b/ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.tsx @@ -1,12 +1,11 @@ import { useLinkWithVariables } from 'hooks/utils/useLinkWithVariables'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { NavItemProps } from './NavItem.types'; +import { NavItemProps } from './SidebarNavItem.types'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; -import { getLinkProps, hasChildMatch, shouldShowBadge } from './NavItem.utils'; -import { getStyles } from './NavItem.styles'; +import { getLinkProps, hasChildMatch, shouldShowBadge } from './SidebarNavItem.utils'; +import { getStyles } from './SidebarNavItem.styles'; import { useTheme } from '@mui/material/styles'; -import ListItemButton from '@mui/material/ListItemButton'; -import ListItemIcon from '@mui/material/ListItemIcon'; +import { NavItem } from '@percona/percona-ui'; import ListItemText from '@mui/material/ListItemText'; import Stack from '@mui/material/Stack'; import ListItem from '@mui/material/ListItem'; @@ -14,14 +13,12 @@ import List from '@mui/material/List'; import Collapse from '@mui/material/Collapse'; import Divider from '@mui/material/Divider'; import IconButton from '@mui/material/IconButton'; -import Box from '@mui/material/Box'; import NavItemIcon from './nav-item-icon/NavItemIcon'; import NavItemTooltip from './nav-item-tooltip/NavItemTooltip'; import { DRAWER_WIDTH } from '../drawer/Drawer.constants'; -import NavItemDot from './nav-item-dot/NavItemDot'; import NavItemBadge from './nav-item-badge/NavItemBadge'; -const NavItem: FC = ({ +const SidebarNavItem: FC = ({ activeItem, item, drawerOpen, @@ -38,7 +35,7 @@ const NavItem: FC = ({ ); const linkProps = getLinkProps(item, url); const theme = useTheme(); - const styles = getStyles(theme, active, drawerOpen, level); + const styles = getStyles(theme, drawerOpen, level); const dataTestid = `navitem-${item.id}`; const showBadge = shouldShowBadge(item, open); @@ -93,38 +90,29 @@ const NavItem: FC = ({ alignItems="center" justifyContent="space-between" sx={{ - width: level === 0 ? DRAWER_WIDTH : undefined, + width: level === 0 ? DRAWER_WIDTH : '100%', }} data-testid={dataTestid + '-list-item'} > - : undefined} + showDot={showBadge && !!item.icon} + badge={ + item.badge && item.badgeAlwaysVisible && drawerOpen + ? + : undefined + } + selected={active} sx={[ - styles.listItemButton, level === 0 && styles.navItemRootCollapsible, + !drawerOpen && { justifyContent: 'center' }, ]} + {...(linkProps as Omit & { component?: React.ElementType })} onClick={handleOpenCollapsible} - {...linkProps} data-testid={dataTestid} data-navlevel={level} - > - {item.icon && ( - - - - - - )} - - {item.badge && item.badgeAlwaysVisible && drawerOpen && ( - - )} - + /> {drawerOpen && ( = ({ > {item.children.map((item) => ( - = ({ - : undefined} + badge={item.badge ? : undefined} + selected={active} sx={[ - styles.listItemButton, styles.leafItem, level === 0 && styles.navItemRoot, + !drawerOpen && { justifyContent: 'center' }, ]} - selected={active} - {...linkProps} + {...(linkProps as Omit & { component?: React.ElementType })} onClick={handleItemClick} data-testid={dataTestid} data-navlevel={level} - > - {item.icon ? ( - - - - ) : ( - - )} - - {item.badge && } - + /> ); }; -export default NavItem; +export default SidebarNavItem; diff --git a/ui/apps/pmm/src/components/sidebar/nav-item/NavItem.types.ts b/ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.types.ts similarity index 100% rename from ui/apps/pmm/src/components/sidebar/nav-item/NavItem.types.ts rename to ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.types.ts diff --git a/ui/apps/pmm/src/components/sidebar/nav-item/NavItem.utils.ts b/ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.utils.ts similarity index 96% rename from ui/apps/pmm/src/components/sidebar/nav-item/NavItem.utils.ts rename to ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.utils.ts index c57449c3f89..cf4b01ebdcc 100644 --- a/ui/apps/pmm/src/components/sidebar/nav-item/NavItem.utils.ts +++ b/ui/apps/pmm/src/components/sidebar/nav-item/SidebarNavItem.utils.ts @@ -8,7 +8,7 @@ export const getLinkProps = (item: NavItem, url?: string) => { if (item.target && item.url) { return { - component: 'a', + component: 'a' as const, target: item.target, href: url, }; diff --git a/ui/apps/pmm/src/components/sidebar/nav-item/index.ts b/ui/apps/pmm/src/components/sidebar/nav-item/index.ts index 559575122e4..aed47979f83 100644 --- a/ui/apps/pmm/src/components/sidebar/nav-item/index.ts +++ b/ui/apps/pmm/src/components/sidebar/nav-item/index.ts @@ -1 +1 @@ -export { default as NavItem } from './NavItem'; +export { default as SidebarNavItem } from './SidebarNavItem'; diff --git a/ui/apps/pmm/src/components/sidebar/nav-item/nav-item-dot/NavItemDot.tsx b/ui/apps/pmm/src/components/sidebar/nav-item/nav-item-dot/NavItemDot.tsx deleted file mode 100644 index 300b5513bdf..00000000000 --- a/ui/apps/pmm/src/components/sidebar/nav-item/nav-item-dot/NavItemDot.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import Badge from '@mui/material/Badge'; -import { FC, memo, PropsWithChildren } from 'react'; - -interface Props extends PropsWithChildren { - show: boolean; -} - -const NavItemDot: FC = memo(({ show, children }) => - show ? ( - - {children} - - ) : ( - <>{children} - ) -); - -export default NavItemDot; diff --git a/ui/yarn.lock b/ui/yarn.lock index 557fe8c8344..b0c4f12e887 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -1620,10 +1620,10 @@ resolved "https://registry.yarnpkg.com/@percona/eslint-config-react/-/eslint-config-react-1.1.0.tgz#db69fcf5d6bb43e6c842f462e2c1c84d5f3eb281" integrity sha512-Tk9mNYslXrxW/gdS/rzxHbLuEXoNCw8r2t/pB8CXZjBl46VLMGspljbyI6525uNNfyO5H0iJQKCJu0Ckf+5erA== -"@percona/percona-ui@1.0.16": - version "1.0.16" - resolved "https://registry.yarnpkg.com/@percona/percona-ui/-/percona-ui-1.0.16.tgz#103d2611458890100963089c8729d447c28c39e7" - integrity sha512-cHdwPimD1MPHv0RCuGIp6XAgBvhlEpIP6ybTNfEs4pLi/B3ukh0h7rRLUiGck+ocj1TEFsJSzv3ayhFFYCJVhw== +"@percona/percona-ui@1.0.17": + version "1.0.17" + resolved "https://registry.yarnpkg.com/@percona/percona-ui/-/percona-ui-1.0.17.tgz#0295cb55066077cc01a60e37c5ed1ecb14c2f7a7" + integrity sha512-UeOI+I+2PMoSY6GINHNq4iDIPuKY7CVBOn5ozVJ9odTofMB6UOXeilhWV8JVzviPJJUDg+sPKT30NFEOjcm3PA== dependencies: "@fontsource/poppins" "^5.2.7" "@fontsource/roboto" "^5.2.9" @@ -10334,7 +10334,16 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10424,7 +10433,14 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11509,7 +11525,16 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==