import { type LucideIcon } from 'lucide-react'; import clsx from 'clsx'; import { MouseEventHandler, PropsWithChildren } from 'react'; import { AutomationTestingProps } from '@/types'; import { Icon } from '@@/Icon'; import { Badge } from '@@/Badge'; import { useSidebarState } from '../useSidebarState'; import { Wrapper } from './Wrapper'; import { SidebarTooltip } from './SidebarTooltip'; import { useSidebarSrefActive } from './useSidebarSrefActive'; interface Props extends AutomationTestingProps { icon?: LucideIcon; to: string; params?: object; label: string; isSubMenu?: boolean; ignorePaths?: string[]; /** When a create or detail path id differs from the list path, includePaths can be used to specify which paths should also mark the item as active. * * E.g. including the portainer.wizard.endpoints (create environment) path to activate the portainer.endpoints sidebar item. */ includePaths?: string[]; count?: number; } export function SidebarItem({ icon, to, params, label, isSubMenu = false, ignorePaths = [], includePaths = [], count, 'data-cy': dataCy, }: Props) { const { isOpen } = useSidebarState(); const anchorProps = useSidebarSrefActive(to, undefined, params, undefined, { ignorePaths, includePaths, }); const sidebarAnchor = ( {!!icon && svg]:w-4')} />} {(isOpen || isSubMenu) && {label}} ); if (isOpen || isSubMenu) return sidebarAnchor; return ( {label} } > {sidebarAnchor} ); } type ItemAnchorProps = { href?: string; onClick: MouseEventHandler; className: string; isOpen: boolean; isSubMenu: boolean; dataCy: string; count?: number; }; function ItemAnchor({ href, onClick, className, isOpen, isSubMenu, dataCy, count, children, }: PropsWithChildren) { return ( {children} {(isOpen || isSubMenu) && count !== undefined && count > 0 && ( // 99 is for a conventional badge overflow cap, same pattern as GitHub/Slack notification badges {count > 99 ? '99+' : count} )} ); }