| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | import { cloneDeep } from 'lodash'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import { config } from '@grafana/runtime'; | 
					
						
							| 
									
										
										
										
											2024-12-06 01:49:11 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   behaviors, | 
					
						
							|  |  |  |   ConstantVariable, | 
					
						
							|  |  |  |   CustomVariable, | 
					
						
							|  |  |  |   DataSourceVariable, | 
					
						
							|  |  |  |   IntervalVariable, | 
					
						
							|  |  |  |   QueryVariable, | 
					
						
							|  |  |  |   TextBoxVariable, | 
					
						
							|  |  |  |   sceneGraph, | 
					
						
							|  |  |  |   GroupByVariable, | 
					
						
							|  |  |  |   AdHocFiltersVariable, | 
					
						
							| 
									
										
										
										
											2024-12-14 06:29:22 +08:00
										 |  |  |   SceneDataTransformer, | 
					
						
							| 
									
										
										
										
											2024-12-06 01:49:11 +08:00
										 |  |  | } from '@grafana/scenes'; | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   AdhocVariableKind, | 
					
						
							|  |  |  |   ConstantVariableKind, | 
					
						
							|  |  |  |   CustomVariableKind, | 
					
						
							|  |  |  |   DashboardV2Spec, | 
					
						
							|  |  |  |   DatasourceVariableKind, | 
					
						
							|  |  |  |   GroupByVariableKind, | 
					
						
							|  |  |  |   IntervalVariableKind, | 
					
						
							|  |  |  |   QueryVariableKind, | 
					
						
							|  |  |  |   TextVariableKind, | 
					
						
							| 
									
										
										
										
											2025-01-16 20:18:47 +08:00
										 |  |  | } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0'; | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/examples'; | 
					
						
							| 
									
										
										
										
											2025-01-13 20:07:45 +08:00
										 |  |  | import { AnnoKeyDashboardIsNew } from 'app/features/apiserver/types'; | 
					
						
							| 
									
										
										
										
											2024-12-18 05:17:09 +08:00
										 |  |  | import { DashboardWithAccessInfo } from 'app/features/dashboard/api/types'; | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 01:49:11 +08:00
										 |  |  | import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet'; | 
					
						
							| 
									
										
										
										
											2024-12-14 06:29:22 +08:00
										 |  |  | import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager'; | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | import { DashboardLayoutManager } from '../scene/types'; | 
					
						
							|  |  |  | import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; | 
					
						
							|  |  |  | import { getQueryRunnerFor } from '../utils/utils'; | 
					
						
							| 
									
										
										
										
											2024-12-06 01:49:11 +08:00
										 |  |  | import { validateVariable, validateVizPanel } from '../v2schema/test-helpers'; | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-09 23:14:41 +08:00
										 |  |  | import { SnapshotVariable } from './custom-variables/SnapshotVariable'; | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   getLibraryPanelElement, | 
					
						
							|  |  |  |   getPanelElement, | 
					
						
							|  |  |  |   transformSaveModelSchemaV2ToScene, | 
					
						
							|  |  |  | } from './transformSaveModelSchemaV2ToScene'; | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | import { transformCursorSynctoEnum } from './transformToV2TypesUtils'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const defaultDashboard: DashboardWithAccessInfo<DashboardV2Spec> = { | 
					
						
							|  |  |  |   kind: 'DashboardWithAccessInfo', | 
					
						
							|  |  |  |   metadata: { | 
					
						
							|  |  |  |     name: 'dashboard-uid', | 
					
						
							|  |  |  |     namespace: 'default', | 
					
						
							|  |  |  |     labels: {}, | 
					
						
							| 
									
										
										
										
											2025-01-02 19:23:58 +08:00
										 |  |  |     resourceVersion: '123', | 
					
						
							|  |  |  |     creationTimestamp: 'creationTs', | 
					
						
							|  |  |  |     annotations: { | 
					
						
							|  |  |  |       'grafana.app/createdBy': 'user:createBy', | 
					
						
							|  |  |  |       'grafana.app/folder': 'folder-uid', | 
					
						
							|  |  |  |       'grafana.app/updatedBy': 'user:updatedBy', | 
					
						
							|  |  |  |       'grafana.app/updatedTimestamp': 'updatedTs', | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |   }, | 
					
						
							|  |  |  |   spec: handyTestingSchema, | 
					
						
							| 
									
										
										
										
											2025-01-02 19:23:58 +08:00
										 |  |  |   access: { | 
					
						
							|  |  |  |     url: '/d/abc', | 
					
						
							|  |  |  |     slug: 'what-a-dashboard', | 
					
						
							|  |  |  |   }, | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |   apiVersion: 'v2', | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | jest.mock('@grafana/runtime', () => ({ | 
					
						
							|  |  |  |   ...jest.requireActual('@grafana/runtime'), | 
					
						
							|  |  |  |   getDataSourceSrv: () => ({ | 
					
						
							|  |  |  |     getInstanceSettings: jest.fn(), | 
					
						
							|  |  |  |   }), | 
					
						
							|  |  |  | })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe('transformSaveModelSchemaV2ToScene', () => { | 
					
						
							|  |  |  |   beforeAll(() => { | 
					
						
							|  |  |  |     config.featureToggles.groupByVariable = true; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   afterAll(() => { | 
					
						
							|  |  |  |     config.featureToggles.groupByVariable = false; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should initialize the DashboardScene with the model state', () => { | 
					
						
							|  |  |  |     const scene = transformSaveModelSchemaV2ToScene(defaultDashboard); | 
					
						
							|  |  |  |     const dashboardControls = scene.state.controls!; | 
					
						
							|  |  |  |     const dash = defaultDashboard.spec; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(scene.state.uid).toEqual(defaultDashboard.metadata.name); | 
					
						
							|  |  |  |     expect(scene.state.title).toEqual(dash.title); | 
					
						
							|  |  |  |     expect(scene.state.description).toEqual(dash.description); | 
					
						
							|  |  |  |     expect(scene.state.editable).toEqual(dash.editable); | 
					
						
							| 
									
										
										
										
											2024-11-28 17:45:31 +08:00
										 |  |  |     expect(scene.state.preload).toEqual(false); | 
					
						
							| 
									
										
										
										
											2025-01-02 19:23:58 +08:00
										 |  |  |     expect(scene.state.version).toEqual(123); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |     expect(scene.state.tags).toEqual(dash.tags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const liveNow = scene.state.$behaviors?.find((b) => b instanceof behaviors.LiveNowTimer); | 
					
						
							|  |  |  |     expect(liveNow?.state.enabled).toEqual(dash.liveNow); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const cursorSync = scene.state.$behaviors?.find((b) => b instanceof behaviors.CursorSync); | 
					
						
							|  |  |  |     expect(transformCursorSynctoEnum(cursorSync?.state.sync)).toEqual(dash.cursorSync); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Dashboard links
 | 
					
						
							|  |  |  |     expect(scene.state.links).toHaveLength(dash.links.length); | 
					
						
							|  |  |  |     expect(scene.state.links![0].title).toBe(dash.links[0].title); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Time settings
 | 
					
						
							|  |  |  |     const time = dash.timeSettings; | 
					
						
							|  |  |  |     const refreshPicker = dashboardSceneGraph.getRefreshPicker(scene)!; | 
					
						
							|  |  |  |     const timeRange = sceneGraph.getTimeRange(scene)!; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Time settings
 | 
					
						
							|  |  |  |     expect(refreshPicker.state.refresh).toEqual(time.autoRefresh); | 
					
						
							|  |  |  |     expect(refreshPicker.state.intervals).toEqual(time.autoRefreshIntervals); | 
					
						
							|  |  |  |     expect(timeRange?.state.fiscalYearStartMonth).toEqual(dash.timeSettings.fiscalYearStartMonth); | 
					
						
							|  |  |  |     expect(timeRange?.state.value.raw).toEqual({ from: dash.timeSettings.from, to: dash.timeSettings.to }); | 
					
						
							|  |  |  |     expect(dashboardControls.state.hideTimeControls).toEqual(dash.timeSettings.hideTimepicker); | 
					
						
							|  |  |  |     expect(timeRange?.state.UNSAFE_nowDelay).toEqual(dash.timeSettings.nowDelay); | 
					
						
							|  |  |  |     expect(timeRange?.state.timeZone).toEqual(dash.timeSettings.timezone); | 
					
						
							|  |  |  |     expect(timeRange?.state.weekStart).toEqual(dash.timeSettings.weekStart); | 
					
						
							|  |  |  |     expect(dashboardControls).toBeDefined(); | 
					
						
							|  |  |  |     expect(dashboardControls.state.refreshPicker.state.intervals).toEqual(time.autoRefreshIntervals); | 
					
						
							|  |  |  |     expect(dashboardControls.state.hideTimeControls).toBe(time.hideTimepicker); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 01:49:11 +08:00
										 |  |  |     // Variables
 | 
					
						
							|  |  |  |     const variables = scene.state?.$variables; | 
					
						
							|  |  |  |     expect(variables?.state.variables).toHaveLength(dash.variables.length); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[0], | 
					
						
							|  |  |  |       variableKind: dash.variables[0] as QueryVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: QueryVariable, | 
					
						
							|  |  |  |       index: 0, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[1], | 
					
						
							|  |  |  |       variableKind: dash.variables[1] as CustomVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: CustomVariable, | 
					
						
							|  |  |  |       index: 1, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[2], | 
					
						
							|  |  |  |       variableKind: dash.variables[2] as DatasourceVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: DataSourceVariable, | 
					
						
							|  |  |  |       index: 2, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[3], | 
					
						
							|  |  |  |       variableKind: dash.variables[3] as ConstantVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: ConstantVariable, | 
					
						
							|  |  |  |       index: 3, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[4], | 
					
						
							|  |  |  |       variableKind: dash.variables[4] as IntervalVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: IntervalVariable, | 
					
						
							|  |  |  |       index: 4, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[5], | 
					
						
							|  |  |  |       variableKind: dash.variables[5] as TextVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: TextBoxVariable, | 
					
						
							|  |  |  |       index: 5, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[6], | 
					
						
							|  |  |  |       variableKind: dash.variables[6] as GroupByVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: GroupByVariable, | 
					
						
							|  |  |  |       index: 6, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     validateVariable({ | 
					
						
							|  |  |  |       sceneVariable: variables?.state.variables[7], | 
					
						
							|  |  |  |       variableKind: dash.variables[7] as AdhocVariableKind, | 
					
						
							|  |  |  |       scene: scene, | 
					
						
							|  |  |  |       dashSpec: dash, | 
					
						
							|  |  |  |       sceneVariableClass: AdHocFiltersVariable, | 
					
						
							|  |  |  |       index: 7, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Annotations
 | 
					
						
							|  |  |  |     expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet); | 
					
						
							|  |  |  |     const dataLayers = scene.state.$data as DashboardDataLayerSet; | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers).toHaveLength(dash.annotations.length); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[0].state.name).toBe(dash.annotations[0].spec.name); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[0].state.isEnabled).toBe(dash.annotations[0].spec.enable); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[0].state.isHidden).toBe(dash.annotations[0].spec.hide); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Enabled
 | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[1].state.name).toBe(dash.annotations[1].spec.name); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[1].state.isEnabled).toBe(dash.annotations[1].spec.enable); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[1].state.isHidden).toBe(dash.annotations[1].spec.hide); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Disabled
 | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[2].state.name).toBe(dash.annotations[2].spec.name); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[2].state.isEnabled).toBe(dash.annotations[2].spec.enable); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[2].state.isHidden).toBe(dash.annotations[2].spec.hide); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Hidden
 | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[3].state.name).toBe(dash.annotations[3].spec.name); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[3].state.isEnabled).toBe(dash.annotations[3].spec.enable); | 
					
						
							|  |  |  |     expect(dataLayers.state.annotationLayers[3].state.isHidden).toBe(dash.annotations[3].spec.hide); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // To be implemented
 | 
					
						
							|  |  |  |     // expect(timePicker.state.ranges).toEqual(dash.timeSettings.quickRanges);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // VizPanel
 | 
					
						
							|  |  |  |     const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels(); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     expect(vizPanels).toHaveLength(2); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-14 06:29:22 +08:00
										 |  |  |     // Layout
 | 
					
						
							|  |  |  |     const layout = scene.state.body as DefaultGridLayoutManager; | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Panel
 | 
					
						
							|  |  |  |     const panel = getPanelElement(dash, 'panel-1')!; | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children.length).toBe(2); | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[0].state.key).toBe(`grid-item-${panel.spec.id}`); | 
					
						
							| 
									
										
										
										
											2024-12-14 06:29:22 +08:00
										 |  |  |     const gridLayoutItemSpec = dash.layout.spec.items[0].spec; | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[0].state.width).toBe(gridLayoutItemSpec.width); | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[0].state.height).toBe(gridLayoutItemSpec.height); | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[0].state.x).toBe(gridLayoutItemSpec.x); | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[0].state.y).toBe(gridLayoutItemSpec.y); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     const vizPanel = vizPanels.find((p) => p.state.key === 'panel-1')!; | 
					
						
							|  |  |  |     validateVizPanel(vizPanel, dash); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Library Panel
 | 
					
						
							| 
									
										
										
										
											2025-01-23 19:57:45 +08:00
										 |  |  |     const libraryPanel = getLibraryPanelElement(dash, 'panel-2')!; | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[1].state.key).toBe(`grid-item-${libraryPanel.spec.id}`); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     const libraryGridLayoutItemSpec = dash.layout.spec.items[1].spec; | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[1].state.width).toBe(libraryGridLayoutItemSpec.width); | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[1].state.height).toBe(libraryGridLayoutItemSpec.height); | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[1].state.x).toBe(libraryGridLayoutItemSpec.x); | 
					
						
							|  |  |  |     expect(layout.state.grid.state.children[1].state.y).toBe(libraryGridLayoutItemSpec.y); | 
					
						
							| 
									
										
										
										
											2025-01-23 19:57:45 +08:00
										 |  |  |     const vizLibraryPanel = vizPanels.find((p) => p.state.key === 'panel-2')!; | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     validateVizPanel(vizLibraryPanel, dash); | 
					
						
							| 
									
										
										
										
											2024-12-14 06:29:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Transformations
 | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     const panelWithTransformations = vizPanels.find((p) => p.state.key === 'panel-1')!; | 
					
						
							|  |  |  |     expect((panelWithTransformations.state.$data as SceneDataTransformer)?.state.transformations[0]).toEqual( | 
					
						
							|  |  |  |       getPanelElement(dash, 'panel-1')!.spec.data.spec.transformations[0].spec | 
					
						
							| 
									
										
										
										
											2024-12-14 06:29:22 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should set panel ds if it is mixed DS', () => { | 
					
						
							|  |  |  |     const dashboard = cloneDeep(defaultDashboard); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     getPanelElement(dashboard.spec, 'panel-1')?.spec.data.spec.queries.push({ | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |       kind: 'PanelQuery', | 
					
						
							|  |  |  |       spec: { | 
					
						
							|  |  |  |         refId: 'A', | 
					
						
							|  |  |  |         datasource: { | 
					
						
							|  |  |  |           type: 'graphite', | 
					
						
							|  |  |  |           uid: 'datasource1', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         hidden: false, | 
					
						
							|  |  |  |         query: { | 
					
						
							|  |  |  |           kind: 'prometheus', | 
					
						
							|  |  |  |           spec: { | 
					
						
							|  |  |  |             expr: 'test-query', | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels(); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     expect(vizPanels.length).toBe(2); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |     expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.type).toBe('mixed'); | 
					
						
							|  |  |  |     expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.uid).toBe(MIXED_DATASOURCE_NAME); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should set panel ds as undefined if it is not mixed DS', () => { | 
					
						
							|  |  |  |     const dashboard = cloneDeep(defaultDashboard); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     getPanelElement(dashboard.spec, 'panel-1')?.spec.data.spec.queries.push({ | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |       kind: 'PanelQuery', | 
					
						
							|  |  |  |       spec: { | 
					
						
							|  |  |  |         refId: 'A', | 
					
						
							|  |  |  |         datasource: { | 
					
						
							|  |  |  |           type: 'prometheus', | 
					
						
							|  |  |  |           uid: 'datasource1', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         hidden: false, | 
					
						
							|  |  |  |         query: { | 
					
						
							|  |  |  |           kind: 'prometheus', | 
					
						
							|  |  |  |           spec: { | 
					
						
							|  |  |  |             expr: 'test-query', | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels(); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     expect(vizPanels.length).toBe(2); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |     expect(getQueryRunnerFor(vizPanels[0])?.state.datasource).toBeUndefined(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-28 18:36:09 +08:00
										 |  |  |   it('should set panel ds as mixed if one ds is undefined', () => { | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |     const dashboard = cloneDeep(defaultDashboard); | 
					
						
							| 
									
										
										
										
											2024-11-28 18:36:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     getPanelElement(dashboard.spec, 'panel-1')?.spec.data.spec.queries.push({ | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |       kind: 'PanelQuery', | 
					
						
							|  |  |  |       spec: { | 
					
						
							|  |  |  |         refId: 'A', | 
					
						
							|  |  |  |         hidden: false, | 
					
						
							|  |  |  |         query: { | 
					
						
							|  |  |  |           kind: 'prometheus', | 
					
						
							|  |  |  |           spec: { | 
					
						
							|  |  |  |             expr: 'test-query', | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels(); | 
					
						
							| 
									
										
										
										
											2025-01-20 19:44:36 +08:00
										 |  |  |     expect(vizPanels.length).toBe(2); | 
					
						
							| 
									
										
										
										
											2024-11-28 18:36:09 +08:00
										 |  |  |     expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.type).toBe('mixed'); | 
					
						
							|  |  |  |     expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.uid).toBe(MIXED_DATASOURCE_NAME); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2024-12-31 18:56:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-09 23:14:41 +08:00
										 |  |  |   describe('When creating a snapshot dashboard scene', () => { | 
					
						
							|  |  |  |     it('should initialize a dashboard scene with SnapshotVariables', () => { | 
					
						
							|  |  |  |       const snapshot: DashboardWithAccessInfo<DashboardV2Spec> = { | 
					
						
							|  |  |  |         ...defaultDashboard, | 
					
						
							|  |  |  |         metadata: { | 
					
						
							|  |  |  |           ...defaultDashboard.metadata, | 
					
						
							|  |  |  |           annotations: { | 
					
						
							|  |  |  |             ...defaultDashboard.metadata.annotations, | 
					
						
							|  |  |  |             'grafana.app/dashboard-is-snapshot': true, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const scene = transformSaveModelSchemaV2ToScene(snapshot); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // check variables were converted to snapshot variables
 | 
					
						
							|  |  |  |       expect(scene.state.$variables?.state.variables).toHaveLength(8); | 
					
						
							|  |  |  |       expect(scene.state.$variables?.getByName('customVar')).toBeInstanceOf(SnapshotVariable); | 
					
						
							|  |  |  |       expect(scene.state.$variables?.getByName('adhocVar')).toBeInstanceOf(AdHocFiltersVariable); | 
					
						
							|  |  |  |       expect(scene.state.$variables?.getByName('intervalVar')).toBeInstanceOf(SnapshotVariable); | 
					
						
							|  |  |  |       // custom snapshot
 | 
					
						
							|  |  |  |       const customSnapshot = scene.state.$variables?.getByName('customVar') as SnapshotVariable; | 
					
						
							|  |  |  |       expect(customSnapshot.state.value).toBe('option1'); | 
					
						
							|  |  |  |       expect(customSnapshot.state.text).toBe('option1'); | 
					
						
							|  |  |  |       expect(customSnapshot.state.isReadOnly).toBe(true); | 
					
						
							|  |  |  |       // adhoc snapshot
 | 
					
						
							|  |  |  |       const adhocSnapshot = scene.state.$variables?.getByName('adhocVar') as AdHocFiltersVariable; | 
					
						
							|  |  |  |       const adhocVariable = snapshot.spec.variables[7] as AdhocVariableKind; | 
					
						
							|  |  |  |       expect(adhocSnapshot.state.filters).toEqual(adhocVariable.spec.filters); | 
					
						
							|  |  |  |       expect(adhocSnapshot.state.readOnly).toBe(true); | 
					
						
							|  |  |  |       // interval snapshot
 | 
					
						
							|  |  |  |       const intervalSnapshot = scene.state.$variables?.getByName('intervalVar') as SnapshotVariable; | 
					
						
							|  |  |  |       expect(intervalSnapshot.state.value).toBe('1m'); | 
					
						
							|  |  |  |       expect(intervalSnapshot.state.text).toBe('1m'); | 
					
						
							|  |  |  |       expect(intervalSnapshot.state.isReadOnly).toBe(true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-02 19:23:58 +08:00
										 |  |  |   describe('meta', () => { | 
					
						
							|  |  |  |     describe('initializes meta based on k8s resource', () => { | 
					
						
							|  |  |  |       it('handles undefined access values', () => { | 
					
						
							|  |  |  |         const scene = transformSaveModelSchemaV2ToScene(defaultDashboard); | 
					
						
							|  |  |  |         // when access metadata undefined
 | 
					
						
							|  |  |  |         expect(scene.state.meta.canShare).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.canSave).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.canStar).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.canEdit).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.canDelete).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.canAdmin).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.annotationsPermissions).toBe(undefined); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(scene.state.meta.url).toBe('/d/abc'); | 
					
						
							|  |  |  |         expect(scene.state.meta.slug).toBe('what-a-dashboard'); | 
					
						
							|  |  |  |         expect(scene.state.meta.created).toBe('creationTs'); | 
					
						
							|  |  |  |         expect(scene.state.meta.createdBy).toBe('user:createBy'); | 
					
						
							|  |  |  |         expect(scene.state.meta.updated).toBe('updatedTs'); | 
					
						
							|  |  |  |         expect(scene.state.meta.updatedBy).toBe('user:updatedBy'); | 
					
						
							|  |  |  |         expect(scene.state.meta.folderUid).toBe('folder-uid'); | 
					
						
							|  |  |  |         expect(scene.state.meta.version).toBe(123); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('handles access metadata values', () => { | 
					
						
							|  |  |  |         const dashboard: DashboardWithAccessInfo<DashboardV2Spec> = { | 
					
						
							|  |  |  |           ...defaultDashboard, | 
					
						
							|  |  |  |           access: { | 
					
						
							|  |  |  |             canSave: false, | 
					
						
							|  |  |  |             canEdit: false, | 
					
						
							|  |  |  |             canDelete: false, | 
					
						
							|  |  |  |             canShare: false, | 
					
						
							|  |  |  |             canStar: false, | 
					
						
							|  |  |  |             canAdmin: false, | 
					
						
							|  |  |  |             annotationsPermissions: { | 
					
						
							|  |  |  |               dashboard: { | 
					
						
							|  |  |  |                 canAdd: false, | 
					
						
							|  |  |  |                 canEdit: false, | 
					
						
							|  |  |  |                 canDelete: false, | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |               organization: { | 
					
						
							|  |  |  |                 canAdd: false, | 
					
						
							|  |  |  |                 canEdit: false, | 
					
						
							|  |  |  |                 canDelete: false, | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(scene.state.meta.canShare).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.canSave).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.canStar).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.canEdit).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.canDelete).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.canAdmin).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.annotationsPermissions).toEqual(dashboard.access.annotationsPermissions); | 
					
						
							|  |  |  |         expect(scene.state.meta.version).toBe(123); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2024-12-31 18:56:42 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2025-01-02 19:23:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     describe('Editable false dashboard', () => { | 
					
						
							|  |  |  |       let dashboard: DashboardWithAccessInfo<DashboardV2Spec>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							|  |  |  |         dashboard = { | 
					
						
							|  |  |  |           ...cloneDeep(defaultDashboard), | 
					
						
							|  |  |  |           spec: { | 
					
						
							|  |  |  |             ...defaultDashboard.spec, | 
					
						
							|  |  |  |             editable: false, | 
					
						
							| 
									
										
										
										
											2024-12-31 18:56:42 +08:00
										 |  |  |           }, | 
					
						
							| 
									
										
										
										
											2025-01-02 19:23:58 +08:00
										 |  |  |         }; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       it('Should set meta canEdit and canSave to false', () => { | 
					
						
							|  |  |  |         const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  |         expect(scene.state.meta.canMakeEditable).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(scene.state.meta.canSave).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.canEdit).toBe(false); | 
					
						
							|  |  |  |         expect(scene.state.meta.canDelete).toBe(false); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe('when does not have save permissions', () => { | 
					
						
							|  |  |  |         it('Should set meta correct meta', () => { | 
					
						
							|  |  |  |           dashboard.access.canSave = false; | 
					
						
							|  |  |  |           const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  |           expect(scene.state.meta.canMakeEditable).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(scene.state.meta.canSave).toBe(false); | 
					
						
							|  |  |  |           expect(scene.state.meta.canEdit).toBe(false); | 
					
						
							|  |  |  |           expect(scene.state.meta.canDelete).toBe(false); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('Editable true dashboard', () => { | 
					
						
							|  |  |  |       let dashboard: DashboardWithAccessInfo<DashboardV2Spec>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							|  |  |  |         dashboard = { | 
					
						
							|  |  |  |           ...cloneDeep(defaultDashboard), | 
					
						
							|  |  |  |           spec: { | 
					
						
							|  |  |  |             ...defaultDashboard.spec, | 
					
						
							|  |  |  |             editable: true, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       it('Should set meta canEdit and canSave to false', () => { | 
					
						
							|  |  |  |         const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(scene.state.meta.canMakeEditable).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(scene.state.meta.canSave).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.canEdit).toBe(true); | 
					
						
							|  |  |  |         expect(scene.state.meta.canDelete).toBe(true); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2025-01-13 20:07:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     describe('is new dashboard handling', () => { | 
					
						
							|  |  |  |       it('handles undefined is new dashbaord annotation', () => { | 
					
						
							|  |  |  |         const scene = transformSaveModelSchemaV2ToScene(defaultDashboard); | 
					
						
							|  |  |  |         expect(scene.state.meta.isNew).toBe(false); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       it('handles defined is new dashbaord annotation', () => { | 
					
						
							|  |  |  |         const dashboard: DashboardWithAccessInfo<DashboardV2Spec> = { | 
					
						
							|  |  |  |           ...defaultDashboard, | 
					
						
							|  |  |  |           metadata: { | 
					
						
							|  |  |  |             ...defaultDashboard.metadata, | 
					
						
							|  |  |  |             annotations: { | 
					
						
							|  |  |  |               ...defaultDashboard.metadata.annotations, | 
					
						
							|  |  |  |               [AnnoKeyDashboardIsNew]: true, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         const scene = transformSaveModelSchemaV2ToScene(dashboard); | 
					
						
							|  |  |  |         expect(scene.state.meta.isNew).toBe(true); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2024-12-31 18:56:42 +08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2024-11-27 21:35:37 +08:00
										 |  |  | }); |