DashboardScene: Simplify controls a bit (#82908)

* DashboardScene: Simplify controls a bit

* update tests

* more test updates

* Update

* improvements

* Fix

* Fix merge

* Update

* update
This commit is contained in:
Torkel Ödegaard 2024-02-20 08:43:02 +01:00 committed by GitHub
parent 57499845c2
commit 6db2d1a411
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 115 additions and 331 deletions

View File

@ -65,13 +65,7 @@ function EmbeddedDashboardRenderer({ model, initialState, onStateChange }: Rende
return (
<div className={styles.canvas}>
{controls && (
<div className={styles.controls}>
{controls.map((control) => (
<control.Component key={control.state.key} model={control} />
))}
</div>
)}
{controls && <controls.Component model={controls} />}
<div className={styles.body}>
<body.Component model={body} />
</div>

View File

@ -37,13 +37,7 @@ export function PanelEditorRenderer({ model }: SceneComponentProps<PanelEditor>)
>
<div className={styles.body}>
<div className={styles.canvasContent}>
{controls && (
<div className={styles.controls}>
{controls.map((control) => (
<control.Component key={control.state.key} model={control} />
))}
</div>
)}
{controls && <controls.Component model={controls} />}
<Splitter
direction="column"
primaryPaneStyles={{ minHeight: 0, paddingBottom: !dataPane ? 16 : 0 }}

View File

@ -1,41 +1,89 @@
import { css, cx } from '@emotion/css';
import React from 'react';
import { SceneObjectState, SceneObject, SceneObjectBase, SceneComponentProps } from '@grafana/scenes';
import { Box, Stack } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import {
SceneObjectState,
SceneObject,
SceneObjectBase,
SceneComponentProps,
SceneTimePicker,
SceneRefreshPicker,
SceneDebugger,
} from '@grafana/scenes';
import { Box, Stack, useStyles2 } from '@grafana/ui';
import { getDashboardSceneFor } from '../utils/utils';
import { DashboardLinksControls } from './DashboardLinksControls';
interface DashboardControlsState extends SceneObjectState {
variableControls: SceneObject[];
timeControls: SceneObject[];
linkControls: DashboardLinksControls;
timePicker: SceneTimePicker;
refreshPicker: SceneRefreshPicker;
hideTimeControls?: boolean;
}
export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
static Component = DashboardControlsRenderer;
public constructor(state: Partial<DashboardControlsState>) {
super({
variableControls: [],
timePicker: state.timePicker ?? new SceneTimePicker({}),
refreshPicker: state.refreshPicker ?? new SceneRefreshPicker({}),
...state,
});
}
}
function DashboardControlsRenderer({ model }: SceneComponentProps<DashboardControls>) {
const { variableControls, linkControls, timeControls, hideTimeControls } = model.useState();
const { variableControls, refreshPicker, timePicker, hideTimeControls } = model.useState();
const dashboard = getDashboardSceneFor(model);
const { links, meta, editPanel } = dashboard.useState();
const styles = useStyles2(getStyles);
const showDebugger = location.search.includes('scene-debugger');
return (
<Stack
grow={1}
direction={{
md: 'row',
xs: 'column',
}}
>
<div className={cx(styles.controls, meta.isEmbedded && styles.embedded)}>
<Stack grow={1} wrap={'wrap'}>
{variableControls.map((c) => (
<c.Component model={c} key={c.state.key} />
))}
<Box grow={1} />
<linkControls.Component model={linkControls} />
{!editPanel && <DashboardLinksControls links={links} uid={dashboard.state.uid} />}
</Stack>
<Stack justifyContent={'flex-end'}>
{!hideTimeControls && timeControls.map((c) => <c.Component model={c} key={c.state.key} />)}
</Stack>
</Stack>
{!hideTimeControls && (
<Stack justifyContent={'flex-end'}>
<timePicker.Component model={timePicker} />
<refreshPicker.Component model={refreshPicker} />
</Stack>
)}
{showDebugger && <SceneDebugger scene={model} key={'scene-debugger'} />}
</div>
);
}
function getStyles(theme: GrafanaTheme2) {
return {
controls: css({
display: 'flex',
alignItems: 'flex-start',
gap: theme.spacing(1),
position: 'sticky',
top: 0,
background: theme.colors.background.canvas,
zIndex: theme.zIndex.activePanel,
padding: theme.spacing(2, 0),
width: '100%',
marginLeft: 'auto',
[theme.breakpoints.down('sm')]: {
flexDirection: 'column-reverse',
alignItems: 'stretch',
},
}),
embedded: css({
background: 'unset',
position: 'unset',
}),
};
}

View File

@ -2,7 +2,6 @@ import React from 'react';
import { sanitizeUrl } from '@grafana/data/src/text/sanitize';
import { selectors } from '@grafana/e2e-selectors';
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
import { DashboardLink } from '@grafana/schema';
import { Tooltip } from '@grafana/ui';
import {
@ -12,17 +11,13 @@ import {
import { getLinkSrv } from 'app/features/panel/panellinks/link_srv';
import { LINK_ICON_MAP } from '../settings/links/utils';
import { getDashboardSceneFor } from '../utils/utils';
interface DashboardLinksControlsState extends SceneObjectState {}
export class DashboardLinksControls extends SceneObjectBase<DashboardLinksControlsState> {
static Component = DashboardLinksControlsRenderer;
export interface Props {
links: DashboardLink[];
uid?: string;
}
function DashboardLinksControlsRenderer({ model }: SceneComponentProps<DashboardLinksControls>) {
const { links, uid } = getDashboardSceneFor(model).useState();
export function DashboardLinksControls({ links, uid }: Props) {
if (!links || !uid) {
return null;
}

View File

@ -3,7 +3,6 @@ import {
sceneGraph,
SceneGridItem,
SceneGridLayout,
SceneRefreshPicker,
SceneTimeRange,
SceneQueryRunner,
SceneVariableSet,
@ -22,7 +21,6 @@ import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
import { djb2Hash } from '../utils/djb2Hash';
import { DashboardControls } from './DashboardControls';
import { DashboardLinksControls } from './DashboardLinksControls';
import { DashboardScene, DashboardSceneState } from './DashboardScene';
jest.mock('../settings/version-history/HistorySrv');
@ -94,14 +92,14 @@ describe('DashboardScene', () => {
});
it('A change to time picker visibility settings should set isDirty true', () => {
const dashboardControls = dashboardSceneGraph.getDashboardControls(scene)!;
const dashboardControls = scene.state.controls!;
const prevState = dashboardControls.state.hideTimeControls;
dashboardControls.setState({ hideTimeControls: true });
expect(scene.state.isDirty).toBe(true);
scene.exitEditMode({ skipConfirm: true });
expect(dashboardSceneGraph.getDashboardControls(scene)!.state.hideTimeControls).toEqual(prevState);
expect(scene.state.controls!.state.hideTimeControls).toEqual(prevState);
});
it('A change to time zone should set isDirty true', () => {
@ -217,17 +215,7 @@ function buildTestScene(overrides?: Partial<DashboardSceneState>) {
$timeRange: new SceneTimeRange({
timeZone: 'browser',
}),
controls: [
new DashboardControls({
variableControls: [],
linkControls: new DashboardLinksControls({}),
timeControls: [
new SceneRefreshPicker({
intervals: ['1s'],
}),
],
}),
],
controls: new DashboardControls({}),
body: new SceneGridLayout({
children: [
new SceneGridItem({

View File

@ -75,7 +75,7 @@ export interface DashboardSceneState extends SceneObjectState {
/** NavToolbar actions */
actions?: SceneObject[];
/** Fixed row at the top of the canvas with for example variables and time range controls */
controls?: SceneObject[];
controls?: DashboardControls;
/** True when editing */
isEditing?: boolean;
/** True when user made a change */

View File

@ -3,7 +3,7 @@ import React from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
import { SceneComponentProps, SceneDebugger } from '@grafana/scenes';
import { SceneComponentProps } from '@grafana/scenes';
import { CustomScrollbar, useStyles2 } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { getNavModel } from 'app/core/selectors/navModel';
@ -21,7 +21,6 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
const pageNav = model.getPageNav(location, navIndex);
const bodyToRender = model.getBodyToRender();
const navModel = getNavModel(navIndex, 'dashboards/browse');
const showDebugger = location.search.includes('scene-debugger');
if (editview) {
return (
@ -32,23 +31,11 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
);
}
const emptyState = (
<>
<div className={styles.controls}>{showDebugger && <SceneDebugger scene={model} key={'scene-debugger'} />}</div>
<DashboardEmpty dashboard={model} canCreate={!!model.state.meta.canEdit} />
</>
);
const emptyState = <DashboardEmpty dashboard={model} canCreate={!!model.state.meta.canEdit} />;
const withPanels = (
<>
{controls && (
<div className={styles.controls}>
{controls.map((control) => (
<control.Component key={control.state.key} model={control} />
))}
{showDebugger && <SceneDebugger scene={model} key={'scene-debugger'} />}
</div>
)}
{controls && <controls.Component model={controls} />}
<div className={cx(styles.body)}>
<bodyToRender.Component model={bodyToRender} />
</div>
@ -88,18 +75,5 @@ function getStyles(theme: GrafanaTheme2) {
gap: '8px',
marginBottom: theme.spacing(2),
}),
controls: css({
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
gap: theme.spacing(1),
position: 'sticky',
top: 0,
background: theme.colors.background.canvas,
zIndex: theme.zIndex.activePanel,
padding: theme.spacing(2, 0),
marginLeft: 'auto',
}),
};
}

View File

@ -26,8 +26,6 @@ import {
SceneGridLayout,
SceneGridRow,
SceneQueryRunner,
SceneRefreshPicker,
SceneTimePicker,
VizPanel,
} from '@grafana/scenes';
import {
@ -44,7 +42,6 @@ import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
import { DASHBOARD_DATASOURCE_PLUGIN_ID } from 'app/plugins/datasource/dashboard/types';
import { DashboardDataDTO } from 'app/types';
import { DashboardControls } from '../scene/DashboardControls';
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
import { PanelTimeRange } from '../scene/PanelTimeRange';
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
@ -112,7 +109,7 @@ describe('transformSaveModelToScene', () => {
const oldModel = new DashboardModel(dash);
const scene = createDashboardSceneFromDashboardModel(oldModel);
const dashboardControls = scene.state.controls![0] as DashboardControls;
const dashboardControls = scene.state.controls!;
expect(scene.state.title).toBe('test');
expect(scene.state.uid).toBe('test-uid');
@ -127,13 +124,8 @@ describe('transformSaveModelToScene', () => {
expect(scene.state?.$variables?.getByName('constant')).toBeInstanceOf(ConstantVariable);
expect(scene.state?.$variables?.getByName('CoolFilters')).toBeInstanceOf(AdHocFiltersVariable);
expect(dashboardControls).toBeDefined();
expect(dashboardControls).toBeInstanceOf(DashboardControls);
expect(dashboardControls.state.timeControls).toHaveLength(2);
expect(dashboardControls.state.timeControls[0]).toBeInstanceOf(SceneTimePicker);
expect(dashboardControls.state.timeControls[1]).toBeInstanceOf(SceneRefreshPicker);
expect((dashboardControls.state.timeControls[1] as SceneRefreshPicker).state.intervals).toEqual(
defaultTimePickerConfig.refresh_intervals
);
expect(dashboardControls.state.refreshPicker.state.intervals).toEqual(defaultTimePickerConfig.refresh_intervals);
expect(dashboardControls.state.hideTimeControls).toBe(true);
});
@ -1039,9 +1031,7 @@ describe('transformSaveModelToScene', () => {
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} });
expect(scene.state.$data).toBeInstanceOf(SceneDataLayers);
expect((scene.state.controls![0] as DashboardControls)!.state.variableControls[1]).toBeInstanceOf(
SceneDataLayerControls
);
expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls);
const dataLayers = scene.state.$data as SceneDataLayers;
expect(dataLayers.state.layers).toHaveLength(4);
@ -1069,9 +1059,7 @@ describe('transformSaveModelToScene', () => {
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} });
expect(scene.state.$data).toBeInstanceOf(SceneDataLayers);
expect((scene.state.controls![0] as DashboardControls)!.state.variableControls[1]).toBeInstanceOf(
SceneDataLayerControls
);
expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls);
const dataLayers = scene.state.$data as SceneDataLayers;
expect(dataLayers.state.layers).toHaveLength(5);
@ -1085,9 +1073,7 @@ describe('transformSaveModelToScene', () => {
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} });
expect(scene.state.$data).toBeInstanceOf(SceneDataLayers);
expect((scene.state.controls![0] as DashboardControls)!.state.variableControls[1]).toBeInstanceOf(
SceneDataLayerControls
);
expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls);
const dataLayers = scene.state.$data as SceneDataLayers;
expect(dataLayers.state.layers).toHaveLength(5);

View File

@ -36,7 +36,6 @@ import { DashboardDTO } from 'app/types';
import { AlertStatesDataLayer } from '../scene/AlertStatesDataLayer';
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
import { DashboardControls } from '../scene/DashboardControls';
import { DashboardLinksControls } from '../scene/DashboardLinksControls';
import { registerDashboardMacro } from '../scene/DashboardMacro';
import { DashboardScene } from '../scene/DashboardScene';
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
@ -268,21 +267,16 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
layers,
})
: undefined,
controls: [
new DashboardControls({
variableControls: [new VariableValueSelectors({}), new SceneDataLayerControls()],
timeControls: [
new SceneTimePicker({}),
new SceneRefreshPicker({
refresh: oldModel.refresh,
intervals: oldModel.timepicker.refresh_intervals,
withText: true,
}),
],
linkControls: new DashboardLinksControls({}),
hideTimeControls: oldModel.timepicker.hidden,
controls: new DashboardControls({
variableControls: [new VariableValueSelectors({}), new SceneDataLayerControls()],
timePicker: new SceneTimePicker({}),
refreshPicker: new SceneRefreshPicker({
refresh: oldModel.refresh,
intervals: oldModel.timepicker.refresh_intervals,
withText: true,
}),
],
hideTimeControls: oldModel.timepicker.hidden,
}),
});
return dashboardScene;

View File

@ -12,7 +12,6 @@ import {
SceneDataTransformer,
SceneVariableSet,
LocalValueVariable,
SceneRefreshPicker,
} from '@grafana/scenes';
import {
AnnotationQuery,
@ -34,7 +33,6 @@ import { getPanelDataFrames } from 'app/features/dashboard/components/HelpWizard
import { DASHBOARD_SCHEMA_VERSION } from 'app/features/dashboard/state/DashboardMigrator';
import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
import { DashboardControls } from '../scene/DashboardControls';
import { DashboardScene } from '../scene/DashboardScene';
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
@ -54,9 +52,6 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa
const variablesSet = state.$variables;
const body = state.body;
let refreshIntervals: string[] | undefined;
let hideTimePicker: boolean | undefined;
let panels: Panel[] = [];
let graphTooltip = defaultDashboard.graphTooltip;
let variables: VariableModel[] = [];
@ -92,16 +87,7 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa
variables = sceneVariablesSetToVariables(variablesSet);
}
if (state.controls && state.controls[0] instanceof DashboardControls) {
hideTimePicker = state.controls[0].state.hideTimeControls;
const timeControls = state.controls[0].state.timeControls;
for (const control of timeControls) {
if (control instanceof SceneRefreshPicker && control.state.intervals) {
refreshIntervals = control.state.intervals;
}
}
}
const controlsState = state.controls?.state;
if (state.$behaviors) {
for (const behavior of state.$behaviors!) {
@ -113,8 +99,8 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa
const timePickerWithoutDefaults = removeDefaults<TimePickerConfig>(
{
refresh_intervals: refreshIntervals,
hidden: hideTimePicker,
refresh_intervals: controlsState?.refreshPicker.state.intervals,
hidden: controlsState?.hideTimeControls,
nowDelay: timeRange.UNSAFE_nowDelay,
},
defaultTimePickerConfig

View File

@ -2,18 +2,10 @@ import { render as RTLRender } from '@testing-library/react';
import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import {
behaviors,
SceneGridLayout,
SceneGridItem,
SceneRefreshPicker,
SceneTimeRange,
SceneTimePicker,
} from '@grafana/scenes';
import { behaviors, SceneGridLayout, SceneGridItem, SceneTimeRange } from '@grafana/scenes';
import { DashboardCursorSync } from '@grafana/schema';
import { DashboardControls } from '../scene/DashboardControls';
import { DashboardLinksControls } from '../scene/DashboardLinksControls';
import { DashboardScene } from '../scene/DashboardScene';
import { activateFullSceneTree } from '../utils/test-utils';
@ -225,18 +217,7 @@ async function buildTestScene() {
const dashboard = new DashboardScene({
$timeRange: new SceneTimeRange({}),
$behaviors: [new behaviors.CursorSync({ sync: DashboardCursorSync.Off })],
controls: [
new DashboardControls({
variableControls: [],
linkControls: new DashboardLinksControls({}),
timeControls: [
new SceneTimePicker({}),
new SceneRefreshPicker({
intervals: ['1s'],
}),
],
}),
],
controls: new DashboardControls({}),
title: 'hello',
uid: 'dash-1',
meta: {

View File

@ -1,15 +1,7 @@
import {
behaviors,
SceneGridLayout,
SceneGridItem,
SceneRefreshPicker,
SceneTimeRange,
SceneTimePicker,
} from '@grafana/scenes';
import { behaviors, SceneGridLayout, SceneGridItem, SceneTimeRange } from '@grafana/scenes';
import { DashboardCursorSync } from '@grafana/schema';
import { DashboardControls } from '../scene/DashboardControls';
import { DashboardLinksControls } from '../scene/DashboardLinksControls';
import { DashboardScene } from '../scene/DashboardScene';
import { activateFullSceneTree } from '../utils/test-utils';
@ -38,19 +30,9 @@ describe('GeneralSettingsEditView', () => {
expect(settings.getTimeRange()).toBe(dashboard.state.$timeRange);
});
it('should return the dashboard refresh picker', () => {
expect(settings.getRefreshPicker()).toBe(
(dashboard.state?.controls?.[0] as DashboardControls)?.state?.timeControls?.[1]
);
});
it('should return the cursor sync', () => {
expect(settings.getCursorSync()).toBe(dashboard.state.$behaviors?.[0]);
});
it('should return the dashboard controls', () => {
expect(settings.getDashboardControls()).toBe(dashboard.state.controls?.[0]);
});
});
describe('Dashboard updates', () => {
@ -133,18 +115,7 @@ async function buildTestScene() {
const dashboard = new DashboardScene({
$timeRange: new SceneTimeRange({}),
$behaviors: [new behaviors.CursorSync({ sync: DashboardCursorSync.Off })],
controls: [
new DashboardControls({
variableControls: [],
linkControls: new DashboardLinksControls({}),
timeControls: [
new SceneTimePicker({}),
new SceneRefreshPicker({
intervals: ['1s'],
}),
],
}),
],
controls: new DashboardControls({}),
title: 'hello',
uid: 'dash-1',
meta: {

View File

@ -22,7 +22,6 @@ import { DeleteDashboardButton } from 'app/features/dashboard/components/DeleteD
import { DashboardScene } from '../scene/DashboardScene';
import { NavToolbarActions } from '../scene/NavToolbarActions';
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
import { getDashboardSceneFor } from '../utils/utils';
import { DashboardEditView, DashboardEditViewState, useDashboardEditPageNav } from './utils';
@ -61,7 +60,7 @@ export class GeneralSettingsEditView
}
public getRefreshPicker() {
return dashboardSceneGraph.getRefreshPicker(this._dashboard);
return this.getDashboardControls().state.refreshPicker;
}
public getCursorSync() {
@ -75,7 +74,7 @@ export class GeneralSettingsEditView
}
public getDashboardControls() {
return dashboardSceneGraph.getDashboardControls(this._dashboard);
return this._dashboard.state.controls!;
}
public onTitleChange = (value: string) => {
@ -151,8 +150,8 @@ export class GeneralSettingsEditView
const { title, description, tags, meta, editable } = model.getDashboard().useState();
const { sync: graphTooltip } = model.getCursorSync()?.useState() || {};
const { timeZone, weekStart, UNSAFE_nowDelay: nowDelay } = model.getTimeRange().useState();
const { intervals } = model.getRefreshPicker()?.useState() || {};
const { hideTimeControls } = model.getDashboardControls()?.useState() || {};
const { intervals } = model.getRefreshPicker().useState();
const { hideTimeControls } = model.getDashboardControls().useState();
return (
<Page navModel={navModel} pageNav={pageNav} layout={PageLayoutType.Standard}>

View File

@ -3,11 +3,9 @@ import {
behaviors,
SceneGridItem,
SceneGridLayout,
SceneRefreshPicker,
SceneQueryRunner,
SceneTimeRange,
VizPanel,
SceneTimePicker,
SceneDataTransformer,
SceneDataLayers,
} from '@grafana/scenes';
@ -17,7 +15,6 @@ import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
import { AlertStatesDataLayer } from '../scene/AlertStatesDataLayer';
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
import { DashboardControls } from '../scene/DashboardControls';
import { DashboardLinksControls } from '../scene/DashboardLinksControls';
import { DashboardScene } from '../scene/DashboardScene';
import { NEW_LINK } from '../settings/links/utils';
@ -37,7 +34,7 @@ describe('DashboardModelCompatibilityWrapper', () => {
expect(wrapper.time.from).toBe('now-6h');
expect(wrapper.timezone).toBe('America/New_York');
expect(wrapper.weekStart).toBe('friday');
expect(wrapper.timepicker.refresh_intervals).toEqual(['1s']);
expect(wrapper.timepicker.refresh_intervals![0]).toEqual('5s');
expect(wrapper.timepicker.hidden).toEqual(true);
expect(wrapper.panels).toHaveLength(5);
@ -60,9 +57,7 @@ describe('DashboardModelCompatibilityWrapper', () => {
expect(wrapper.panels[3].datasource).toEqual({ uid: 'gdev-testdata', type: 'grafana-testdata-datasource' });
expect(wrapper.panels[4].datasource).toEqual({ uid: SHARED_DASHBOARD_QUERY, type: 'datasource' });
(scene.state.controls![0] as DashboardControls).setState({
hideTimeControls: false,
});
scene.state.controls!.setState({ hideTimeControls: false });
const wrapper2 = new DashboardModelCompatibilityWrapper(scene);
expect(wrapper2.timepicker.hidden).toEqual(false);
@ -175,19 +170,9 @@ function setup() {
}),
],
}),
controls: [
new DashboardControls({
variableControls: [],
linkControls: new DashboardLinksControls({}),
timeControls: [
new SceneTimePicker({}),
new SceneRefreshPicker({
intervals: ['1s'],
}),
],
hideTimeControls: true,
}),
],
controls: new DashboardControls({
hideTimeControls: true,
}),
body: new SceneGridLayout({
children: [
new SceneGridItem({

View File

@ -17,7 +17,6 @@ import { DashboardScene } from '../scene/DashboardScene';
import { dataLayersToAnnotations } from '../serialization/dataLayersToAnnotations';
import { PanelModelCompatibilityWrapper } from './PanelModelCompatibilityWrapper';
import { dashboardSceneGraph } from './dashboardSceneGraph';
import { findVizPanelByKey, getVizPanelKeyForPanelId } from './utils';
/**
@ -68,8 +67,8 @@ export class DashboardModelCompatibilityWrapper {
public get timepicker() {
return {
refresh_intervals: dashboardSceneGraph.getRefreshPicker(this._scene)?.state.intervals,
hidden: dashboardSceneGraph.getDashboardControls(this._scene)?.state.hideTimeControls ?? false,
refresh_intervals: this._scene.state.controls!.state.refreshPicker.state.intervals,
hidden: this._scene.state.controls!.state.hideTimeControls ?? false,
};
}

View File

@ -4,8 +4,6 @@ import {
SceneGridLayout,
SceneGridRow,
SceneQueryRunner,
SceneRefreshPicker,
SceneTimePicker,
SceneTimeRange,
VizPanel,
} from '@grafana/scenes';
@ -13,7 +11,6 @@ import {
import { AlertStatesDataLayer } from '../scene/AlertStatesDataLayer';
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
import { DashboardControls } from '../scene/DashboardControls';
import { DashboardLinksControls } from '../scene/DashboardLinksControls';
import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene';
import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks';
@ -21,67 +18,6 @@ import { dashboardSceneGraph } from './dashboardSceneGraph';
import { findVizPanelByKey } from './utils';
describe('dashboardSceneGraph', () => {
describe('getTimePicker', () => {
it('should return null if no time picker', () => {
const scene = buildTestScene({
controls: [
new DashboardControls({
variableControls: [],
linkControls: new DashboardLinksControls({}),
timeControls: [],
}),
],
});
const timePicker = dashboardSceneGraph.getTimePicker(scene);
expect(timePicker).toBeNull();
});
it('should return time picker', () => {
const scene = buildTestScene();
const timePicker = dashboardSceneGraph.getTimePicker(scene);
expect(timePicker).not.toBeNull();
});
});
describe('getRefreshPicker', () => {
it('should return null if no refresh picker', () => {
const scene = buildTestScene({
controls: [
new DashboardControls({
variableControls: [],
linkControls: new DashboardLinksControls({}),
timeControls: [],
}),
],
});
const refreshPicker = dashboardSceneGraph.getRefreshPicker(scene);
expect(refreshPicker).toBeNull();
});
it('should return refresh picker', () => {
const scene = buildTestScene();
const refreshPicker = dashboardSceneGraph.getRefreshPicker(scene);
expect(refreshPicker).not.toBeNull();
});
});
describe('getDashboardControls', () => {
it('should return null if no dashboard controls', () => {
const scene = buildTestScene({ controls: [] });
const dashboardControls = dashboardSceneGraph.getDashboardControls(scene);
expect(dashboardControls).toBeNull();
});
it('should return dashboard controls', () => {
const scene = buildTestScene();
const dashboardControls = dashboardSceneGraph.getDashboardControls(scene);
expect(dashboardControls).not.toBeNull();
});
});
describe('getPanelLinks', () => {
it('should throw if no links object defined', () => {
const scene = buildTestScene();
@ -155,18 +91,7 @@ function buildTestScene(overrides?: Partial<DashboardSceneState>) {
title: 'hello',
uid: 'dash-1',
$timeRange: new SceneTimeRange({}),
controls: [
new DashboardControls({
variableControls: [],
linkControls: new DashboardLinksControls({}),
timeControls: [
new SceneTimePicker({}),
new SceneRefreshPicker({
intervals: ['1s'],
}),
],
}),
],
controls: new DashboardControls({}),
$data: new SceneDataLayers({
layers: [
new DashboardAnnotationsDataLayer({

View File

@ -1,48 +1,14 @@
import {
SceneTimePicker,
SceneRefreshPicker,
VizPanel,
SceneGridItem,
SceneGridRow,
SceneDataLayers,
sceneGraph,
} from '@grafana/scenes';
import { VizPanel, SceneGridItem, SceneGridRow, SceneDataLayers, sceneGraph } from '@grafana/scenes';
import { DashboardControls } from '../scene/DashboardControls';
import { DashboardScene } from '../scene/DashboardScene';
import { VizPanelLinks } from '../scene/PanelLinks';
function getTimePicker(scene: DashboardScene) {
const dashboardControls = getDashboardControls(scene);
if (dashboardControls) {
const timePicker = dashboardControls.state.timeControls.find((c) => c instanceof SceneTimePicker);
if (timePicker && timePicker instanceof SceneTimePicker) {
return timePicker;
}
}
return null;
return scene.state.controls?.state.timePicker;
}
function getRefreshPicker(scene: DashboardScene) {
const dashboardControls = getDashboardControls(scene);
if (dashboardControls) {
for (const control of dashboardControls.state.timeControls) {
if (control instanceof SceneRefreshPicker) {
return control;
}
}
}
return null;
}
function getDashboardControls(scene: DashboardScene) {
if (scene.state.controls?.[0] instanceof DashboardControls) {
return scene.state.controls[0];
}
return null;
return scene.state.controls?.state.refreshPicker;
}
function getPanelLinks(panel: VizPanel) {
@ -92,7 +58,6 @@ function getDataLayers(scene: DashboardScene): SceneDataLayers {
export const dashboardSceneGraph = {
getTimePicker,
getRefreshPicker,
getDashboardControls,
getPanelLinks,
getVizPanels,
getDataLayers,