import { css, cx } from '@emotion/css'; import { Item } from '@react-stately/collections'; import React from 'react'; import { GrafanaTheme2, locationUtil, NavMenuItemType, NavModelItem } from '@grafana/data'; import { locationService } from '@grafana/runtime'; import { toIconName, useTheme2 } from '@grafana/ui'; import { NavBarItemMenu } from './NavBarItemMenu'; import { NavBarItemMenuTrigger } from './NavBarItemMenuTrigger'; import { getNavBarItemWithoutMenuStyles } from './NavBarItemWithoutMenu'; import { NavBarMenuItem } from './NavBarMenuItem'; import { useNavBarContext } from './context'; import { getNavTitle } from './navBarItem-translations'; import { getNavModelItemKey } from './utils'; export interface Props { isActive?: boolean; className?: string; reverseMenuDirection?: boolean; link: NavModelItem; } const NavBarItem = ({ isActive = false, className, reverseMenuDirection = false, link }: Props) => { const theme = useTheme2(); const menuItems = link.children ?? []; const { menuIdOpen } = useNavBarContext(); // Spreading `menuItems` here as otherwise we'd be mutating props const menuItemsSorted = reverseMenuDirection ? [...menuItems].reverse() : menuItems; const filteredItems = menuItemsSorted .filter((item) => !item.hideFromMenu) .map((i) => ({ ...i, menuItemType: NavMenuItemType.Item })); const adjustHeightForBorder = filteredItems.length === 0; const styles = getStyles(theme, adjustHeightForBorder, isActive); const section: NavModelItem = { ...link, children: filteredItems, menuItemType: NavMenuItemType.Section, }; const items: NavModelItem[] = [section].concat(filteredItems); const onNavigate = (item: NavModelItem) => { const { url, target, onClick } = item; onClick?.(); if (url) { if (!target && url.startsWith('/')) { locationService.push(locationUtil.stripBaseFromUrl(url)); } else { window.open(url, target); } } }; const linkText = getNavTitle(link.id) ?? link.text; return (
  • {(item: NavModelItem) => { const itemText = getNavTitle(item.id) ?? item.text; const isSection = item.menuItemType === NavMenuItemType.Section; const iconName = item.icon ? toIconName(item.icon) : undefined; const icon = item.showIconInNavbar && !isSection ? iconName : undefined; return ( ); }}
  • ); }; export default NavBarItem; const getStyles = (theme: GrafanaTheme2, adjustHeightForBorder: boolean, isActive?: boolean) => ({ ...getNavBarItemWithoutMenuStyles(theme, isActive), containerHover: css({ backgroundColor: theme.colors.action.hover, color: theme.colors.text.primary, }), primaryText: css({ color: theme.colors.text.primary, }), header: css({ height: `calc(${theme.spacing(6)} - ${adjustHeightForBorder ? 2 : 1}px)`, fontSize: theme.typography.h4.fontSize, fontWeight: theme.typography.h4.fontWeight, padding: `${theme.spacing(1)} ${theme.spacing(2)}`, whiteSpace: 'nowrap', width: '100%', }), });