mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScene serialization: Handle transformations and queries (#75907)
* Serialization: Handle transformations and queries * Betterer
This commit is contained in:
parent
40a41113aa
commit
1a5d5c2820
@ -3016,7 +3016,8 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "4"]
|
||||||
],
|
],
|
||||||
"public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts:5381": [
|
"public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||||
|
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||||
],
|
],
|
||||||
"public/app/features/dashboard-scene/utils/test-utils.ts:5381": [
|
"public/app/features/dashboard-scene/utils/test-utils.ts:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||||
|
@ -123,6 +123,11 @@ exports[`transformSceneToSaveModel Given a scene with rows Should transform back
|
|||||||
</div>",
|
</div>",
|
||||||
"mode": "markdown",
|
"mode": "markdown",
|
||||||
},
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
},
|
||||||
|
],
|
||||||
"title": "",
|
"title": "",
|
||||||
"transformations": [],
|
"transformations": [],
|
||||||
"transparent": false,
|
"transparent": false,
|
||||||
@ -266,6 +271,10 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
|||||||
"links": [],
|
"links": [],
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "testdata",
|
||||||
|
"uid": "PD8C576611E62080A",
|
||||||
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"color": {
|
"color": {
|
||||||
@ -298,6 +307,18 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
|||||||
"sort": "none",
|
"sort": "none",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"alias": "series",
|
||||||
|
"datasource": {
|
||||||
|
"type": "testdata",
|
||||||
|
"uid": "PD8C576611E62080A",
|
||||||
|
},
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "random_walk",
|
||||||
|
"seriesCount": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
"title": "Simple time series graph ",
|
"title": "Simple time series graph ",
|
||||||
"transformations": [],
|
"transformations": [],
|
||||||
"transparent": false,
|
"transparent": false,
|
||||||
@ -317,6 +338,10 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
|||||||
"type": "row",
|
"type": "row",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "testdata",
|
||||||
|
"uid": "PD8C576611E62080A",
|
||||||
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {},
|
"defaults": {},
|
||||||
"overrides": [],
|
"overrides": [],
|
||||||
@ -329,6 +354,18 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
|||||||
},
|
},
|
||||||
"id": 29,
|
"id": 29,
|
||||||
"options": {},
|
"options": {},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"alias": "series",
|
||||||
|
"datasource": {
|
||||||
|
"type": "testdata",
|
||||||
|
"uid": "PD8C576611E62080A",
|
||||||
|
},
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "random_walk",
|
||||||
|
"seriesCount": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
"title": "panel inside row",
|
"title": "panel inside row",
|
||||||
"transformations": [],
|
"transformations": [],
|
||||||
"transparent": false,
|
"transparent": false,
|
||||||
@ -355,6 +392,11 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
|||||||
"content": "content",
|
"content": "content",
|
||||||
"mode": "markdown",
|
"mode": "markdown",
|
||||||
},
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
},
|
||||||
|
],
|
||||||
"title": "Transparent text panel",
|
"title": "Transparent text panel",
|
||||||
"transformations": [],
|
"transformations": [],
|
||||||
"transparent": true,
|
"transparent": true,
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
} from '@grafana/scenes';
|
} from '@grafana/scenes';
|
||||||
import { Panel, RowPanel } from '@grafana/schema';
|
import { Panel, RowPanel } from '@grafana/schema';
|
||||||
import { PanelModel } from 'app/features/dashboard/state';
|
import { PanelModel } from 'app/features/dashboard/state';
|
||||||
|
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||||
|
|
||||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||||
|
|
||||||
@ -131,6 +132,189 @@ describe('transformSceneToSaveModel', () => {
|
|||||||
expect(saveModel.annotations?.list?.[3].hide).toEqual(false);
|
expect(saveModel.annotations?.list?.[3].hide).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Queries', () => {
|
||||||
|
it('Given panel with queries', () => {
|
||||||
|
const panel = buildGridItemFromPanelSchema({
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
},
|
||||||
|
maxDataPoints: 100,
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
expr: 'A',
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
refId: 'B',
|
||||||
|
expr: 'B',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = gridItemToPanel(panel);
|
||||||
|
|
||||||
|
expect(result.maxDataPoints).toBe(100);
|
||||||
|
expect(result.targets?.length).toBe(2);
|
||||||
|
expect(result.targets?.[0]).toEqual({
|
||||||
|
refId: 'A',
|
||||||
|
expr: 'A',
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.datasource).toEqual({
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Given panel with transformations', () => {
|
||||||
|
const panel = buildGridItemFromPanelSchema({
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
},
|
||||||
|
maxDataPoints: 100,
|
||||||
|
|
||||||
|
transformations: [
|
||||||
|
{
|
||||||
|
id: 'reduce',
|
||||||
|
options: {
|
||||||
|
reducers: ['max'],
|
||||||
|
mode: 'reduceFields',
|
||||||
|
includeTimeField: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
expr: 'A',
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
refId: 'B',
|
||||||
|
expr: 'B',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = gridItemToPanel(panel);
|
||||||
|
|
||||||
|
expect(result.transformations.length).toBe(1);
|
||||||
|
|
||||||
|
expect(result.maxDataPoints).toBe(100);
|
||||||
|
expect(result.targets?.length).toBe(2);
|
||||||
|
expect(result.targets?.[0]).toEqual({
|
||||||
|
refId: 'A',
|
||||||
|
expr: 'A',
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.datasource).toEqual({
|
||||||
|
type: 'grafana-testdata',
|
||||||
|
uid: 'abc',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Given panel with shared query', () => {
|
||||||
|
const panel = buildGridItemFromPanelSchema({
|
||||||
|
datasource: {
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
},
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
panelId: 1,
|
||||||
|
datasource: {
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = gridItemToPanel(panel);
|
||||||
|
|
||||||
|
expect(result.targets?.length).toBe(1);
|
||||||
|
expect(result.targets?.[0]).toEqual({
|
||||||
|
refId: 'A',
|
||||||
|
panelId: 1,
|
||||||
|
datasource: {
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.datasource).toEqual({
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Given panel with shared query and transformations', () => {
|
||||||
|
const panel = buildGridItemFromPanelSchema({
|
||||||
|
datasource: {
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
},
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
panelId: 1,
|
||||||
|
datasource: {
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
transformations: [
|
||||||
|
{
|
||||||
|
id: 'reduce',
|
||||||
|
options: {
|
||||||
|
reducers: ['max'],
|
||||||
|
mode: 'reduceFields',
|
||||||
|
includeTimeField: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = gridItemToPanel(panel);
|
||||||
|
|
||||||
|
expect(result.transformations.length).toBe(1);
|
||||||
|
|
||||||
|
expect(result.targets?.length).toBe(1);
|
||||||
|
expect(result.targets?.[0]).toEqual({
|
||||||
|
refId: 'A',
|
||||||
|
panelId: 1,
|
||||||
|
datasource: {
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.datasource).toEqual({
|
||||||
|
type: 'datasource',
|
||||||
|
uid: SHARED_DASHBOARD_QUERY,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export function buildGridItemFromPanelSchema(panel: Partial<Panel>): SceneGridItemLike {
|
export function buildGridItemFromPanelSchema(panel: Partial<Panel>): SceneGridItemLike {
|
||||||
|
@ -7,14 +7,26 @@ import {
|
|||||||
VizPanel,
|
VizPanel,
|
||||||
dataLayers,
|
dataLayers,
|
||||||
SceneDataLayerProvider,
|
SceneDataLayerProvider,
|
||||||
|
SceneQueryRunner,
|
||||||
|
SceneDataTransformer,
|
||||||
} from '@grafana/scenes';
|
} from '@grafana/scenes';
|
||||||
import { AnnotationQuery, Dashboard, defaultDashboard, FieldConfigSource, Panel, RowPanel } from '@grafana/schema';
|
import {
|
||||||
|
AnnotationQuery,
|
||||||
|
Dashboard,
|
||||||
|
DataTransformerConfig,
|
||||||
|
defaultDashboard,
|
||||||
|
FieldConfigSource,
|
||||||
|
Panel,
|
||||||
|
RowPanel,
|
||||||
|
} from '@grafana/schema';
|
||||||
import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object';
|
import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object';
|
||||||
|
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||||
|
|
||||||
import { DashboardScene } from '../scene/DashboardScene';
|
import { DashboardScene } from '../scene/DashboardScene';
|
||||||
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
|
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
|
||||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||||
|
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||||
|
|
||||||
export function transformSceneToSaveModel(scene: DashboardScene): Dashboard {
|
export function transformSceneToSaveModel(scene: DashboardScene): Dashboard {
|
||||||
@ -118,6 +130,58 @@ export function gridItemToPanel(gridItem: SceneGridItemLike): Panel {
|
|||||||
panel.hideTimeOverride = panelTime.state.hideTimeOverride;
|
panel.hideTimeOverride = panelTime.state.hideTimeOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dataProvider = vizPanel.state.$data;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
panel.targets = dataProvider.state.queries;
|
||||||
|
panel.maxDataPoints = dataProvider.state.maxDataPoints;
|
||||||
|
panel.datasource = dataProvider.state.datasource;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
panel.maxDataPoints = panelData.state.maxDataPoints;
|
||||||
|
panel.datasource = panelData.state.datasource;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.transformations = dataProvider.state.transformations as DataTransformerConfig[];
|
||||||
|
}
|
||||||
|
|
||||||
if (vizPanel.state.displayMode === 'transparent') {
|
if (vizPanel.state.displayMode === 'transparent') {
|
||||||
panel.transparent = true;
|
panel.transparent = true;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ export function createPanelDataProvider(panel: PanelModel): SceneDataProvider |
|
|||||||
dataProvider = new ShareQueryDataProvider({ query: panel.targets[0] });
|
dataProvider = new ShareQueryDataProvider({ query: panel.targets[0] });
|
||||||
} else {
|
} else {
|
||||||
dataProvider = new SceneQueryRunner({
|
dataProvider = new SceneQueryRunner({
|
||||||
|
datasource: panel.datasource ?? undefined,
|
||||||
queries: panel.targets,
|
queries: panel.targets,
|
||||||
maxDataPoints: panel.maxDataPoints ?? undefined,
|
maxDataPoints: panel.maxDataPoints ?? undefined,
|
||||||
dataLayerFilter: {
|
dataLayerFilter: {
|
||||||
|
Loading…
Reference in New Issue
Block a user