diff --git a/src/app/controllers/dash.js b/src/app/controllers/dash.js index e40db93fd7e..3706a0a4109 100644 --- a/src/app/controllers/dash.js +++ b/src/app/controllers/dash.js @@ -11,7 +11,9 @@ function (angular, $, config, _) { var module = angular.module('grafana.controllers'); module.controller('DashCtrl', function( - $scope, $rootScope, dashboardKeybindings, filterSrv, dashboardSrv, panelMoveSrv, timer) { + $scope, $rootScope, dashboardKeybindings, + filterSrv, dashboardSrv, dashboardViewStateSrv, + panelMoveSrv, timer) { $scope.editor = { index: 0 }; $scope.panelNames = config.panels; @@ -24,9 +26,9 @@ function (angular, $, config, _) { $scope.setupDashboard = function(event, dashboardData) { timer.cancel_all(); - $rootScope.fullscreen = false; - $scope.dashboard = dashboardSrv.create(dashboardData); + $scope.dashboardViewState = dashboardViewStateSrv.create($scope); + $scope.grafana.style = $scope.dashboard.style; $scope.filter = filterSrv; diff --git a/src/app/controllers/dashLoader.js b/src/app/controllers/dashLoader.js index 27071213d8f..720c4634628 100644 --- a/src/app/controllers/dashLoader.js +++ b/src/app/controllers/dashLoader.js @@ -14,6 +14,7 @@ function (angular, _, moment, config) { $scope.init = function() { $scope.db = datasourceSrv.getGrafanaDB(); + $scope.onAppEvent('save-dashboard', function() { $scope.saveDashboard(); }); @@ -23,10 +24,6 @@ function (angular, _, moment, config) { }); }; - $scope.exitFullscreen = function() { - $scope.emitAppEvent('panel-fullscreen-exit'); - }; - $scope.set_default = function() { window.localStorage.grafanaDashboardDefault = $location.path(); alertSrv.set('Home Set','This page has been set as your default dashboard','success',5000); @@ -78,6 +75,7 @@ function (angular, _, moment, config) { .then(function(result) { alertSrv.set('Dashboard Saved', 'Dashboard has been saved as "' + result.title + '"','success', 5000); + $location.search({}); $location.path(result.url); $rootScope.$emit('dashboard-saved', $scope.dashboard); 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/controllers/search.js b/src/app/controllers/search.js index 6c504e1b925..e30031a0713 100644 --- a/src/app/controllers/search.js +++ b/src/app/controllers/search.js @@ -41,6 +41,7 @@ function (angular, _, config, $) { var selectedDash = $scope.results.dashboards[$scope.selectedIndex]; if (selectedDash) { + $location.search({}); $location.path("/dashboard/db/" + selectedDash.id); setTimeout(function() { $('body').click(); // hack to force dropdown to close; diff --git a/src/app/directives/grafanaGraph.js b/src/app/directives/grafanaGraph.js index 323db2141bd..5b474bbbe24 100755 --- a/src/app/directives/grafanaGraph.js +++ b/src/app/directives/grafanaGraph.js @@ -21,7 +21,6 @@ function (angular, $, kbn, moment, _) { var legendSideLastValue = null; scope.$on('refresh',function() { - if (scope.otherPanelInFullscreenMode()) { return; } scope.get_data(); }); @@ -39,6 +38,10 @@ function (angular, $, kbn, moment, _) { // Receive render events scope.$on('render',function(event, renderData) { data = renderData || data; + if (!data) { + scope.get_data(); + return; + } annotations = data.annotations || annotations; render_panel(); }); diff --git a/src/app/panels/graph/module.js b/src/app/panels/graph/module.js index 8daa773c620..3dba7c096cb 100644 --- a/src/app/panels/graph/module.js +++ b/src/app/panels/graph/module.js @@ -188,13 +188,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) { _.defaults($scope.panel.grid, _d.grid); _.defaults($scope.panel.legend, _d.legend); - $scope.init = function() { - panelSrv.init($scope); - $scope.hiddenSeries = {}; - if (!$scope.skipDataOnInit) { - $scope.get_data(); - } - }; + $scope.hiddenSeries = {}; $scope.updateTimeRange = function () { $scope.range = $scope.filter.timeRange(); @@ -210,10 +204,6 @@ function (angular, app, $, _, kbn, moment, timeSeries) { }; $scope.get_data = function() { - delete $scope.panel.error; - - $scope.panelMeta.loading = true; - $scope.updateTimeRange(); var metricsQuery = { @@ -297,10 +287,6 @@ function (angular, app, $, _, kbn, moment, timeSeries) { return series; }; - $scope.otherPanelInFullscreenMode = function() { - return $rootScope.fullscreen && !$scope.fullscreen; - }; - $scope.render = function(data) { $scope.$emit('render', data); }; @@ -371,7 +357,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) { $scope.render(); }; - $scope.init(); + panelSrv.init($scope); }); }); diff --git a/src/app/partials/dashLoader.html b/src/app/partials/dashLoader.html index 4fd73b864c9..28413d32c0b 100644 --- a/src/app/partials/dashLoader.html +++ b/src/app/partials/dashLoader.html @@ -4,7 +4,7 @@ } -
  • +
  • Back to dashboard diff --git a/src/app/partials/dashboard.html b/src/app/partials/dashboard.html index 39a287489dd..b6a7287f536 100644 --- a/src/app/partials/dashboard.html +++ b/src/app/partials/dashboard.html @@ -1,4 +1,4 @@ -
    +
    -
    +
    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/routes/dashboard-from-db.js b/src/app/routes/dashboard-from-db.js index a2202ef518d..dfbcf3af3b1 100644 --- a/src/app/routes/dashboard-from-db.js +++ b/src/app/routes/dashboard-from-db.js @@ -11,6 +11,7 @@ function (angular) { .when('/dashboard/db/:id', { templateUrl: 'app/partials/dashboard.html', controller : 'DashFromDBProvider', + reloadOnSearch: false, }) .when('/dashboard/elasticsearch/:id', { templateUrl: 'app/partials/dashboard.html', diff --git a/src/app/services/all.js b/src/app/services/all.js index a1479355def..62deab62e5e 100644 --- a/src/app/services/all.js +++ b/src/app/services/all.js @@ -11,5 +11,6 @@ define([ './unsavedChangesSrv', './dashboard/dashboardKeyBindings', './dashboard/dashboardSrv', + './dashboard/dashboardViewStateSrv', ], function () {}); diff --git a/src/app/services/dashboard/dashboardKeyBindings.js b/src/app/services/dashboard/dashboardKeyBindings.js index 304e10ea5d3..f4e2b6f0df7 100644 --- a/src/app/services/dashboard/dashboardKeyBindings.js +++ b/src/app/services/dashboard/dashboardKeyBindings.js @@ -12,20 +12,6 @@ function(angular, $) { this.shortcuts = function(scope) { - scope.onAppEvent('panel-fullscreen-enter', function() { - $rootScope.fullscreen = true; - }); - - scope.onAppEvent('panel-fullscreen-exit', function() { - $rootScope.fullscreen = false; - }); - - scope.onAppEvent('dashboard-saved', function() { - if ($rootScope.fullscreen) { - scope.emitAppEvent('panel-fullscreen-exit'); - } - }); - scope.$on('$destroy', function() { keyboardManager.unbind('ctrl+f'); keyboardManager.unbind('ctrl+h'); @@ -67,7 +53,7 @@ function(angular, $) { modalData.$scope.dismiss(); } - scope.emitAppEvent('panel-fullscreen-exit'); + scope.exitFullscreen(); }, { inputDisabled: true }); }; }); diff --git a/src/app/services/dashboard/dashboardSrv.js b/src/app/services/dashboard/dashboardSrv.js index 002f19cca15..43c93379dd9 100644 --- a/src/app/services/dashboard/dashboardSrv.js +++ b/src/app/services/dashboard/dashboardSrv.js @@ -10,7 +10,7 @@ function (angular, $, kbn, _) { var module = angular.module('grafana.services'); - module.service('dashboardSrv', function(timer, $rootScope, $timeout) { + module.factory('dashboardSrv', function(timer, $rootScope, $timeout) { function DashboardModel (data) { @@ -29,6 +29,8 @@ function (angular, $, kbn, _) { this.time = data.time || { from: 'now-6h', to: 'now' }; this.templating = data.templating || { list: [] }; this.refresh = data.refresh; + this.version = data.version || 0; + this.$state = data.$state; if (this.nav.length === 0) { this.nav.push({ type: 'timepicker' }); @@ -47,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'); }; @@ -75,12 +136,32 @@ function (angular, $, kbn, _) { p.updateSchema = function(old) { var i, j, row, panel; - var isChanged = false; + var oldVersion = this.version; + this.version = 3; - if (this.version === 2) { + if (oldVersion === 3) { return; } + // Version 3 schema changes + // ensure panel ids + 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]; + if (!panel.id) { + panel.id = maxId; + maxId += 1; + } + } + } + + if (oldVersion === 2) { + return; + } + + // Version 2 schema changes if (old.services) { if (old.services.filter) { this.time = old.services.filter.time; @@ -95,7 +176,6 @@ function (angular, $, kbn, _) { panel = row.panels[j]; if (panel.type === 'graphite') { panel.type = 'graph'; - isChanged = true; } if (panel.type === 'graph') { @@ -128,7 +208,7 @@ function (angular, $, kbn, _) { } } - this.version = 2; + this.version = 3; }; return { diff --git a/src/app/services/dashboard/dashboardViewStateSrv.js b/src/app/services/dashboard/dashboardViewStateSrv.js new file mode 100644 index 00000000000..dd7831df2d2 --- /dev/null +++ b/src/app/services/dashboard/dashboardViewStateSrv.js @@ -0,0 +1,157 @@ +define([ + 'angular', + 'lodash', + 'jquery', +], +function (angular, _, $) { + 'use strict'; + + var module = angular.module('grafana.services'); + + module.factory('dashboardViewStateSrv', function($location, $timeout) { + + // represents the transient view state + // like fullscreen panel & edit + function DashboardViewState($scope) { + var self = this; + + $scope.exitFullscreen = function() { + self.update({ fullscreen: false }); + }; + + $scope.onAppEvent('dashboard-saved', function() { + self.update({ fullscreen: false }); + }); + + $scope.onAppEvent('$routeUpdate', function() { + var urlState = self.getQueryStringState(); + console.log("route updated!"); + if (self.needsSync(urlState)) { + self.update(urlState, true); + } + }); + + this.panelScopes = []; + this.$scope = $scope; + + this.update(this.getQueryStringState(), true); + } + + DashboardViewState.prototype.needsSync = function(urlState) { + if (urlState.fullscreen !== this.fullscreen) { return true; } + if (urlState.edit !== this.edit) { return true; } + if (urlState.panelId !== this.panelId) { return true; } + return false; + }; + + DashboardViewState.prototype.getQueryStringState = function() { + var queryParams = $location.search(); + return { + panelId: parseInt(queryParams.panelId) || null, + fullscreen: queryParams.fullscreen ? true : false, + edit: queryParams.edit ? true : false + }; + }; + + DashboardViewState.prototype.update = function(state, skipUrlSync) { + _.extend(this, state); + + if (!this.fullscreen) { + this.panelId = null; + this.edit = false; + } + + if (!skipUrlSync) { + $location.search({ + fullscreen: this.fullscreen ? true : null, + panelId: this.panelId, + edit: this.edit ? true : null + }); + } + + this.syncState(); + }; + + DashboardViewState.prototype.syncState = function() { + if (this.panelScopes.length === 0) { return; } + + if (this.fullscreen) { + if (this.fullscreenPanel) { + this.leaveFullscreen(false); + } + var panelScope = this.getPanelScope(this.panelId); + this.enterFullscreen(panelScope); + return; + } + + if (this.fullscreenPanel) { + this.leaveFullscreen(true); + } + }; + + DashboardViewState.prototype.getPanelScope = function(id) { + return _.find(this.panelScopes, function(panelScope) { + return panelScope.panel.id === id; + }); + }; + + DashboardViewState.prototype.leaveFullscreen = function(render) { + var self = this; + + self.fullscreenPanel.editMode = false; + self.fullscreenPanel.fullscreen = false; + delete self.fullscreenPanel.height; + + if (!render) { return false;} + + $timeout(function() { + if (self.oldTimeRange !== self.fullscreenPanel.range) { + self.$scope.dashboard.emit_refresh(); + } + else { + self.fullscreenPanel.$emit('render'); + } + delete self.fullscreenPanel; + }); + }; + + DashboardViewState.prototype.enterFullscreen = function(panelScope) { + var docHeight = $(window).height(); + var editHeight = Math.floor(docHeight * 0.3); + var fullscreenHeight = Math.floor(docHeight * 0.7); + this.oldTimeRange = panelScope.range; + + panelScope.height = this.edit ? editHeight : fullscreenHeight; + panelScope.editMode = this.edit; + this.fullscreenPanel = panelScope; + + $(window).scrollTop(0); + + panelScope.fullscreen = true; + + $timeout(function() { + panelScope.$emit('render'); + }); + }; + + DashboardViewState.prototype.registerPanel = function(panelScope) { + var self = this; + self.panelScopes.push(panelScope); + + if (self.panelId === panelScope.panel.id) { + self.enterFullscreen(panelScope); + } + + panelScope.$on('$destroy', function() { + self.panelScopes = _.without(self.panelScopes, panelScope); + }); + }; + + return { + create: function($scope) { + return new DashboardViewState($scope); + } + }; + + }); +}); diff --git a/src/app/services/panelSrv.js b/src/app/services/panelSrv.js index b5d5e8e06d0..fd0c732f43b 100644 --- a/src/app/services/panelSrv.js +++ b/src/app/services/panelSrv.js @@ -1,9 +1,8 @@ define([ 'angular', 'lodash', - 'jquery', ], -function (angular, _, $) { +function (angular, _) { 'use strict'; var module = angular.module('grafana.services'); @@ -22,12 +21,12 @@ function (angular, _, $) { }, { text: 'Edit', - click: "toggleFullscreenEdit()", + click: "toggleFullscreen(true)", condition: $scope.panelMeta.fullscreenEdit }, { text: "Fullscreen", - click: 'toggleFullscreen()', + click: 'toggleFullscreen(false)', condition: $scope.panelMeta.fullscreenView }, { @@ -71,46 +70,6 @@ function (angular, _, $) { }); }; - $scope.enterFullscreenMode = function(options) { - var docHeight = $(window).height(); - var editHeight = Math.floor(docHeight * 0.3); - var fullscreenHeight = Math.floor(docHeight * 0.7); - var oldTimeRange = $scope.range; - - $scope.height = options.edit ? editHeight : fullscreenHeight; - $scope.editMode = options.edit; - - if (!$scope.fullscreen) { - var closeEditMode = $rootScope.$on('panel-fullscreen-exit', function() { - $scope.editMode = false; - $scope.fullscreen = false; - delete $scope.height; - - closeEditMode(); - - $timeout(function() { - if (oldTimeRange !== $scope.range) { - $scope.dashboard.emit_refresh(); - } - else { - $scope.$emit('render'); - } - }); - }); - } - - $(window).scrollTop(0); - - $scope.fullscreen = true; - - $rootScope.$emit('panel-fullscreen-enter'); - - $timeout(function() { - $scope.$emit('render'); - }); - - }; - $scope.addDataQuery = function() { $scope.panel.targets.push({target: ''}); }; @@ -135,22 +94,12 @@ function (angular, _, $) { $scope.get_data(); }; - $scope.toggleFullscreenEdit = function() { - if ($scope.editMode) { - $rootScope.$emit('panel-fullscreen-exit'); - return; - } - - $scope.enterFullscreenMode({edit: true}); + $scope.toggleFullscreen = function(edit) { + $scope.dashboardViewState.update({ fullscreen: true, edit: edit, panelId: $scope.panel.id }); }; - $scope.toggleFullscreen = function() { - if ($scope.fullscreen && !$scope.editMode) { - $rootScope.$emit('panel-fullscreen-exit'); - return; - } - - $scope.enterFullscreenMode({ edit: false }); + $scope.otherPanelInFullscreenMode = function() { + return $scope.dashboardViewState.fullscreen && !$scope.fullscreen; }; // Post init phase @@ -162,6 +111,24 @@ function (angular, _, $) { $scope.datasources = datasourceSrv.getMetricSources(); $scope.setDatasource($scope.panel.datasource); + + $scope.dashboardViewState.registerPanel($scope); + + if ($scope.get_data) { + var panel_get_data = $scope.get_data; + $scope.get_data = function() { + if ($scope.otherPanelInFullscreenMode()) { return; } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + + panel_get_data(); + }; + + if (!$scope.skipDataOnInit) { + $scope.get_data(); + } + } }; }); diff --git a/src/app/services/playlistSrv.js b/src/app/services/playlistSrv.js index 0e9459832f6..c7cd453bfd3 100644 --- a/src/app/services/playlistSrv.js +++ b/src/app/services/playlistSrv.js @@ -68,6 +68,7 @@ function (angular, _, kbn) { timerInstance = setInterval(function() { $rootScope.$apply(function() { angular.element(window).unbind('resize'); + $location.search({}); $location.path(dashboards[index % dashboards.length].url); index++; }); diff --git a/src/app/services/unsavedChangesSrv.js b/src/app/services/unsavedChangesSrv.js index 92425ea89ca..6ec373ed837 100644 --- a/src/app/services/unsavedChangesSrv.js +++ b/src/app/services/unsavedChangesSrv.js @@ -28,10 +28,12 @@ function(angular, _, config) { $rootScope.$on("dashboard-saved", function(event, savedDashboard) { self.original = angular.copy(savedDashboard); self.current = savedDashboard; + self.orignalPath = $location.path(); }); $rootScope.$on("$routeChangeSuccess", function() { self.original = null; + self.originalPath = $location.path(); }); window.onbeforeunload = function() { @@ -42,6 +44,11 @@ function(angular, _, config) { this.init = function() { $rootScope.$on("$locationChangeStart", function(event, next) { + if (self.originalPath === $location.path()) { + console.log("skipping"); + return; + } + if (self.has_unsaved_changes()) { event.preventDefault(); self.next = next; diff --git a/src/index.html b/src/index.html index 3d9d95ed484..8c5c8ff5c91 100644 --- a/src/index.html +++ b/src/index.html @@ -27,7 +27,7 @@ {{alert.title}}
    {{$index + 1}} alert(s)
    -
    +
    diff --git a/src/test/specs/dashboardSrv-specs.js b/src/test/specs/dashboardSrv-specs.js index 6a43845a7d7..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] }}, @@ -54,6 +112,10 @@ define([ expect(model.title).to.be('No Title'); }); + it('should have panel id', function() { + expect(graph.id).to.be(1); + }); + it('should move time and filtering list', function() { expect(model.time.from).to.be('now-1d'); expect(model.templating.list[0]).to.be(1); @@ -73,10 +135,9 @@ define([ }); it('dashboard schema version should be set to latest', function() { - expect(model.version).to.be(2); + expect(model.version).to.be(3); }); }); - }); diff --git a/src/test/specs/dashboardViewStateSrv-specs.js b/src/test/specs/dashboardViewStateSrv-specs.js new file mode 100644 index 00000000000..92e444d55d0 --- /dev/null +++ b/src/test/specs/dashboardViewStateSrv-specs.js @@ -0,0 +1,37 @@ +define([ + 'services/dashboard/dashboardViewStateSrv' +], function() { + 'use strict'; + + describe('when updating view state', function() { + var viewState, location; + + beforeEach(module('grafana.services')); + + beforeEach(inject(function(dashboardViewStateSrv, $location, $rootScope) { + $rootScope.onAppEvent = function(){}; + viewState = dashboardViewStateSrv.create($rootScope); + location = $location; + })); + + describe('to fullscreen true and edit true', function() { + it('should update querystring and view state', function() { + var updateState = { fullscreen: true, edit: true, panelId: 1 }; + viewState.update(updateState); + expect(location.search()).to.eql(updateState); + expect(viewState.fullscreen).to.be(true); + }); + }); + + describe('to fullscreen false', function() { + it('should remove params from query string', function() { + viewState.update({fullscreen: true, panelId: 1, edit: true}); + viewState.update({fullscreen: false}); + expect(location.search()).to.eql({}); + expect(viewState.fullscreen).to.be(false); + }); + }); + + }); + +}); diff --git a/src/test/specs/helpers.js b/src/test/specs/helpers.js index 0383b69b5c0..cd31779cc99 100644 --- a/src/test/specs/helpers.js +++ b/src/test/specs/helpers.js @@ -26,6 +26,8 @@ define([ self.scope.panel = {}; self.scope.row = { panels:[] }; self.scope.filter = new FilterSrvStub(); + self.scope.dashboard = {}; + self.scope.dashboardViewState = new DashboardViewStateStub(); $rootScope.colors = []; for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); } @@ -54,6 +56,11 @@ define([ }; } + function DashboardViewStateStub() { + this.registerPanel = function() { + }; + } + function FilterSrvStub() { this.time = { from:'now-1h', to: 'now'}; this.timeRange = function(parse) { 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'); - }); - }); - }); }); diff --git a/src/test/test-main.js b/src/test/test-main.js index 4f30ef7910e..c7aa212d1cc 100644 --- a/src/test/test-main.js +++ b/src/test/test-main.js @@ -124,6 +124,7 @@ require([ 'specs/filterSrv-specs', 'specs/kbn-format-specs', 'specs/dashboardSrv-specs', + 'specs/dashboardViewStateSrv-specs', 'specs/influxSeries-specs' ], function () { window.__karma__.start();