diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.tsx index 32e161338b1..509e1bf65c7 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControls.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControls.tsx @@ -11,6 +11,7 @@ interface DashboardControlsState extends SceneObjectState { variableControls: SceneObject[]; timeControls: SceneObject[]; linkControls: DashboardLinksControls; + hideTimeControls?: boolean; } export class DashboardControls extends SceneObjectBase { static Component = DashboardControlsRenderer; @@ -18,7 +19,7 @@ export class DashboardControls extends SceneObjectBase { function DashboardControlsRenderer({ model }: SceneComponentProps) { const dashboard = getDashboardSceneFor(model); - const { variableControls, linkControls, timeControls } = model.useState(); + const { variableControls, linkControls, timeControls, hideTimeControls } = model.useState(); const { isEditing } = dashboard.useState(); return ( @@ -40,9 +41,7 @@ function DashboardControlsRenderer({ model }: SceneComponentProps )} - {timeControls.map((c) => ( - - ))} + {!hideTimeControls && timeControls.map((c) => )} ); diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index bede40a4ae0..58132f4dc94 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -56,47 +56,55 @@ describe('DashboardScene', () => { }); it.each` - prop | value - ${'title'} | ${'new title'} - ${'description'} | ${'new description'} - ${'tags'} | ${['tag1', 'tag2']} - ${'editable'} | ${false} - ${'graphTooltip'} | ${1} + prop | value + ${'title'} | ${'new title'} + ${'description'} | ${'new description'} + ${'tags'} | ${['tag3', 'tag4']} + ${'editable'} | ${false} `( 'A change to $prop should set isDirty true', ({ prop, value }: { prop: keyof DashboardSceneState; value: any }) => { + const prevState = scene.state[prop]; scene.setState({ [prop]: value }); expect(scene.state.isDirty).toBe(true); - // TODO: Discard doesn't restore the previous state - // scene.onDiscard(); - // expect(scene.state[prop]).toBe(prevState); + scene.onDiscard(); + expect(scene.state[prop]).toEqual(prevState); } ); - // TODO: Make the dashboard to restore the defaults on discard - it.skip('A change to refresh picker interval settings should set isDirty true', () => { + it('A change to refresh picker interval settings should set isDirty true', () => { const refreshPicker = dashboardSceneGraph.getRefreshPicker(scene)!; - const prevState = refreshPicker.state.intervals; + const prevState = [...refreshPicker.state.intervals!]; refreshPicker.setState({ intervals: ['10s'] }); expect(scene.state.isDirty).toBe(true); scene.onDiscard(); - expect(refreshPicker.state.intervals).toEqual(prevState); + expect(dashboardSceneGraph.getRefreshPicker(scene)!.state.intervals).toEqual(prevState); }); - // TODO: Make the dashboard to restore the defaults on discard - it.skip('A change to time zone should set isDirty true', () => { - const timeRange = scene.state.$timeRange!; + it('A change to time picker visibility settings should set isDirty true', () => { + const dashboardControls = dashboardSceneGraph.getDashboardControls(scene)!; + const prevState = dashboardControls.state.hideTimeControls; + dashboardControls.setState({ hideTimeControls: true }); + + expect(scene.state.isDirty).toBe(true); + + scene.onDiscard(); + expect(dashboardSceneGraph.getDashboardControls(scene)!.state.hideTimeControls).toEqual(prevState); + }); + + it('A change to time zone should set isDirty true', () => { + const timeRange = sceneGraph.getTimeRange(scene)!; const prevState = timeRange.state.timeZone; timeRange.setState({ timeZone: 'UTC' }); expect(scene.state.isDirty).toBe(true); scene.onDiscard(); - expect(timeRange.state.timeZone).toBe(prevState); + expect(sceneGraph.getTimeRange(scene)!.state.timeZone).toBe(prevState); }); }); }); @@ -148,7 +156,12 @@ function buildTestScene(overrides?: Partial) { const scene = new DashboardScene({ title: 'hello', uid: 'dash-1', - $timeRange: new SceneTimeRange({}), + description: 'hello description', + tags: ['tag1', 'tag2'], + editable: true, + $timeRange: new SceneTimeRange({ + timeZone: 'browser', + }), controls: [ new DashboardControls({ variableControls: [], diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index 86415822b23..75fdf7afe91 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -33,6 +33,7 @@ import { djb2Hash } from '../utils/djb2Hash'; import { getDashboardUrl } from '../utils/urlBuilders'; import { forceRenderChildren, getClosestVizPanel, getPanelIdForVizPanel, isPanelClone } from '../utils/utils'; +import { DashboardControls } from './DashboardControls'; import { DashboardSceneUrlSync } from './DashboardSceneUrlSync'; import { ViewPanelScene } from './ViewPanelScene'; import { setupKeyboardShortcuts } from './keyboardShortcuts'; @@ -249,6 +250,11 @@ export class DashboardScene extends SceneObjectBase { if (event.payload.changedObject instanceof SceneTimeRange) { this.setIsDirty(); } + if (event.payload.changedObject instanceof DashboardControls) { + if (Object.prototype.hasOwnProperty.call(event.payload.partialUpdate, 'hideTimeControls')) { + this.setIsDirty(); + } + } } ); } diff --git a/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap b/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap index 2295c3b3c0d..f3114324f74 100644 --- a/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap +++ b/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap @@ -558,18 +558,12 @@ exports[`transformSceneToSaveModel Given a simple scene with custom settings Sho "to": "now", }, "timepicker": { - "hidden": false, + "hidden": true, "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", "5m", "15m", "30m", "1h", - "2h", - "1d", ], "time_options": [ "5m", diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts index 98fd0cb7310..2afc8afe5d5 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts @@ -22,9 +22,18 @@ import { SceneGridItem, SceneGridLayout, SceneGridRow, + SceneRefreshPicker, + SceneTimePicker, VizPanel, } from '@grafana/scenes'; -import { DashboardCursorSync, defaultDashboard, Panel, RowPanel, VariableType } from '@grafana/schema'; +import { + DashboardCursorSync, + defaultDashboard, + defaultTimePickerConfig, + Panel, + RowPanel, + VariableType, +} from '@grafana/schema'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { createPanelSaveModel } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures'; import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard'; @@ -58,6 +67,10 @@ describe('transformSaveModelToScene', () => { weekStart: 'saturday', fiscalYearStartMonth: 2, timezone: 'America/New_York', + timepicker: { + ...defaultTimePickerConfig, + hidden: true, + }, templating: { list: [ { @@ -93,6 +106,7 @@ describe('transformSaveModelToScene', () => { const oldModel = new DashboardModel(dash); const scene = createDashboardSceneFromDashboardModel(oldModel); + const dashboardControls = scene.state.controls![0] as DashboardControls; expect(scene.state.title).toBe('test'); expect(scene.state.uid).toBe('test-uid'); @@ -100,13 +114,19 @@ describe('transformSaveModelToScene', () => { expect(scene.state?.$timeRange?.state.fiscalYearStartMonth).toEqual(2); expect(scene.state?.$timeRange?.state.timeZone).toEqual('America/New_York'); expect(scene.state?.$timeRange?.state.weekStart).toEqual('saturday'); + expect(scene.state?.$variables?.state.variables).toHaveLength(1); - expect(scene.state.controls).toBeDefined(); - expect(scene.state.controls![0]).toBeInstanceOf(DashboardControls); - expect((scene.state.controls![0] as DashboardControls).state.variableControls[1]).toBeInstanceOf(AdHocFilterSet); - expect( - ((scene.state.controls![0] as DashboardControls).state.variableControls[1] as AdHocFilterSet).state.name - ).toBe('CoolFilters'); + expect(dashboardControls).toBeDefined(); + expect(dashboardControls).toBeInstanceOf(DashboardControls); + expect(dashboardControls.state.variableControls[1]).toBeInstanceOf(AdHocFilterSet); + expect((dashboardControls.state.variableControls[1] as AdHocFilterSet).state.name).toBe('CoolFilters'); + 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.hideTimeControls).toBe(true); }); it('should apply cursor sync behavior', () => { diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index 54e7fcd04e5..77ee443707a 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -268,16 +268,15 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) controls: [ new DashboardControls({ variableControls: [new VariableValueSelectors({}), ...filtersSets, new SceneDataLayerControls()], - timeControls: Boolean(oldModel.timepicker.hidden) - ? [] - : [ - new SceneTimePicker({}), - new SceneRefreshPicker({ - refresh: oldModel.refresh, - intervals: oldModel.timepicker.refresh_intervals, - }), - ], + timeControls: [ + new SceneTimePicker({}), + new SceneRefreshPicker({ + refresh: oldModel.refresh, + intervals: oldModel.timepicker.refresh_intervals, + }), + ], linkControls: new DashboardLinksControls({}), + hideTimeControls: oldModel.timepicker.hidden, }), ], }); diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts index 03be204e311..2cd2edc8828 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts @@ -51,6 +51,7 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa const variablesSet = state.$variables; const body = state.body; let refresh_intervals = defaultTimePickerConfig.refresh_intervals; + let hideTimePicker: boolean = defaultTimePickerConfig.hidden; let panels: Panel[] = []; let graphTooltip = defaultDashboard.graphTooltip; let variables: VariableModel[] = []; @@ -87,6 +88,8 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa } if (state.controls && state.controls[0] instanceof DashboardControls) { + hideTimePicker = state.controls[0].state.hideTimeControls ?? hideTimePicker; + const timeControls = state.controls[0].state.timeControls; for (const control of timeControls) { if (control instanceof SceneRefreshPicker && control.state.intervals) { @@ -123,6 +126,7 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa timepicker: { ...defaultTimePickerConfig, refresh_intervals, + hidden: hideTimePicker, }, panels, annotations: { diff --git a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.test.tsx b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.test.tsx index f767fb0d814..245f9334fdd 100644 --- a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.test.tsx +++ b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.test.tsx @@ -1,4 +1,11 @@ -import { behaviors, SceneGridLayout, SceneGridItem, SceneRefreshPicker, SceneTimeRange } from '@grafana/scenes'; +import { + behaviors, + SceneGridLayout, + SceneGridItem, + SceneRefreshPicker, + SceneTimeRange, + SceneTimePicker, +} from '@grafana/scenes'; import { DashboardCursorSync } from '@grafana/schema'; import { DashboardControls } from '../scene/DashboardControls'; @@ -33,13 +40,17 @@ describe('GeneralSettingsEditView', () => { it('should return the dashboard refresh picker', () => { expect(settings.getRefreshPicker()).toBe( - (dashboard.state?.controls?.[0] as DashboardControls)?.state?.timeControls?.[0] + (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', () => { @@ -108,6 +119,12 @@ describe('GeneralSettingsEditView', () => { expect(settings.getCursorSync()?.state.sync).toBe(DashboardCursorSync.Crosshair); }); + + it('A change to time picker visiblity settings updates the dashboard state', () => { + settings.onHideTimePickerChange(true); + + expect(settings.getDashboardControls()?.state.hideTimeControls).toBe(true); + }); }); }); @@ -121,6 +138,7 @@ async function buildTestScene() { variableControls: [], linkControls: new DashboardLinksControls({}), timeControls: [ + new SceneTimePicker({}), new SceneRefreshPicker({ intervals: ['1s'], }), diff --git a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx index c4ef84e831c..75185f94a23 100644 --- a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx +++ b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx @@ -1,7 +1,7 @@ import React, { ChangeEvent } from 'react'; import { PageLayoutType } from '@grafana/data'; -import { behaviors, SceneComponentProps, SceneObjectBase, SceneTimePicker, sceneGraph } from '@grafana/scenes'; +import { behaviors, SceneComponentProps, SceneObjectBase, sceneGraph } from '@grafana/scenes'; import { TimeZone } from '@grafana/schema'; import { Box, @@ -20,7 +20,6 @@ import { t, Trans } from 'app/core/internationalization'; import { TimePickerSettings } from 'app/features/dashboard/components/DashboardSettings/TimePickerSettings'; import { DeleteDashboardButton } from 'app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton'; -import { DashboardControls } from '../scene/DashboardControls'; import { DashboardScene } from '../scene/DashboardScene'; import { NavToolbarActions } from '../scene/NavToolbarActions'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; @@ -75,6 +74,10 @@ export class GeneralSettingsEditView return; } + public getDashboardControls() { + return dashboardSceneGraph.getDashboardControls(this._dashboard); + } + public onTitleChange = (value: string) => { this._dashboard.setState({ title: value }); }; @@ -126,16 +129,9 @@ export class GeneralSettingsEditView }; public onHideTimePickerChange = (value: boolean) => { - if (this._dashboard.state.controls instanceof DashboardControls) { - for (const control of this._dashboard.state.controls.state.timeControls) { - if (control instanceof SceneTimePicker) { - control.setState({ - // TODO: Control visibility from DashboardControls - // hidden: value, - }); - } - } - } + this.getDashboardControls()?.setState({ + hideTimeControls: value, + }); }; public onLiveNowChange = (value: boolean) => { @@ -152,6 +148,7 @@ export class GeneralSettingsEditView const { sync: graphTooltip } = model.getCursorSync()?.useState() || {}; const { timeZone, weekStart } = model.getTimeRange().useState(); const { intervals } = model.getRefreshPicker()?.useState() || {}; + const { hideTimeControls } = model.getDashboardControls()?.useState() || {}; return ( @@ -232,8 +229,7 @@ export class GeneralSettingsEditView onHideTimePickerChange={model.onHideTimePickerChange} onLiveNowChange={model.onLiveNowChange} refreshIntervals={intervals} - // TODO: Control visibility of time picker - // timePickerHidden={timepicker?.state?.hidden} + timePickerHidden={hideTimeControls} // TODO: Implement this in dashboard scene // nowDelay={timepicker.nowDelay || ''} // TODO: Implement this in dashboard scene diff --git a/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.test.ts b/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.test.ts index cf226284e63..2cf0bf38ddf 100644 --- a/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.test.ts +++ b/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.test.ts @@ -34,7 +34,7 @@ describe('DashboardModelCompatibilityWrapper', () => { expect(wrapper.timepicker.hidden).toEqual(true); (scene.state.controls![0] as DashboardControls).setState({ - timeControls: [new SceneTimePicker({})], + hideTimeControls: false, }); const wrapper2 = new DashboardModelCompatibilityWrapper(scene); @@ -99,10 +99,12 @@ function setup() { variableControls: [], linkControls: new DashboardLinksControls({}), timeControls: [ + new SceneTimePicker({}), new SceneRefreshPicker({ intervals: ['1s'], }), ], + hideTimeControls: true, }), ], body: new SceneGridLayout({ diff --git a/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.ts b/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.ts index bdbba18c5f6..eb17a92a148 100644 --- a/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.ts +++ b/public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.ts @@ -63,7 +63,7 @@ export class DashboardModelCompatibilityWrapper { public get timepicker() { return { refresh_intervals: dashboardSceneGraph.getRefreshPicker(this._scene)?.state.intervals, - hidden: !Boolean(dashboardSceneGraph.getTimePicker(this._scene)), + hidden: dashboardSceneGraph.getDashboardControls(this._scene)?.state.hideTimeControls ?? false, }; } diff --git a/public/app/features/dashboard-scene/utils/dashboardSceneGraph.test.ts b/public/app/features/dashboard-scene/utils/dashboardSceneGraph.test.ts index 005b63d09c6..44f045df7a8 100644 --- a/public/app/features/dashboard-scene/utils/dashboardSceneGraph.test.ts +++ b/public/app/features/dashboard-scene/utils/dashboardSceneGraph.test.ts @@ -1,25 +1,30 @@ -import { DashboardDataDTO } from 'app/types'; +import { + SceneGridItem, + SceneGridLayout, + SceneQueryRunner, + SceneRefreshPicker, + SceneTimePicker, + SceneTimeRange, + VizPanel, +} from '@grafana/scenes'; -import dashboard_to_load from '../serialization/testfiles/dashboard_to_load1.json'; -import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene'; +import { DashboardControls } from '../scene/DashboardControls'; +import { DashboardLinksControls } from '../scene/DashboardLinksControls'; +import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene'; import { dashboardSceneGraph } from './dashboardSceneGraph'; describe('dashboardSceneGraph', () => { describe('getTimePicker', () => { it('should return null if no time picker', () => { - const dashboard: DashboardDataDTO = { - ...(dashboard_to_load as unknown as DashboardDataDTO), - timepicker: { - hidden: true, - refresh_intervals: [], - time_options: [], - }, - }; - - const scene = transformSaveModelToScene({ - dashboard: dashboard as unknown as DashboardDataDTO, - meta: {}, + const scene = buildTestScene({ + controls: [ + new DashboardControls({ + variableControls: [], + linkControls: new DashboardLinksControls({}), + timeControls: [], + }), + ], }); const timePicker = dashboardSceneGraph.getTimePicker(scene); @@ -27,10 +32,7 @@ describe('dashboardSceneGraph', () => { }); it('should return time picker', () => { - const scene = transformSaveModelToScene({ - dashboard: dashboard_to_load as unknown as DashboardDataDTO, - meta: {}, - }); + const scene = buildTestScene(); const timePicker = dashboardSceneGraph.getTimePicker(scene); expect(timePicker).not.toBeNull(); }); @@ -38,18 +40,14 @@ describe('dashboardSceneGraph', () => { describe('getRefreshPicker', () => { it('should return null if no refresh picker', () => { - const dashboard: DashboardDataDTO = { - ...(dashboard_to_load as unknown as DashboardDataDTO), - timepicker: { - hidden: true, - refresh_intervals: [], - time_options: [], - }, - }; - - const scene = transformSaveModelToScene({ - dashboard: dashboard as unknown as DashboardDataDTO, - meta: {}, + const scene = buildTestScene({ + controls: [ + new DashboardControls({ + variableControls: [], + linkControls: new DashboardLinksControls({}), + timeControls: [], + }), + ], }); const refreshPicker = dashboardSceneGraph.getRefreshPicker(scene); @@ -57,12 +55,76 @@ describe('dashboardSceneGraph', () => { }); it('should return refresh picker', () => { - const scene = transformSaveModelToScene({ - dashboard: dashboard_to_load as unknown as DashboardDataDTO, - meta: {}, - }); + 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(); + }); + }); }); + +function buildTestScene(overrides?: Partial) { + const scene = new DashboardScene({ + title: 'hello', + uid: 'dash-1', + $timeRange: new SceneTimeRange({}), + controls: [ + new DashboardControls({ + variableControls: [], + linkControls: new DashboardLinksControls({}), + timeControls: [ + new SceneTimePicker({}), + new SceneRefreshPicker({ + intervals: ['1s'], + }), + ], + }), + ], + body: new SceneGridLayout({ + children: [ + new SceneGridItem({ + key: 'griditem-1', + x: 0, + body: new VizPanel({ + title: 'Panel A', + key: 'panel-1', + pluginId: 'table', + $data: new SceneQueryRunner({ key: 'data-query-runner', queries: [{ refId: 'A' }] }), + }), + }), + new SceneGridItem({ + body: new VizPanel({ + title: 'Panel B', + key: 'panel-2', + pluginId: 'table', + }), + }), + new SceneGridItem({ + body: new VizPanel({ + title: 'Panel B', + key: 'panel-2-clone-1', + pluginId: 'table', + $data: new SceneQueryRunner({ key: 'data-query-runner2', queries: [{ refId: 'A' }] }), + }), + }), + ], + }), + ...overrides, + }); + + return scene; +} diff --git a/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts b/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts index 1a046a7a1e1..666b764b001 100644 --- a/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts +++ b/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts @@ -4,10 +4,9 @@ import { DashboardControls } from '../scene/DashboardControls'; import { DashboardScene } from '../scene/DashboardScene'; function getTimePicker(scene: DashboardScene) { - const controls = scene.state.controls; + const dashboardControls = getDashboardControls(scene); - if (controls && controls[0] instanceof DashboardControls) { - const dashboardControls = controls[0]; + if (dashboardControls) { const timePicker = dashboardControls.state.timeControls.find((c) => c instanceof SceneTimePicker); if (timePicker && timePicker instanceof SceneTimePicker) { return timePicker; @@ -18,8 +17,10 @@ function getTimePicker(scene: DashboardScene) { } function getRefreshPicker(scene: DashboardScene) { - if (scene.state.controls?.[0] instanceof DashboardControls) { - for (const control of scene.state.controls[0].state.timeControls) { + const dashboardControls = getDashboardControls(scene); + + if (dashboardControls) { + for (const control of dashboardControls.state.timeControls) { if (control instanceof SceneRefreshPicker) { return control; } @@ -28,7 +29,15 @@ function getRefreshPicker(scene: DashboardScene) { return null; } +function getDashboardControls(scene: DashboardScene) { + if (scene.state.controls?.[0] instanceof DashboardControls) { + return scene.state.controls[0]; + } + return null; +} + export const dashboardSceneGraph = { getTimePicker, getRefreshPicker, + getDashboardControls, };