Dashboard Scene: Fix issue for Dashboard Datasource and library panel (#93220)
This commit is contained in:
@@ -569,6 +569,87 @@ describe('DashboardDatasourceBehaviour', () => {
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should wait for library panel to load before running queries', async () => {
|
||||
const libPanelBehavior = new LibraryPanelBehavior({
|
||||
isLoaded: false,
|
||||
title: 'Panel title',
|
||||
uid: 'fdcvggvfy2qdca',
|
||||
name: 'My Library Panel',
|
||||
_loadedPanel: undefined,
|
||||
});
|
||||
|
||||
const sourcePanel = new VizPanel({
|
||||
key: 'panel-1',
|
||||
title: 'Panel A',
|
||||
pluginId: 'table',
|
||||
$behaviors: [libPanelBehavior],
|
||||
$data: new SceneQueryRunner({
|
||||
datasource: { uid: 'grafana' },
|
||||
queries: [{ refId: 'A', queryType: 'randomWalk' }],
|
||||
}),
|
||||
});
|
||||
|
||||
// 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 spyRunQueries = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
expect(spyRunQueries).not.toHaveBeenCalled();
|
||||
|
||||
// Simulate library panel being loaded
|
||||
libPanelBehavior.setState({
|
||||
isLoaded: true,
|
||||
title: 'Panel title',
|
||||
uid: 'fdcvggvfy2qdca',
|
||||
name: 'My Library Panel',
|
||||
_loadedPanel: undefined,
|
||||
});
|
||||
|
||||
expect(spyRunQueries).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
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 {
|
||||
findVizPanelByKey,
|
||||
getDashboardSceneFor,
|
||||
getLibraryPanelBehavior,
|
||||
getQueryRunnerFor,
|
||||
getVizPanelKeyForPanelId,
|
||||
} from '../utils/utils';
|
||||
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
import { LibraryPanelBehaviorState } from './LibraryPanelBehavior';
|
||||
|
||||
interface DashboardDatasourceBehaviourState extends SceneObjectState {}
|
||||
|
||||
@@ -16,48 +25,77 @@ export class DashboardDatasourceBehaviour extends SceneObjectBase<DashboardDatas
|
||||
}
|
||||
|
||||
private _activationHandler() {
|
||||
const queryRunner = this.parent;
|
||||
const dashboardDsQueryRunner = this.parent;
|
||||
let libraryPanelSub: Unsubscribable;
|
||||
let dashboard: DashboardScene;
|
||||
if (!(queryRunner instanceof SceneQueryRunner)) {
|
||||
if (!(dashboardDsQueryRunner instanceof SceneQueryRunner)) {
|
||||
throw new Error('DashboardDatasourceBehaviour must be attached to a SceneQueryRunner');
|
||||
}
|
||||
|
||||
if (queryRunner.state.datasource?.uid !== SHARED_DASHBOARD_QUERY) {
|
||||
if (dashboardDsQueryRunner.state.datasource?.uid !== SHARED_DASHBOARD_QUERY) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
dashboard = getDashboardSceneFor(queryRunner);
|
||||
dashboard = getDashboardSceneFor(dashboardDsQueryRunner);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
const dashboardQuery = queryRunner.state.queries.find((query) => query.panelId !== undefined);
|
||||
const dashboardQuery = dashboardDsQueryRunner.state.queries.find((query) => query.panelId !== undefined);
|
||||
|
||||
if (!dashboardQuery) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find the source panel referenced in the the dashboard ds query
|
||||
const panelId = dashboardQuery.panelId;
|
||||
const vizKey = getVizPanelKeyForPanelId(panelId);
|
||||
const panel = findVizPanelByKey(dashboard, vizKey);
|
||||
const sourcePanel = findVizPanelByKey(dashboard, vizKey);
|
||||
|
||||
if (!(panel instanceof VizPanel)) {
|
||||
if (!(sourcePanel instanceof VizPanel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourcePanelQueryRunner = getQueryRunnerFor(panel);
|
||||
//check if the source panel is a library panel and wait for it to load
|
||||
const libraryPanelBehaviour = getLibraryPanelBehavior(sourcePanel);
|
||||
if (libraryPanelBehaviour && !libraryPanelBehaviour.state.isLoaded) {
|
||||
libraryPanelSub = libraryPanelBehaviour.subscribeToState((newLibPanel) => {
|
||||
this.handleLibPanelStateUpdates(newLibPanel, dashboardDsQueryRunner, sourcePanel);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const sourcePanelQueryRunner = getQueryRunnerFor(sourcePanel);
|
||||
|
||||
if (!sourcePanelQueryRunner) {
|
||||
throw new Error('Could not find SceneQueryRunner for panel');
|
||||
}
|
||||
|
||||
if (this.prevRequestId && this.prevRequestId !== sourcePanelQueryRunner.state.data?.request?.requestId) {
|
||||
queryRunner.runQueries();
|
||||
dashboardDsQueryRunner.runQueries();
|
||||
}
|
||||
|
||||
return () => {
|
||||
this.prevRequestId = sourcePanelQueryRunner?.state.data?.request?.requestId;
|
||||
if (libraryPanelSub) {
|
||||
libraryPanelSub.unsubscribe();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private handleLibPanelStateUpdates(
|
||||
newLibPanel: LibraryPanelBehaviorState,
|
||||
dashboardDsQueryRunner: SceneQueryRunner,
|
||||
sourcePanel: VizPanel
|
||||
) {
|
||||
if (newLibPanel && newLibPanel?.isLoaded) {
|
||||
const libPanelQueryRunner = getQueryRunnerFor(sourcePanel);
|
||||
|
||||
if (!(libPanelQueryRunner instanceof SceneQueryRunner)) {
|
||||
throw new Error('Could not find SceneQueryRunner for library panel');
|
||||
}
|
||||
dashboardDsQueryRunner.runQueries();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
||||
|
||||
import { DashboardGridItem } from './DashboardGridItem';
|
||||
|
||||
interface LibraryPanelBehaviorState extends SceneObjectState {
|
||||
export interface LibraryPanelBehaviorState 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;
|
||||
|
||||
Reference in New Issue
Block a user