diff --git a/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx b/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx index e2c61f98f7e..cb16dfac8ca 100644 --- a/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx @@ -76,6 +76,7 @@ function getStyles(theme: GrafanaTheme2) { display: 'flex', position: 'absolute', zIndex: 1, + right: 0, boxSizing: 'border-box', alignItems: 'center', background: theme.colors.background.secondary, diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx index 5fb4e4e072f..2c4d8255789 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx @@ -60,11 +60,6 @@ it('renders panel with a header if prop leftItems', () => { expect(screen.getByTestId('header-container')).toBeInTheDocument(); }); -it('renders panel with hover header if no title, no leftItems, hoverHeader is undefined but menu is present', () => { - setup({ title: '', leftItems: undefined, hoverHeader: undefined, menu:
Menu
}); - expect(screen.getByTestId('hover-header-container')).toBeInTheDocument(); -}); - it('renders panel with a hovering header if prop hoverHeader is true', () => { setup({ title: 'Test Panel Header', hoverHeader: true }); @@ -87,12 +82,6 @@ it('renders panel with a header with icons in place if prop titleItems', () => { expect(screen.getByTestId('title-items-container')).toBeInTheDocument(); }); -it('renders panel with a hover header if prop menu is present and hoverHeader is false', () => { - setup({ menu:
Menu
, hoverHeader: false }); - - expect(screen.getByTestId('hover-header-container')).toBeInTheDocument(); -}); - it('renders panel with a show-on-hover menu icon if prop menu', () => { setup({ menu:
Menu
}); diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx index 398cb586fc6..3ff8f3b0e2b 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx @@ -84,19 +84,7 @@ export function PanelChrome({ }: PanelChromeProps) { const theme = useTheme2(); const styles = useStyles2(getStyles); - - // To Do rely on hoverHeader prop for header, not separate props - // once hoverHeader is implemented - // - // Backwards compatibility for having a designated space for the header - - const hasHeader = - hoverHeader === false && - (title.length > 0 || - titleItems !== undefined || - description !== '' || - loadingState === LoadingState.Streaming || - (leftItems?.length ?? 0) > 0); + const hasHeader = !hoverHeader; const headerHeight = getHeaderHeight(theme, hasHeader); const { contentStyle, innerWidth, innerHeight } = getContentStyle(padding, theme, width, headerHeight, height); @@ -122,13 +110,10 @@ export function PanelChrome({ )} - - - {titleItems !== undefined && ( -
- {titleItems} -
- )} +
+ + {titleItems} +
{loadingState === LoadingState.Streaming && ( @@ -141,23 +126,34 @@ export function PanelChrome({ ); return ( -
+
{loadingState === LoadingState.Loading ? : null}
- {(hoverHeader || !hasHeader) && menu && ( - - {headerContent} - + {hoverHeader && ( + <> + {menu && ( + + {headerContent} + + )} + {statusMessage && ( +
+ +
+ )} + )} {hasHeader && (
+ {statusMessage && ( +
+ +
+ )} + {headerContent}
@@ -175,15 +171,6 @@ export function PanelChrome({
)} - {statusMessage && ( - - )} -
{children(innerWidth, innerHeight)}
@@ -245,6 +232,7 @@ const getStyles = (theme: GrafanaTheme2) => { visibility: 'hidden', opacity: '0', }, + '&:focus-visible, &:hover': { // only show menu icon on hover or focused panel '.show-on-hover': { @@ -256,8 +244,7 @@ const getStyles = (theme: GrafanaTheme2) => { '&:focus-visible': { outline: `1px solid ${theme.colors.action.focus}`, }, - }), - regularHeader: css({ + '&:focus-within': { '.show-on-hover': { visibility: 'visible', @@ -281,7 +268,6 @@ const getStyles = (theme: GrafanaTheme2) => { label: 'panel-header', display: 'flex', alignItems: 'center', - padding: theme.spacing(0, 0, 0, padding), }), streaming: css({ label: 'panel-streaming', @@ -295,7 +281,7 @@ const getStyles = (theme: GrafanaTheme2) => { title: css({ label: 'panel-title', marginBottom: 0, // override default h6 margin-bottom - paddingRight: theme.spacing(1), + padding: theme.spacing(0, padding), textOverflow: 'ellipsis', overflow: 'hidden', whiteSpace: 'nowrap', @@ -316,14 +302,11 @@ const getStyles = (theme: GrafanaTheme2) => { visibility: 'hidden', border: 'none', }), - errorContainer: css({ + errorContainerFloating: css({ label: 'error-container', position: 'absolute', - left: '50%', - transform: 'translateX(-50%)', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', + left: 0, + top: 0, zIndex: theme.zIndex.tooltip, }), leftItems: css({ diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx index 55fd516f6ba..7e83298fd3a 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx @@ -1,4 +1,4 @@ -import { cx, css } from '@emotion/css'; +import { css } from '@emotion/css'; import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; @@ -7,18 +7,17 @@ import { useStyles2 } from '../../themes'; import { ToolbarButton } from '../ToolbarButton/ToolbarButton'; export interface Props { - className?: string; message?: string; onClick?: (e: React.SyntheticEvent) => void; ariaLabel?: string; } -export function PanelStatus({ className, message, onClick, ariaLabel = 'status' }: Props) { +export function PanelStatus({ message, onClick, ariaLabel = 'status' }: Props) { const styles = useStyles2(getStyles); return ( { }), timeshift: css({ color: theme.colors.text.link, + gap: theme.spacing(0.5), '&:hover': { color: theme.colors.emphasize(theme.colors.text.link, 0.03), diff --git a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx index 6e2c72fc71a..b6648bfc838 100644 --- a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx +++ b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx @@ -631,12 +631,13 @@ export class PanelStateWrapper extends PureComponent { const { transparent } = panel; const alertState = data.alertState?.state; + const hasHoverHeader = this.hasOverlayHeader(); const containerClassNames = classNames({ 'panel-container': true, 'panel-container--absolute': isSoloRoute(locationService.getLocation().pathname), 'panel-container--transparent': transparent, - 'panel-container--no-title': this.hasOverlayHeader(), + 'panel-container--no-title': hasHoverHeader, [`panel-alert-state--${alertState}`]: alertState !== undefined, }); @@ -648,6 +649,7 @@ export class PanelStateWrapper extends PureComponent { (data.series.length > 0 && data.series.some((v) => (v.meta?.notices?.length ?? 0) > 0)) || (data.request && data.request.timeInfo) || alertState; + const titleItems = showTitleItems && ( { dragClassCancel="grid-drag-cancel" padding={padding} hoverHeaderOffset={hoverHeaderOffset} - hoverHeader={title ? false : true} + hoverHeader={this.hasOverlayHeader()} displayMode={transparent ? 'transparent' : 'default'} > {(innerWidth, innerHeight) => (