PanelChrome: Styling issues (#62466)

* all panel icons are 16x16 in size; allow ToolbarButton to have its icon size set from outside;

* use TitleItem for streaming too, so that the style of focus-visible is the same

* allow menu icon to be visible when panel is focused

* remove some styling of title icons in panel header

* panel alert notices are too big

* PanelHeaderNotice: Fix styling issue with background and hover when
feature toggle is not enable

---------

Co-authored-by: Alexandra Vargas <alexa1866@gmail.com>
pull/62551/head
Polina Boneva 2 years ago committed by GitHub
parent 6c02c7079f
commit d48a8fd227
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx
  2. 2
      packages/grafana-ui/src/components/PanelChrome/PanelDescription.tsx
  3. 1
      packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx
  4. 2
      packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx
  5. 10
      packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx
  6. 8
      public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx
  7. 5
      public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.tsx
  8. 4
      public/app/features/dashboard/dashgrid/PanelLinks.tsx

@ -13,6 +13,7 @@ import { Tooltip } from '../Tooltip';
import { PanelDescription } from './PanelDescription'; import { PanelDescription } from './PanelDescription';
import { PanelStatus } from './PanelStatus'; import { PanelStatus } from './PanelStatus';
import { TitleItem } from './TitleItem';
/** /**
* @internal * @internal
@ -101,11 +102,6 @@ export function PanelChrome({
cursor: dragClass ? 'move' : 'auto', cursor: dragClass ? 'move' : 'auto',
}; };
const itemStyles: CSSProperties = {
minHeight: headerHeight,
minWidth: headerHeight,
};
const containerStyles: CSSProperties = { width, height }; const containerStyles: CSSProperties = { width, height };
const ariaLabel = title ? selectors.components.Panels.Panel.containerByTitle(title) : 'Panel'; const ariaLabel = title ? selectors.components.Panels.Panel.containerByTitle(title) : 'Panel';
@ -133,11 +129,11 @@ export function PanelChrome({
)} )}
{loadingState === LoadingState.Streaming && ( {loadingState === LoadingState.Streaming && (
<div className={styles.item} style={itemStyles} data-testid="panel-streaming">
<Tooltip content="Streaming"> <Tooltip content="Streaming">
<Icon name="circle-mono" size="sm" className={styles.streaming} /> <TitleItem className={dragClassCancel} data-testid="panel-streaming">
<Icon name="circle-mono" size="md" className={styles.streaming} />
</TitleItem>
</Tooltip> </Tooltip>
</div>
)} )}
<div className={styles.rightAligned}> <div className={styles.rightAligned}>
@ -147,6 +143,7 @@ export function PanelChrome({
aria-label={`Menu for panel with ${title ? `title ${title}` : 'no title'}`} aria-label={`Menu for panel with ${title ? `title ${title}` : 'no title'}`}
title="Menu" title="Menu"
icon="ellipsis-v" icon="ellipsis-v"
iconSize="md"
narrow narrow
data-testid="panel-menu-button" data-testid="panel-menu-button"
className={cx(styles.menuItem, dragClassCancel, 'menu-icon')} className={cx(styles.menuItem, dragClassCancel, 'menu-icon')}
@ -224,7 +221,7 @@ const getStyles = (theme: GrafanaTheme2) => {
flexDirection: 'column', flexDirection: 'column',
flex: '1 1 0', flex: '1 1 0',
'&:focus-visible, &:hover': { '&:focus-within, &:hover': {
// only show menu icon on hover or focused panel // only show menu icon on hover or focused panel
'.menu-icon': { '.menu-icon': {
visibility: 'visible', visibility: 'visible',
@ -265,6 +262,7 @@ const getStyles = (theme: GrafanaTheme2) => {
title: css({ title: css({
label: 'panel-title', label: 'panel-title',
marginBottom: 0, // override default h6 margin-bottom marginBottom: 0, // override default h6 margin-bottom
paddingRight: theme.spacing(1),
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
overflow: 'hidden', overflow: 'hidden',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
@ -298,9 +296,6 @@ const getStyles = (theme: GrafanaTheme2) => {
}), }),
titleItems: css({ titleItems: css({
display: 'flex', display: 'flex',
alignItems: 'center',
overflow: 'hidden',
padding: theme.spacing(1),
}), }),
}; };
}; };

@ -28,7 +28,7 @@ export function PanelDescription({ description, className }: Props) {
return description !== '' ? ( return description !== '' ? (
<Tooltip interactive content={getDescriptionContent}> <Tooltip interactive content={getDescriptionContent}>
<TitleItem className={cx(className, styles.description)}> <TitleItem className={cx(className, styles.description)}>
<Icon name="info-circle" size="lg" title="description" /> <Icon name="info-circle" size="md" title="description" />
</TitleItem> </TitleItem>
</Tooltip> </Tooltip>
) : null; ) : null;

@ -22,6 +22,7 @@ export function PanelStatus({ className, message, onClick, ariaLabel = 'status'
onClick={onClick} onClick={onClick}
variant={'destructive'} variant={'destructive'}
icon="exclamation-triangle" icon="exclamation-triangle"
iconSize="md"
tooltip={message || ''} tooltip={message || ''}
aria-label={ariaLabel} aria-label={ariaLabel}
/> />

@ -55,7 +55,7 @@ const getStyles = (theme: GrafanaTheme2) => {
border: 'none', border: 'none',
borderRadius: `${theme.shape.borderRadius()}`, borderRadius: `${theme.shape.borderRadius()}`,
padding: `${theme.spacing(0, 1)}`, padding: `${theme.spacing(0, 1)}`,
height: `${theme.spacing(theme.components.height.md)}`, height: `${theme.spacing(theme.components.panel.headerHeight)}`,
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',

@ -6,6 +6,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { styleMixins, useStyles2 } from '../../themes'; import { styleMixins, useStyles2 } from '../../themes';
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins'; import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
import { IconSize } from '../../types/icon';
import { getPropertiesForVariant } from '../Button'; import { getPropertiesForVariant } from '../Button';
import { Icon } from '../Icon/Icon'; import { Icon } from '../Icon/Icon';
import { Tooltip } from '../Tooltip'; import { Tooltip } from '../Tooltip';
@ -13,6 +14,8 @@ import { Tooltip } from '../Tooltip';
type CommonProps = { type CommonProps = {
/** Icon name */ /** Icon name */
icon?: IconName | React.ReactNode; icon?: IconName | React.ReactNode;
/** Icon size */
iconSize?: IconSize;
/** Tooltip */ /** Tooltip */
tooltip?: string; tooltip?: string;
/** For image icons */ /** For image icons */
@ -42,6 +45,7 @@ export const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>(
{ {
tooltip, tooltip,
icon, icon,
iconSize,
className, className,
children, children,
imgSrc, imgSrc,
@ -83,7 +87,7 @@ export const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>(
aria-expanded={isOpen} aria-expanded={isOpen}
{...rest} {...rest}
> >
{renderIcon(icon)} {renderIcon(icon, iconSize)}
{imgSrc && <img className={styles.img} src={imgSrc} alt={imgAlt ?? ''} />} {imgSrc && <img className={styles.img} src={imgSrc} alt={imgAlt ?? ''} />}
{children && !iconOnly && <div className={contentStyles}>{children}</div>} {children && !iconOnly && <div className={contentStyles}>{children}</div>}
{isOpen === false && <Icon name="angle-down" />} {isOpen === false && <Icon name="angle-down" />}
@ -108,13 +112,13 @@ function getButtonAriaLabel(ariaLabel: string | undefined, tooltip: string | und
return ariaLabel ? ariaLabel : tooltip ? selectors.components.PageToolbar.item(tooltip) : undefined; return ariaLabel ? ariaLabel : tooltip ? selectors.components.PageToolbar.item(tooltip) : undefined;
} }
function renderIcon(icon: IconName | React.ReactNode) { function renderIcon(icon: IconName | React.ReactNode, iconSize?: IconSize) {
if (!icon) { if (!icon) {
return null; return null;
} }
if (isIconName(icon)) { if (isIconName(icon)) {
return <Icon name={icon} size="lg" />; return <Icon name={icon} size={`${iconSize ? iconSize : 'lg'}`} />;
} }
return icon; return icon;

@ -21,6 +21,7 @@ export const PanelHeaderNotice: FC<Props> = ({ notice, onClick }) => {
<ToolbarButton <ToolbarButton
className={styles.notice} className={styles.notice}
icon={iconName} icon={iconName}
iconSize="md"
key={notice.severity} key={notice.severity}
tooltip={notice.text} tooltip={notice.text}
onClick={(e) => onClick(e, notice.inspect!)} onClick={(e) => onClick(e, notice.inspect!)}
@ -31,7 +32,7 @@ export const PanelHeaderNotice: FC<Props> = ({ notice, onClick }) => {
if (notice.link) { if (notice.link) {
return ( return (
<a className={styles.notice} aria-label={notice.text} href={notice.link} target="_blank" rel="noreferrer"> <a className={styles.notice} aria-label={notice.text} href={notice.link} target="_blank" rel="noreferrer">
<Icon name={iconName} style={{ marginRight: '8px' }} /> <Icon name={iconName} style={{ marginRight: '8px' }} size="md" />
</a> </a>
); );
} }
@ -39,7 +40,7 @@ export const PanelHeaderNotice: FC<Props> = ({ notice, onClick }) => {
return ( return (
<Tooltip key={notice.severity} content={notice.text}> <Tooltip key={notice.severity} content={notice.text}>
<span className={styles.iconTooltip}> <span className={styles.iconTooltip}>
<Icon name={iconName} size="lg" /> <Icon name={iconName} size="md" />
</span> </span>
</Tooltip> </Tooltip>
); );
@ -47,12 +48,13 @@ export const PanelHeaderNotice: FC<Props> = ({ notice, onClick }) => {
const getStyles = (theme: GrafanaTheme2) => ({ const getStyles = (theme: GrafanaTheme2) => ({
notice: css({ notice: css({
background: 'inherit',
border: 'none', border: 'none',
borderRadius: theme.shape.borderRadius(), borderRadius: theme.shape.borderRadius(),
}), }),
iconTooltip: css({ iconTooltip: css({
color: `${theme.colors.text.secondary}`, color: `${theme.colors.text.secondary}`,
backgroundColor: `${theme.colors.background.primary}`, backgroundColor: 'inherit',
cursor: 'auto', cursor: 'auto',
border: 'none', border: 'none',
borderRadius: `${theme.shape.borderRadius()}`, borderRadius: `${theme.shape.borderRadius()}`,

@ -30,7 +30,7 @@ export function PanelHeaderTitleItems(props: Props) {
[styles.alerting]: alertState === AlertState.Alerting, [styles.alerting]: alertState === AlertState.Alerting,
})} })}
> >
<Icon name={alertState === 'alerting' ? 'heart-break' : 'heart'} className="panel-alert-icon" /> <Icon name={alertState === 'alerting' ? 'heart-break' : 'heart'} className="panel-alert-icon" size="md" />
</PanelChrome.TitleItem> </PanelChrome.TitleItem>
</Tooltip> </Tooltip>
); );
@ -40,8 +40,7 @@ export function PanelHeaderTitleItems(props: Props) {
{data.request && data.request.timeInfo && ( {data.request && data.request.timeInfo && (
<Tooltip content={<TimePickerTooltip timeRange={data.request?.range} timeZone={data.request?.timezone} />}> <Tooltip content={<TimePickerTooltip timeRange={data.request?.range} timeZone={data.request?.timezone} />}>
<PanelChrome.TitleItem className={styles.timeshift}> <PanelChrome.TitleItem className={styles.timeshift}>
<Icon name="clock-nine" /> <Icon name="clock-nine" size="md" /> {data.request?.timeInfo}
{data.request?.timeInfo}
</PanelChrome.TitleItem> </PanelChrome.TitleItem>
</Tooltip> </Tooltip>
)} )}

@ -32,13 +32,13 @@ export function PanelLinks({ panelLinks, onShowPanelLinks }: Props) {
target={linkModel.target} target={linkModel.target}
title={linkModel.title} title={linkModel.title}
> >
<Icon name="external-link-alt" size="lg" /> <Icon name="external-link-alt" size="md" />
</PanelChrome.TitleItem> </PanelChrome.TitleItem>
); );
} else { } else {
return ( return (
<Dropdown overlay={getLinksContent}> <Dropdown overlay={getLinksContent}>
<ToolbarButton icon="external-link-alt" aria-label="panel links" className={styles.menuTrigger} /> <ToolbarButton icon="external-link-alt" iconSize="md" aria-label="panel links" className={styles.menuTrigger} />
</Dropdown> </Dropdown>
); );
} }

Loading…
Cancel
Save