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"]
|
||||
],
|
||||
"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": [
|
||||
[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>",
|
||||
"mode": "markdown",
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "",
|
||||
"transformations": [],
|
||||
"transparent": false,
|
||||
@ -266,6 +271,10 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A",
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@ -298,6 +307,18 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
||||
"sort": "none",
|
||||
},
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"alias": "series",
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A",
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"seriesCount": 1,
|
||||
},
|
||||
],
|
||||
"title": "Simple time series graph ",
|
||||
"transformations": [],
|
||||
"transparent": false,
|
||||
@ -317,6 +338,10 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
||||
"type": "row",
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A",
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": [],
|
||||
@ -329,6 +354,18 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
||||
},
|
||||
"id": 29,
|
||||
"options": {},
|
||||
"targets": [
|
||||
{
|
||||
"alias": "series",
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A",
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"seriesCount": 1,
|
||||
},
|
||||
],
|
||||
"title": "panel inside row",
|
||||
"transformations": [],
|
||||
"transparent": false,
|
||||
@ -355,6 +392,11 @@ exports[`transformSceneToSaveModel Given a simple scene Should transform back to
|
||||
"content": "content",
|
||||
"mode": "markdown",
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "Transparent text panel",
|
||||
"transformations": [],
|
||||
"transparent": true,
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
} from '@grafana/scenes';
|
||||
import { Panel, RowPanel } from '@grafana/schema';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
|
||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||
|
||||
@ -131,6 +132,189 @@ describe('transformSceneToSaveModel', () => {
|
||||
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 {
|
||||
|
@ -7,14 +7,26 @@ import {
|
||||
VizPanel,
|
||||
dataLayers,
|
||||
SceneDataLayerProvider,
|
||||
SceneQueryRunner,
|
||||
SceneDataTransformer,
|
||||
} 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 { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
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';
|
||||
|
||||
export function transformSceneToSaveModel(scene: DashboardScene): Dashboard {
|
||||
@ -118,6 +130,58 @@ export function gridItemToPanel(gridItem: SceneGridItemLike): Panel {
|
||||
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') {
|
||||
panel.transparent = true;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ export function createPanelDataProvider(panel: PanelModel): SceneDataProvider |
|
||||
dataProvider = new ShareQueryDataProvider({ query: panel.targets[0] });
|
||||
} else {
|
||||
dataProvider = new SceneQueryRunner({
|
||||
datasource: panel.datasource ?? undefined,
|
||||
queries: panel.targets,
|
||||
maxDataPoints: panel.maxDataPoints ?? undefined,
|
||||
dataLayerFilter: {
|
||||
|
Loading…
Reference in New Issue
Block a user