From 10269cb7f50c6342a84d7e0ba27adbb22694c648 Mon Sep 17 00:00:00 2001 From: Alexa V <239999+axelavargas@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:32:05 +0100 Subject: [PATCH] Grafana UI: Add description to Menu component (#77808) Co-authored-by: Ashley Harrison --- .../src/components/Menu/Menu.story.tsx | 36 ++++++++++++++++++ .../src/components/Menu/MenuItem.tsx | 37 ++++++++++++++----- .../src/components/Menu/SubMenu.tsx | 4 +- .../components/CreateNewButton.test.tsx | 13 ++++--- .../AddPanelButton/AddPanelMenu.test.tsx | 2 +- 5 files changed, 74 insertions(+), 18 deletions(-) diff --git a/packages/grafana-ui/src/components/Menu/Menu.story.tsx b/packages/grafana-ui/src/components/Menu/Menu.story.tsx index e3e0c597f5c..4a547fb84ae 100644 --- a/packages/grafana-ui/src/components/Menu/Menu.story.tsx +++ b/packages/grafana-ui/src/components/Menu/Menu.story.tsx @@ -49,6 +49,42 @@ export function Examples() { + + + + , + , + , + , + , + ]} + />, + ]} + shortcut="p s" + /> + , + , + , + ]} + /> + + + diff --git a/packages/grafana-ui/src/components/Menu/MenuItem.tsx b/packages/grafana-ui/src/components/Menu/MenuItem.tsx index 74ef322bd43..03fed08adaf 100644 --- a/packages/grafana-ui/src/components/Menu/MenuItem.tsx +++ b/packages/grafana-ui/src/components/Menu/MenuItem.tsx @@ -7,6 +7,7 @@ import { useStyles2 } from '../../themes'; import { getFocusStyles } from '../../themes/mixins'; import { IconName } from '../../types/icon'; import { Icon } from '../Icon/Icon'; +import { Stack } from '../Layout/Stack/Stack'; import { SubMenu } from './SubMenu'; @@ -17,6 +18,8 @@ export type MenuItemElement = HTMLAnchorElement & HTMLButtonElement & HTMLDivEle export interface MenuItemProps { /** Label of the menu item */ label: string; + /** Description of item */ + description?: string; /** Aria label for accessibility support */ ariaLabel?: string; /** Aria checked for accessibility support */ @@ -57,6 +60,7 @@ export const MenuItem = React.memo( url, icon, label, + description, ariaLabel, ariaChecked, target, @@ -104,6 +108,7 @@ export const MenuItem = React.memo( }, className ); + const disabledProps = { [ItemElement === 'button' ? 'disabled' : 'aria-disabled']: disabled, ...(ItemElement === 'a' && disabled && { href: undefined, onClick: undefined }), @@ -159,10 +164,9 @@ export const MenuItem = React.memo( tabIndex={tabIndex} {...disabledProps} > - <> + {icon && } {label} -
{hasShortcut && (
@@ -181,7 +185,16 @@ export const MenuItem = React.memo( /> )}
- + + {description && ( +
+ {description} +
+ )} ); }) @@ -197,7 +210,8 @@ const getStyles = (theme: GrafanaTheme2) => { whiteSpace: 'nowrap', color: theme.colors.text.primary, display: 'flex', - alignItems: 'center', + flexDirection: 'column', + alignItems: 'stretch', padding: theme.spacing(0.5, 2), minHeight: theme.spacing(4), margin: 0, @@ -234,7 +248,7 @@ const getStyles = (theme: GrafanaTheme2) => { }), disabled: css({ color: theme.colors.action.disabledText, - + label: 'menu-item-disabled', '&:hover, &:focus, &:focus-visible': { cursor: 'not-allowed', background: 'none', @@ -243,8 +257,6 @@ const getStyles = (theme: GrafanaTheme2) => { }), icon: css({ opacity: 0.7, - marginRight: '10px', - marginLeft: '-4px', color: theme.colors.text.secondary, }), rightWrapper: css({ @@ -252,9 +264,6 @@ const getStyles = (theme: GrafanaTheme2) => { alignItems: 'center', marginLeft: 'auto', }), - shortcutIcon: css({ - marginRight: theme.spacing(1), - }), withShortcut: css({ minWidth: theme.spacing(10.5), }), @@ -266,5 +275,13 @@ const getStyles = (theme: GrafanaTheme2) => { color: theme.colors.text.secondary, opacity: 0.7, }), + description: css({ + ...theme.typography.bodySmall, + color: theme.colors.text.secondary, + textAlign: 'start', + }), + descriptionWithIcon: css({ + marginLeft: theme.spacing(3), + }), }; }; diff --git a/packages/grafana-ui/src/components/Menu/SubMenu.tsx b/packages/grafana-ui/src/components/Menu/SubMenu.tsx index 03b9229b1bf..4159f62a071 100644 --- a/packages/grafana-ui/src/components/Menu/SubMenu.tsx +++ b/packages/grafana-ui/src/components/Menu/SubMenu.tsx @@ -49,8 +49,8 @@ export const SubMenu = React.memo( return ( <> -
- +
+
{isOpen && (
{ it('should display the correct urls with a given parent folder', async () => { await renderAndOpen(mockParentFolder); - expect(screen.getByText('New dashboard')).toHaveAttribute( + expect(screen.getByRole('link', { name: 'New dashboard' })).toHaveAttribute( 'href', `/dashboard/new?folderUid=${mockParentFolder.uid}` ); - expect(screen.getByText('Import')).toHaveAttribute('href', `/dashboard/import?folderUid=${mockParentFolder.uid}`); + expect(screen.getByRole('link', { name: 'Import' })).toHaveAttribute( + 'href', + `/dashboard/import?folderUid=${mockParentFolder.uid}` + ); }); it('should display urls without params when there is no parent folder', async () => { await renderAndOpen(); - expect(screen.getByText('New dashboard')).toHaveAttribute('href', '/dashboard/new'); - expect(screen.getByText('Import')).toHaveAttribute('href', '/dashboard/import'); + expect(screen.getByRole('link', { name: 'New dashboard' })).toHaveAttribute('href', '/dashboard/new'); + expect(screen.getByRole('link', { name: 'Import' })).toHaveAttribute('href', '/dashboard/import'); }); it('clicking the "New folder" button opens the drawer', async () => { @@ -57,7 +60,7 @@ describe('NewActionsButton', () => { const newButton = screen.getByText('New'); await userEvent.click(newButton); - expect(screen.getByText('New dashboard')).toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'New dashboard' })).toBeInTheDocument(); expect(screen.getByText('Import')).toBeInTheDocument(); expect(screen.queryByText('New folder')).not.toBeInTheDocument(); }); diff --git a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx index b97e76ed0f4..ecd44d27f03 100644 --- a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx +++ b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx @@ -68,7 +68,7 @@ it('renders with all buttons enabled except paste a panel', () => { expect(screen.getByText('visualization', { exact: false })).not.toBeDisabled(); expect(screen.getByText('row', { exact: false })).not.toBeDisabled(); expect(screen.getByText('library', { exact: false })).not.toBeDisabled(); - expect(screen.getByText('paste panel', { exact: false })).toBeDisabled(); + expect(screen.getByRole('menuitem', { name: 'Paste panel' })).toBeDisabled(); }); it('renders with all buttons enabled', () => {