mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Check source panel for updates in Dashboard DS panel (#85655)
* Check source panel for updates in Dashboard DS panel * Test * made it better * cleanup * cleanup and tests * fix failing tests * find the correct dashboard query * revert mixed check in dashboard behaviour * Dashboard data source: Return error when used in mixed data source (#85765) * MixedDS: Inform about dashboard ds not being supported * lint fix --------- Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
This commit is contained in:
parent
f79dd7c7f9
commit
b6249d6a50
@ -0,0 +1,547 @@
|
||||
import { map, of } from 'rxjs';
|
||||
|
||||
import {
|
||||
DataQuery,
|
||||
DataQueryRequest,
|
||||
DataSourceApi,
|
||||
DataSourceJsonData,
|
||||
DataSourceRef,
|
||||
LoadingState,
|
||||
PanelData,
|
||||
} from '@grafana/data';
|
||||
import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks';
|
||||
import { setPluginImportUtils } from '@grafana/runtime';
|
||||
import { SceneGridLayout, SceneQueryRunner, VizPanel } from '@grafana/scenes';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
import { DASHBOARD_DATASOURCE_PLUGIN_ID } from 'app/plugins/datasource/dashboard/types';
|
||||
|
||||
import { VizPanelManager } from '../panel-edit/VizPanelManager';
|
||||
import { activateFullSceneTree } from '../utils/test-utils';
|
||||
|
||||
import { DashboardDatasourceBehaviour } from './DashboardDatasourceBehaviour';
|
||||
import { DashboardGridItem } from './DashboardGridItem';
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
|
||||
const grafanaDs = {
|
||||
id: 1,
|
||||
uid: '-- Grafana --',
|
||||
name: 'grafana',
|
||||
type: 'grafana',
|
||||
meta: {
|
||||
id: 'grafana',
|
||||
},
|
||||
getRef: () => {
|
||||
return { type: 'grafana', uid: '-- Grafana --' };
|
||||
},
|
||||
};
|
||||
|
||||
const dashboardDs: DataSourceApi = {
|
||||
meta: {
|
||||
id: DASHBOARD_DATASOURCE_PLUGIN_ID,
|
||||
},
|
||||
name: SHARED_DASHBOARD_QUERY,
|
||||
type: SHARED_DASHBOARD_QUERY,
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
getRef: () => {
|
||||
return { type: SHARED_DASHBOARD_QUERY, uid: SHARED_DASHBOARD_QUERY };
|
||||
},
|
||||
} as DataSourceApi<DataQuery, DataSourceJsonData, {}>;
|
||||
|
||||
setPluginImportUtils({
|
||||
importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})),
|
||||
getPanelPluginFromCache: (id: string) => undefined,
|
||||
});
|
||||
|
||||
const runRequestMock = jest.fn().mockImplementation((ds: DataSourceApi, request: DataQueryRequest) => {
|
||||
const result: PanelData = {
|
||||
state: LoadingState.Loading,
|
||||
series: [],
|
||||
timeRange: request.range,
|
||||
request,
|
||||
};
|
||||
|
||||
return of([]).pipe(
|
||||
map(() => {
|
||||
result.state = LoadingState.Done;
|
||||
result.series = [];
|
||||
|
||||
return result;
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getRunRequest: () => (ds: DataSourceApi, request: DataQueryRequest) => {
|
||||
return runRequestMock(ds, request);
|
||||
},
|
||||
getDataSourceSrv: () => {
|
||||
return {
|
||||
get: async (ref: DataSourceRef) => {
|
||||
if (ref.uid === 'grafana') {
|
||||
return grafanaDs;
|
||||
}
|
||||
|
||||
if (ref.uid === SHARED_DASHBOARD_QUERY) {
|
||||
return dashboardDs;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
getInstanceSettings: jest.fn().mockResolvedValue({ uid: 'ds1' }),
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
describe('DashboardDatasourceBehaviour', () => {
|
||||
describe('Given scene with a dashboard DS panel and a source panel', () => {
|
||||
let scene: DashboardScene, sourcePanel: VizPanel, dashboardDSPanel: VizPanel, sceneDeactivate: () => void;
|
||||
|
||||
beforeEach(async () => {
|
||||
({ scene, sourcePanel, dashboardDSPanel, sceneDeactivate } = await buildTestScene());
|
||||
});
|
||||
|
||||
it('Should re-run query of dashboardDS panel when source query re-runs', async () => {
|
||||
// spy on runQueries that will be called by the behaviour
|
||||
const spy = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
// deactivate scene to mimic going into panel edit
|
||||
sceneDeactivate();
|
||||
// run source panel queries and update request ID
|
||||
(sourcePanel.state.$data as SceneQueryRunner).runQueries();
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
// activate scene to mimic coming back from panel edit
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Should not run query of dashboardDS panel when source panel queries do not change', async () => {
|
||||
// spy on runQueries
|
||||
const spy = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
// deactivate scene to mimic going into panel edit
|
||||
sceneDeactivate();
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
// activate scene to mimic coming back from panel edit
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Should not re-run queries in behaviour when adding a dashboardDS panel to the scene', async () => {
|
||||
const sourcePanel = new VizPanel({
|
||||
title: 'Panel A',
|
||||
pluginId: 'table',
|
||||
key: 'panel-1',
|
||||
$data: new SceneQueryRunner({
|
||||
datasource: { uid: 'grafana' },
|
||||
queries: [{ refId: 'A', queryType: 'randomWalk' }],
|
||||
}),
|
||||
});
|
||||
|
||||
const behaviour = new DashboardDatasourceBehaviour({});
|
||||
|
||||
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: [behaviour],
|
||||
}),
|
||||
});
|
||||
|
||||
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,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
const spy = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
const layout = scene.state.body as SceneGridLayout;
|
||||
|
||||
// we add the new panel, it should run it's query as usual
|
||||
layout.setState({
|
||||
children: [
|
||||
...layout.state.children,
|
||||
new DashboardGridItem({
|
||||
key: 'griditem-2',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 10,
|
||||
height: 12,
|
||||
body: dashboardDSPanel,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
dashboardDSPanel.activate();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
// since there is no previous request ID on dashboard load, the behaviour should not re-run queries
|
||||
expect(behaviour['prevRequestId']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('Should not re-run queries in behaviour on scene load', async () => {
|
||||
const sourcePanel = new VizPanel({
|
||||
title: 'Panel A',
|
||||
pluginId: 'table',
|
||||
key: 'panel-1',
|
||||
$data: new SceneQueryRunner({
|
||||
datasource: { uid: 'grafana' },
|
||||
queries: [{ refId: 'A', queryType: 'randomWalk' }],
|
||||
}),
|
||||
});
|
||||
|
||||
const behaviour = new DashboardDatasourceBehaviour({});
|
||||
|
||||
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: [behaviour],
|
||||
}),
|
||||
});
|
||||
|
||||
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,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const spy = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
// since there is no previous request ID on dashboard load, the behaviour should not re-run queries
|
||||
expect(behaviour['prevRequestId']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('Should exit behaviour early if not in a dashboard scene', async () => {
|
||||
// spy on runQueries
|
||||
const spy = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
const vizPanelManager = new VizPanelManager({
|
||||
panel: dashboardDSPanel.clone({ $data: undefined }),
|
||||
$data: dashboardDSPanel.state.$data?.clone(),
|
||||
sourcePanel: dashboardDSPanel.getRef(),
|
||||
});
|
||||
|
||||
vizPanelManager.activate();
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Should not re-run queries if dashboard DS panel references an invalid source panel', async () => {
|
||||
const sourcePanel = new VizPanel({
|
||||
title: 'Panel A',
|
||||
pluginId: 'table',
|
||||
key: 'panel-1',
|
||||
$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: 10 }],
|
||||
$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,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const sceneDeactivate = activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
// spy on runQueries
|
||||
const spy = jest.spyOn(dashboardDSPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
// deactivate scene to mimic going into panel edit
|
||||
sceneDeactivate();
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
// activate scene to mimic coming back from panel edit
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Given scene with no DashboardDS panel', () => {
|
||||
it('Should not re-run queries and exit early in behaviour', async () => {
|
||||
const sourcePanel = new VizPanel({
|
||||
title: 'Panel A',
|
||||
pluginId: 'table',
|
||||
key: 'panel-1',
|
||||
$data: new SceneQueryRunner({
|
||||
datasource: { uid: 'grafana' },
|
||||
queries: [{ refId: 'A', queryType: 'randomWalk' }],
|
||||
}),
|
||||
});
|
||||
|
||||
const anotherPanel = new VizPanel({
|
||||
title: 'Panel B',
|
||||
pluginId: 'table',
|
||||
key: 'panel-2',
|
||||
$data: new SceneQueryRunner({
|
||||
datasource: { uid: 'grafana' },
|
||||
queries: [{ refId: 'A', queryType: 'randomWalk' }],
|
||||
}),
|
||||
});
|
||||
|
||||
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: anotherPanel,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const sceneDeactivate = activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
// spy on runQueries
|
||||
const spy = jest.spyOn(anotherPanel.state.$data as SceneQueryRunner, 'runQueries');
|
||||
|
||||
// deactivate scene to mimic going into panel edit
|
||||
sceneDeactivate();
|
||||
// run source panel queries and update request ID
|
||||
(sourcePanel.state.$data as SceneQueryRunner).runQueries();
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
// activate scene to mimic coming back from panel edit
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Given an invalid state', () => {
|
||||
it('Should throw an error if behaviour is not attached to a SceneQueryRunner', () => {
|
||||
const behaviour = new DashboardDatasourceBehaviour({});
|
||||
|
||||
expect(() => behaviour.activate()).toThrow('DashboardDatasourceBehaviour must be attached to a SceneQueryRunner');
|
||||
});
|
||||
|
||||
it('Should throw an error if source panel does not have a SceneQueryRunner', async () => {
|
||||
const sourcePanel = new VizPanel({
|
||||
title: 'Panel A',
|
||||
pluginId: 'table',
|
||||
key: 'panel-1',
|
||||
$data: undefined,
|
||||
});
|
||||
|
||||
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,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
try {
|
||||
activateFullSceneTree(scene);
|
||||
} catch (e) {
|
||||
expect(e).toEqual(new Error('Could not find SceneQueryRunner for panel'));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function buildTestScene() {
|
||||
const sourcePanel = new VizPanel({
|
||||
title: 'Panel A',
|
||||
pluginId: 'table',
|
||||
key: 'panel-1',
|
||||
$data: new SceneQueryRunner({
|
||||
datasource: { uid: 'grafana' },
|
||||
queries: [{ refId: 'A', queryType: 'randomWalk' }],
|
||||
}),
|
||||
});
|
||||
|
||||
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,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const sceneDeactivate = activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
return { scene, sourcePanel, dashboardDSPanel, sceneDeactivate };
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
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';
|
||||
|
||||
interface DashboardDatasourceBehaviourState extends SceneObjectState {}
|
||||
|
||||
export class DashboardDatasourceBehaviour extends SceneObjectBase<DashboardDatasourceBehaviourState> {
|
||||
private prevRequestId: string | undefined;
|
||||
public constructor(state: DashboardDatasourceBehaviourState) {
|
||||
super(state);
|
||||
|
||||
this.addActivationHandler(() => this._activationHandler());
|
||||
}
|
||||
|
||||
private _activationHandler() {
|
||||
const queryRunner = this.parent;
|
||||
let dashboard: DashboardScene;
|
||||
|
||||
if (!(queryRunner instanceof SceneQueryRunner)) {
|
||||
throw new Error('DashboardDatasourceBehaviour must be attached to a SceneQueryRunner');
|
||||
}
|
||||
|
||||
if (queryRunner.state.datasource?.uid !== SHARED_DASHBOARD_QUERY) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
dashboard = getDashboardSceneFor(queryRunner);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
const dashboardQuery = queryRunner.state.queries.find((query) => query.panelId !== undefined);
|
||||
|
||||
if (!dashboardQuery) {
|
||||
return;
|
||||
}
|
||||
|
||||
const panelId = dashboardQuery.panelId;
|
||||
const vizKey = getVizPanelKeyForPanelId(panelId);
|
||||
const panel = findVizPanelByKey(dashboard, vizKey);
|
||||
|
||||
if (!(panel instanceof VizPanel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourcePanelQueryRunner = getQueryRunnerFor(panel);
|
||||
|
||||
if (!(sourcePanelQueryRunner instanceof SceneQueryRunner)) {
|
||||
throw new Error('Could not find SceneQueryRunner for panel');
|
||||
}
|
||||
|
||||
if (this.prevRequestId && this.prevRequestId !== sourcePanelQueryRunner.state.data?.request?.requestId) {
|
||||
queryRunner.runQueries();
|
||||
}
|
||||
|
||||
return () => {
|
||||
this.prevRequestId = sourcePanelQueryRunner.state.data?.request?.requestId;
|
||||
};
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ import { config } from '@grafana/runtime';
|
||||
import { SceneDataProvider, SceneDataTransformer, SceneQueryRunner } from '@grafana/scenes';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
|
||||
import { DashboardDatasourceBehaviour } from '../scene/DashboardDatasourceBehaviour';
|
||||
|
||||
export function createPanelDataProvider(panel: PanelModel): SceneDataProvider | undefined {
|
||||
// Skip setting query runner for panels without queries
|
||||
if (!panel.targets?.length) {
|
||||
@ -25,6 +27,7 @@ export function createPanelDataProvider(panel: PanelModel): SceneDataProvider |
|
||||
dataLayerFilter: {
|
||||
panelId: panel.id,
|
||||
},
|
||||
$behaviors: [new DashboardDatasourceBehaviour({})],
|
||||
});
|
||||
|
||||
// Wrap inner data provider in a data transformer
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
} from '@grafana/scenes';
|
||||
import { initialIntervalVariableModelState } from 'app/features/variables/interval/reducer';
|
||||
|
||||
import { DashboardDatasourceBehaviour } from '../scene/DashboardDatasourceBehaviour';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
|
||||
import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks';
|
||||
@ -222,6 +223,7 @@ export function getDefaultVizPanel(dashboard: DashboardScene): VizPanel {
|
||||
$data: new SceneQueryRunner({
|
||||
queries: [{ refId: 'A' }],
|
||||
datasource: getDataSourceRef(getDataSourceSrv().getInstanceSettings(null)!),
|
||||
$behaviors: [new DashboardDatasourceBehaviour({})],
|
||||
}),
|
||||
transformations: [],
|
||||
}),
|
||||
|
@ -27,6 +27,10 @@ export class DashboardDatasource extends DataSourceApi<DashboardQuery> {
|
||||
query(options: DataQueryRequest<DashboardQuery>): Observable<DataQueryResponse> {
|
||||
const scene: SceneObject | undefined = options.scopedVars?.__sceneObject?.value;
|
||||
|
||||
if (options.requestId.indexOf('mixed') > -1) {
|
||||
throw new Error('Dashboard data source cannot be used with Mixed data source.');
|
||||
}
|
||||
|
||||
if (!scene) {
|
||||
throw new Error('Can only be called from a scene');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user