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