mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardDataSource: Implement sharing logic inside the data source (#80526)
* Make dashboard data source query actually use DashboardDataSource * remove commented out bit * Always wrap SceneQueryRunner with SceneDataTransformer * Update Dashboard model compat wrapper tests * DashboardQueryEditor test * VizPanelManager tests update * transform save model to scene tests update * Betterer * PanelMenuBehavior test update * Few more bits * Prettier --------- Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
This commit is contained in:
parent
bffb28c177
commit
8157711893
@ -2384,23 +2384,15 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/DashboardScene.test.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
@ -2445,8 +2437,17 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.ts:5381": [
|
||||
<<<<<<< HEAD
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||
||||||| eb8dfe7933d
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"]
|
||||
=======
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
>>>>>>> 6073626683dd3e9f437a533ef55fd79baaceb982
|
||||
],
|
||||
"public/app/features/dashboard-scene/utils/test-utils.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
@ -4819,9 +4820,6 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/datasource/cloudwatch/utils/logsRetry.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
"public/app/plugins/datasource/dashboard/runSharedRequest.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||
|
@ -3,19 +3,15 @@ import { Unsubscribable } from 'rxjs';
|
||||
|
||||
import {
|
||||
SceneComponentProps,
|
||||
SceneDataTransformer,
|
||||
SceneObjectBase,
|
||||
SceneObjectState,
|
||||
SceneObjectUrlSyncConfig,
|
||||
SceneObjectUrlValues,
|
||||
SceneQueryRunner,
|
||||
VizPanel,
|
||||
sceneGraph,
|
||||
} from '@grafana/scenes';
|
||||
import { Tab, TabContent, TabsBar } from '@grafana/ui';
|
||||
import { shouldShowAlertingTab } from 'app/features/dashboard/components/PanelEditor/state/selectors';
|
||||
|
||||
import { ShareQueryDataProvider } from '../../scene/ShareQueryDataProvider';
|
||||
import { VizPanelManager } from '../VizPanelManager';
|
||||
|
||||
import { PanelDataAlertingTab } from './PanelDataAlertingTab';
|
||||
@ -96,30 +92,10 @@ export class PanelDataPane extends SceneObjectBase<PanelDataPaneState> {
|
||||
});
|
||||
}
|
||||
|
||||
private getDataObjects(): [SceneQueryRunner | ShareQueryDataProvider | undefined, SceneDataTransformer | undefined] {
|
||||
const dataObj = sceneGraph.getData(this.panelManager.state.panel);
|
||||
|
||||
let runner: SceneQueryRunner | ShareQueryDataProvider | undefined;
|
||||
let transformer: SceneDataTransformer | undefined;
|
||||
|
||||
if (dataObj instanceof SceneQueryRunner || dataObj instanceof ShareQueryDataProvider) {
|
||||
runner = dataObj;
|
||||
}
|
||||
|
||||
if (dataObj instanceof SceneDataTransformer) {
|
||||
transformer = dataObj;
|
||||
if (transformer.state.$data instanceof SceneQueryRunner) {
|
||||
runner = transformer.state.$data;
|
||||
}
|
||||
}
|
||||
|
||||
return [runner, transformer];
|
||||
}
|
||||
|
||||
private buildTabs() {
|
||||
const panelManager = this.panelManager;
|
||||
const panel = panelManager.state.panel;
|
||||
const [runner] = this.getDataObjects();
|
||||
const runner = this.panelManager.queryRunner;
|
||||
const tabs: PanelDataPaneTab[] = [];
|
||||
|
||||
if (panel) {
|
||||
@ -129,6 +105,7 @@ export class PanelDataPane extends SceneObjectBase<PanelDataPaneState> {
|
||||
this.setState({ tabs });
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.meta.skipDataQuery) {
|
||||
this.setState({ tabs });
|
||||
return;
|
||||
|
@ -1,16 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
import { DataSourceApi, DataSourceInstanceSettings, IconName } from '@grafana/data';
|
||||
import { SceneObjectBase, SceneComponentProps, SceneQueryRunner, sceneGraph } from '@grafana/scenes';
|
||||
import { SceneObjectBase, SceneComponentProps, sceneGraph } from '@grafana/scenes';
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
import { QueryEditorRows } from 'app/features/query/components/QueryEditorRows';
|
||||
import { QueryGroupTopSection } from 'app/features/query/components/QueryGroup';
|
||||
import { DashboardQueryEditor } from 'app/plugins/datasource/dashboard';
|
||||
import { GrafanaQuery } from 'app/plugins/datasource/grafana/types';
|
||||
import { QueryGroupOptions } from 'app/types';
|
||||
|
||||
import { PanelTimeRange } from '../../scene/PanelTimeRange';
|
||||
import { ShareQueryDataProvider } from '../../scene/ShareQueryDataProvider';
|
||||
import { VizPanelManager } from '../VizPanelManager';
|
||||
|
||||
import { PanelDataPaneTabState, PanelDataPaneTab } from './types';
|
||||
@ -30,17 +28,7 @@ export class PanelDataQueriesTab extends SceneObjectBase<PanelDataQueriesTabStat
|
||||
}
|
||||
|
||||
getItemsCount() {
|
||||
const dataObj = this._panelManager.state.panel.state.$data!;
|
||||
|
||||
if (dataObj instanceof ShareQueryDataProvider) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dataObj instanceof SceneQueryRunner) {
|
||||
return dataObj.state.queries.length;
|
||||
}
|
||||
|
||||
return null;
|
||||
return this.getQueries().length;
|
||||
}
|
||||
|
||||
constructor(panelManager: VizPanelManager) {
|
||||
@ -52,9 +40,7 @@ export class PanelDataQueriesTab extends SceneObjectBase<PanelDataQueriesTabStat
|
||||
buildQueryOptions(): QueryGroupOptions {
|
||||
const panelManager = this._panelManager;
|
||||
const panelObj = this._panelManager.state.panel;
|
||||
const dataObj = panelObj.state.$data!;
|
||||
const queryRunner = this._panelManager.queryRunner;
|
||||
|
||||
const timeRangeObj = sceneGraph.getTimeRange(panelObj);
|
||||
|
||||
let timeRangeOpts: QueryGroupOptions['timeRange'] = {
|
||||
@ -71,14 +57,7 @@ export class PanelDataQueriesTab extends SceneObjectBase<PanelDataQueriesTabStat
|
||||
};
|
||||
}
|
||||
|
||||
let queries: QueryGroupOptions['queries'] = [];
|
||||
if (dataObj instanceof ShareQueryDataProvider) {
|
||||
queries = [dataObj.state.query];
|
||||
}
|
||||
|
||||
if (dataObj instanceof SceneQueryRunner) {
|
||||
queries = dataObj.state.queries;
|
||||
}
|
||||
let queries: QueryGroupOptions['queries'] = queryRunner.state.queries;
|
||||
|
||||
return {
|
||||
// TODO
|
||||
@ -120,11 +99,6 @@ export class PanelDataQueriesTab extends SceneObjectBase<PanelDataQueriesTabStat
|
||||
};
|
||||
|
||||
getQueries() {
|
||||
const dataObj = this._panelManager.state.panel.state.$data!;
|
||||
|
||||
if (dataObj instanceof ShareQueryDataProvider) {
|
||||
return [dataObj.state.query];
|
||||
}
|
||||
return this._panelManager.queryRunner.state.queries;
|
||||
}
|
||||
|
||||
@ -134,9 +108,8 @@ export class PanelDataQueriesTab extends SceneObjectBase<PanelDataQueriesTabStat
|
||||
}
|
||||
|
||||
function PanelDataQueriesTabRendered({ model }: SceneComponentProps<PanelDataQueriesTab>) {
|
||||
const { panel, datasource, dsSettings } = model.panelManager.useState();
|
||||
const { $data: dataObj } = panel.useState();
|
||||
const { data } = dataObj!.useState();
|
||||
const { datasource, dsSettings } = model.panelManager.useState();
|
||||
const { data } = model.panelManager.queryRunner.useState();
|
||||
|
||||
if (!datasource || !dsSettings || !data) {
|
||||
return null;
|
||||
@ -154,18 +127,14 @@ function PanelDataQueriesTabRendered({ model }: SceneComponentProps<PanelDataQue
|
||||
onOpenQueryInspector={model.onOpenInspector}
|
||||
/>
|
||||
|
||||
{dataObj instanceof ShareQueryDataProvider ? (
|
||||
<DashboardQueryEditor queries={model.getQueries()} panelData={data} onChange={model.onQueriesChange} />
|
||||
) : (
|
||||
<QueryEditorRows
|
||||
data={data}
|
||||
queries={model.getQueries()}
|
||||
dsSettings={dsSettings}
|
||||
onAddQuery={() => {}}
|
||||
onQueriesChange={model.onQueriesChange}
|
||||
onRunQueries={model.onRunQueries}
|
||||
/>
|
||||
)}
|
||||
<QueryEditorRows
|
||||
data={data}
|
||||
queries={model.getQueries()}
|
||||
dsSettings={dsSettings}
|
||||
onAddQuery={() => {}}
|
||||
onQueriesChange={model.onQueriesChange}
|
||||
onRunQueries={model.onRunQueries}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import {
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
import { DashboardModelCompatibilityWrapper } from '../utils/DashboardModelCompatibilityWrapper';
|
||||
import { getDashboardUrl } from '../utils/urlBuilders';
|
||||
|
||||
@ -106,13 +105,6 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
||||
|
||||
const panelMngr = this.state.panelRef.resolve();
|
||||
|
||||
// Remove data provider if it's a share query. For editing purposes the data provider is cloned and attached to the
|
||||
// ShareQueryDataProvider when panel is in edit mode.
|
||||
// TODO: Handle transformations when we get on transformations edit.
|
||||
if (panelMngr.state.panel.state.$data instanceof ShareQueryDataProvider) {
|
||||
panelMngr.state.panel.state.$data.setState({ $data: undefined });
|
||||
}
|
||||
|
||||
if (sourcePanel.parent instanceof SceneGridItem) {
|
||||
sourcePanel.parent.setState({ body: panelMngr.state.panel.clone() });
|
||||
}
|
||||
@ -154,6 +146,7 @@ export function buildPanelEditScene(dashboard: DashboardScene, panel: VizPanel):
|
||||
direction: 'column',
|
||||
primary: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
minHeight: 200,
|
||||
children: [vizPanelMgr],
|
||||
}),
|
||||
secondary: new SceneFlexItem({
|
||||
|
@ -10,7 +10,6 @@ import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
import { DASHBOARD_DATASOURCE_PLUGIN_ID } from 'app/plugins/datasource/dashboard/types';
|
||||
|
||||
import { PanelTimeRange, PanelTimeRangeState } from '../scene/PanelTimeRange';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
|
||||
import { DashboardModelCompatibilityWrapper } from '../utils/DashboardModelCompatibilityWrapper';
|
||||
import { findVizPanelByKey } from '../utils/utils';
|
||||
@ -426,11 +425,7 @@ describe('VizPanelManager', () => {
|
||||
vizPanelManager.activate();
|
||||
await Promise.resolve();
|
||||
|
||||
const panel = vizPanelManager.state.panel;
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
|
||||
expect((panel.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
expect(vizPanelManager.queryRunner.state.datasource).toEqual({
|
||||
uid: 'gdev-testdata',
|
||||
type: 'grafana-testdata-datasource',
|
||||
});
|
||||
@ -446,7 +441,7 @@ describe('VizPanelManager', () => {
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect((panel.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
expect(vizPanelManager.queryRunner.state.datasource).toEqual({
|
||||
uid: 'gdev-prometheus',
|
||||
type: 'grafana-prometheus-datasource',
|
||||
});
|
||||
@ -457,11 +452,7 @@ describe('VizPanelManager', () => {
|
||||
vizPanelManager.activate();
|
||||
await Promise.resolve();
|
||||
|
||||
const panel = vizPanelManager.state.panel;
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
|
||||
expect((panel.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
expect(vizPanelManager.queryRunner.state.datasource).toEqual({
|
||||
uid: 'gdev-testdata',
|
||||
type: 'grafana-testdata-datasource',
|
||||
});
|
||||
@ -477,7 +468,10 @@ describe('VizPanelManager', () => {
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(ShareQueryDataProvider);
|
||||
expect(vizPanelManager.queryRunner.state.datasource).toEqual({
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
type: 'datasource',
|
||||
});
|
||||
});
|
||||
|
||||
it('changing from dashboard data source to a plugin', async () => {
|
||||
@ -485,100 +479,10 @@ describe('VizPanelManager', () => {
|
||||
vizPanelManager.activate();
|
||||
await Promise.resolve();
|
||||
|
||||
const panel = vizPanelManager.state.panel;
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(ShareQueryDataProvider);
|
||||
|
||||
await vizPanelManager.changePanelDataSource({
|
||||
name: 'grafana-prometheus',
|
||||
type: 'grafana-prometheus-datasource',
|
||||
uid: 'gdev-prometheus',
|
||||
meta: {
|
||||
name: 'Prometheus',
|
||||
module: 'prometheus',
|
||||
id: 'grafana-prometheus-datasource',
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
expect((panel.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
uid: 'gdev-prometheus',
|
||||
type: 'grafana-prometheus-datasource',
|
||||
});
|
||||
});
|
||||
|
||||
describe('with transformations', () => {
|
||||
it('changing from one plugin to another', async () => {
|
||||
const { vizPanelManager } = setupTest('panel-2');
|
||||
vizPanelManager.activate();
|
||||
await Promise.resolve();
|
||||
|
||||
const panel = vizPanelManager.state.panel;
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
|
||||
expect((panel.state.$data?.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
uid: 'gdev-testdata',
|
||||
type: 'grafana-testdata-datasource',
|
||||
});
|
||||
|
||||
await vizPanelManager.changePanelDataSource({
|
||||
name: 'grafana-prometheus',
|
||||
type: 'grafana-prometheus-datasource',
|
||||
uid: 'gdev-prometheus',
|
||||
meta: {
|
||||
name: 'Prometheus',
|
||||
module: 'prometheus',
|
||||
id: 'grafana-prometheus-datasource',
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
expect((panel.state.$data?.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
uid: 'gdev-prometheus',
|
||||
type: 'grafana-prometheus-datasource',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('changing from a plugin to dashboard data source', async () => {
|
||||
const { vizPanelManager } = setupTest('panel-2');
|
||||
vizPanelManager.activate();
|
||||
await Promise.resolve();
|
||||
|
||||
const panel = vizPanelManager.state.panel;
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
|
||||
expect((panel.state.$data?.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
uid: 'gdev-testdata',
|
||||
type: 'grafana-testdata-datasource',
|
||||
});
|
||||
|
||||
await vizPanelManager.changePanelDataSource({
|
||||
name: SHARED_DASHBOARD_QUERY,
|
||||
type: 'datasource',
|
||||
expect(vizPanelManager.queryRunner.state.datasource).toEqual({
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
meta: {
|
||||
name: 'Prometheus',
|
||||
module: 'prometheus',
|
||||
id: DASHBOARD_DATASOURCE_PLUGIN_ID,
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
expect(panel.state.$data?.state.$data).toBeInstanceOf(ShareQueryDataProvider);
|
||||
});
|
||||
|
||||
it('changing from a dashboard data source to a plugin', async () => {
|
||||
const { vizPanelManager } = setupTest('panel-4');
|
||||
vizPanelManager.activate();
|
||||
await Promise.resolve();
|
||||
|
||||
const panel = vizPanelManager.state.panel;
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
expect(panel.state.$data?.state.$data).toBeInstanceOf(ShareQueryDataProvider);
|
||||
type: 'datasource',
|
||||
});
|
||||
|
||||
await vizPanelManager.changePanelDataSource({
|
||||
name: 'grafana-prometheus',
|
||||
@ -591,9 +495,7 @@ describe('VizPanelManager', () => {
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(panel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
expect(panel.state.$data?.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
expect((panel.state.$data?.state.$data as SceneQueryRunner).state.datasource).toEqual({
|
||||
expect(vizPanelManager.queryRunner.state.datasource).toEqual({
|
||||
uid: 'gdev-prometheus',
|
||||
type: 'grafana-prometheus-datasource',
|
||||
});
|
||||
@ -655,15 +557,8 @@ describe('VizPanelManager', () => {
|
||||
panelId: panelWithTransformations.id,
|
||||
},
|
||||
]);
|
||||
expect(vizPanelManager.panelData).toBeInstanceOf(ShareQueryDataProvider);
|
||||
expect((vizPanelManager.panelData as ShareQueryDataProvider).state.query.panelId).toBe(
|
||||
panelWithTransformations.id
|
||||
);
|
||||
expect(vizPanelManager.panelData.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
expect(vizPanelManager.panelData.state.$data?.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
expect((vizPanelManager.panelData.state.$data?.state.$data as SceneQueryRunner).state.queries).toEqual(
|
||||
panelWithTransformations.targets
|
||||
);
|
||||
expect(vizPanelManager.panelData).toBeInstanceOf(SceneDataTransformer);
|
||||
expect(vizPanelManager.queryRunner.state.queries[0].panelId).toEqual(panelWithTransformations.id);
|
||||
|
||||
// Changing dashboard query to a panel with queries only
|
||||
vizPanelManager.changeQueries([
|
||||
@ -676,9 +571,8 @@ describe('VizPanelManager', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
expect(vizPanelManager.panelData).toBeInstanceOf(ShareQueryDataProvider);
|
||||
expect((vizPanelManager.panelData as ShareQueryDataProvider).state.query.panelId).toBe(panelWithQueriesOnly.id);
|
||||
expect(vizPanelManager.queryRunner.state.queries).toEqual(panelWithQueriesOnly.targets);
|
||||
expect(vizPanelManager.panelData).toBeInstanceOf(SceneDataTransformer);
|
||||
expect(vizPanelManager.queryRunner.state.queries[0].panelId).toBe(panelWithQueriesOnly.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -4,10 +4,8 @@ import {
|
||||
DataSourceApi,
|
||||
DataSourceInstanceSettings,
|
||||
FieldConfigSource,
|
||||
LoadingState,
|
||||
PanelModel,
|
||||
filterFieldConfigOverrides,
|
||||
getDefaultTimeRange,
|
||||
isStandardFieldProp,
|
||||
restoreCustomOverrideRules,
|
||||
} from '@grafana/data';
|
||||
@ -21,21 +19,17 @@ import {
|
||||
DeepPartial,
|
||||
SceneQueryRunner,
|
||||
sceneGraph,
|
||||
SceneDataTransformer,
|
||||
SceneDataProvider,
|
||||
} from '@grafana/scenes';
|
||||
import { DataQuery, DataSourceRef } from '@grafana/schema';
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
import { getPluginVersion } from 'app/features/dashboard/state/PanelModel';
|
||||
import { storeLastUsedDataSourceInLocalStorage } from 'app/features/datasources/components/picker/utils';
|
||||
import { updateQueries } from 'app/features/query/state/updateQueries';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
import { DASHBOARD_DATASOURCE_PLUGIN_ID, DashboardQuery } from 'app/plugins/datasource/dashboard/types';
|
||||
import { GrafanaQuery } from 'app/plugins/datasource/grafana/types';
|
||||
import { QueryGroupOptions } from 'app/types';
|
||||
|
||||
import { PanelTimeRange, PanelTimeRangeState } from '../scene/PanelTimeRange';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||
import { getPanelIdForVizPanel, getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
interface VizPanelManagerState extends SceneObjectState {
|
||||
panel: VizPanel;
|
||||
@ -73,16 +67,7 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
|
||||
return;
|
||||
}
|
||||
|
||||
let datasourceToLoad: DataSourceRef | undefined;
|
||||
|
||||
if (dataObj instanceof ShareQueryDataProvider) {
|
||||
datasourceToLoad = {
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
type: DASHBOARD_DATASOURCE_PLUGIN_ID,
|
||||
};
|
||||
} else {
|
||||
datasourceToLoad = this.queryRunner.state.datasource;
|
||||
}
|
||||
let datasourceToLoad = this.queryRunner.state.datasource;
|
||||
|
||||
if (!datasourceToLoad) {
|
||||
return;
|
||||
@ -166,93 +151,28 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
|
||||
newSettings: DataSourceInstanceSettings,
|
||||
defaultQueries?: DataQuery[] | GrafanaQuery[]
|
||||
) {
|
||||
const { panel, dsSettings } = this.state;
|
||||
const dataObj = panel.state.$data;
|
||||
if (!dataObj) {
|
||||
return;
|
||||
}
|
||||
const { dsSettings } = this.state;
|
||||
const queryRunner = this.queryRunner;
|
||||
|
||||
const currentDS = dsSettings ? await getDataSourceSrv().get({ uid: dsSettings.uid }) : undefined;
|
||||
const nextDS = await getDataSourceSrv().get({ uid: newSettings.uid });
|
||||
|
||||
const currentQueries = [];
|
||||
if (dataObj instanceof SceneQueryRunner) {
|
||||
currentQueries.push(...dataObj.state.queries);
|
||||
} else if (dataObj instanceof ShareQueryDataProvider) {
|
||||
currentQueries.push(dataObj.state.query);
|
||||
}
|
||||
const currentQueries = queryRunner.state.queries;
|
||||
|
||||
// We need to pass in newSettings.uid as well here as that can be a variable expression and we want to store that in the query model not the current ds variable value
|
||||
const queries = defaultQueries || (await updateQueries(nextDS, newSettings.uid, currentQueries, currentDS));
|
||||
|
||||
if (dataObj instanceof SceneQueryRunner) {
|
||||
// Changing to Dashboard data source
|
||||
if (newSettings.uid === SHARED_DASHBOARD_QUERY) {
|
||||
// Changing from one plugin to another
|
||||
const sharedProvider = new ShareQueryDataProvider({
|
||||
query: queries[0],
|
||||
$data: new SceneQueryRunner({
|
||||
queries: [],
|
||||
}),
|
||||
data: {
|
||||
series: [],
|
||||
state: LoadingState.NotStarted,
|
||||
timeRange: getDefaultTimeRange(),
|
||||
},
|
||||
});
|
||||
panel.setState({ $data: sharedProvider });
|
||||
} else {
|
||||
dataObj.setState({
|
||||
datasource: {
|
||||
type: newSettings.type,
|
||||
uid: newSettings.uid,
|
||||
},
|
||||
queries,
|
||||
});
|
||||
if (defaultQueries) {
|
||||
dataObj.runQueries();
|
||||
}
|
||||
}
|
||||
} else if (dataObj instanceof ShareQueryDataProvider && newSettings.uid !== SHARED_DASHBOARD_QUERY) {
|
||||
const dataProvider = new SceneQueryRunner({
|
||||
datasource: {
|
||||
type: newSettings.type,
|
||||
uid: newSettings.uid,
|
||||
},
|
||||
queries,
|
||||
});
|
||||
panel.setState({ $data: dataProvider });
|
||||
} else if (dataObj instanceof SceneDataTransformer) {
|
||||
const data = dataObj.clone();
|
||||
|
||||
let provider: SceneDataProvider = new SceneQueryRunner({
|
||||
datasource: {
|
||||
type: newSettings.type,
|
||||
uid: newSettings.uid,
|
||||
},
|
||||
queries,
|
||||
});
|
||||
|
||||
if (newSettings.uid === SHARED_DASHBOARD_QUERY) {
|
||||
provider = new ShareQueryDataProvider({
|
||||
query: queries[0],
|
||||
$data: new SceneQueryRunner({
|
||||
queries: [],
|
||||
}),
|
||||
data: {
|
||||
series: [],
|
||||
state: LoadingState.NotStarted,
|
||||
timeRange: getDefaultTimeRange(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
data.setState({
|
||||
$data: provider,
|
||||
});
|
||||
|
||||
panel.setState({ $data: data });
|
||||
queryRunner.setState({
|
||||
datasource: {
|
||||
type: newSettings.type,
|
||||
uid: newSettings.uid,
|
||||
},
|
||||
queries,
|
||||
});
|
||||
if (defaultQueries) {
|
||||
queryRunner.runQueries();
|
||||
}
|
||||
|
||||
this.loadDataSource();
|
||||
}
|
||||
|
||||
@ -293,19 +213,8 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
|
||||
}
|
||||
|
||||
public changeQueries<T extends DataQuery>(queries: T[]) {
|
||||
const dataObj = this.state.panel.state.$data;
|
||||
const runner = this.queryRunner;
|
||||
|
||||
if (dataObj instanceof ShareQueryDataProvider && queries.length > 0) {
|
||||
const dashboardQuery = queries[0] as DashboardQuery;
|
||||
if (dashboardQuery.panelId) {
|
||||
dataObj.setState({
|
||||
query: dashboardQuery,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
runner.setState({ queries });
|
||||
}
|
||||
runner.setState({ queries });
|
||||
}
|
||||
|
||||
public inspectPanel() {
|
||||
@ -319,17 +228,13 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
|
||||
}
|
||||
|
||||
get queryRunner(): SceneQueryRunner {
|
||||
const dataObj = this.state.panel.state.$data;
|
||||
// Panel data object is always SceneQueryRunner wrapped in a SceneDataTransformer
|
||||
const runner = getQueryRunnerFor(this.state.panel);
|
||||
|
||||
if (dataObj instanceof ShareQueryDataProvider) {
|
||||
return dataObj.state.$data as SceneQueryRunner;
|
||||
if (!runner) {
|
||||
throw new Error('Query runner not found');
|
||||
}
|
||||
|
||||
if (dataObj instanceof SceneDataTransformer) {
|
||||
return dataObj.state.$data as SceneQueryRunner;
|
||||
}
|
||||
|
||||
return dataObj as SceneQueryRunner;
|
||||
return runner;
|
||||
}
|
||||
|
||||
get panelData(): SceneDataProvider {
|
||||
|
@ -6,15 +6,7 @@ import {
|
||||
getTimeZone,
|
||||
} from '@grafana/data';
|
||||
import { config, getPluginLinkExtensions, locationService } from '@grafana/runtime';
|
||||
import {
|
||||
LocalValueVariable,
|
||||
SceneDataTransformer,
|
||||
SceneGridRow,
|
||||
SceneQueryRunner,
|
||||
VizPanel,
|
||||
VizPanelMenu,
|
||||
sceneGraph,
|
||||
} from '@grafana/scenes';
|
||||
import { LocalValueVariable, SceneGridRow, VizPanel, VizPanelMenu, sceneGraph } from '@grafana/scenes';
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
@ -26,12 +18,11 @@ import { addDataTrailPanelAction } from 'app/features/trails/dashboardIntegratio
|
||||
import { ShareModal } from '../sharing/ShareModal';
|
||||
import { DashboardInteractions } from '../utils/interactions';
|
||||
import { getDashboardUrl, getInspectUrl, getViewPanelUrl, tryGetExploreUrlForPanel } from '../utils/urlBuilders';
|
||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||
import { getPanelIdForVizPanel, getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
import { LibraryVizPanel } from './LibraryVizPanel';
|
||||
import { VizPanelLinks } from './PanelLinks';
|
||||
import { ShareQueryDataProvider } from './ShareQueryDataProvider';
|
||||
|
||||
/**
|
||||
* Behavior is called when VizPanelMenu is activated (ie when it's opened).
|
||||
@ -233,22 +224,10 @@ export function getPanelLinksBehavior(panel: PanelModel) {
|
||||
|
||||
function createExtensionContext(panel: VizPanel, dashboard: DashboardScene): PluginExtensionPanelContext {
|
||||
const timeRange = sceneGraph.getTimeRange(panel);
|
||||
let queryRunner = panel.state.$data;
|
||||
let targets: DataQuery[] = [];
|
||||
let queryRunner = getQueryRunnerFor(panel);
|
||||
const targets: DataQuery[] = queryRunner?.state.queries as DataQuery[];
|
||||
const id = getPanelIdForVizPanel(panel);
|
||||
|
||||
if (queryRunner instanceof SceneDataTransformer) {
|
||||
queryRunner = queryRunner.state.$data;
|
||||
}
|
||||
|
||||
if (queryRunner instanceof SceneQueryRunner) {
|
||||
targets = queryRunner.state.queries;
|
||||
}
|
||||
|
||||
if (queryRunner instanceof ShareQueryDataProvider) {
|
||||
targets = [queryRunner.state.query];
|
||||
}
|
||||
|
||||
let scopedVars = {};
|
||||
|
||||
// Handle panel repeats scenario
|
||||
|
@ -1,121 +0,0 @@
|
||||
import { getDefaultTimeRange, LoadingState } from '@grafana/data';
|
||||
import {
|
||||
SceneDataNode,
|
||||
SceneFlexItem,
|
||||
SceneFlexLayout,
|
||||
sceneGraph,
|
||||
SceneObjectBase,
|
||||
SceneObjectState,
|
||||
} from '@grafana/scenes';
|
||||
|
||||
import { activateFullSceneTree } from '../utils/test-utils';
|
||||
import { getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
|
||||
import { ShareQueryDataProvider } from './ShareQueryDataProvider';
|
||||
|
||||
export class SceneDummyPanel extends SceneObjectBase<SceneObjectState> {}
|
||||
|
||||
describe('ShareQueryDataProvider', () => {
|
||||
it('Should find and subscribe to another VizPanels data provider', () => {
|
||||
const panel = new SceneDummyPanel({
|
||||
key: getVizPanelKeyForPanelId(2),
|
||||
$data: new ShareQueryDataProvider({
|
||||
query: { refId: 'A', panelId: 1 },
|
||||
}),
|
||||
});
|
||||
|
||||
const sourceData = new SceneDataNode({
|
||||
data: {
|
||||
series: [],
|
||||
state: LoadingState.Done,
|
||||
timeRange: getDefaultTimeRange(),
|
||||
structureRev: 11,
|
||||
},
|
||||
});
|
||||
|
||||
const scene = new SceneFlexLayout({
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: new SceneDummyPanel({
|
||||
key: getVizPanelKeyForPanelId(1),
|
||||
$data: sourceData,
|
||||
}),
|
||||
}),
|
||||
new SceneFlexItem({ body: panel }),
|
||||
],
|
||||
});
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(sceneGraph.getData(panel).state.data?.structureRev).toBe(11);
|
||||
|
||||
sourceData.setState({ data: { ...sourceData.state.data!, structureRev: 12 } });
|
||||
|
||||
expect(sceneGraph.getData(panel).state.data?.structureRev).toBe(12);
|
||||
});
|
||||
|
||||
it('should find and update to another VizPanels data provider when query changed', () => {
|
||||
const sharedQuery = new ShareQueryDataProvider({
|
||||
query: { refId: 'A', panelId: 1 },
|
||||
});
|
||||
const panelWithSharedQuery = new SceneDummyPanel({
|
||||
key: getVizPanelKeyForPanelId(3),
|
||||
$data: sharedQuery,
|
||||
});
|
||||
|
||||
const sourceData1 = new SceneDataNode({
|
||||
data: {
|
||||
series: [],
|
||||
state: LoadingState.Done,
|
||||
timeRange: getDefaultTimeRange(),
|
||||
structureRev: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const sourceData2 = new SceneDataNode({
|
||||
data: {
|
||||
series: [],
|
||||
state: LoadingState.Done,
|
||||
timeRange: getDefaultTimeRange(),
|
||||
structureRev: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const sourcePanel1 = new SceneDummyPanel({
|
||||
key: getVizPanelKeyForPanelId(1),
|
||||
$data: sourceData1,
|
||||
});
|
||||
|
||||
const sourcePanel2 = new SceneDummyPanel({
|
||||
key: getVizPanelKeyForPanelId(2),
|
||||
$data: sourceData2,
|
||||
});
|
||||
|
||||
const scene = new SceneFlexLayout({
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: sourcePanel1,
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: sourcePanel2,
|
||||
}),
|
||||
new SceneFlexItem({ body: panelWithSharedQuery }),
|
||||
],
|
||||
});
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(sceneGraph.getData(panelWithSharedQuery).state.data?.structureRev).toBe(1);
|
||||
|
||||
sharedQuery.setState({
|
||||
query: {
|
||||
refId: 'A',
|
||||
panelId: 2,
|
||||
},
|
||||
});
|
||||
|
||||
expect(sceneGraph.getData(panelWithSharedQuery).state.data?.structureRev).toBe(100);
|
||||
sourceData2.setState({ data: { ...sourceData2.state.data!, structureRev: 101 } });
|
||||
expect(sceneGraph.getData(panelWithSharedQuery).state.data?.structureRev).toBe(101);
|
||||
});
|
||||
});
|
@ -1,196 +0,0 @@
|
||||
import { Observable, ReplaySubject, Unsubscribable } from 'rxjs';
|
||||
|
||||
import { getDefaultTimeRange, LoadingState, PanelData } from '@grafana/data';
|
||||
import {
|
||||
SceneDataProvider,
|
||||
SceneDataProviderResult,
|
||||
SceneDataState,
|
||||
SceneDataTransformer,
|
||||
SceneDeactivationHandler,
|
||||
SceneObject,
|
||||
SceneObjectBase,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardQuery } from 'app/plugins/datasource/dashboard/types';
|
||||
|
||||
import { PanelEditor } from '../panel-edit/PanelEditor';
|
||||
import { getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
|
||||
export interface ShareQueryDataProviderState extends SceneDataState {
|
||||
query: DashboardQuery;
|
||||
}
|
||||
|
||||
export class ShareQueryDataProvider extends SceneObjectBase<ShareQueryDataProviderState> implements SceneDataProvider {
|
||||
private _querySub: Unsubscribable | undefined;
|
||||
private _sourceDataDeactivationHandler?: SceneDeactivationHandler;
|
||||
private _results = new ReplaySubject<SceneDataProviderResult>();
|
||||
private _sourceProvider?: SceneDataProvider;
|
||||
private _passContainerWidth = false;
|
||||
|
||||
constructor(state: ShareQueryDataProviderState) {
|
||||
super({
|
||||
data: emptyPanelData,
|
||||
...state,
|
||||
});
|
||||
|
||||
this.addActivationHandler(this._onActivate);
|
||||
}
|
||||
|
||||
// Will detect the root of the scene and if it's a PanelEditor, it will clone the data from the source panel.
|
||||
// We are doing it because the source panel's original scene (dashboard) does not exist in the edit mode.
|
||||
private _setupEditMode(panelId: number, root: PanelEditor) {
|
||||
const keyToFind = getVizPanelKeyForPanelId(panelId);
|
||||
const source = findObjectInScene(
|
||||
root.state.dashboardRef.resolve(),
|
||||
(scene: SceneObject) => scene.state.key === keyToFind
|
||||
);
|
||||
|
||||
if (source) {
|
||||
// Indicate that when de-activated, i.e. navigating back to dashboard, the cloned$data state needs to be removed
|
||||
// so that the panel on the dashboar can use data from the actual source panel.
|
||||
this.setState({
|
||||
$data: source.state.$data!.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _onActivate = () => {
|
||||
const root = this.getRoot();
|
||||
if (root instanceof PanelEditor && this.state.query.panelId) {
|
||||
this._setupEditMode(this.state.query.panelId, root);
|
||||
}
|
||||
// TODO handle changes to query model (changed panelId / withTransforms)
|
||||
this.subscribeToState(this._onStateChanged);
|
||||
/**
|
||||
* If the panel uses a shared query, we clone the source runner and attach it as a data provider for the shared one.
|
||||
* This way the source panel does not to be present in the edit scene hierarchy.
|
||||
*/
|
||||
|
||||
this._subscribeToSource();
|
||||
|
||||
return () => {
|
||||
if (this._querySub) {
|
||||
this._querySub.unsubscribe();
|
||||
}
|
||||
if (this._sourceDataDeactivationHandler) {
|
||||
this._sourceDataDeactivationHandler();
|
||||
this._sourceDataDeactivationHandler = undefined;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
public getResultsStream(): Observable<SceneDataProviderResult> {
|
||||
return this._results;
|
||||
}
|
||||
|
||||
private _subscribeToSource() {
|
||||
const { query } = this.state;
|
||||
|
||||
if (this._querySub) {
|
||||
this._querySub.unsubscribe();
|
||||
}
|
||||
|
||||
if (this._sourceDataDeactivationHandler) {
|
||||
this._sourceDataDeactivationHandler();
|
||||
this._sourceDataDeactivationHandler = undefined;
|
||||
}
|
||||
|
||||
if (this.state.$data) {
|
||||
this._sourceProvider = this.state.$data;
|
||||
this._passContainerWidth = true;
|
||||
} else {
|
||||
if (!query.panelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const keyToFind = getVizPanelKeyForPanelId(query.panelId);
|
||||
const source = findObjectInScene(this.getRoot(), (scene: SceneObject) => scene.state.key === keyToFind);
|
||||
|
||||
if (!source) {
|
||||
console.log('Shared dashboard query refers to a panel that does not exist in the scene');
|
||||
return;
|
||||
}
|
||||
|
||||
this._sourceProvider = source.state.$data;
|
||||
if (!this._sourceProvider) {
|
||||
console.log('No source data found for shared dashboard query');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the source is not active we need to pass the container width
|
||||
if (!this._sourceProvider.isActive) {
|
||||
this._passContainerWidth = true;
|
||||
}
|
||||
|
||||
// This will activate if sourceData is part of hidden panel
|
||||
// Also make sure the sourceData is not deactivated if hidden later
|
||||
this._sourceDataDeactivationHandler = this._sourceProvider.activate();
|
||||
|
||||
// If source is a data transformer we might need to get the inner query runner instead depending on withTransforms option
|
||||
if (this._sourceProvider instanceof SceneDataTransformer && !query.withTransforms) {
|
||||
if (!this._sourceProvider.state.$data) {
|
||||
throw new Error('No source inner query runner found in data transformer');
|
||||
}
|
||||
this._sourceProvider = this._sourceProvider.state.$data;
|
||||
}
|
||||
|
||||
this._querySub = this._sourceProvider.subscribeToState((state) => {
|
||||
this._results.next({
|
||||
origin: this,
|
||||
data: state.data || {
|
||||
state: LoadingState.Done,
|
||||
series: [],
|
||||
timeRange: getDefaultTimeRange(),
|
||||
},
|
||||
});
|
||||
|
||||
this.setState({ data: state.data });
|
||||
});
|
||||
|
||||
// Copy the initial state
|
||||
this.setState({ data: this._sourceProvider.state.data || emptyPanelData });
|
||||
}
|
||||
|
||||
private _onStateChanged = (n: ShareQueryDataProviderState, p: ShareQueryDataProviderState) => {
|
||||
const root = this.getRoot();
|
||||
// If the query changed, we need to find the new source panel and subscribe to it
|
||||
if (n.query !== p.query && n.query.panelId) {
|
||||
if (root instanceof PanelEditor) {
|
||||
this._setupEditMode(n.query.panelId, root);
|
||||
}
|
||||
this._subscribeToSource();
|
||||
}
|
||||
};
|
||||
|
||||
public setContainerWidth(width: number) {
|
||||
if (this._passContainerWidth && this._sourceProvider) {
|
||||
this._sourceProvider.setContainerWidth?.(width);
|
||||
}
|
||||
}
|
||||
|
||||
public isDataReadyToDisplay() {
|
||||
if (this._sourceProvider && this._sourceProvider.isDataReadyToDisplay) {
|
||||
return this._sourceProvider.isDataReadyToDisplay();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function findObjectInScene(scene: SceneObject, check: (scene: SceneObject) => boolean): SceneObject | null {
|
||||
if (check(scene)) {
|
||||
return scene;
|
||||
}
|
||||
|
||||
let found: SceneObject | null = null;
|
||||
|
||||
scene.forEachChild((child) => {
|
||||
let maybe = findObjectInScene(child, check);
|
||||
if (maybe) {
|
||||
found = maybe;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
const emptyPanelData: PanelData = { state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() };
|
@ -98,6 +98,7 @@ describe('sceneVariablesSetToVariables', () => {
|
||||
allValue: 'test-all',
|
||||
isMulti: true,
|
||||
});
|
||||
|
||||
const set = new SceneVariableSet({
|
||||
variables: [variable],
|
||||
});
|
||||
|
@ -22,6 +22,7 @@ import {
|
||||
SceneGridItem,
|
||||
SceneGridLayout,
|
||||
SceneGridRow,
|
||||
SceneQueryRunner,
|
||||
SceneRefreshPicker,
|
||||
SceneTimePicker,
|
||||
VizPanel,
|
||||
@ -44,7 +45,6 @@ import { DashboardControls } from '../scene/DashboardControls';
|
||||
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
import { getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
import dashboard_to_load1 from './testfiles/dashboard_to_load1.json';
|
||||
@ -382,7 +382,9 @@ describe('transformSaveModelToScene', () => {
|
||||
};
|
||||
|
||||
const { vizPanel } = buildGridItemForTest(panel);
|
||||
expect(vizPanel.state.$data).toBeInstanceOf(ShareQueryDataProvider);
|
||||
expect(vizPanel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
expect(vizPanel.state.$data?.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
expect((vizPanel.state.$data?.state.$data as SceneQueryRunner).state.queries).toEqual(panel.targets);
|
||||
});
|
||||
|
||||
it('should not set SceneQueryRunner for plugins with skipDataQuery', () => {
|
||||
|
@ -28,7 +28,6 @@ import {
|
||||
} from '@grafana/schema';
|
||||
import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object';
|
||||
import { getPanelDataFrames } from 'app/features/dashboard/components/HelpWizard/utils';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
|
||||
|
||||
import { DashboardControls } from '../scene/DashboardControls';
|
||||
@ -37,7 +36,6 @@ import { LibraryVizPanel } from '../scene/LibraryVizPanel';
|
||||
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||
|
||||
import { GRAFANA_DATASOURCE_REF } from './const';
|
||||
@ -231,21 +229,6 @@ function vizPanelDataToPanel(
|
||||
const dataProvider = vizPanel.state.$data;
|
||||
|
||||
const panel: Pick<Panel, 'datasource' | 'targets' | 'maxDataPoints' | 'transformations'> = {};
|
||||
// Dashboard datasource handling
|
||||
if (dataProvider instanceof ShareQueryDataProvider) {
|
||||
panel.datasource = {
|
||||
type: 'datasource',
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
};
|
||||
panel.targets = [
|
||||
{
|
||||
datasource: { ...panel.datasource },
|
||||
refId: 'A',
|
||||
panelId: dataProvider.state.query.panelId,
|
||||
topic: dataProvider.state.query.topic,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// Regular queries handling
|
||||
if (dataProvider instanceof SceneQueryRunner) {
|
||||
@ -257,20 +240,6 @@ function vizPanelDataToPanel(
|
||||
// Transformations handling
|
||||
if (dataProvider instanceof SceneDataTransformer) {
|
||||
const panelData = dataProvider.state.$data;
|
||||
if (panelData instanceof ShareQueryDataProvider) {
|
||||
panel.datasource = {
|
||||
type: 'datasource',
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
};
|
||||
panel.targets = [
|
||||
{
|
||||
datasource: { ...panel.datasource },
|
||||
refId: 'A',
|
||||
panelId: panelData.state.query.panelId,
|
||||
topic: panelData.state.query.topic,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (panelData instanceof SceneQueryRunner) {
|
||||
panel.targets = panelData.state.queries;
|
||||
|
@ -16,7 +16,6 @@ import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
import { DashboardControls } from '../scene/DashboardControls';
|
||||
import { DashboardLinksControls } from '../scene/DashboardLinksControls';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
|
||||
import { DashboardModelCompatibilityWrapper } from './DashboardModelCompatibilityWrapper';
|
||||
|
||||
@ -41,18 +40,14 @@ describe('DashboardModelCompatibilityWrapper', () => {
|
||||
expect(wrapper.panels[0].targets[0]).toEqual({ refId: 'A' });
|
||||
expect(wrapper.panels[1].targets).toHaveLength(0);
|
||||
expect(wrapper.panels[2].targets).toHaveLength(1);
|
||||
expect(wrapper.panels[2].targets).toEqual([
|
||||
{ datasource: { uid: SHARED_DASHBOARD_QUERY, type: 'datasource' }, refId: 'A', panelId: 1 },
|
||||
]);
|
||||
expect(wrapper.panels[2].targets).toEqual([{ refId: 'A', panelId: 1 }]);
|
||||
expect(wrapper.panels[3].targets).toHaveLength(1);
|
||||
expect(wrapper.panels[3].targets[0]).toEqual({ refId: 'A' });
|
||||
expect(wrapper.panels[4].targets).toHaveLength(1);
|
||||
expect(wrapper.panels[4].targets).toEqual([
|
||||
{ datasource: { uid: SHARED_DASHBOARD_QUERY, type: 'datasource' }, refId: 'A', panelId: 1 },
|
||||
]);
|
||||
expect(wrapper.panels[4].targets).toEqual([{ refId: 'A', panelId: 1 }]);
|
||||
|
||||
expect(wrapper.panels[0].datasource).toEqual({ uid: 'gdev-testdata', type: 'grafana-testdata-datasource' });
|
||||
expect(wrapper.panels[1].datasource).toEqual(null);
|
||||
expect(wrapper.panels[1].datasource).toEqual(undefined);
|
||||
expect(wrapper.panels[2].datasource).toEqual({ uid: SHARED_DASHBOARD_QUERY, type: 'datasource' });
|
||||
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' });
|
||||
@ -162,7 +157,11 @@ function setup() {
|
||||
title: 'Panel with a shared query',
|
||||
key: 'panel-3',
|
||||
pluginId: 'table',
|
||||
$data: new ShareQueryDataProvider({ query: { refId: 'A', panelId: 1 } }),
|
||||
$data: new SceneQueryRunner({
|
||||
key: 'data-query-runner',
|
||||
queries: [{ refId: 'A', panelId: 1 }],
|
||||
datasource: { uid: SHARED_DASHBOARD_QUERY, type: 'datasource' },
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
|
||||
@ -187,7 +186,11 @@ function setup() {
|
||||
key: 'panel-4',
|
||||
pluginId: 'table',
|
||||
$data: new SceneDataTransformer({
|
||||
$data: new ShareQueryDataProvider({ query: { refId: 'A', panelId: 1 } }),
|
||||
$data: new SceneQueryRunner({
|
||||
key: 'data-query-runner',
|
||||
queries: [{ refId: 'A', panelId: 1 }],
|
||||
datasource: { uid: SHARED_DASHBOARD_QUERY, type: 'datasource' },
|
||||
}),
|
||||
transformations: [],
|
||||
}),
|
||||
}),
|
||||
|
@ -10,18 +10,15 @@ import {
|
||||
SceneGridLayout,
|
||||
SceneGridRow,
|
||||
SceneObject,
|
||||
SceneQueryRunner,
|
||||
VizPanel,
|
||||
} from '@grafana/scenes';
|
||||
import { DataSourceRef } from '@grafana/schema';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
|
||||
import { dashboardSceneGraph } from './dashboardSceneGraph';
|
||||
import { findVizPanelByKey, getPanelIdForVizPanel, getVizPanelKeyForPanelId } from './utils';
|
||||
import { findVizPanelByKey, getPanelIdForVizPanel, getQueryRunnerFor, getVizPanelKeyForPanelId } from './utils';
|
||||
|
||||
/**
|
||||
* Will move this to make it the main way we remain somewhat compatible with getDashboardSrv().getCurrent
|
||||
@ -248,60 +245,17 @@ class PanelCompatibilityWrapper {
|
||||
}
|
||||
|
||||
public get targets() {
|
||||
if (this._vizPanel.state.$data instanceof SceneQueryRunner) {
|
||||
return this._vizPanel.state.$data.state.queries;
|
||||
const queryRunner = getQueryRunnerFor(this._vizPanel);
|
||||
if (!queryRunner) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (this._vizPanel.state.$data instanceof ShareQueryDataProvider) {
|
||||
return [
|
||||
{
|
||||
datasource: {
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
type: 'datasource',
|
||||
},
|
||||
...this._vizPanel.state.$data.state.query,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (this._vizPanel.state.$data instanceof SceneDataTransformer) {
|
||||
if (this._vizPanel.state.$data.state.$data instanceof ShareQueryDataProvider) {
|
||||
return [
|
||||
{
|
||||
datasource: {
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
type: 'datasource',
|
||||
},
|
||||
...this._vizPanel.state.$data.state.$data.state.query,
|
||||
},
|
||||
];
|
||||
}
|
||||
if (this._vizPanel.state.$data.state.$data instanceof SceneQueryRunner) {
|
||||
return this._vizPanel.state.$data.state.$data.state.queries;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
return queryRunner.state.queries;
|
||||
}
|
||||
|
||||
public get datasource(): DataSourceRef | null {
|
||||
if (this._vizPanel.state.$data instanceof SceneQueryRunner) {
|
||||
return this._vizPanel.state.$data.state.datasource ?? null;
|
||||
}
|
||||
|
||||
if (this._vizPanel.state.$data instanceof ShareQueryDataProvider) {
|
||||
return { uid: SHARED_DASHBOARD_QUERY, type: 'datasource' };
|
||||
}
|
||||
|
||||
if (this._vizPanel.state.$data instanceof SceneDataTransformer) {
|
||||
if (this._vizPanel.state.$data.state.$data instanceof ShareQueryDataProvider) {
|
||||
return { uid: SHARED_DASHBOARD_QUERY, type: 'datasource' };
|
||||
}
|
||||
|
||||
return (this._vizPanel.state.$data.state.$data as SceneQueryRunner).state.datasource ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
public get datasource(): DataSourceRef | null | undefined {
|
||||
const queryRunner = getQueryRunnerFor(this._vizPanel);
|
||||
return queryRunner?.state.datasource;
|
||||
}
|
||||
|
||||
public refresh() {
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
import { SceneDataProvider, SceneDataTransformer, SceneQueryRunner } from '@grafana/scenes';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
|
||||
export function createPanelDataProvider(panel: PanelModel): SceneDataProvider | undefined {
|
||||
// Skip setting query runner for panels without queries
|
||||
@ -18,27 +15,19 @@ export function createPanelDataProvider(panel: PanelModel): SceneDataProvider |
|
||||
|
||||
let dataProvider: SceneDataProvider | undefined = undefined;
|
||||
|
||||
if (panel.datasource?.uid === SHARED_DASHBOARD_QUERY) {
|
||||
dataProvider = new ShareQueryDataProvider({ query: panel.targets[0] });
|
||||
} else {
|
||||
dataProvider = new SceneQueryRunner({
|
||||
datasource: panel.datasource ?? undefined,
|
||||
queries: panel.targets,
|
||||
maxDataPoints: panel.maxDataPoints ?? undefined,
|
||||
maxDataPointsFromWidth: true,
|
||||
dataLayerFilter: {
|
||||
panelId: panel.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
dataProvider = new SceneQueryRunner({
|
||||
datasource: panel.datasource ?? undefined,
|
||||
queries: panel.targets,
|
||||
maxDataPoints: panel.maxDataPoints ?? undefined,
|
||||
maxDataPointsFromWidth: true,
|
||||
dataLayerFilter: {
|
||||
panelId: panel.id,
|
||||
},
|
||||
});
|
||||
|
||||
// Wrap inner data provider in a data transformer
|
||||
if (panel.transformations?.length) {
|
||||
dataProvider = new SceneDataTransformer({
|
||||
$data: dataProvider,
|
||||
transformations: panel.transformations,
|
||||
});
|
||||
}
|
||||
|
||||
return dataProvider;
|
||||
return new SceneDataTransformer({
|
||||
$data: dataProvider,
|
||||
transformations: panel.transformations || [],
|
||||
});
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import { DataSourceModal } from 'app/features/datasources/components/picker/Data
|
||||
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
|
||||
import { dataSource as expressionDatasource } from 'app/features/expressions/ExpressionDatasource';
|
||||
import { AngularDeprecationPluginNotice } from 'app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice';
|
||||
import { DashboardQueryEditor, isSharedDashboardQuery } from 'app/plugins/datasource/dashboard';
|
||||
import { isSharedDashboardQuery } from 'app/plugins/datasource/dashboard';
|
||||
import { GrafanaQuery } from 'app/plugins/datasource/grafana/types';
|
||||
import { QueryGroupOptions } from 'app/types';
|
||||
|
||||
@ -252,16 +252,6 @@ export class QueryGroup extends PureComponent<Props, State> {
|
||||
renderQueries(dsSettings: DataSourceInstanceSettings) {
|
||||
const { onRunQueries } = this.props;
|
||||
const { data, queries } = this.state;
|
||||
if (isSharedDashboardQuery(dsSettings.name)) {
|
||||
return (
|
||||
<DashboardQueryEditor
|
||||
queries={queries}
|
||||
panelData={data}
|
||||
onChange={this.onQueriesChange}
|
||||
onRunQueries={onRunQueries}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div aria-label={selectors.components.QueryTab.content}>
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
} from '../../../features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { DashboardQueryEditor } from './DashboardQueryEditor';
|
||||
import { DashboardDatasource } from './datasource';
|
||||
import { SHARED_DASHBOARD_QUERY } from './types';
|
||||
|
||||
jest.mock('app/core/config', () => ({
|
||||
@ -78,10 +79,11 @@ describe('DashboardQueryEditor', () => {
|
||||
it('does not show a panel with the SHARED_DASHBOARD_QUERY datasource as an option in the dropdown', async () => {
|
||||
render(
|
||||
<DashboardQueryEditor
|
||||
queries={mockQueries}
|
||||
panelData={mockPanelData}
|
||||
datasource={{} as DashboardDatasource}
|
||||
query={mockQueries[0]}
|
||||
data={mockPanelData}
|
||||
onChange={mockOnChange}
|
||||
onRunQueries={mockOnRunQueries}
|
||||
onRunQuery={mockOnRunQueries}
|
||||
/>
|
||||
);
|
||||
const select = screen.getByText('Choose panel');
|
||||
@ -101,10 +103,11 @@ describe('DashboardQueryEditor', () => {
|
||||
mockDashboard.initEditPanel(mockDashboard.panels[0]);
|
||||
render(
|
||||
<DashboardQueryEditor
|
||||
queries={mockQueries}
|
||||
panelData={mockPanelData}
|
||||
datasource={{} as DashboardDatasource}
|
||||
query={mockQueries[0]}
|
||||
data={mockPanelData}
|
||||
onChange={mockOnChange}
|
||||
onRunQueries={mockOnRunQueries}
|
||||
onRunQuery={mockOnRunQueries}
|
||||
/>
|
||||
);
|
||||
const select = screen.getByText('Choose panel');
|
||||
|
@ -4,7 +4,7 @@ import pluralize from 'pluralize';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { DataQuery, GrafanaTheme2, PanelData, SelectableValue, DataTopic } from '@grafana/data';
|
||||
import { DataQuery, GrafanaTheme2, SelectableValue, DataTopic, QueryEditorProps } from '@grafana/data';
|
||||
import {
|
||||
Card,
|
||||
Field,
|
||||
@ -22,27 +22,22 @@ import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { filterPanelDataToQuery } from 'app/features/query/components/QueryEditorRow';
|
||||
|
||||
import { DashboardDatasource } from './datasource';
|
||||
import { DashboardQuery, ResultInfo, SHARED_DASHBOARD_QUERY } from './types';
|
||||
|
||||
function getQueryDisplayText(query: DataQuery): string {
|
||||
return JSON.stringify(query);
|
||||
}
|
||||
|
||||
interface Props {
|
||||
queries: DataQuery[];
|
||||
panelData: PanelData;
|
||||
onChange: (queries: DataQuery[]) => void;
|
||||
onRunQueries?: () => void;
|
||||
}
|
||||
interface Props extends QueryEditorProps<DashboardDatasource, DashboardQuery> {}
|
||||
|
||||
const topics = [
|
||||
{ label: 'All data', value: false },
|
||||
{ label: 'Annotations', value: true, description: 'Include annotations as regular data' },
|
||||
];
|
||||
|
||||
export function DashboardQueryEditor({ panelData, queries, onChange, onRunQueries }: Props) {
|
||||
export function DashboardQueryEditor({ data, query, onChange, onRunQuery }: Props) {
|
||||
const { value: defaultDatasource } = useAsync(() => getDatasourceSrv().get());
|
||||
const query = queries[0] as DashboardQuery;
|
||||
|
||||
const panel = useMemo(() => {
|
||||
const dashboard = getDashboardSrv().getCurrent();
|
||||
@ -50,7 +45,7 @@ export function DashboardQueryEditor({ panelData, queries, onChange, onRunQuerie
|
||||
}, [query.panelId]);
|
||||
|
||||
const { value: results, loading: loadingResults } = useAsync(async (): Promise<ResultInfo[]> => {
|
||||
if (!panel) {
|
||||
if (!panel || !data) {
|
||||
return [];
|
||||
}
|
||||
const mainDS = await getDatasourceSrv().get(panel.datasource);
|
||||
@ -58,7 +53,7 @@ export function DashboardQueryEditor({ panelData, queries, onChange, onRunQuerie
|
||||
panel.targets.map(async (query) => {
|
||||
const ds = query.datasource ? await getDatasourceSrv().get(query.datasource) : mainDS;
|
||||
const fmt = ds.getQueryDisplayText || getQueryDisplayText;
|
||||
const queryData = filterPanelDataToQuery(panelData, query.refId) ?? panelData;
|
||||
const queryData = filterPanelDataToQuery(data, query.refId) ?? data;
|
||||
return {
|
||||
refId: query.refId,
|
||||
query: fmt(query),
|
||||
@ -69,16 +64,14 @@ export function DashboardQueryEditor({ panelData, queries, onChange, onRunQuerie
|
||||
};
|
||||
})
|
||||
);
|
||||
}, [panelData, panel]);
|
||||
}, [data, panel]);
|
||||
|
||||
const onUpdateQuery = useCallback(
|
||||
(query: DashboardQuery) => {
|
||||
onChange([query]);
|
||||
if (onRunQueries) {
|
||||
onRunQueries();
|
||||
}
|
||||
onChange(query);
|
||||
onRunQuery();
|
||||
},
|
||||
[onChange, onRunQueries]
|
||||
[onChange, onRunQuery]
|
||||
);
|
||||
|
||||
const onPanelChanged = useCallback(
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { Observable, map, of } from 'rxjs';
|
||||
|
||||
import {
|
||||
DataSourceApi,
|
||||
DataQueryRequest,
|
||||
@ -5,6 +7,13 @@ import {
|
||||
DataSourceInstanceSettings,
|
||||
TestDataSourceResponse,
|
||||
} from '@grafana/data';
|
||||
import { SceneDataProvider, SceneDataTransformer, SceneObject } from '@grafana/scenes';
|
||||
import { PanelEditor } from 'app/features/dashboard-scene/panel-edit/PanelEditor';
|
||||
import {
|
||||
findVizPanelByKey,
|
||||
getQueryRunnerFor,
|
||||
getVizPanelKeyForPanelId,
|
||||
} from 'app/features/dashboard-scene/utils/utils';
|
||||
|
||||
import { DashboardQuery } from './types';
|
||||
|
||||
@ -20,8 +29,68 @@ export class DashboardDatasource extends DataSourceApi<DashboardQuery> {
|
||||
return `Dashboard Reference: ${query.panelId}`;
|
||||
}
|
||||
|
||||
query(options: DataQueryRequest<DashboardQuery>): Promise<DataQueryResponse> {
|
||||
return Promise.reject('This should not be called directly');
|
||||
query(options: DataQueryRequest<DashboardQuery>): Observable<DataQueryResponse> {
|
||||
const scene: SceneObject | undefined = options.scopedVars?.__sceneObject?.value;
|
||||
|
||||
if (!scene) {
|
||||
throw new Error('Can only be called from a scene');
|
||||
}
|
||||
|
||||
const query = options.targets[0];
|
||||
if (!query) {
|
||||
return of({ data: [] });
|
||||
}
|
||||
|
||||
const panelId = query.panelId;
|
||||
|
||||
if (!panelId) {
|
||||
return of({ data: [] });
|
||||
}
|
||||
|
||||
let sourcePanel = this.findSourcePanel(scene, panelId);
|
||||
|
||||
if (!sourcePanel) {
|
||||
return of({ data: [], error: { message: 'Could not find source panel' } });
|
||||
}
|
||||
|
||||
let sourceDataProvider: SceneDataProvider | undefined = getQueryRunnerFor(sourcePanel);
|
||||
|
||||
if (!sourceDataProvider || !sourceDataProvider.getResultsStream) {
|
||||
return of({ data: [] });
|
||||
}
|
||||
|
||||
if (query.withTransforms && sourceDataProvider.parent) {
|
||||
const transformer = sourceDataProvider.parent;
|
||||
if (transformer && transformer instanceof SceneDataTransformer) {
|
||||
sourceDataProvider = transformer;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sourceDataProvider?.isActive) {
|
||||
sourceDataProvider?.activate();
|
||||
sourceDataProvider.setContainerWidth!(500);
|
||||
}
|
||||
|
||||
return sourceDataProvider.getResultsStream!().pipe(
|
||||
map((result) => {
|
||||
return {
|
||||
data: result.data.series,
|
||||
state: result.data.state,
|
||||
errors: result.data.errors,
|
||||
error: result.data.error,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private findSourcePanel(scene: SceneObject, panelId: number) {
|
||||
let sceneToSearch = scene.getRoot();
|
||||
|
||||
if (sceneToSearch instanceof PanelEditor) {
|
||||
sceneToSearch = sceneToSearch.state.dashboardRef.resolve();
|
||||
}
|
||||
|
||||
return findVizPanelByKey(sceneToSearch, getVizPanelKeyForPanelId(panelId));
|
||||
}
|
||||
|
||||
testDatasource(): Promise<TestDataSourceResponse> {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DataSourcePlugin } from '@grafana/data';
|
||||
|
||||
import { DashboardQueryEditor } from './DashboardQueryEditor';
|
||||
import { DashboardDatasource } from './datasource';
|
||||
|
||||
export const plugin = new DataSourcePlugin(DashboardDatasource);
|
||||
export const plugin = new DataSourcePlugin(DashboardDatasource).setQueryEditor(DashboardQueryEditor);
|
||||
|
Loading…
Reference in New Issue
Block a user