diff --git a/public/app/features/dashboard/dashboardCtrl.js b/public/app/features/dashboard/dashboardCtrl.js
index ba86f9f5dba..41453bd77e3 100644
--- a/public/app/features/dashboard/dashboardCtrl.js
+++ b/public/app/features/dashboard/dashboardCtrl.js
@@ -48,6 +48,7 @@ function (angular, $, config) {
// the rest of the dashboard can load
templateValuesSrv.init(dashboard).finally(function() {
dynamicDashboardSrv.init(dashboard);
+
$scope.dashboard = dashboard;
$scope.dashboardMeta = dashboard.meta;
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
diff --git a/public/app/features/dashboard/dashboardSrv.js b/public/app/features/dashboard/dashboardSrv.js
index 02d8f51fafe..afe5e7964c6 100644
--- a/public/app/features/dashboard/dashboardSrv.js
+++ b/public/app/features/dashboard/dashboardSrv.js
@@ -10,7 +10,7 @@ function (angular, $, kbn, _, moment) {
var module = angular.module('grafana.services');
- module.factory('dashboardSrv', function(contextSrv) {
+ module.factory('dashboardSrv', function() {
function DashboardModel (data, meta) {
if (!data) {
@@ -59,10 +59,6 @@ function (angular, $, kbn, _, moment) {
meta.canStar = meta.canStar === false ? false : true;
meta.canDelete = meta.canDelete === false ? false : true;
- if (contextSrv.hasRole('Viewer')) {
- meta.canSave = false;
- }
-
if (!this.editable) {
meta.canEdit = false;
meta.canDelete = false;
diff --git a/public/app/features/dashboard/dynamicDashboardSrv.js b/public/app/features/dashboard/dynamicDashboardSrv.js
index 286eb116e25..8d099a9f6c6 100644
--- a/public/app/features/dashboard/dynamicDashboardSrv.js
+++ b/public/app/features/dashboard/dynamicDashboardSrv.js
@@ -8,8 +8,11 @@ function (angular, _) {
var module = angular.module('grafana.services');
module.service('dynamicDashboardSrv', function() {
+ var self = this;
this.init = function(dashboard) {
+ this.iteration = 0;
+
this.handlePanelRepeats(dashboard);
this.handleRowRepeats(dashboard);
};
@@ -112,6 +115,15 @@ function (angular, _) {
};
+ this.getRepeatPanel = function(sourcePanel, row) {
+ for (var i = 0; i < row.panels.length; i++) {
+ var panel = row.panels[i];
+ if (panel.sourcePanel === sourcePanel) {
+ return panel;
+ }
+ }
+ };
+
this.repeatPanel = function(panel, row, dashboard) {
var variables = dashboard.templating.list;
var variable = _.findWhere(variables, {name: panel.repeat.replace('$', '')});
@@ -137,7 +149,6 @@ function (angular, _) {
panel.scopedVars = {};
panel.scopedVars[variable.name] = option;
}
- console.log('duplicatePanel');
});
};
diff --git a/public/app/features/dashboard/partials/dashboardTopNav.html b/public/app/features/dashboard/partials/dashboardTopNav.html
index 6f85d6b4e02..89a6a185759 100644
--- a/public/app/features/dashboard/partials/dashboardTopNav.html
+++ b/public/app/features/dashboard/partials/dashboardTopNav.html
@@ -27,7 +27,7 @@
-
+
diff --git a/public/app/features/dashboard/unsavedChangesSrv.js b/public/app/features/dashboard/unsavedChangesSrv.js
index eec884551ec..3fd942f1139 100644
--- a/public/app/features/dashboard/unsavedChangesSrv.js
+++ b/public/app/features/dashboard/unsavedChangesSrv.js
@@ -12,7 +12,7 @@ function(angular, _, config) {
var module = angular.module('grafana.services');
- module.service('unsavedChangesSrv', function($rootScope, $modal, $q, $location, $timeout) {
+ module.service('unsavedChangesSrv', function($rootScope, $modal, $q, $location, $timeout, contextSrv) {
var self = this;
var modalScope = $rootScope.$new();
@@ -37,6 +37,7 @@ function(angular, _, config) {
});
this.ignoreChanges = function() {
+ if (!contextSrv.isEditor) { return true; }
if (!self.current || !self.current.meta) { return true; }
var meta = self.current.meta;
diff --git a/public/test/specs/dashboardSrv-specs.js b/public/test/specs/dashboardSrv-specs.js
index 35d248888c7..93f6c04aa13 100644
--- a/public/test/specs/dashboardSrv-specs.js
+++ b/public/test/specs/dashboardSrv-specs.js
@@ -1,17 +1,12 @@
define([
- 'helpers',
'features/dashboard/dashboardSrv'
-], function(helpers) {
+], function() {
'use strict';
describe('dashboardSrv', function() {
var _dashboardSrv;
- var contextSrv = new helpers.ContextSrvStub();
beforeEach(module('grafana.services'));
- beforeEach(module(function($provide) {
- $provide.value('contextSrv', contextSrv);
- }));
beforeEach(inject(function(dashboardSrv) {
_dashboardSrv = dashboardSrv;
@@ -29,7 +24,7 @@ define([
});
it('should have meta', function() {
- expect(model.meta.canSave).to.be(false);
+ expect(model.meta.canSave).to.be(true);
expect(model.meta.canShare).to.be(true);
});
diff --git a/public/test/specs/dynamicDashboardSrv-specs.js b/public/test/specs/dynamicDashboardSrv-specs.js
new file mode 100644
index 00000000000..3fdc6faf14f
--- /dev/null
+++ b/public/test/specs/dynamicDashboardSrv-specs.js
@@ -0,0 +1,65 @@
+define([
+ 'features/dashboard/dynamicDashboardSrv',
+ 'features/dashboard/dashboardSrv'
+], function() {
+ 'use strict';
+
+ describe('dynamicDashboardSrv', function() {
+ var _dynamicDashboardSrv;
+ var _dashboardSrv;
+
+ beforeEach(module('grafana.services'));
+
+ beforeEach(inject(function(dynamicDashboardSrv, dashboardSrv) {
+ _dynamicDashboardSrv = dynamicDashboardSrv;
+ _dashboardSrv = dashboardSrv;
+ }));
+
+ describe('given dashboard with panel repeat', function() {
+ var model;
+
+ beforeEach(function() {
+ model = _dashboardSrv.create({
+ rows: [
+ {
+ panels: [{id: 2, repeat: '$apps'}]
+ }
+ ],
+ templating: {
+ list: [{
+ name: 'apps',
+ current: {
+ text: 'se1, se2',
+ value: ['se1', 'se2']
+ },
+ options: [
+ {text: 'se1', value: 'se1', selected: true},
+ {text: 'se2', value: 'se2', selected: true},
+ ]
+ }]
+ }
+ }, {});
+
+ _dynamicDashboardSrv.init(model);
+ });
+
+ it('should repeat panel one time', function() {
+ expect(model.rows[0].panels.length).to.be(2);
+ });
+
+ it('should mark panel repeated', function() {
+ expect(model.rows[0].panels[0].linked).to.be(undefined);
+ expect(model.rows[0].panels[0].repeat).to.be('$apps');
+ expect(model.rows[0].panels[1].linked).to.be(true);
+ expect(model.rows[0].panels[1].repeat).to.be(null);
+ });
+
+ it('should set scopedVars on panels', function() {
+ expect(model.rows[0].panels[0].scopedVars.apps.value).to.be('se1');
+ expect(model.rows[0].panels[1].scopedVars.apps.value).to.be('se2');
+ });
+
+ });
+
+ });
+});
diff --git a/public/test/test-main.js b/public/test/test-main.js
index a38f8dca32b..2dc85cc65ef 100644
--- a/public/test/test-main.js
+++ b/public/test/test-main.js
@@ -140,6 +140,7 @@ require([
'specs/dashboardSrv-specs',
'specs/dashboardViewStateSrv-specs',
'specs/soloPanelCtrl-specs',
+ 'specs/dynamicDashboardSrv-specs',
];
var pluginSpecs = (config.plugins.specs || []).map(function (spec) {