diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx index 584bc082c4b..42a879a57ea 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx @@ -236,6 +236,11 @@ export const Examples = () => { title: 'Default title', collapsible: true, })} + {renderPanel('Menu always visible', { + title: 'Menu always visible', + showMenuAlways: true, + menu, + })} {renderPanel('Panel with action link', { title: 'Panel with action link', actions: ( diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx index d9acab30c2d..bb3d63d723f 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx @@ -111,6 +111,13 @@ it('renders panel with a show-on-hover menu icon if prop menu', () => { expect(screen.getByTestId('panel-menu-button')).not.toBeVisible(); }); +it('renders panel with an always visible menu icon if prop showMenuAlways is true', () => { + setup({ menu:
Menu
, showMenuAlways: true }); + + expect(screen.getByTestId('panel-menu-button')).toBeInTheDocument(); + expect(screen.getByTestId('panel-menu-button')).toBeVisible(); +}); + it('renders error status in the panel header if any given', () => { setup({ statusMessage: 'Error test' }); diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx index e50f103339f..14da2a42c06 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx @@ -83,6 +83,10 @@ interface AutoSize extends BaseProps { interface Collapsible { collapsible: boolean; collapsed?: boolean; + /** + * If true, the VizPanelMenu will always be visible in the panel header. Defaults to false. + */ + showMenuAlways?: boolean; /** * callback when collapsing or expanding the panel */ @@ -94,6 +98,7 @@ interface Collapsible { interface HoverHeader { collapsible?: never; collapsed?: never; + showMenuAlways?: never; onToggleCollapse?: never; hoverHeader?: boolean; hoverHeaderOffset?: number; @@ -134,6 +139,7 @@ export function PanelChrome({ onFocus, onMouseMove, onMouseEnter, + showMenuAlways = false, }: PanelChromeProps) { const theme = useTheme2(); const styles = useStyles2(getStyles); @@ -150,7 +156,7 @@ export function PanelChrome({ } // hover menu is only shown on hover when not on touch devices - const showOnHoverClass = 'show-on-hover'; + const showOnHoverClass = showMenuAlways ? 'always-show' : 'show-on-hover'; const isPanelTransparent = displayMode === 'transparent'; const headerHeight = getHeaderHeight(theme, hasHeader); @@ -390,6 +396,13 @@ const getStyles = (theme: GrafanaTheme2) => { display: 'flex', flexDirection: 'column', + '.always-show': { + background: 'none', + '&:focus-visible, &:hover': { + background: theme.colors.secondary.shade, + }, + }, + '.show-on-hover': { opacity: '0', visibility: 'hidden',