Commit bfd7e104 by Alexander Zobnin Committed by Torkel Ödegaard

Fix variables values passing when both repeat rows and panels is used (#10488)

* dashboard: repeat rows and panels tests

* fix variable values passing when both repeat rows and panels is used
parent b76958f0
...@@ -230,10 +230,6 @@ export class DashboardModel { ...@@ -230,10 +230,6 @@ export class DashboardModel {
} }
cleanUpRepeats() { cleanUpRepeats() {
this.processRepeats(true);
}
processRepeats(cleanUpOnly?: boolean) {
if (this.snapshot || this.templating.list.length === 0) { if (this.snapshot || this.templating.list.length === 0) {
return; return;
} }
...@@ -248,11 +244,7 @@ export class DashboardModel { ...@@ -248,11 +244,7 @@ export class DashboardModel {
for (let i = 0; i < this.panels.length; i++) { for (let i = 0; i < this.panels.length; i++) {
let panel = this.panels[i]; let panel = this.panels[i];
if (panel.repeat) { if ((!panel.repeat || panel.repeatedByRow) && panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
if (!cleanUpOnly) {
this.repeatPanel(panel, i);
}
} else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
panelsToRemove.push(panel); panelsToRemove.push(panel);
} }
} }
...@@ -264,6 +256,26 @@ export class DashboardModel { ...@@ -264,6 +256,26 @@ export class DashboardModel {
this.events.emit('repeats-processed'); this.events.emit('repeats-processed');
} }
processRepeats(cleanUpOnly?: boolean) {
if (this.snapshot || this.templating.list.length === 0) {
return;
}
this.cleanUpRepeats();
this.iteration = (this.iteration || new Date().getTime()) + 1;
for (let i = 0; i < this.panels.length; i++) {
let panel = this.panels[i];
if (panel.repeat) {
this.repeatPanel(panel, i);
}
}
this.sortPanelsByGridPos();
this.events.emit('repeats-processed');
}
getPanelRepeatClone(sourcePanel, valueIndex, sourcePanelIndex) { getPanelRepeatClone(sourcePanel, valueIndex, sourcePanelIndex) {
// if first clone return source // if first clone return source
if (valueIndex === 0) { if (valueIndex === 0) {
...@@ -282,21 +294,21 @@ export class DashboardModel { ...@@ -282,21 +294,21 @@ export class DashboardModel {
return clone; return clone;
} }
getRowRepeatClone(sourcePanel, valueIndex, sourcePanelIndex) { getRowRepeatClone(sourceRowPanel, valueIndex, sourcePanelIndex) {
// if first clone return source // if first clone return source
if (valueIndex === 0) { if (valueIndex === 0) {
if (!sourcePanel.collapsed) { if (!sourceRowPanel.collapsed) {
let rowPanels = this.getRowPanels(sourcePanelIndex); let rowPanels = this.getRowPanels(sourcePanelIndex);
sourcePanel.panels = rowPanels; sourceRowPanel.panels = rowPanels;
} }
return sourcePanel; return sourceRowPanel;
} }
let clone = new PanelModel(sourcePanel.getSaveModel()); let clone = new PanelModel(sourceRowPanel.getSaveModel());
// for row clones we need to figure out panels under row to clone and where to insert clone // for row clones we need to figure out panels under row to clone and where to insert clone
let rowPanels, insertPos; let rowPanels, insertPos;
if (sourcePanel.collapsed) { if (sourceRowPanel.collapsed) {
rowPanels = _.cloneDeep(sourcePanel.panels); rowPanels = _.cloneDeep(sourceRowPanel.panels);
clone.panels = rowPanels; clone.panels = rowPanels;
// insert copied row after preceding row // insert copied row after preceding row
insertPos = sourcePanelIndex + valueIndex; insertPos = sourcePanelIndex + valueIndex;
...@@ -333,7 +345,7 @@ export class DashboardModel { ...@@ -333,7 +345,7 @@ export class DashboardModel {
let copy; let copy;
copy = this.getPanelRepeatClone(panel, index, panelIndex); copy = this.getPanelRepeatClone(panel, index, panelIndex);
copy.scopedVars = {}; copy.scopedVars = copy.scopedVars || {};
copy.scopedVars[variable.name] = option; copy.scopedVars[variable.name] = option;
if (panel.repeatDirection === REPEAT_DIR_VERTICAL) { if (panel.repeatDirection === REPEAT_DIR_VERTICAL) {
...@@ -342,7 +354,6 @@ export class DashboardModel { ...@@ -342,7 +354,6 @@ export class DashboardModel {
} else { } else {
// set width based on how many are selected // set width based on how many are selected
// assumed the repeated panels should take up full row width // assumed the repeated panels should take up full row width
copy.gridPos.w = Math.max(GRID_COLUMN_COUNT / selectedOptions.length, minWidth); copy.gridPos.w = Math.max(GRID_COLUMN_COUNT / selectedOptions.length, minWidth);
copy.gridPos.x = xPos; copy.gridPos.x = xPos;
copy.gridPos.y = yPos; copy.gridPos.y = yPos;
...@@ -363,7 +374,7 @@ export class DashboardModel { ...@@ -363,7 +374,7 @@ export class DashboardModel {
let yPos = panel.gridPos.y; let yPos = panel.gridPos.y;
function setScopedVars(panel, variableOption) { function setScopedVars(panel, variableOption) {
panel.scopedVars = {}; panel.scopedVars = panel.scopedVars || {};
panel.scopedVars[variable.name] = variableOption; panel.scopedVars[variable.name] = variableOption;
} }
...@@ -381,7 +392,7 @@ export class DashboardModel { ...@@ -381,7 +392,7 @@ export class DashboardModel {
_.each(rowPanels, (rowPanel, i) => { _.each(rowPanels, (rowPanel, i) => {
setScopedVars(rowPanel, option); setScopedVars(rowPanel, option);
if (optionIndex > 0) { if (optionIndex > 0) {
this.updateRepeatedPanelIds(rowPanel); this.updateRepeatedPanelIds(rowPanel, true);
} }
}); });
rowCopy.gridPos.y += optionIndex; rowCopy.gridPos.y += optionIndex;
...@@ -394,7 +405,7 @@ export class DashboardModel { ...@@ -394,7 +405,7 @@ export class DashboardModel {
setScopedVars(rowPanel, option); setScopedVars(rowPanel, option);
if (optionIndex > 0) { if (optionIndex > 0) {
let cloneRowPanel = new PanelModel(rowPanel); let cloneRowPanel = new PanelModel(rowPanel);
this.updateRepeatedPanelIds(cloneRowPanel); this.updateRepeatedPanelIds(cloneRowPanel, true);
// For exposed row additionally set proper Y grid position and add it to dashboard panels // For exposed row additionally set proper Y grid position and add it to dashboard panels
cloneRowPanel.gridPos.y += rowHeight * optionIndex; cloneRowPanel.gridPos.y += rowHeight * optionIndex;
this.panels.splice(insertPos + i, 0, cloneRowPanel); this.panels.splice(insertPos + i, 0, cloneRowPanel);
...@@ -413,11 +424,15 @@ export class DashboardModel { ...@@ -413,11 +424,15 @@ export class DashboardModel {
} }
} }
updateRepeatedPanelIds(panel: PanelModel) { updateRepeatedPanelIds(panel: PanelModel, repeatedByRow?: boolean) {
panel.repeatPanelId = panel.id; panel.repeatPanelId = panel.id;
panel.id = this.getNextPanelId(); panel.id = this.getNextPanelId();
panel.repeatIteration = this.iteration; panel.repeatIteration = this.iteration;
if (repeatedByRow) {
panel.repeatedByRow = true;
} else {
panel.repeat = null; panel.repeat = null;
}
return panel; return panel;
} }
......
...@@ -26,6 +26,7 @@ export class PanelModel { ...@@ -26,6 +26,7 @@ export class PanelModel {
repeatIteration?: number; repeatIteration?: number;
repeatPanelId?: number; repeatPanelId?: number;
repeatDirection?: string; repeatDirection?: string;
repeatedByRow?: boolean;
minSpan?: number; minSpan?: number;
collapsed?: boolean; collapsed?: boolean;
panels?: any; panels?: any;
......
...@@ -382,3 +382,132 @@ describe('given dashboard with row repeat', function() { ...@@ -382,3 +382,132 @@ describe('given dashboard with row repeat', function() {
expect(panel_ids.length).toEqual(_.uniq(panel_ids).length); expect(panel_ids.length).toEqual(_.uniq(panel_ids).length);
}); });
}); });
describe('given dashboard with row and panel repeat', () => {
let dashboard, dashboardJSON;
beforeEach(() => {
dashboardJSON = {
panels: [
{
id: 1,
type: 'row',
repeat: 'region',
gridPos: { x: 0, y: 0, h: 1, w: 24 },
},
{ id: 2, type: 'graph', repeat: 'app', gridPos: { x: 0, y: 1, h: 1, w: 6 } },
],
templating: {
list: [
{
name: 'region',
current: {
text: 'reg1, reg2',
value: ['reg1', 'reg2'],
},
options: [
{ text: 'reg1', value: 'reg1', selected: true },
{ text: 'reg2', value: 'reg2', selected: true },
{ text: 'reg3', value: 'reg3', selected: false },
],
},
{
name: 'app',
current: {
text: 'se1, se2',
value: ['se1', 'se2'],
},
options: [
{ text: 'se1', value: 'se1', selected: true },
{ text: 'se2', value: 'se2', selected: true },
{ text: 'se3', value: 'se3', selected: false },
],
},
],
},
};
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
});
it('should repeat row and panels for each row', () => {
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph']);
});
it('should clean up old repeated panels', () => {
dashboardJSON.panels = [
{
id: 1,
type: 'row',
repeat: 'region',
gridPos: { x: 0, y: 0, h: 1, w: 24 },
},
{ id: 2, type: 'graph', repeat: 'app', gridPos: { x: 0, y: 1, h: 1, w: 6 } },
{ id: 3, type: 'graph', repeatPanelId: 2, repeatIteration: 101, gridPos: { x: 7, y: 1, h: 1, w: 6 } },
{
id: 11,
type: 'row',
repeatPanelId: 1,
repeatIteration: 101,
gridPos: { x: 0, y: 2, h: 1, w: 24 },
},
{ id: 12, type: 'graph', repeatPanelId: 2, repeatIteration: 101, gridPos: { x: 0, y: 3, h: 1, w: 6 } },
];
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph']);
});
it('should set scopedVars for each row', () => {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
expect(dashboard.panels[0].scopedVars).toMatchObject({
region: { text: 'reg1', value: 'reg1' },
});
expect(dashboard.panels[3].scopedVars).toMatchObject({
region: { text: 'reg2', value: 'reg2' },
});
});
it('should set panel-repeat variable for each panel', () => {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
expect(dashboard.panels[1].scopedVars).toMatchObject({
app: { text: 'se1', value: 'se1' },
});
expect(dashboard.panels[2].scopedVars).toMatchObject({
app: { text: 'se2', value: 'se2' },
});
expect(dashboard.panels[4].scopedVars).toMatchObject({
app: { text: 'se1', value: 'se1' },
});
expect(dashboard.panels[5].scopedVars).toMatchObject({
app: { text: 'se2', value: 'se2' },
});
});
it('should set row-repeat variable for each panel', () => {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
expect(dashboard.panels[1].scopedVars).toMatchObject({
region: { text: 'reg1', value: 'reg1' },
});
expect(dashboard.panels[2].scopedVars).toMatchObject({
region: { text: 'reg1', value: 'reg1' },
});
expect(dashboard.panels[4].scopedVars).toMatchObject({
region: { text: 'reg2', value: 'reg2' },
});
expect(dashboard.panels[5].scopedVars).toMatchObject({
region: { text: 'reg2', value: 'reg2' },
});
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment