diff --git a/packaging/publish/publish.sh b/packaging/publish/publish.sh index dd0c935d2cd..23d20b5a613 100755 --- a/packaging/publish/publish.sh +++ b/packaging/publish/publish.sh @@ -1,22 +1,22 @@ #! /usr/bin/env bash -deb_ver=3.0.0-beta41460581169 -rpm_ver=3.0.0-beta41460581169 +deb_ver=3.0.0-beta51460658374 +rpm_ver=3.0.0-beta51460658374 #rpm_ver=3.0.0-1 -wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb +#wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb #package_cloud push grafana/stable/debian/jessie grafana_${deb_ver}_amd64.deb #package_cloud push grafana/stable/debian/wheezy grafana_${deb_ver}_amd64.deb -package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb -package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb +#package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb +#package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb -wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm +#wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm -package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm -ackage_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm +#package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm +package_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm # package_cloud push grafana/stable/el/7 grafana-${version}-1.x86_64.rpm # package_cloud push grafana/stable/el/6 grafana-${version}-1.x86_64.rpm diff --git a/public/app/features/dashboard/all.js b/public/app/features/dashboard/all.js index d110019add6..9d370921332 100644 --- a/public/app/features/dashboard/all.js +++ b/public/app/features/dashboard/all.js @@ -1,5 +1,5 @@ define([ - './dashboardCtrl', + './dashboard_ctrl', './dashboardLoaderSrv', './dashnav/dashnav', './submenu/submenu', @@ -14,7 +14,6 @@ define([ './unsavedChangesSrv', './timepicker/timepicker', './graphiteImportCtrl', - './dynamicDashboardSrv', './importCtrl', './impression_store', ], function () {}); diff --git a/public/app/features/dashboard/dashboardCtrl.js b/public/app/features/dashboard/dashboardCtrl.js deleted file mode 100644 index b6702631155..00000000000 --- a/public/app/features/dashboard/dashboardCtrl.js +++ /dev/null @@ -1,147 +0,0 @@ -define([ - 'angular', - 'jquery', - 'app/core/config', - 'moment', -], -function (angular, $, config, moment) { - "use strict"; - - var module = angular.module('grafana.controllers'); - - module.controller('DashboardCtrl', function( - $scope, - $rootScope, - dashboardKeybindings, - timeSrv, - templateValuesSrv, - dynamicDashboardSrv, - dashboardSrv, - unsavedChangesSrv, - dashboardViewStateSrv, - contextSrv, - $timeout) { - - $scope.editor = { index: 0 }; - $scope.panels = config.panels; - - var resizeEventTimeout; - - this.init = function(dashboard) { - $scope.resetRow(); - $scope.registerWindowResizeEvent(); - $scope.onAppEvent('show-json-editor', $scope.showJsonEditor); - $scope.setupDashboard(dashboard); - }; - - $scope.setupDashboard = function(data) { - $rootScope.performance.dashboardLoadStart = new Date().getTime(); - $rootScope.performance.panelsInitialized = 0; - $rootScope.performance.panelsRendered = 0; - - var dashboard = dashboardSrv.create(data.dashboard, data.meta); - dashboardSrv.setCurrent(dashboard); - - // init services - timeSrv.init(dashboard); - - // template values service needs to initialize completely before - // the rest of the dashboard can load - templateValuesSrv.init(dashboard).finally(function() { - dynamicDashboardSrv.init(dashboard); - unsavedChangesSrv.init(dashboard, $scope); - - $scope.dashboard = dashboard; - $scope.dashboardMeta = dashboard.meta; - $scope.dashboardViewState = dashboardViewStateSrv.create($scope); - - dashboardKeybindings.shortcuts($scope); - - $scope.updateSubmenuVisibility(); - $scope.setWindowTitleAndTheme(); - - $scope.appEvent("dashboard-loaded", $scope.dashboard); - }).catch(function(err) { - if (err.data && err.data.message) { err.message = err.data.message; } - $scope.appEvent("alert-error", ['Dashboard init failed', 'Template variables could not be initialized: ' + err.message]); - }); - }; - - $scope.updateSubmenuVisibility = function() { - $scope.submenuEnabled = $scope.dashboard.isSubmenuFeaturesEnabled(); - }; - - $scope.setWindowTitleAndTheme = function() { - window.document.title = config.window_title_prefix + $scope.dashboard.title; - }; - - $scope.broadcastRefresh = function() { - $rootScope.performance.panelsRendered = 0; - $rootScope.$broadcast('refresh'); - }; - - $scope.addRow = function(dash, row) { - dash.rows.push(row); - }; - - $scope.addRowDefault = function() { - $scope.resetRow(); - $scope.row.title = 'New row'; - $scope.addRow($scope.dashboard, $scope.row); - }; - - $scope.resetRow = function() { - $scope.row = { - title: '', - height: '250px', - editable: true, - }; - }; - - $scope.showJsonEditor = function(evt, options) { - var editScope = $rootScope.$new(); - editScope.object = options.object; - editScope.updateHandler = options.updateHandler; - $scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope }); - }; - - $scope.onDrop = function(panelId, row, dropTarget) { - var info = $scope.dashboard.getPanelInfoById(panelId); - if (dropTarget) { - var dropInfo = $scope.dashboard.getPanelInfoById(dropTarget.id); - dropInfo.row.panels[dropInfo.index] = info.panel; - info.row.panels[info.index] = dropTarget; - var dragSpan = info.panel.span; - info.panel.span = dropTarget.span; - dropTarget.span = dragSpan; - } - else { - info.row.panels.splice(info.index, 1); - info.panel.span = 12 - $scope.dashboard.rowSpan(row); - row.panels.push(info.panel); - } - - $rootScope.$broadcast('render'); - }; - - $scope.registerWindowResizeEvent = function() { - angular.element(window).bind('resize', function() { - $timeout.cancel(resizeEventTimeout); - resizeEventTimeout = $timeout(function() { $scope.$broadcast('render'); }, 200); - }); - $scope.$on('$destroy', function() { - angular.element(window).unbind('resize'); - }); - }; - - $scope.timezoneChanged = function() { - $rootScope.$broadcast("refresh"); - }; - - $scope.formatDate = function(date) { - return moment(date).format('MMM Do YYYY, h:mm:ss a'); - }; - - }); - -}); diff --git a/public/app/features/dashboard/dashboard_ctrl.ts b/public/app/features/dashboard/dashboard_ctrl.ts new file mode 100644 index 00000000000..f7acac4e1b7 --- /dev/null +++ b/public/app/features/dashboard/dashboard_ctrl.ts @@ -0,0 +1,154 @@ +/// + +import config from 'app/core/config'; +import angular from 'angular'; +import moment from 'moment'; +import _ from 'lodash'; + +import coreModule from 'app/core/core_module'; +import {DynamicDashboardSrv} from './dynamic_dashboard_srv'; + +export class DashboardCtrl { + + /** @ngInject */ + constructor( + private $scope, + private $rootScope, + dashboardKeybindings, + timeSrv, + templateValuesSrv, + dashboardSrv, + unsavedChangesSrv, + dashboardViewStateSrv, + contextSrv, + $timeout) { + + $scope.editor = { index: 0 }; + $scope.panels = config.panels; + $scope.dynamicDashboardSrv = new DynamicDashboardSrv(); + + var resizeEventTimeout; + + $scope.setupDashboard = function(data) { + $rootScope.performance.dashboardLoadStart = new Date().getTime(); + $rootScope.performance.panelsInitialized = 0; + $rootScope.performance.panelsRendered = 0; + + var dashboard = dashboardSrv.create(data.dashboard, data.meta); + dashboardSrv.setCurrent(dashboard); + + // init services + timeSrv.init(dashboard); + + // template values service needs to initialize completely before + // the rest of the dashboard can load + templateValuesSrv.init(dashboard).finally(function() { + $scope.dynamicDashboardSrv.init(dashboard); + + unsavedChangesSrv.init(dashboard, $scope); + + $scope.dashboard = dashboard; + $scope.dashboardMeta = dashboard.meta; + $scope.dashboardViewState = dashboardViewStateSrv.create($scope); + + dashboardKeybindings.shortcuts($scope); + + $scope.updateSubmenuVisibility(); + $scope.setWindowTitleAndTheme(); + + $scope.appEvent("dashboard-loaded", $scope.dashboard); + }).catch(function(err) { + if (err.data && err.data.message) { err.message = err.data.message; } + $scope.appEvent("alert-error", ['Dashboard init failed', 'Template variables could not be initialized: ' + err.message]); + }); + }; + + $scope.templateVariableUpdated = function() { + $scope.dynamicDashboardSrv.update($scope.dashboard); + }; + + $scope.updateSubmenuVisibility = function() { + $scope.submenuEnabled = $scope.dashboard.isSubmenuFeaturesEnabled(); + }; + + $scope.setWindowTitleAndTheme = function() { + window.document.title = config.window_title_prefix + $scope.dashboard.title; + }; + + $scope.broadcastRefresh = function() { + $rootScope.performance.panelsRendered = 0; + $rootScope.$broadcast('refresh'); + }; + + $scope.addRow = function(dash, row) { + dash.rows.push(row); + }; + + $scope.addRowDefault = function() { + $scope.resetRow(); + $scope.row.title = 'New row'; + $scope.addRow($scope.dashboard, $scope.row); + }; + + $scope.resetRow = function() { + $scope.row = { + title: '', + height: '250px', + editable: true, + }; + }; + + $scope.showJsonEditor = function(evt, options) { + var editScope = $rootScope.$new(); + editScope.object = options.object; + editScope.updateHandler = options.updateHandler; + $scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope }); + }; + + $scope.onDrop = function(panelId, row, dropTarget) { + var info = $scope.dashboard.getPanelInfoById(panelId); + if (dropTarget) { + var dropInfo = $scope.dashboard.getPanelInfoById(dropTarget.id); + dropInfo.row.panels[dropInfo.index] = info.panel; + info.row.panels[info.index] = dropTarget; + var dragSpan = info.panel.span; + info.panel.span = dropTarget.span; + dropTarget.span = dragSpan; + } else { + info.row.panels.splice(info.index, 1); + info.panel.span = 12 - $scope.dashboard.rowSpan(row); + row.panels.push(info.panel); + } + + $rootScope.$broadcast('render'); + }; + + $scope.registerWindowResizeEvent = function() { + angular.element(window).bind('resize', function() { + $timeout.cancel(resizeEventTimeout); + resizeEventTimeout = $timeout(function() { $scope.$broadcast('render'); }, 200); + }); + $scope.$on('$destroy', function() { + angular.element(window).unbind('resize'); + }); + }; + + $scope.timezoneChanged = function() { + $rootScope.$broadcast("refresh"); + }; + + $scope.formatDate = function(date) { + return moment(date).format('MMM Do YYYY, h:mm:ss a'); + }; + } + + init(dashboard) { + this.$scope.resetRow(); + this.$scope.registerWindowResizeEvent(); + this.$scope.onAppEvent('show-json-editor', this.$scope.showJsonEditor); + this.$scope.onAppEvent('template-variable-value-updated', this.$scope.templateVariableUpdated); + this.$scope.setupDashboard(dashboard); + } +} + +coreModule.controller('DashboardCtrl', DashboardCtrl); diff --git a/public/app/features/dashboard/dynamicDashboardSrv.js b/public/app/features/dashboard/dynamicDashboardSrv.js deleted file mode 100644 index 9e369733f45..00000000000 --- a/public/app/features/dashboard/dynamicDashboardSrv.js +++ /dev/null @@ -1,181 +0,0 @@ -define([ - 'angular', - 'lodash', -], -function (angular, _) { - 'use strict'; - - var module = angular.module('grafana.services'); - - module.service('dynamicDashboardSrv', function() { - var self = this; - - this.init = function(dashboard) { - if (dashboard.snapshot) { return; } - - this.iteration = new Date().getTime(); - this.process(dashboard); - }; - - this.update = function(dashboard) { - if (dashboard.snapshot) { return; } - - this.iteration = this.iteration + 1; - this.process(dashboard); - }; - - this.process = function(dashboard) { - if (dashboard.templating.list.length === 0) { return; } - this.dashboard = dashboard; - - var i, j, row, panel; - for (i = 0; i < this.dashboard.rows.length; i++) { - row = this.dashboard.rows[i]; - // handle row repeats - if (row.repeat) { - this.repeatRow(row, i); - } - // clean up old left overs - else if (row.repeatRowId && row.repeatIteration !== this.iteration) { - this.dashboard.rows.splice(i, 1); - i = i - 1; - continue; - } - - // repeat panels - for (j = 0; j < row.panels.length; j++) { - panel = row.panels[j]; - if (panel.repeat) { - this.repeatPanel(panel, row); - } - // clean up old left overs - else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) { - row.panels = _.without(row.panels, panel); - j = j - 1; - } else if (!_.isEmpty(panel.scopedVars) && panel.repeatIteration !== this.iteration) { - panel.scopedVars = {}; - } - } - } - }; - - // returns a new row clone or reuses a clone from previous iteration - this.getRowClone = function(sourceRow, repeatIndex, sourceRowIndex) { - if (repeatIndex === 0) { - return sourceRow; - } - - var i, panel, row, copy; - var sourceRowId = sourceRowIndex + 1; - - // look for row to reuse - for (i = 0; i < this.dashboard.rows.length; i++) { - row = this.dashboard.rows[i]; - if (row.repeatRowId === sourceRowId && row.repeatIteration !== this.iteration) { - copy = row; - break; - } - } - - if (!copy) { - copy = angular.copy(sourceRow); - this.dashboard.rows.splice(sourceRowIndex + repeatIndex, 0, copy); - - // set new panel ids - for (i = 0; i < copy.panels.length; i++) { - panel = copy.panels[i]; - panel.id = this.dashboard.getNextPanelId(); - } - } - - copy.repeat = null; - copy.repeatRowId = sourceRowId; - copy.repeatIteration = this.iteration; - return copy; - }; - - // returns a new row clone or reuses a clone from previous iteration - this.repeatRow = function(row, rowIndex) { - var variables = this.dashboard.templating.list; - var variable = _.findWhere(variables, {name: row.repeat}); - if (!variable) { - return; - } - - var selected, copy, i, panel; - if (variable.current.text === 'All') { - selected = variable.options.slice(1, variable.options.length); - } else { - selected = _.filter(variable.options, {selected: true}); - } - - _.each(selected, function(option, index) { - copy = self.getRowClone(row, index, rowIndex); - copy.scopedVars = {}; - copy.scopedVars[variable.name] = option; - - for (i = 0; i < copy.panels.length; i++) { - panel = copy.panels[i]; - panel.scopedVars = {}; - panel.scopedVars[variable.name] = option; - panel.repeatIteration = this.iteration; - } - }, this); - }; - - this.getPanelClone = function(sourcePanel, row, index) { - // if first clone return source - if (index === 0) { - return sourcePanel; - } - - var i, tmpId, panel, clone; - - // first try finding an existing clone to use - for (i = 0; i < row.panels.length; i++) { - panel = row.panels[i]; - if (panel.repeatIteration !== this.iteration && panel.repeatPanelId === sourcePanel.id) { - clone = panel; - break; - } - } - - if (!clone) { - clone = { id: this.dashboard.getNextPanelId() }; - row.panels.push(clone); - } - - // save id - tmpId = clone.id; - // copy properties from source - angular.copy(sourcePanel, clone); - // restore id - clone.id = tmpId; - clone.repeatIteration = this.iteration; - clone.repeatPanelId = sourcePanel.id; - clone.repeat = null; - return clone; - }; - - this.repeatPanel = function(panel, row) { - var variables = this.dashboard.templating.list; - var variable = _.findWhere(variables, {name: panel.repeat}); - if (!variable) { return; } - - var selected; - if (variable.current.text === 'All') { - selected = variable.options.slice(1, variable.options.length); - } else { - selected = _.filter(variable.options, {selected: true}); - } - - _.each(selected, function(option, index) { - var copy = self.getPanelClone(panel, row, index); - copy.span = Math.max(12 / selected.length, panel.minSpan); - copy.scopedVars = copy.scopedVars || {}; - copy.scopedVars[variable.name] = option; - }); - }; - - }); -}); diff --git a/public/app/features/dashboard/dynamic_dashboard_srv.ts b/public/app/features/dashboard/dynamic_dashboard_srv.ts new file mode 100644 index 00000000000..340bca69b40 --- /dev/null +++ b/public/app/features/dashboard/dynamic_dashboard_srv.ts @@ -0,0 +1,175 @@ +/// + +import config from 'app/core/config'; +import angular from 'angular'; +import _ from 'lodash'; + +export class DynamicDashboardSrv { + iteration: number; + dashboard: any; + + init(dashboard) { + if (dashboard.snapshot) { return; } + + this.iteration = new Date().getTime(); + this.process(dashboard); + } + + update(dashboard) { + if (dashboard.snapshot) { return; } + + this.iteration = this.iteration + 1; + this.process(dashboard); + } + + process(dashboard) { + if (dashboard.templating.list.length === 0) { return; } + this.dashboard = dashboard; + + var i, j, row, panel; + for (i = 0; i < this.dashboard.rows.length; i++) { + row = this.dashboard.rows[i]; + // handle row repeats + if (row.repeat) { + this.repeatRow(row, i); + } else if (row.repeatRowId && row.repeatIteration !== this.iteration) { + // clean up old left overs + this.dashboard.rows.splice(i, 1); + i = i - 1; + continue; + } + + // repeat panels + for (j = 0; j < row.panels.length; j++) { + panel = row.panels[j]; + if (panel.repeat) { + this.repeatPanel(panel, row); + } else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) { + // clean up old left overs + row.panels = _.without(row.panels, panel); + j = j - 1; + } else if (!_.isEmpty(panel.scopedVars) && panel.repeatIteration !== this.iteration) { + panel.scopedVars = {}; + } + } + } + } + + // returns a new row clone or reuses a clone from previous iteration + getRowClone(sourceRow, repeatIndex, sourceRowIndex) { + if (repeatIndex === 0) { + return sourceRow; + } + + var i, panel, row, copy; + var sourceRowId = sourceRowIndex + 1; + + // look for row to reuse + for (i = 0; i < this.dashboard.rows.length; i++) { + row = this.dashboard.rows[i]; + if (row.repeatRowId === sourceRowId && row.repeatIteration !== this.iteration) { + copy = row; + break; + } + } + + if (!copy) { + copy = angular.copy(sourceRow); + this.dashboard.rows.splice(sourceRowIndex + repeatIndex, 0, copy); + + // set new panel ids + for (i = 0; i < copy.panels.length; i++) { + panel = copy.panels[i]; + panel.id = this.dashboard.getNextPanelId(); + } + } + + copy.repeat = null; + copy.repeatRowId = sourceRowId; + copy.repeatIteration = this.iteration; + return copy; + } + + // returns a new row clone or reuses a clone from previous iteration + repeatRow(row, rowIndex) { + var variables = this.dashboard.templating.list; + var variable = _.findWhere(variables, {name: row.repeat}); + if (!variable) { + return; + } + + var selected, copy, i, panel; + if (variable.current.text === 'All') { + selected = variable.options.slice(1, variable.options.length); + } else { + selected = _.filter(variable.options, {selected: true}); + } + + _.each(selected, (option, index) => { + copy = this.getRowClone(row, index, rowIndex); + copy.scopedVars = {}; + copy.scopedVars[variable.name] = option; + + for (i = 0; i < copy.panels.length; i++) { + panel = copy.panels[i]; + panel.scopedVars = {}; + panel.scopedVars[variable.name] = option; + panel.repeatIteration = this.iteration; + } + }); + } + + getPanelClone(sourcePanel, row, index) { + // if first clone return source + if (index === 0) { + return sourcePanel; + } + + var i, tmpId, panel, clone; + + // first try finding an existing clone to use + for (i = 0; i < row.panels.length; i++) { + panel = row.panels[i]; + if (panel.repeatIteration !== this.iteration && panel.repeatPanelId === sourcePanel.id) { + clone = panel; + break; + } + } + + if (!clone) { + clone = { id: this.dashboard.getNextPanelId() }; + row.panels.push(clone); + } + + // save id + tmpId = clone.id; + // copy properties from source + angular.copy(sourcePanel, clone); + // restore id + clone.id = tmpId; + clone.repeatIteration = this.iteration; + clone.repeatPanelId = sourcePanel.id; + clone.repeat = null; + return clone; + } + + repeatPanel(panel, row) { + var variables = this.dashboard.templating.list; + var variable = _.findWhere(variables, {name: panel.repeat}); + if (!variable) { return; } + + var selected; + if (variable.current.text === 'All') { + selected = variable.options.slice(1, variable.options.length); + } else { + selected = _.filter(variable.options, {selected: true}); + } + + _.each(selected, (option, index) => { + var copy = this.getPanelClone(panel, row, index); + copy.span = Math.max(12 / selected.length, panel.minSpan); + copy.scopedVars = copy.scopedVars || {}; + copy.scopedVars[variable.name] = option; + }); + } +} diff --git a/public/app/features/dashboard/submenu/submenu.ts b/public/app/features/dashboard/submenu/submenu.ts index a9899c3a4b8..8e7984a4085 100644 --- a/public/app/features/dashboard/submenu/submenu.ts +++ b/public/app/features/dashboard/submenu/submenu.ts @@ -8,7 +8,7 @@ export class SubmenuCtrl { dashboard: any; /** @ngInject */ - constructor(private $rootScope, private templateValuesSrv, private dynamicDashboardSrv) { + constructor(private $rootScope, private templateValuesSrv) { this.annotations = this.dashboard.templating.list; this.variables = this.dashboard.templating.list; } @@ -24,7 +24,6 @@ export class SubmenuCtrl { variableUpdated(variable) { this.templateValuesSrv.variableUpdated(variable).then(() => { - this.dynamicDashboardSrv.update(this.dashboard); this.$rootScope.$emit('template-variable-value-updated'); this.$rootScope.$broadcast('refresh'); }); diff --git a/public/test/core/utils/emitter_specs.ts b/public/test/core/utils/emitter_specs.ts index f7076c46719..fec4d02a649 100644 --- a/public/test/core/utils/emitter_specs.ts +++ b/public/test/core/utils/emitter_specs.ts @@ -24,7 +24,7 @@ describe("Emitter", () => { expect(sub2Called).to.be(true); }); - it.only('should handle errors', () => { + it('should handle errors', () => { var events = new Emitter(); var sub1Called = 0; var sub2Called = 0; diff --git a/public/test/specs/dynamicDashboardSrv-specs.js b/public/test/specs/dynamicDashboardSrv-specs.js deleted file mode 100644 index b988203009a..00000000000 --- a/public/test/specs/dynamicDashboardSrv-specs.js +++ /dev/null @@ -1,267 +0,0 @@ -define([ - 'app/features/dashboard/dynamicDashboardSrv', - 'app/features/dashboard/dashboardSrv' -], function() { - 'use strict'; - - function dynamicDashScenario(desc, func) { - - describe(desc, function() { - var ctx = {}; - - ctx.setup = function (setupFunc) { - - beforeEach(module('grafana.services')); - beforeEach(module(function($provide) { - $provide.value('contextSrv', { - user: { timezone: 'utc'} - }); - })); - - beforeEach(inject(function(dynamicDashboardSrv, dashboardSrv) { - ctx.dynamicDashboardSrv = dynamicDashboardSrv; - ctx.dashboardSrv = dashboardSrv; - - var model = { - rows: [], - templating: { list: [] } - }; - - setupFunc(model); - ctx.dash = ctx.dashboardSrv.create(model); - ctx.dynamicDashboardSrv.init(ctx.dash); - ctx.rows = ctx.dash.rows; - })); - }; - - func(ctx); - }); - } - - dynamicDashScenario('given dashboard with panel repeat', function(ctx) { - ctx.setup(function(dash) { - dash.rows.push({ - panels: [{id: 2, repeat: 'apps'}] - }); - dash.templating.list.push({ - name: 'apps', - current: { - text: 'se1, se2, se3', - value: ['se1', 'se2', 'se3'] - }, - options: [ - {text: 'se1', value: 'se1', selected: true}, - {text: 'se2', value: 'se2', selected: true}, - {text: 'se3', value: 'se3', selected: true}, - {text: 'se4', value: 'se4', selected: false} - ] - }); - }); - - it('should repeat panel one time', function() { - expect(ctx.rows[0].panels.length).to.be(3); - }); - - it('should mark panel repeated', function() { - expect(ctx.rows[0].panels[0].repeat).to.be('apps'); - expect(ctx.rows[0].panels[1].repeatPanelId).to.be(2); - }); - - it('should set scopedVars on panels', function() { - expect(ctx.rows[0].panels[0].scopedVars.apps.value).to.be('se1'); - expect(ctx.rows[0].panels[1].scopedVars.apps.value).to.be('se2'); - expect(ctx.rows[0].panels[2].scopedVars.apps.value).to.be('se3'); - }); - - describe('After a second iteration', function() { - var repeatedPanelAfterIteration1; - - beforeEach(function() { - repeatedPanelAfterIteration1 = ctx.rows[0].panels[1]; - ctx.rows[0].panels[0].fill = 10; - ctx.dynamicDashboardSrv.update(ctx.dash); - }); - - it('should have reused same panel instances', function() { - expect(ctx.rows[0].panels[1]).to.be(repeatedPanelAfterIteration1); - }); - - it('reused panel should copy properties from source', function() { - expect(ctx.rows[0].panels[1].fill).to.be(10); - }); - - it('should have same panel count', function() { - expect(ctx.rows[0].panels.length).to.be(3); - }); - }); - - describe('After a second iteration and selected values reduced', function() { - beforeEach(function() { - ctx.dash.templating.list[0].options[1].selected = false; - - ctx.dynamicDashboardSrv.update(ctx.dash); - }); - - it('should clean up repeated panel', function() { - expect(ctx.rows[0].panels.length).to.be(2); - }); - }); - - describe('After a second iteration and panel repeat is turned off', function() { - beforeEach(function() { - ctx.rows[0].panels[0].repeat = null; - ctx.dynamicDashboardSrv.update(ctx.dash); - }); - - it('should clean up repeated panel', function() { - expect(ctx.rows[0].panels.length).to.be(1); - }); - - it('should remove scoped vars from reused panel', function() { - expect(ctx.rows[0].panels[0].scopedVars).to.be.empty(); - }); - }); - - }); - - dynamicDashScenario('given dashboard with row repeat', function(ctx) { - ctx.setup(function(dash) { - dash.rows.push({ - repeat: 'servers', - panels: [{id: 2}] - }); - dash.rows.push({panels: []}); - dash.templating.list.push({ - name: 'servers', - current: { - text: 'se1, se2', - value: ['se1', 'se2'] - }, - options: [ - {text: 'se1', value: 'se1', selected: true}, - {text: 'se2', value: 'se2', selected: true}, - ] - }); - }); - - it('should repeat row one time', function() { - expect(ctx.rows.length).to.be(3); - }); - - it('should keep panel ids on first row', function() { - expect(ctx.rows[0].panels[0].id).to.be(2); - }); - - it('should keep first row as repeat', function() { - expect(ctx.rows[0].repeat).to.be('servers'); - }); - - it('should clear repeat field on repeated row', function() { - expect(ctx.rows[1].repeat).to.be(null); - }); - - it('should add scopedVars to rows', function() { - expect(ctx.rows[0].scopedVars.servers.value).to.be('se1'); - expect(ctx.rows[1].scopedVars.servers.value).to.be('se2'); - }); - - it('should generate a repeartRowId based on repeat row index', function() { - expect(ctx.rows[1].repeatRowId).to.be(1); - }); - - it('should set scopedVars on row panels', function() { - expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); - expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); - }); - - describe('After a second iteration', function() { - var repeatedRowAfterFirstIteration; - - beforeEach(function() { - repeatedRowAfterFirstIteration = ctx.rows[1]; - ctx.rows[0].height = 500; - ctx.dynamicDashboardSrv.update(ctx.dash); - }); - - it('should still only have 2 rows', function() { - expect(ctx.rows.length).to.be(3); - }); - - it.skip('should have updated props from source', function() { - expect(ctx.rows[1].height).to.be(500); - }); - - it('should reuse row instance', function() { - expect(ctx.rows[1]).to.be(repeatedRowAfterFirstIteration); - }); - }); - - describe('After a second iteration and selected values reduced', function() { - beforeEach(function() { - ctx.dash.templating.list[0].options[1].selected = false; - ctx.dynamicDashboardSrv.update(ctx.dash); - }); - - it('should remove repeated second row', function() { - expect(ctx.rows.length).to.be(2); - }); - }); - }); - - dynamicDashScenario('given dashboard with row repeat and panel repeat', function(ctx) { - ctx.setup(function(dash) { - dash.rows.push({ - repeat: 'servers', - panels: [{id: 2, repeat: 'metric'}] - }); - dash.templating.list.push({ - name: 'servers', - current: { text: 'se1, se2', value: ['se1', 'se2'] }, - options: [ - {text: 'se1', value: 'se1', selected: true}, - {text: 'se2', value: 'se2', selected: true}, - ] - }); - dash.templating.list.push({ - name: 'metric', - current: { text: 'm1, m2', value: ['m1', 'm2'] }, - options: [ - {text: 'm1', value: 'm1', selected: true}, - {text: 'm2', value: 'm2', selected: true}, - ] - }); - }); - - it('should repeat row one time', function() { - expect(ctx.rows.length).to.be(2); - }); - - it('should repeat panel on both rows', function() { - expect(ctx.rows[0].panels.length).to.be(2); - expect(ctx.rows[1].panels.length).to.be(2); - }); - - it('should keep panel ids on first row', function() { - expect(ctx.rows[0].panels[0].id).to.be(2); - }); - - it('should mark second row as repeated', function() { - expect(ctx.rows[0].repeat).to.be('servers'); - }); - - it('should clear repeat field on repeated row', function() { - expect(ctx.rows[1].repeat).to.be(null); - }); - - it('should generate a repeartRowId based on repeat row index', function() { - expect(ctx.rows[1].repeatRowId).to.be(1); - }); - - it('should set scopedVars on row panels', function() { - expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); - expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); - }); - - }); - -}); diff --git a/public/test/specs/dynamic_dashboard_srv_specs.ts b/public/test/specs/dynamic_dashboard_srv_specs.ts new file mode 100644 index 00000000000..6f233fcb9ff --- /dev/null +++ b/public/test/specs/dynamic_dashboard_srv_specs.ts @@ -0,0 +1,264 @@ +import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; + +import 'app/features/dashboard/dashboardSrv'; +import {DynamicDashboardSrv} from '../../app/features/dashboard/dynamic_dashboard_srv'; + +function dynamicDashScenario(desc, func) { + + describe(desc, function() { + var ctx: any = {}; + + ctx.setup = function (setupFunc) { + + beforeEach(angularMocks.module('grafana.services')); + beforeEach(angularMocks.module(function($provide) { + $provide.value('contextSrv', { + user: { timezone: 'utc'} + }); + })); + + beforeEach(angularMocks.inject(function(dashboardSrv) { + ctx.dashboardSrv = dashboardSrv; + var model = { + rows: [], + templating: { list: [] } + }; + + setupFunc(model); + ctx.dash = ctx.dashboardSrv.create(model); + ctx.dynamicDashboardSrv = new DynamicDashboardSrv(); + ctx.dynamicDashboardSrv.init(ctx.dash); + ctx.rows = ctx.dash.rows; + })); + }; + + func(ctx); + }); +} + +dynamicDashScenario('given dashboard with panel repeat', function(ctx) { + ctx.setup(function(dash) { + dash.rows.push({ + panels: [{id: 2, repeat: 'apps'}] + }); + dash.templating.list.push({ + name: 'apps', + current: { + text: 'se1, se2, se3', + value: ['se1', 'se2', 'se3'] + }, + options: [ + {text: 'se1', value: 'se1', selected: true}, + {text: 'se2', value: 'se2', selected: true}, + {text: 'se3', value: 'se3', selected: true}, + {text: 'se4', value: 'se4', selected: false} + ] + }); + }); + + it('should repeat panel one time', function() { + expect(ctx.rows[0].panels.length).to.be(3); + }); + + it('should mark panel repeated', function() { + expect(ctx.rows[0].panels[0].repeat).to.be('apps'); + expect(ctx.rows[0].panels[1].repeatPanelId).to.be(2); + }); + + it('should set scopedVars on panels', function() { + expect(ctx.rows[0].panels[0].scopedVars.apps.value).to.be('se1'); + expect(ctx.rows[0].panels[1].scopedVars.apps.value).to.be('se2'); + expect(ctx.rows[0].panels[2].scopedVars.apps.value).to.be('se3'); + }); + + describe('After a second iteration', function() { + var repeatedPanelAfterIteration1; + + beforeEach(function() { + repeatedPanelAfterIteration1 = ctx.rows[0].panels[1]; + ctx.rows[0].panels[0].fill = 10; + ctx.dynamicDashboardSrv.update(ctx.dash); + }); + + it('should have reused same panel instances', function() { + expect(ctx.rows[0].panels[1]).to.be(repeatedPanelAfterIteration1); + }); + + it('reused panel should copy properties from source', function() { + expect(ctx.rows[0].panels[1].fill).to.be(10); + }); + + it('should have same panel count', function() { + expect(ctx.rows[0].panels.length).to.be(3); + }); + }); + + describe('After a second iteration and selected values reduced', function() { + beforeEach(function() { + ctx.dash.templating.list[0].options[1].selected = false; + + ctx.dynamicDashboardSrv.update(ctx.dash); + }); + + it('should clean up repeated panel', function() { + expect(ctx.rows[0].panels.length).to.be(2); + }); + }); + + describe('After a second iteration and panel repeat is turned off', function() { + beforeEach(function() { + ctx.rows[0].panels[0].repeat = null; + ctx.dynamicDashboardSrv.update(ctx.dash); + }); + + it('should clean up repeated panel', function() { + expect(ctx.rows[0].panels.length).to.be(1); + }); + + it('should remove scoped vars from reused panel', function() { + expect(ctx.rows[0].panels[0].scopedVars).to.be.empty(); + }); + }); + +}); + +dynamicDashScenario('given dashboard with row repeat', function(ctx) { + ctx.setup(function(dash) { + dash.rows.push({ + repeat: 'servers', + panels: [{id: 2}] + }); + dash.rows.push({panels: []}); + dash.templating.list.push({ + name: 'servers', + current: { + text: 'se1, se2', + value: ['se1', 'se2'] + }, + options: [ + {text: 'se1', value: 'se1', selected: true}, + {text: 'se2', value: 'se2', selected: true}, + ] + }); + }); + + it('should repeat row one time', function() { + expect(ctx.rows.length).to.be(3); + }); + + it('should keep panel ids on first row', function() { + expect(ctx.rows[0].panels[0].id).to.be(2); + }); + + it('should keep first row as repeat', function() { + expect(ctx.rows[0].repeat).to.be('servers'); + }); + + it('should clear repeat field on repeated row', function() { + expect(ctx.rows[1].repeat).to.be(null); + }); + + it('should add scopedVars to rows', function() { + expect(ctx.rows[0].scopedVars.servers.value).to.be('se1'); + expect(ctx.rows[1].scopedVars.servers.value).to.be('se2'); + }); + + it('should generate a repeartRowId based on repeat row index', function() { + expect(ctx.rows[1].repeatRowId).to.be(1); + }); + + it('should set scopedVars on row panels', function() { + expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); + expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); + }); + + describe('After a second iteration', function() { + var repeatedRowAfterFirstIteration; + + beforeEach(function() { + repeatedRowAfterFirstIteration = ctx.rows[1]; + ctx.rows[0].height = 500; + ctx.dynamicDashboardSrv.update(ctx.dash); + }); + + it('should still only have 2 rows', function() { + expect(ctx.rows.length).to.be(3); + }); + + it.skip('should have updated props from source', function() { + expect(ctx.rows[1].height).to.be(500); + }); + + it('should reuse row instance', function() { + expect(ctx.rows[1]).to.be(repeatedRowAfterFirstIteration); + }); + }); + + describe('After a second iteration and selected values reduced', function() { + beforeEach(function() { + ctx.dash.templating.list[0].options[1].selected = false; + ctx.dynamicDashboardSrv.update(ctx.dash); + }); + + it('should remove repeated second row', function() { + expect(ctx.rows.length).to.be(2); + }); + }); +}); + +dynamicDashScenario('given dashboard with row repeat and panel repeat', function(ctx) { + ctx.setup(function(dash) { + dash.rows.push({ + repeat: 'servers', + panels: [{id: 2, repeat: 'metric'}] + }); + dash.templating.list.push({ + name: 'servers', + current: { text: 'se1, se2', value: ['se1', 'se2'] }, + options: [ + {text: 'se1', value: 'se1', selected: true}, + {text: 'se2', value: 'se2', selected: true}, + ] + }); + dash.templating.list.push({ + name: 'metric', + current: { text: 'm1, m2', value: ['m1', 'm2'] }, + options: [ + {text: 'm1', value: 'm1', selected: true}, + {text: 'm2', value: 'm2', selected: true}, + ] + }); + }); + + it('should repeat row one time', function() { + expect(ctx.rows.length).to.be(2); + }); + + it('should repeat panel on both rows', function() { + expect(ctx.rows[0].panels.length).to.be(2); + expect(ctx.rows[1].panels.length).to.be(2); + }); + + it('should keep panel ids on first row', function() { + expect(ctx.rows[0].panels[0].id).to.be(2); + }); + + it('should mark second row as repeated', function() { + expect(ctx.rows[0].repeat).to.be('servers'); + }); + + it('should clear repeat field on repeated row', function() { + expect(ctx.rows[1].repeat).to.be(null); + }); + + it('should generate a repeartRowId based on repeat row index', function() { + expect(ctx.rows[1].repeatRowId).to.be(1); + }); + + it('should set scopedVars on row panels', function() { + expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); + expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); + }); + +}); +