mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 23:55:47 -06:00
Chore: Migrate DashboardRow
SCSS styles (#88768)
migrate dashboard-row styles
This commit is contained in:
parent
372c9d46d5
commit
c6d07194cc
@ -2,11 +2,13 @@ import { screen, render } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { createTheme } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/types';
|
||||
|
||||
import { PanelModel } from '../../state/PanelModel';
|
||||
|
||||
import { DashboardRow } from './DashboardRow';
|
||||
import { DashboardRow, UnthemedDashboardRow } from './DashboardRow';
|
||||
|
||||
describe('DashboardRow', () => {
|
||||
let panel: PanelModel, dashboardMock: any;
|
||||
@ -25,18 +27,18 @@ describe('DashboardRow', () => {
|
||||
panel = new PanelModel({ collapsed: false });
|
||||
});
|
||||
|
||||
it('Should not have collapsed class when collaped is false', () => {
|
||||
it('Should correctly show expanded state when the panel is expanded', () => {
|
||||
render(<DashboardRow panel={panel} dashboard={dashboardMock} />);
|
||||
const row = screen.getByTestId('dashboard-row-container');
|
||||
const row = screen.getByTestId(selectors.components.DashboardRow.title(''));
|
||||
expect(row).toBeInTheDocument();
|
||||
expect(row).not.toHaveClass('dashboard-row--collapsed');
|
||||
expect(row).toHaveAttribute('aria-expanded', 'true');
|
||||
});
|
||||
|
||||
it('Should collapse when the panel is collapsed', async () => {
|
||||
it('Should correctly show expanded state when the panel is collapsed', async () => {
|
||||
const panel = new PanelModel({ collapsed: true });
|
||||
render(<DashboardRow panel={panel} dashboard={dashboardMock} />);
|
||||
const row = screen.getByTestId('dashboard-row-container');
|
||||
expect(row).toHaveClass('dashboard-row--collapsed');
|
||||
const row = screen.getByTestId(selectors.components.DashboardRow.title(''));
|
||||
expect(row).toHaveAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
it('Should collapse after clicking title', async () => {
|
||||
@ -79,7 +81,7 @@ describe('DashboardRow', () => {
|
||||
},
|
||||
});
|
||||
const rowPanel = new PanelModel({ collapsed: true, panels: [panel] });
|
||||
const dashboardRow = new DashboardRow({ panel: rowPanel, dashboard: dashboardMock });
|
||||
const dashboardRow = new UnthemedDashboardRow({ panel: rowPanel, dashboard: dashboardMock, theme: createTheme() });
|
||||
expect(dashboardRow.getWarning()).toBeDefined();
|
||||
});
|
||||
|
||||
@ -91,7 +93,7 @@ describe('DashboardRow', () => {
|
||||
},
|
||||
});
|
||||
const rowPanel = new PanelModel({ collapsed: true, panels: [panel] });
|
||||
const dashboardRow = new DashboardRow({ panel: rowPanel, dashboard: dashboardMock });
|
||||
const dashboardRow = new UnthemedDashboardRow({ panel: rowPanel, dashboard: dashboardMock, theme: createTheme() });
|
||||
expect(dashboardRow.getWarning()).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
@ -1,11 +1,12 @@
|
||||
import classNames from 'classnames';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { indexOf } from 'lodash';
|
||||
import React from 'react';
|
||||
import { Unsubscribable } from 'rxjs';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
|
||||
import { Icon, TextLink } from '@grafana/ui';
|
||||
import { Icon, TextLink, Themeable2, withTheme2 } from '@grafana/ui';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/types';
|
||||
|
||||
@ -14,12 +15,12 @@ import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { PanelModel } from '../../state/PanelModel';
|
||||
import { RowOptionsButton } from '../RowOptions/RowOptionsButton';
|
||||
|
||||
export interface DashboardRowProps {
|
||||
export interface DashboardRowProps extends Themeable2 {
|
||||
panel: PanelModel;
|
||||
dashboard: DashboardModel;
|
||||
}
|
||||
|
||||
export class DashboardRow extends React.Component<DashboardRowProps> {
|
||||
export class UnthemedDashboardRow extends React.Component<DashboardRowProps> {
|
||||
sub?: Unsubscribable;
|
||||
|
||||
componentDidMount() {
|
||||
@ -93,32 +94,39 @@ export class DashboardRow extends React.Component<DashboardRowProps> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const classes = classNames({
|
||||
'dashboard-row': true,
|
||||
'dashboard-row--collapsed': this.props.panel.collapsed,
|
||||
});
|
||||
|
||||
const title = getTemplateSrv().replace(this.props.panel.title, this.props.panel.scopedVars, 'text');
|
||||
const count = this.props.panel.panels ? this.props.panel.panels.length : 0;
|
||||
const panels = count === 1 ? 'panel' : 'panels';
|
||||
const canEdit = this.props.dashboard.meta.canEdit === true;
|
||||
const collapsed = this.props.panel.collapsed;
|
||||
const styles = getStyles(this.props.theme);
|
||||
|
||||
return (
|
||||
<div className={classes} data-testid="dashboard-row-container">
|
||||
<div
|
||||
className={cx(styles.dashboardRow, {
|
||||
[styles.dashboardRowCollapsed]: collapsed,
|
||||
})}
|
||||
data-testid="dashboard-row-container"
|
||||
>
|
||||
<button
|
||||
className="dashboard-row__title pointer"
|
||||
aria-expanded={!collapsed}
|
||||
className={cx(styles.title, 'pointer')}
|
||||
type="button"
|
||||
data-testid={selectors.components.DashboardRow.title(title)}
|
||||
onClick={this.onToggle}
|
||||
>
|
||||
<Icon name={this.props.panel.collapsed ? 'angle-right' : 'angle-down'} />
|
||||
<Icon name={collapsed ? 'angle-right' : 'angle-down'} />
|
||||
{title}
|
||||
<span className="dashboard-row__panel_count">
|
||||
<span
|
||||
className={cx(styles.count, {
|
||||
[styles.countCollapsed]: collapsed,
|
||||
})}
|
||||
>
|
||||
({count} {panels})
|
||||
</span>
|
||||
</button>
|
||||
{canEdit && (
|
||||
<div className="dashboard-row__actions">
|
||||
<div className={styles.actions}>
|
||||
<RowOptionsButton
|
||||
title={this.props.panel.title}
|
||||
repeat={this.props.panel.repeat}
|
||||
@ -130,16 +138,114 @@ export class DashboardRow extends React.Component<DashboardRowProps> {
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{this.props.panel.collapsed === true && (
|
||||
{collapsed === true && (
|
||||
/* disabling the a11y rules here as the button handles keyboard interactions */
|
||||
/* this is just to provide a better experience for mouse users */
|
||||
/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
|
||||
<div className="dashboard-row__toggle-target" onClick={this.onToggle}>
|
||||
<div
|
||||
className={cx({
|
||||
[styles.toggleTargetCollapsed]: collapsed,
|
||||
})}
|
||||
onClick={this.onToggle}
|
||||
>
|
||||
|
||||
</div>
|
||||
)}
|
||||
{canEdit && <div data-testid="dashboard-row-drag" className="dashboard-row__drag grid-drag-handle" />}
|
||||
{canEdit && (
|
||||
<div
|
||||
data-testid="dashboard-row-drag"
|
||||
className={cx(styles.dragHandle, 'grid-drag-handle', {
|
||||
[styles.dragHandleCollapsed]: collapsed,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const DashboardRow = withTheme2(UnthemedDashboardRow);
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
const actions = css({
|
||||
color: theme.colors.text.secondary,
|
||||
opacity: 0,
|
||||
[theme.transitions.handleMotion('no-preference', 'reduce')]: {
|
||||
transition: '200ms opacity ease-in 200ms',
|
||||
},
|
||||
|
||||
button: {
|
||||
color: theme.colors.text.secondary,
|
||||
paddingLeft: theme.spacing(2),
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
|
||||
'&:hover': {
|
||||
color: theme.colors.text.maxContrast,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
dashboardRow: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
|
||||
'&:hover, &:focus-within': {
|
||||
[`.${actions}`]: {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
dashboardRowCollapsed: css({
|
||||
background: theme.components.panel.background,
|
||||
}),
|
||||
toggleTargetCollapsed: css({
|
||||
flex: 1,
|
||||
cursor: 'pointer',
|
||||
marginRight: '15px',
|
||||
}),
|
||||
title: css({
|
||||
flexGrow: 0,
|
||||
fontSize: theme.typography.h5.fontSize,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
color: theme.colors.text.primary,
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
|
||||
'.fa': {
|
||||
color: theme.colors.text.secondary,
|
||||
fontSize: theme.typography.size.xs,
|
||||
padding: theme.spacing(0, 1),
|
||||
},
|
||||
}),
|
||||
actions,
|
||||
count: css({
|
||||
paddingLeft: theme.spacing(2),
|
||||
color: theme.colors.text.secondary,
|
||||
fontStyle: 'italic',
|
||||
fontSize: theme.typography.size.sm,
|
||||
fontWeight: 'normal',
|
||||
display: 'none',
|
||||
}),
|
||||
countCollapsed: css({
|
||||
display: 'inline-block',
|
||||
}),
|
||||
dragHandle: css({
|
||||
cursor: 'move',
|
||||
width: '16px',
|
||||
height: '100%',
|
||||
background: 'url("public/img/grab_dark.svg") no-repeat 50% 50%',
|
||||
backgroundSize: '8px',
|
||||
visibility: 'hidden',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
}),
|
||||
dragHandleCollapsed: css({
|
||||
visibility: 'visible',
|
||||
opacity: 1,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
@ -39,7 +39,6 @@
|
||||
@import 'components/query_editor';
|
||||
@import 'components/tabbed_view';
|
||||
@import 'components/query_part';
|
||||
@import 'components/row';
|
||||
@import 'components/json_explorer';
|
||||
@import 'components/dashboard_grid';
|
||||
@import 'components/add_data_source';
|
||||
|
@ -1,85 +0,0 @@
|
||||
.dashboard-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 100%;
|
||||
|
||||
&--collapsed {
|
||||
background: $panel-bg;
|
||||
|
||||
.dashboard-row__panel_count {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.dashboard-row__drag {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.dashboard-row__toggle-target {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
.dashboard-row__actions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-row__title {
|
||||
flex-grow: 0;
|
||||
font-size: $font-size-h5;
|
||||
font-weight: $font-weight-semi-bold;
|
||||
color: $text-color;
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
||||
.fa {
|
||||
color: $text-muted;
|
||||
font-size: $font-size-xs;
|
||||
padding: 0 $space-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-row__actions {
|
||||
color: $text-muted;
|
||||
opacity: 0;
|
||||
transition: 200ms opacity ease-in 200ms;
|
||||
|
||||
button {
|
||||
color: $text-color-weak;
|
||||
padding-left: $spacer;
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
color: $link-hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-row__panel_count {
|
||||
padding-left: $spacer;
|
||||
color: $text-color-weak;
|
||||
font-style: italic;
|
||||
font-size: $font-size-sm;
|
||||
font-weight: normal;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-row__drag {
|
||||
cursor: move;
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
background: url('../img/grab_dark.svg') no-repeat 50% 50%;
|
||||
background-size: 8px;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user