diff --git a/packages/grafana-data/src/types/navModel.ts b/packages/grafana-data/src/types/navModel.ts index a90815644e2..23ee7b140a4 100644 --- a/packages/grafana-data/src/types/navModel.ts +++ b/packages/grafana-data/src/types/navModel.ts @@ -1,5 +1,6 @@ import { ComponentType } from 'react'; +import { LinkTarget } from './dataLink'; import { IconName } from './icon'; export interface NavLinkDTO { @@ -11,7 +12,7 @@ export interface NavLinkDTO { icon?: IconName; img?: string; url?: string; - target?: string; + target?: LinkTarget; sortWeight?: number; divider?: boolean; hideFromMenu?: boolean; diff --git a/packages/grafana-ui/src/components/Menu/MenuItem.tsx b/packages/grafana-ui/src/components/Menu/MenuItem.tsx index f6f271478d6..559c0edbcd8 100644 --- a/packages/grafana-ui/src/components/Menu/MenuItem.tsx +++ b/packages/grafana-ui/src/components/Menu/MenuItem.tsx @@ -30,7 +30,7 @@ export interface MenuItemProps { /** Url of the menu item */ url?: string; /** Handler for the click behaviour */ - onClick?: (event?: React.SyntheticEvent, payload?: T) => void; + onClick?: (event?: React.MouseEvent, payload?: T) => void; /** Custom MenuItem styles*/ className?: string; /** Active */ @@ -115,17 +115,7 @@ export const MenuItem = React.memo( className={itemStyle} rel={target === '_blank' ? 'noopener noreferrer' : undefined} href={url} - onClick={ - onClick - ? (event) => { - if (!(event.ctrlKey || event.metaKey || event.shiftKey) && onClick) { - event.preventDefault(); - event.stopPropagation(); - onClick(event); - } - } - : undefined - } + onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} onKeyDown={handleKeys} @@ -136,8 +126,11 @@ export const MenuItem = React.memo( aria-checked={ariaChecked} tabIndex={tabIndex} > - {icon && } - {label} + <> + {icon && } + {label} + + {hasSubMenu && ( { - const { url, target, onClick } = item; - onClick?.(); - - if (url) { - window.open(url, target); - } - }; return ( - - + e.stopPropagation()} className={styles.header}> +
{node.text}
+ {node.subTitle &&
{node.subTitle}
} + + } + > {node.children?.map((item) => { const translationKey = item.id && menuItemTranslations[item.id]; const itemText = translationKey ? i18n._(translationKey) : item.text; - - return !item.target && item.url?.startsWith('/') ? ( - + const showExternalLinkIcon = /^https?:\/\//.test(item.url || ''); + return item.url ? ( + ) : ( - onNavigate(item)} label={itemText} key={item.id} /> + ); })} - {node.subTitle && ( - // Stopping the propagation of the event when clicking the subTitle so the menu - // does not close -
e.stopPropagation()} className={styles.subtitle}> - {node.subTitle} -
- )}
); } const getStyles = (theme: GrafanaTheme2) => { return { - subtitle: css` - background-color: transparent; - border-top: 1px solid ${theme.colors.border.weak}; - color: ${theme.colors.text.secondary}; - font-size: ${theme.typography.bodySmall.fontSize}; - font-weight: ${theme.typography.bodySmall.fontWeight}; - padding: ${theme.spacing(1)} ${theme.spacing(2)} ${theme.spacing(1)}; - text-align: left; - white-space: nowrap; - `, header: css({ - height: `calc(${theme.spacing(6)} - 1px)`, - fontSize: theme.typography.h4.fontSize, - fontWeight: theme.typography.h4.fontWeight, - padding: `${theme.spacing(1)} ${theme.spacing(2)}`, + fontSize: theme.typography.h5.fontSize, + fontWeight: theme.typography.h5.fontWeight, + padding: theme.spacing(0.5, 1), whiteSpace: 'nowrap', - width: '100%', - background: theme.colors.background.secondary, + }), + subTitle: css({ + color: theme.colors.text.secondary, + fontSize: theme.typography.bodySmall.fontSize, }), }; }; diff --git a/public/app/core/components/AppChrome/TopSearchBar.tsx b/public/app/core/components/AppChrome/TopSearchBar.tsx index b0741d83f2f..6c2788dfaff 100644 --- a/public/app/core/components/AppChrome/TopSearchBar.tsx +++ b/public/app/core/components/AppChrome/TopSearchBar.tsx @@ -44,6 +44,7 @@ export function TopSearchBar() { toggleSwitcherModal ).map((item) => enrichWithInteractionTracking(item, false)); + const helpNode = configItems.find((item) => item.id === 'help'); const profileNode = configItems.find((item) => item.id === 'profile'); const signInNode = configItems.find((item) => item.id === 'signin'); @@ -64,11 +65,13 @@ export function TopSearchBar() { />
- - - + {helpNode && ( + }> + + + )}