diff --git a/src/app/controllers/row.js b/src/app/controllers/row.js index 364cf051dac..587c7de42d7 100644 --- a/src/app/controllers/row.js +++ b/src/app/controllers/row.js @@ -32,36 +32,13 @@ function (angular, app, _) { } }; - $scope.rowSpan = function(row) { - return _.reduce(row.panels, function(p,v) { - return p + v.span; - },0); - }; - - // This can be overridden by individual panels + // This can be overridden by individual panels $scope.close_edit = function() { $scope.$broadcast('render'); }; $scope.add_panel = function(panel) { - var rowSpan = $scope.rowSpan($scope.row); - var panelCount = $scope.row.panels.length; - var space = (12 - rowSpan) - panel.span; - - // try to make room of there is no space left - if (space <= 0) { - if (panelCount === 1) { - $scope.row.panels[0].span = 6; - panel.span = 6; - } - else if (panelCount === 2) { - $scope.row.panels[0].span = 4; - $scope.row.panels[1].span = 4; - panel.span = 4; - } - } - - $scope.row.panels.push(panel); + $scope.dashboard.add_panel(panel, $scope.row); }; $scope.delete_row = function() { @@ -100,45 +77,17 @@ function (angular, app, _) { }; $scope.duplicatePanel = function(panel, row) { - row = row || $scope.row; - var currentRowSpan = $scope.rowSpan(row); - if (currentRowSpan <= 9) { - row.panels.push(angular.copy(panel)); - } - else { - var rowsList = $scope.dashboard.rows; - var rowIndex = _.indexOf(rowsList, row); - if (rowIndex === rowsList.length - 1) { - var newRow = angular.copy($scope.row); - newRow.panels = []; - $scope.dashboard.rows.push(newRow); - $scope.duplicatePanel(panel, newRow); - } - else { - $scope.duplicatePanel(panel, rowsList[rowIndex+1]); - } - } + $scope.dashboard.duplicatePanel(panel, row || $scope.row); }; $scope.reset_panel = function(type) { - var - defaultSpan = 12, - _as = 12-$scope.rowSpan($scope.row); + var defaultSpan = 12; + var _as = 12 - $scope.dashboard.rowSpan($scope.row); $scope.panel = { error : false, - /** @scratch /panels/1 - * span:: A number, 1-12, that describes the width of the panel. - */ span : _as < defaultSpan && _as > 0 ? _as : defaultSpan, - /** @scratch /panels/1 - * editable:: Enable or disable the edit button the the panel - */ editable: true, - /** @scratch /panels/1 - * type:: The type of panel this object contains. Each panel type will require additional - * properties. See the panel types list to the right. - */ type : type }; @@ -155,10 +104,6 @@ function (angular, app, _) { $scope.row.height = fixRowHeight($scope.row.height); }; - /** @scratch /panels/2 - * -- - */ - $scope.init(); }); diff --git a/src/app/partials/dashboard.html b/src/app/partials/dashboard.html index 013b924c77a..b6a7287f536 100644 --- a/src/app/partials/dashboard.html +++ b/src/app/partials/dashboard.html @@ -105,7 +105,7 @@ -
+
diff --git a/src/app/partials/roweditor.html b/src/app/partials/roweditor.html index 583c664a3cb..eb3bc9258a6 100644 --- a/src/app/partials/roweditor.html +++ b/src/app/partials/roweditor.html @@ -27,7 +27,7 @@ Title Type - Span ({{rowSpan(row)}}/12) + Span ({{dashboard.rowSpan(row)}}/12) Delete Move @@ -49,7 +49,7 @@

Select Panel Type

- + Note: This row is full, new panels will wrap to a new line. You should add another row. diff --git a/src/app/services/dashboard/dashboardSrv.js b/src/app/services/dashboard/dashboardSrv.js index 9910f1ebfe8..4f72338dbb1 100644 --- a/src/app/services/dashboard/dashboardSrv.js +++ b/src/app/services/dashboard/dashboardSrv.js @@ -49,6 +49,65 @@ function (angular, $, kbn, _) { var p = DashboardModel.prototype; + p.getNextPanelId = function() { + var i, j, row, panel, max = 0; + for (i = 0; i < this.rows.length; i++) { + row = this.rows[i]; + for (j = 0; j < row.panels.length; j++) { + panel = row.panels[j]; + if (panel.id > max) { max = panel.id; } + } + } + return max + 1; + }; + + p.rowSpan = function(row) { + return _.reduce(row.panels, function(p,v) { + return p + v.span; + },0); + }; + + p.add_panel = function(panel, row) { + var rowSpan = this.rowSpan(row); + var panelCount = row.panels.length; + var space = (12 - rowSpan) - panel.span; + panel.id = this.getNextPanelId(); + + // try to make room of there is no space left + if (space <= 0) { + if (panelCount === 1) { + row.panels[0].span = 6; + panel.span = 6; + } + else if (panelCount === 2) { + row.panels[0].span = 4; + row.panels[1].span = 4; + panel.span = 4; + } + } + + row.panels.push(panel); + }; + + p.duplicatePanel = function(panel, row) { + var rowIndex = _.indexOf(this.rows, row); + var newPanel = angular.copy(panel); + newPanel.id = this.getNextPanelId(); + + while(rowIndex < this.rows.length) { + var currentRow = this.rows[rowIndex]; + if (this.rowSpan(currentRow) <= 9) { + currentRow.panels.push(newPanel); + return; + } + rowIndex++; + } + + var newRow = angular.copy(row); + newRow.panels = [newPanel]; + this.rows.push(newRow); + }; + p.emit_refresh = function() { $rootScope.$broadcast('refresh'); }; @@ -86,13 +145,15 @@ function (angular, $, kbn, _) { // Version 3 schema changes // ensure panel ids - var panelId = 1; + var maxId = this.getNextPanelId(); for (i = 0; i < this.rows.length; i++) { row = this.rows[i]; for (j = 0; j < row.panels.length; j++) { panel = row.panels[j]; - panel.id = panelId; - panelId += 1; + if (!panel.id) { + panel.id = maxId; + maxId += 1; + } } } diff --git a/src/test/specs/dashboardSrv-specs.js b/src/test/specs/dashboardSrv-specs.js index 5b09fc1d65a..5e4e96401de 100644 --- a/src/test/specs/dashboardSrv-specs.js +++ b/src/test/specs/dashboardSrv-specs.js @@ -7,7 +7,6 @@ define([ var model; beforeEach(module('grafana.services')); - beforeEach(inject(function(dashboardSrv) { model = dashboardSrv.create({}); })); @@ -24,12 +23,71 @@ define([ }); + describe('when getting next panel id', function() { + var model; + + beforeEach(module('grafana.services')); + beforeEach(inject(function(dashboardSrv) { + model = dashboardSrv.create({ + rows: [{ panels: [{ id: 5 }]}] + }); + })); + + it('should return max id + 1', function() { + expect(model.getNextPanelId()).to.be(6); + }); + }); + + describe('row and panel manipulation', function() { + var dashboard; + + beforeEach(module('grafana.services')); + beforeEach(inject(function(dashboardSrv) { + dashboard = dashboardSrv.create({}); + })); + + it('row span should sum spans', function() { + var spanLeft = dashboard.rowSpan({ panels: [{ span: 2 }, { span: 3 }] }); + expect(spanLeft).to.be(5); + }); + + it('adding default should split span in half', function() { + dashboard.rows = [{ panels: [{ span: 12, id: 7 }] }]; + dashboard.add_panel({span: 4}, dashboard.rows[0]); + + expect(dashboard.rows[0].panels[0].span).to.be(6); + expect(dashboard.rows[0].panels[1].span).to.be(6); + expect(dashboard.rows[0].panels[1].id).to.be(8); + }); + + it('duplicate panel should try to add it to same row', function() { + var panel = { span: 4, attr: '123', id: 10 }; + dashboard.rows = [{ panels: [panel] }]; + dashboard.duplicatePanel(panel, dashboard.rows[0]); + + expect(dashboard.rows[0].panels[0].span).to.be(4); + expect(dashboard.rows[0].panels[1].span).to.be(4); + expect(dashboard.rows[0].panels[1].attr).to.be('123'); + expect(dashboard.rows[0].panels[1].id).to.be(11); + }); + + it('duplicate should add row if there is no space left', function() { + var panel = { span: 12, attr: '123' }; + dashboard.rows = [{ panels: [panel] }]; + dashboard.duplicatePanel(panel, dashboard.rows[0]); + + expect(dashboard.rows[0].panels[0].span).to.be(12); + expect(dashboard.rows[0].panels.length).to.be(1); + expect(dashboard.rows[1].panels[0].attr).to.be('123'); + }); + + }); + describe('when creating dashboard with old schema', function() { var model; var graph; beforeEach(module('grafana.services')); - beforeEach(inject(function(dashboardSrv) { model = dashboardSrv.create({ services: { filter: { time: { from: 'now-1d', to: 'now'}, list: [1] }}, diff --git a/src/test/specs/helpers.js b/src/test/specs/helpers.js index 465e5344779..cd31779cc99 100644 --- a/src/test/specs/helpers.js +++ b/src/test/specs/helpers.js @@ -26,6 +26,7 @@ define([ self.scope.panel = {}; self.scope.row = { panels:[] }; self.scope.filter = new FilterSrvStub(); + self.scope.dashboard = {}; self.scope.dashboardViewState = new DashboardViewStateStub(); $rootScope.colors = []; diff --git a/src/test/specs/row-ctrl-specs.js b/src/test/specs/row-ctrl-specs.js index de149b70fac..41543784f40 100644 --- a/src/test/specs/row-ctrl-specs.js +++ b/src/test/specs/row-ctrl-specs.js @@ -12,50 +12,6 @@ define([ beforeEach(ctx.providePhase()); beforeEach(ctx.createControllerPhase('RowCtrl')); - describe('when getting rowSpan', function() { - it('should return sum of panels spans', function() { - var spanLeft = ctx.scope.rowSpan({ panels: [{ span: 2 }, { span: 3 }] }); - expect(spanLeft).to.be(5); - }); - }); - - describe('when adding panel to row with 12 span panel', function() { - it('should split span in half and add panel with defaults', function() { - ctx.scope.row = { panels: [{ span: 12 }] }; - ctx.scope.add_panel_default('graph'); - - expect(ctx.scope.row.panels[0].span).to.be(6); - expect(ctx.scope.row.panels[1].span).to.be(6); - expect(ctx.scope.row.panels[1].type).to.be('graph'); - }); - }); - - describe('when duplicating panel', function() { - it('should try to add it to same row', function() { - var panel = { span: 4, attr: '123' }; - ctx.scope.row = { panels: [panel] }; - ctx.scope.duplicatePanel(panel, ctx.scope.row); - - expect(ctx.scope.row.panels[0].span).to.be(4); - expect(ctx.scope.row.panels[1].span).to.be(4); - expect(ctx.scope.row.panels[1].attr).to.be('123'); - }); - }); - - describe('when duplicating panel', function() { - it('should add row if there is no space left', function() { - var panel = { span: 12, attr: '123' }; - ctx.scope.row = { panels: [panel] }; - ctx.scope.dashboard = { rows: [ctx.scope.row] }; - - ctx.scope.duplicatePanel(panel, ctx.scope.row); - - expect(ctx.scope.row.panels[0].span).to.be(12); - expect(ctx.scope.row.panels.length).to.be(1); - expect(ctx.scope.dashboard.rows[1].panels[0].attr).to.be('123'); - }); - }); - }); });