Просмотр исходного кода

Merge branch 'master' of github.com:grafana/grafana

Torkel Ödegaard 8 лет назад
Родитель
Сommit
ae9b3186e3

+ 38 - 23
public/app/features/dashboard/dashboard_model.ts

@@ -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 {
 
 
     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 (!cleanUpOnly) {
-          this.repeatPanel(panel, i);
-        }
-      } else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
+      if ((!panel.repeat || panel.repeatedByRow) && panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
         panelsToRemove.push(panel);
         panelsToRemove.push(panel);
       }
       }
     }
     }
@@ -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 {
     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) {
-      rowPanels = _.cloneDeep(sourcePanel.panels);
+    if (sourceRowPanel.collapsed) {
+      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 {
       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 {
       } 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 {
     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 {
         _.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 {
           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 {
     }
     }
   }
   }
 
 
-  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;
-    panel.repeat = null;
+    if (repeatedByRow) {
+      panel.repeatedByRow = true;
+    } else {
+      panel.repeat = null;
+    }
     return panel;
     return panel;
   }
   }
 
 

+ 1 - 0
public/app/features/dashboard/panel_model.ts

@@ -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;

+ 129 - 0
public/app/features/dashboard/specs/repeat.jest.ts

@@ -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' },
+    });
+  });
+});