mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: Adjust styles for very long titles (#52452)
This commit is contained in:
@@ -15,6 +15,7 @@ import { IconButton } from '../IconButton/IconButton';
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
pageIcon?: IconName;
|
pageIcon?: IconName;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
section?: string;
|
||||||
parent?: string;
|
parent?: string;
|
||||||
onGoBack?: () => void;
|
onGoBack?: () => void;
|
||||||
titleHref?: string;
|
titleHref?: string;
|
||||||
@@ -30,6 +31,7 @@ export interface Props {
|
|||||||
export const PageToolbar: FC<Props> = React.memo(
|
export const PageToolbar: FC<Props> = React.memo(
|
||||||
({
|
({
|
||||||
title,
|
title,
|
||||||
|
section,
|
||||||
parent,
|
parent,
|
||||||
pageIcon,
|
pageIcon,
|
||||||
onGoBack,
|
onGoBack,
|
||||||
@@ -59,63 +61,77 @@ export const PageToolbar: FC<Props> = React.memo(
|
|||||||
className
|
className
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const leftItemChildren = leftItems?.map((child, index) => (
|
||||||
|
<div className={styles.leftActionItem} key={index}>
|
||||||
|
{child}
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
|
||||||
|
const titleEl = (
|
||||||
|
<>
|
||||||
|
<span className={styles.noLinkTitle}>{title}</span>
|
||||||
|
{section && <span className={styles.pre}> / {section}</span>}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={mainStyle} aria-label={ariaLabel}>
|
<nav className={mainStyle} aria-label={ariaLabel}>
|
||||||
{pageIcon && !onGoBack && (
|
<div className={styles.leftWrapper}>
|
||||||
<div className={styles.pageIcon}>
|
{pageIcon && !onGoBack && (
|
||||||
<Icon name={pageIcon} size="lg" aria-hidden />
|
<div className={styles.pageIcon}>
|
||||||
</div>
|
<Icon name={pageIcon} size="lg" aria-hidden />
|
||||||
)}
|
</div>
|
||||||
{onGoBack && (
|
|
||||||
<div className={styles.pageIcon}>
|
|
||||||
<IconButton
|
|
||||||
name="arrow-left"
|
|
||||||
tooltip="Go back (Esc)"
|
|
||||||
tooltipPlacement="bottom"
|
|
||||||
size="xxl"
|
|
||||||
aria-label={selectors.components.BackButton.backArrow}
|
|
||||||
onClick={onGoBack}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<nav aria-label="Search links" className={styles.navElement}>
|
|
||||||
{parent && parentHref && (
|
|
||||||
<>
|
|
||||||
<Link
|
|
||||||
aria-label={`Search dashboard in the ${parent} folder`}
|
|
||||||
className={cx(styles.titleText, styles.parentLink, styles.titleLink)}
|
|
||||||
href={parentHref}
|
|
||||||
>
|
|
||||||
{parent} <span className={styles.parentIcon}></span>
|
|
||||||
</Link>
|
|
||||||
{titleHref && (
|
|
||||||
<span className={cx(styles.titleText, styles.titleDivider, styles.parentLink)} aria-hidden>
|
|
||||||
/
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
{onGoBack && (
|
||||||
{title && titleHref && (
|
<div className={styles.pageIcon}>
|
||||||
<h1 className={styles.h1Styles}>
|
<IconButton
|
||||||
<Link
|
name="arrow-left"
|
||||||
aria-label="Search dashboard by name"
|
tooltip="Go back (Esc)"
|
||||||
className={cx(styles.titleText, styles.titleLink)}
|
tooltipPlacement="bottom"
|
||||||
href={titleHref}
|
size="xxl"
|
||||||
>
|
aria-label={selectors.components.BackButton.backArrow}
|
||||||
{title}
|
onClick={onGoBack}
|
||||||
</Link>
|
/>
|
||||||
</h1>
|
</div>
|
||||||
)}
|
)}
|
||||||
{title && !titleHref && <h1 className={styles.titleText}>{title}</h1>}
|
<nav aria-label="Search links" className={styles.navElement}>
|
||||||
</nav>
|
{parent && parentHref && (
|
||||||
{leftItems?.map((child, index) => (
|
<>
|
||||||
<div className={styles.leftActionItem} key={index}>
|
<Link
|
||||||
{child}
|
aria-label={`Search dashboard in the ${parent} folder`}
|
||||||
</div>
|
className={cx(styles.titleText, styles.parentLink, styles.titleLink)}
|
||||||
))}
|
href={parentHref}
|
||||||
|
>
|
||||||
|
{parent} <span className={styles.parentIcon}></span>
|
||||||
|
</Link>
|
||||||
|
{titleHref && (
|
||||||
|
<span className={cx(styles.titleText, styles.titleDivider, styles.parentLink)} aria-hidden>
|
||||||
|
/
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={styles.spacer} />
|
{title && (
|
||||||
|
<div className={styles.titleWrapper}>
|
||||||
|
<h1 className={styles.h1Styles}>
|
||||||
|
{titleHref ? (
|
||||||
|
<Link
|
||||||
|
aria-label="Search dashboard by name"
|
||||||
|
className={cx(styles.titleText, styles.titleLink)}
|
||||||
|
href={titleHref}
|
||||||
|
>
|
||||||
|
{titleEl}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className={styles.titleText}>{titleEl}</div>
|
||||||
|
)}
|
||||||
|
</h1>
|
||||||
|
{leftItemChildren}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
{React.Children.toArray(children)
|
{React.Children.toArray(children)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.map((child, index) => {
|
.map((child, index) => {
|
||||||
@@ -136,21 +152,11 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
const { spacing, typography } = theme;
|
const { spacing, typography } = theme;
|
||||||
|
|
||||||
const focusStyle = getFocusStyles(theme);
|
const focusStyle = getFocusStyles(theme);
|
||||||
const titleStyles = css`
|
|
||||||
font-size: ${typography.size.lg};
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0;
|
|
||||||
max-width: 240px;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
@media ${styleMixins.mediaUp(theme.v1.breakpoints.xl)} {
|
|
||||||
max-width: unset;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
pre: css`
|
||||||
|
white-space: pre;
|
||||||
|
`,
|
||||||
toolbar: css`
|
toolbar: css`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: ${theme.colors.background.canvas};
|
background: ${theme.colors.background.canvas};
|
||||||
@@ -159,7 +165,9 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding: ${theme.spacing(1.5, 2)};
|
padding: ${theme.spacing(1.5, 2)};
|
||||||
`,
|
`,
|
||||||
spacer: css`
|
leftWrapper: css`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
`,
|
`,
|
||||||
pageIcon: css`
|
pageIcon: css`
|
||||||
@@ -170,24 +178,38 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
noLinkTitle: css`
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
`,
|
||||||
titleWrapper: css`
|
titleWrapper: css`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-grow: 1;
|
||||||
min-width: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
|
||||||
`,
|
`,
|
||||||
navElement: css`
|
navElement: css`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
align-items: center;
|
||||||
|
max-width: calc(100vw - 78px);
|
||||||
`,
|
`,
|
||||||
h1Styles: css`
|
h1Styles: css`
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
display: flex;
|
width: 300px;
|
||||||
|
max-width: min-content;
|
||||||
|
flex-grow: 1;
|
||||||
`,
|
`,
|
||||||
parentIcon: css`
|
parentIcon: css`
|
||||||
margin-left: ${theme.spacing(0.5)};
|
margin-left: ${theme.spacing(0.5)};
|
||||||
`,
|
`,
|
||||||
titleText: titleStyles,
|
titleText: css`
|
||||||
|
display: flex;
|
||||||
|
font-size: ${typography.size.lg};
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 2px;
|
||||||
|
`,
|
||||||
titleLink: css`
|
titleLink: css`
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
${focusStyle}
|
${focusStyle}
|
||||||
|
|||||||
@@ -42,7 +42,11 @@ describe('DashboardSettings', () => {
|
|||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByText('Foo / Settings')).toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText(
|
||||||
|
(_, el) => el?.tagName.toLowerCase() === 'h1' && /Foo\s*\/\s*Settings/.test(el?.textContent ?? '')
|
||||||
|
)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
await userEvent.keyboard('{Escape}');
|
await userEvent.keyboard('{Escape}');
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,13 @@ export function DashboardSettings({ dashboard, editview }: Props) {
|
|||||||
return (
|
return (
|
||||||
<FocusScope contain autoFocus>
|
<FocusScope contain autoFocus>
|
||||||
<div className="dashboard-settings" ref={ref} {...overlayProps} {...dialogProps}>
|
<div className="dashboard-settings" ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
<PageToolbar title={`${dashboard.title} / Settings`} parent={folderTitle} onGoBack={onClose} />
|
<PageToolbar
|
||||||
|
className={styles.toolbar}
|
||||||
|
title={dashboard.title}
|
||||||
|
section="Settings"
|
||||||
|
parent={folderTitle}
|
||||||
|
onGoBack={onClose}
|
||||||
|
/>
|
||||||
<CustomScrollbar>
|
<CustomScrollbar>
|
||||||
<div className={styles.scrollInner}>
|
<div className={styles.scrollInner}>
|
||||||
<div className={styles.settingsWrapper}>
|
<div className={styles.settingsWrapper}>
|
||||||
@@ -200,6 +206,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => ({
|
|||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
`,
|
`,
|
||||||
|
toolbar: css`
|
||||||
|
width: 60vw;
|
||||||
|
min-width: min-content;
|
||||||
|
`,
|
||||||
settingsWrapper: css`
|
settingsWrapper: css`
|
||||||
margin: ${theme.spacing(0, 2, 2)};
|
margin: ${theme.spacing(0, 2, 2)};
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper} aria-label={selectors.components.PanelEditor.General.content}>
|
<div className={styles.wrapper} aria-label={selectors.components.PanelEditor.General.content}>
|
||||||
<PageToolbar title={`${dashboard.title} / Edit Panel`} onGoBack={this.onGoBackToDashboard}>
|
<PageToolbar title={dashboard.title} section="Edit Panel" onGoBack={this.onGoBackToDashboard}>
|
||||||
{this.renderEditorActions()}
|
{this.renderEditorActions()}
|
||||||
</PageToolbar>
|
</PageToolbar>
|
||||||
<div className={styles.verticalSplitPanesWrapper}>
|
<div className={styles.verticalSplitPanesWrapper}>
|
||||||
|
|||||||
Reference in New Issue
Block a user