diff --git a/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.test.tsx b/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.test.tsx index 453b3e7983ff..86814f13b4be 100644 --- a/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.test.tsx @@ -21,6 +21,7 @@ import { activateFullSceneTree } from '../utils/test-utils'; import { DashboardDatasourceBehaviour } from './DashboardDatasourceBehaviour'; import { DashboardGridItem } from './DashboardGridItem'; import { DashboardScene } from './DashboardScene'; +import { LibraryVizPanel } from './LibraryVizPanel'; const grafanaDs = { id: 1, @@ -487,6 +488,87 @@ describe('DashboardDatasourceBehaviour', () => { } }); }); + + describe('Library panels', () => { + it('should wait for library panel to be loaded', async () => { + const sourcePanel = new LibraryVizPanel({ + name: 'My Library Panel', + title: 'Panel title', + uid: 'fdcvggvfy2qdca', + panelKey: 'lib-panel', + panel: new VizPanel({ + key: 'panel-1', + title: 'Panel A', + pluginId: 'table', + }), + }); + + // query references inexistent panel + const dashboardDSPanel = new VizPanel({ + title: 'Panel B', + pluginId: 'table', + key: 'panel-2', + $data: new SceneQueryRunner({ + datasource: { uid: SHARED_DASHBOARD_QUERY }, + queries: [{ refId: 'A', panelId: 1 }], + $behaviors: [new DashboardDatasourceBehaviour({})], + }), + }); + + const scene = new DashboardScene({ + title: 'hello', + uid: 'dash-1', + meta: { + canEdit: true, + }, + body: new SceneGridLayout({ + children: [ + new DashboardGridItem({ + key: 'griditem-1', + x: 0, + y: 0, + width: 10, + height: 12, + body: sourcePanel, + }), + new DashboardGridItem({ + key: 'griditem-2', + x: 0, + y: 0, + width: 10, + height: 12, + body: dashboardDSPanel, + }), + ], + }), + }); + + activateFullSceneTree(scene); + + // spy on runQueries + const spy = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries'); + + await new Promise((r) => setTimeout(r, 1)); + + expect(spy).not.toHaveBeenCalled(); + + // Simulate library panel being loaded + sourcePanel.setState({ + isLoaded: true, + panel: new VizPanel({ + title: 'Panel A', + pluginId: 'table', + key: 'panel-1', + $data: new SceneQueryRunner({ + datasource: { uid: 'grafana' }, + queries: [{ refId: 'A', queryType: 'randomWalk' }], + }), + }), + }); + + expect(spy).toHaveBeenCalledTimes(1); + }); + }); }); async function buildTestScene() { diff --git a/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.tsx b/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.tsx index d39903a6ca0c..26fb6f0c8bcb 100644 --- a/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.tsx @@ -1,9 +1,12 @@ +import { Unsubscribable } from 'rxjs'; + import { SceneObjectBase, SceneObjectState, SceneQueryRunner, VizPanel } from '@grafana/scenes'; import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard'; import { findVizPanelByKey, getDashboardSceneFor, getQueryRunnerFor, getVizPanelKeyForPanelId } from '../utils/utils'; import { DashboardScene } from './DashboardScene'; +import { LibraryVizPanel, LibraryVizPanelState } from './LibraryVizPanel'; interface DashboardDatasourceBehaviourState extends SceneObjectState {} @@ -18,6 +21,7 @@ export class DashboardDatasourceBehaviour extends SceneObjectBase { + this.handleLibPanelStateUpdates(n, p, queryRunner); + }); + } + } else { + if (this.prevRequestId && this.prevRequestId !== sourcePanelQueryRunner.state.data?.request?.requestId) { + queryRunner.runQueries(); + } } return () => { - this.prevRequestId = sourcePanelQueryRunner.state.data?.request?.requestId; + this.prevRequestId = sourcePanelQueryRunner?.state.data?.request?.requestId; + if (libraryPanelSub) { + libraryPanelSub.unsubscribe(); + } }; } + + private handleLibPanelStateUpdates(n: LibraryVizPanelState, p: LibraryVizPanelState, queryRunner: SceneQueryRunner) { + if (n.panel && n.panel !== p.panel) { + const libPanelQueryRunner = getQueryRunnerFor(n.panel); + + if (!(libPanelQueryRunner instanceof SceneQueryRunner)) { + throw new Error('Could not find SceneQueryRunner for panel'); + } + + queryRunner.runQueries(); + } + } } diff --git a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx index 53b9c2ddc429..b7a1a4d87219 100644 --- a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx +++ b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx @@ -20,7 +20,7 @@ import { VizPanelLinks, VizPanelLinksMenu } from './PanelLinks'; import { panelLinksBehavior, panelMenuBehavior } from './PanelMenuBehavior'; import { PanelNotices } from './PanelNotices'; -interface LibraryVizPanelState extends SceneObjectState { +export interface LibraryVizPanelState extends SceneObjectState { // Library panels use title from dashboard JSON's panel model, not from library panel definition, hence we pass it. title: string; uid: string;