diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx index 1786c59882b..a261687ea1c 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx @@ -159,6 +159,7 @@ const dashboard = { folderId: 1, folderTitle: 'super folder', }, + isSnapshot: () => false, } as unknown as DashboardModel; const panel = new PanelModel({ diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts index 2567575f3bf..c43026dd293 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts @@ -49,6 +49,7 @@ import { NEW_LINK } from '../settings/links/utils'; import { getQueryRunnerFor } from '../utils/utils'; import { buildNewDashboardSaveModel } from './buildNewDashboardSaveModel'; +import { GRAFANA_DATASOURCE_REF } from './const'; import dashboard_to_load1 from './testfiles/dashboard_to_load1.json'; import repeatingRowsAndPanelsDashboardJson from './testfiles/repeating_rows_and_panels.json'; import { @@ -56,6 +57,7 @@ import { buildGridItemForPanel, createSceneVariableFromVariableModel, transformSaveModelToScene, + convertOldSnapshotToScenesSnapshot, } from './transformSaveModelToScene'; describe('transformSaveModelToScene', () => { @@ -1080,6 +1082,52 @@ describe('transformSaveModelToScene', () => { expect(dataLayers.state.layers[4].state.name).toBe('Alert States'); }); }); + + describe('when rendering a legacy snapshot as scene', () => { + it('should convert snapshotData to snapshot inside targets', () => { + const panel = createPanelSaveModel({ + title: 'test', + gridPos: { x: 1, y: 0, w: 12, h: 8 }, + // @ts-ignore + snapshotData: [ + { + fields: [ + { + name: 'Field 1', + type: 'time', + values: ['value1', 'value2'], + config: {}, + }, + { + name: 'Field 2', + type: 'number', + values: [1], + config: {}, + }, + ], + }, + ], + }) as Panel; + + const oldPanelModel = new PanelModel(panel); + convertOldSnapshotToScenesSnapshot(oldPanelModel); + + expect(oldPanelModel.snapshotData?.length).toStrictEqual(0); + expect(oldPanelModel.targets.length).toStrictEqual(1); + expect(oldPanelModel.datasource).toStrictEqual(GRAFANA_DATASOURCE_REF); + expect(oldPanelModel.targets[0].datasource).toStrictEqual(GRAFANA_DATASOURCE_REF); + expect(oldPanelModel.targets[0].queryType).toStrictEqual('snapshot'); + // @ts-ignore + expect(oldPanelModel.targets[0].snapshot.length).toBe(1); + // @ts-ignore + expect(oldPanelModel.targets[0].snapshot[0].data.values).toStrictEqual([['value1', 'value2'], [1]]); + // @ts-ignore + expect(oldPanelModel.targets[0].snapshot[0].schema.fields).toStrictEqual([ + { config: {}, name: 'Field 1', type: 'time' }, + { config: {}, name: 'Field 2', type: 'number' }, + ]); + }); + }); }); function buildGridItemForTest(saveModel: Partial): { gridItem: SceneGridItem; vizPanel: VizPanel } { diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index 9b7e0c988c5..611375cc10a 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -1,4 +1,4 @@ -import { TypedVariableModel } from '@grafana/data'; +import { DataFrameDTO, DataFrameJSON, TypedVariableModel } from '@grafana/data'; import { config } from '@grafana/runtime'; import { VizPanel, @@ -55,6 +55,7 @@ import { } from '../utils/utils'; import { getAngularPanelMigrationHandler } from './angularMigration'; +import { GRAFANA_DATASOURCE_REF } from './const'; export interface DashboardLoaderState { dashboard?: DashboardScene; @@ -114,6 +115,11 @@ export function createSceneObjectsForPanels(oldPanels: PanelModel[]): SceneGridI panels.push(gridItem); } } else { + // when rendering a snapshot created with the legacy Dashboards convert data to new snapshot format to be compatible with Scenes + if (panel.snapshotData) { + convertOldSnapshotToScenesSnapshot(panel); + } + const panelObject = buildGridItemForPanel(panel); // when processing an expanded row, collect its panels @@ -371,7 +377,7 @@ export function createSceneVariableFromVariableModel(variable: TypedVariableMode } else if (variable.type === 'textbox') { return new TextBoxVariable({ ...commonProperties, - value: variable.query, + value: variable?.current?.value?.[0] ?? variable.query, skipUrlSync: variable.skipUrlSync, hide: variable.hide, }); @@ -528,3 +534,38 @@ function registerPanelInteractionsReporter(scene: DashboardScene) { } }); } + +const convertSnapshotData = (snapshotData: DataFrameDTO[]): DataFrameJSON[] => { + return snapshotData.map((data) => { + return { + data: { + values: data.fields.map((field) => field.values).filter((values): values is unknown[] => values !== undefined), + }, + schema: { + fields: data.fields.map((field) => ({ + name: field.name, + type: field.type, + config: field.config, + })), + }, + }; + }); +}; + +// override panel datasource and targets with snapshot data using the Grafana datasource +export const convertOldSnapshotToScenesSnapshot = (panel: PanelModel) => { + // only old snapshots created with old dashboards contains snapshotData + if (panel.snapshotData) { + panel.datasource = GRAFANA_DATASOURCE_REF; + panel.targets = [ + { + refId: panel.snapshotData[0]?.refId ?? '', + datasource: panel.datasource, + queryType: 'snapshot', + // @ts-ignore + snapshot: convertSnapshotData(panel.snapshotData), + }, + ]; + panel.snapshotData = []; + } +};