diff --git a/public/app/features/dashboard/state/DashboardModel.test.ts b/public/app/features/dashboard/state/DashboardModel.test.ts index f86e3dd0317..d8448135e2e 100644 --- a/public/app/features/dashboard/state/DashboardModel.test.ts +++ b/public/app/features/dashboard/state/DashboardModel.test.ts @@ -572,6 +572,61 @@ describe('DashboardModel', () => { const savedModelWithCollapsedRows: any = model.getSaveModelClone(); expect(savedModelWithCollapsedRows.panels[0].panels.length).toBe(1); }); + + it('getSaveModelClone should not remove repeated panels and scopedVars during snapshot', () => { + const dashboardJSON = { + panels: [ + { id: 1, type: 'row', repeat: 'dc', gridPos: { x: 0, y: 0, h: 1, w: 24 } }, + { id: 2, repeat: 'app', repeatDirection: 'h', gridPos: { x: 0, y: 1, h: 2, w: 8 } }, + ], + templating: { + list: [ + { + name: 'dc', + type: 'custom', + current: { + text: 'dc1 + dc2', + value: ['dc1', 'dc2'], + }, + options: [ + { text: 'dc1', value: 'dc1', selected: true }, + { text: 'dc2', value: 'dc2', selected: true }, + ], + }, + { + name: 'app', + type: 'custom', + current: { + text: 'se1 + se2', + value: ['se1', 'se2'], + }, + options: [ + { text: 'se1', value: 'se1', selected: true }, + { text: 'se2', value: 'se2', selected: true }, + ], + }, + ], + }, + }; + + const model = getDashboardModel(dashboardJSON); + model.processRepeats(); + expect(model.panels.filter((x) => x.type === 'row')).toHaveLength(2); + expect(model.panels.filter((x) => x.type !== 'row')).toHaveLength(4); + expect(model.panels.find((x) => x.type !== 'row')?.scopedVars?.dc.value).toBe('dc1'); + expect(model.panels.find((x) => x.type !== 'row')?.scopedVars?.app.value).toBe('se1'); + + model.snapshot = { timestamp: new Date() }; + const saveModel = model.getSaveModelClone(); + expect(saveModel.panels.filter((x) => x.type === 'row')).toHaveLength(2); + expect(saveModel.panels.filter((x) => x.type !== 'row')).toHaveLength(4); + expect(saveModel.panels.find((x) => x.type !== 'row')?.scopedVars?.dc.value).toBe('dc1'); + expect(saveModel.panels.find((x) => x.type !== 'row')?.scopedVars?.app.value).toBe('se1'); + + model.collapseRows(); + const savedModelWithCollapsedRows: any = model.getSaveModelClone(); + expect(savedModelWithCollapsedRows.panels[0].panels.length).toBe(2); + }); }); describe('Given model with template variable of type query', () => { diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index c9a9cbb3f24..0a179f2d5a4 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -272,6 +272,9 @@ export class DashboardModel { private getPanelSaveModels() { return this.panels .filter((panel: PanelModel) => { + if (this.isSnapshotTruthy()) { + return true; + } if (panel.type === 'add-panel') { return false; } @@ -295,6 +298,9 @@ export class DashboardModel { return panel.getSaveModel(); }) .map((model: any) => { + if (this.isSnapshotTruthy()) { + return model; + } // Clear any scopedVars from persisted mode. This cannot be part of getSaveModel as we need to be able to copy // panel models with preserved scopedVars, for example when going into edit mode. delete model.scopedVars;