diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index 28bc2692997..04389a82c77 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -44,7 +44,7 @@ import { isAllVariable } from '../../variables/utils'; import { DashboardPanelsChangedEvent, RenderEvent } from 'app/types/events'; import { getTimeSrv } from '../services/TimeSrv'; import { mergePanels, PanelMergeInfo } from '../utils/panelMerge'; -import { isOnTheSameGridRow } from './utils'; +import { deleteScopeVars, isOnTheSameGridRow } from './utils'; import { RefreshEvent, TimeRangeUpdatedEvent } from '@grafana/runtime'; import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object'; import { Subscription } from 'rxjs'; @@ -553,9 +553,7 @@ export class DashboardModel { const panelsToRemove = []; // cleanup scopedVars - for (const panel of this.panels) { - delete panel.scopedVars; - } + deleteScopeVars(this.panels); for (let i = 0; i < this.panels.length; i++) { const panel = this.panels[i]; diff --git a/public/app/features/dashboard/state/utils.test.ts b/public/app/features/dashboard/state/utils.test.ts index d6f35a986d5..a1399d82a3d 100644 --- a/public/app/features/dashboard/state/utils.test.ts +++ b/public/app/features/dashboard/state/utils.test.ts @@ -1,5 +1,5 @@ import { PanelModel } from './PanelModel'; -import { isOnTheSameGridRow } from './utils'; +import { deleteScopeVars, isOnTheSameGridRow } from './utils'; import { REPEAT_DIR_HORIZONTAL } from '../../../core/constants'; describe('isOnTheSameGridRow', () => { @@ -33,3 +33,30 @@ describe('isOnTheSameGridRow', () => { }); }); }); + +describe('deleteScopeVars', () => { + describe('when called with a collapsed row with panels', () => { + it('then scopedVars should be deleted on the row and all collapsed panels', () => { + const panel1 = new PanelModel({ + id: 1, + type: 'row', + collapsed: true, + scopedVars: { job: { value: 'myjob', text: 'myjob' } }, + panels: [ + { id: 2, type: 'graph', title: 'Graph', scopedVars: { job: { value: 'myjob', text: 'myjob' } } }, + { id: 3, type: 'graph2', title: 'Graph2', scopedVars: { job: { value: 'myjob', text: 'myjob' } } }, + ], + }); + + expect(panel1.scopedVars).toBeDefined(); + expect(panel1.panels[0].scopedVars).toBeDefined(); + expect(panel1.panels[1].scopedVars).toBeDefined(); + + deleteScopeVars([panel1]); + + expect(panel1.scopedVars).toBeUndefined(); + expect(panel1.panels[0].scopedVars).toBeUndefined(); + expect(panel1.panels[1].scopedVars).toBeUndefined(); + }); + }); +}); diff --git a/public/app/features/dashboard/state/utils.ts b/public/app/features/dashboard/state/utils.ts index 8742b1a1851..7a726900aeb 100644 --- a/public/app/features/dashboard/state/utils.ts +++ b/public/app/features/dashboard/state/utils.ts @@ -15,3 +15,14 @@ export function isOnTheSameGridRow(sourcePanel: PanelModel, otherPanel: PanelMod return false; } + +export function deleteScopeVars(panels: PanelModel[]) { + for (const panel of panels) { + delete panel.scopedVars; + if (panel.panels?.length) { + for (const collapsedPanel of panel.panels) { + delete collapsedPanel.scopedVars; + } + } + } +} diff --git a/public/app/features/variables/inspect/utils.test.ts b/public/app/features/variables/inspect/utils.test.ts index e3524f38346..84149200b41 100644 --- a/public/app/features/variables/inspect/utils.test.ts +++ b/public/app/features/variables/inspect/utils.test.ts @@ -1,14 +1,15 @@ import { + flattenPanels, getAffectedPanelIdsForVariable, getAllAffectedPanelIdsForVariableChange, getDependenciesForVariable, getPropsWithVariable, } from './utils'; -import { PanelModel } from '@grafana/data'; import { variableAdapters } from '../adapters'; import { createDataSourceVariableAdapter } from '../datasource/adapter'; import { createCustomVariableAdapter } from '../custom/adapter'; import { createQueryVariableAdapter } from '../query/adapter'; +import { PanelModel } from 'app/features/dashboard/state'; describe('getPropsWithVariable', () => { it('when called it should return the correct graph', () => { @@ -310,6 +311,49 @@ describe('getAllAffectedPanelIdsForVariableChange ', () => { }); }); +describe('flattenPanels', () => { + describe('when called with a row with collapsed panels', () => { + it('then the result should be correct', () => { + const panel1 = new PanelModel({ + id: 1, + type: 'row', + collapsed: true, + panels: [ + { id: 2, type: 'graph', title: 'Graph' }, + { id: 3, type: 'graph2', title: 'Graph2' }, + ], + }); + const panel2 = new PanelModel({ id: 2, type: 'graph', title: 'Graph' }); + const panel3 = new PanelModel({ id: 3, type: 'graph2', title: 'Graph2' }); + + const result = flattenPanels([panel1]); + + expect(result[0].getSaveModel()).toEqual(panel1.getSaveModel()); + expect(result[1].getSaveModel()).toEqual(panel2.getSaveModel()); + expect(result[2].getSaveModel()).toEqual(panel3.getSaveModel()); + }); + }); + + describe('when called with a row with expanded panels', () => { + it('then the result should be correct', () => { + const panel1 = new PanelModel({ + id: 1, + type: 'row', + collapsed: false, + panels: [], + }); + const panel2 = new PanelModel({ id: 2, type: 'graph', title: 'Graph' }); + const panel3 = new PanelModel({ id: 3, type: 'graph2', title: 'Graph2' }); + + const result = flattenPanels([panel1, panel2, panel3]); + + expect(result[0].getSaveModel()).toEqual(panel1.getSaveModel()); + expect(result[1].getSaveModel()).toEqual(panel2.getSaveModel()); + expect(result[2].getSaveModel()).toEqual(panel3.getSaveModel()); + }); + }); +}); + const dashWithRepeatsAndRows: any = { annotations: { list: [ diff --git a/public/app/features/variables/inspect/utils.ts b/public/app/features/variables/inspect/utils.ts index 79f27b10d3f..35f77855016 100644 --- a/public/app/features/variables/inspect/utils.ts +++ b/public/app/features/variables/inspect/utils.ts @@ -231,13 +231,17 @@ export function getAllAffectedPanelIdsForVariableChange( variables: VariableModel[], panels: PanelModel[] ): number[] { - let affectedPanelIds: number[] = getAffectedPanelIdsForVariable(variableId, panels); - const affectedPanelIdsForAllVariables = getAffectedPanelIdsForVariable(DataLinkBuiltInVars.includeVars, panels); + const flattenedPanels = flattenPanels(panels); + let affectedPanelIds: number[] = getAffectedPanelIdsForVariable(variableId, flattenedPanels); + const affectedPanelIdsForAllVariables = getAffectedPanelIdsForVariable( + DataLinkBuiltInVars.includeVars, + flattenedPanels + ); affectedPanelIds = [...new Set([...affectedPanelIdsForAllVariables, ...affectedPanelIds])]; const dependencies = getDependenciesForVariable(variableId, variables, new Set()); for (const dependency of dependencies) { - const affectedPanelIdsForDependency = getAffectedPanelIdsForVariable(dependency, panels); + const affectedPanelIdsForDependency = getAffectedPanelIdsForVariable(dependency, flattenedPanels); affectedPanelIds = [...new Set([...affectedPanelIdsForDependency, ...affectedPanelIds])]; } @@ -375,3 +379,16 @@ export const getVariableUsages = (variableId: string, usages: VariableUsageTree[ return countLeaves(usage.tree); }; + +export function flattenPanels(panels: PanelModel[]): PanelModel[] { + const result: PanelModel[] = []; + + for (const panel of panels) { + result.push(panel); + if (panel.panels?.length) { + result.push(...flattenPanels(panel.panels.map((p: PanelModel) => new PanelModel(p)))); + } + } + + return result; +}