diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d5721604c4..1e1f1f9aade 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ - [Issue #1331](https://github.com/grafana/grafana/issues/1331). Graph & Singlestat: New axis/unit format selector and more units (kbytes, Joule, Watt, eV), and new design for graph axis & grid tab and single stat options tab views - [Issue #1241](https://github.com/grafana/grafana/issues/1242). Timepicker: New option in timepicker (under dashboard settings), to change ``now`` to be for example ``now-1m``, usefull when you want to ignore last minute because it contains incomplete data - [Issue #171](https://github.com/grafana/grafana/issues/171). Panel: Different time periods, panels can override dashboard relative time and/or add a time shift +- [Issue #1488](https://github.com/grafana/grafana/issues/1488). Dashboard: Clone dashboard / Save as + +**Changes** +- Dashboard title change & save will no longer create a new dashboard, it will just change the title. **Enhancements** - [Issue #1297](https://github.com/grafana/grafana/issues/1297). Graphite: Added cumulative and minimumBelow graphite functions diff --git a/src/app/components/settings.js b/src/app/components/settings.js index 7e896b475ea..078b5519420 100644 --- a/src/app/components/settings.js +++ b/src/app/components/settings.js @@ -27,7 +27,6 @@ function (_, crypto) { playlist_timespan: "1m", unsaved_changes_warning: true, search: { max_results: 100 }, - admin: {}, appSubUrl: "" }; diff --git a/src/app/features/dashboard/all.js b/src/app/features/dashboard/all.js index 1ba0051adf3..a64800867c2 100644 --- a/src/app/features/dashboard/all.js +++ b/src/app/features/dashboard/all.js @@ -1,6 +1,7 @@ define([ './dashboardCtrl', './dashboardNavCtrl', + './cloneDashboardCtrl', './playlistCtrl', './rowCtrl', './sharePanelCtrl', diff --git a/src/app/features/dashboard/cloneDashboardCtrl.js b/src/app/features/dashboard/cloneDashboardCtrl.js new file mode 100644 index 00000000000..855129ecaf9 --- /dev/null +++ b/src/app/features/dashboard/cloneDashboardCtrl.js @@ -0,0 +1,33 @@ +define([ + 'angular', +], +function (angular) { + 'use strict'; + + var module = angular.module('grafana.controllers'); + + module.controller('CloneDashboardCtrl', function($scope, datasourceSrv, $location) { + + $scope.init = function() { + $scope.db = datasourceSrv.getGrafanaDB(); + $scope.clone.id = null; + $scope.clone.editable = true; + $scope.clone.title = $scope.clone.title + " Copy"; + }; + + $scope.saveClone = function() { + $scope.db.saveDashboard($scope.clone) + .then(function(result) { + + $scope.appEvent('alert-success', ['Dashboard saved', 'Saved as ' + result.title]); + $location.url(result.url); + $scope.appEvent('dashboard-saved', $scope.clone); + $scope.dismiss(); + + }, function(err) { + $scope.appEvent('alert-error', ['Save failed', err]); + }); + }; + }); + +}); diff --git a/src/app/features/dashboard/dashboardNavCtrl.js b/src/app/features/dashboard/dashboardNavCtrl.js index b256b24d6cf..f41dd007089 100644 --- a/src/app/features/dashboard/dashboardNavCtrl.js +++ b/src/app/features/dashboard/dashboardNavCtrl.js @@ -65,27 +65,11 @@ function (angular, _, moment, config, store) { window.sessionStorage["grafanaAdminPassword"] = pwd; }; - $scope.isAdmin = function() { - if (!config.admin || !config.admin.password) { return true; } - if ($scope.passwordCache() === config.admin.password) { return true; } - - var password = window.prompt("Admin password", ""); - $scope.passwordCache(password); - - if (password === config.admin.password) { return true; } - - alertSrv.set('Save failed', 'Password incorrect', 'error'); - - return false; - }; - $scope.openSearch = function() { $scope.appEvent('show-dash-search'); }; $scope.saveDashboard = function() { - if (!$scope.isAdmin()) { return false; } - var clone = angular.copy($scope.dashboard); $scope.db.saveDashboard(clone) .then(function(result) { @@ -96,7 +80,7 @@ function (angular, _, moment, config, store) { $location.path(result.url); } - $rootScope.$emit('dashboard-saved', $scope.dashboard); + $scope.appEvent('dashboard-saved', $scope.dashboard); }, function(err) { $scope.appEvent('alert-error', ['Save failed', err]); @@ -104,8 +88,6 @@ function (angular, _, moment, config, store) { }; $scope.deleteDashboard = function() { - if (!$scope.isAdmin()) { return false; } - $scope.appEvent('confirm-modal', { title: 'Delete dashboard', text: 'Do you want to delete dashboard ' + $scope.dashboard.title + '?', @@ -123,6 +105,16 @@ function (angular, _, moment, config, store) { }); }; + $scope.cloneDashboard = function() { + var newScope = $rootScope.$new(); + newScope.clone = angular.copy($scope.dashboard); + + $scope.appEvent('show-modal', { + src: './app/features/dashboard/partials/cloneDashboard.html', + scope: newScope, + }); + }; + $scope.exportDashboard = function() { var blob = new Blob([angular.toJson($scope.dashboard, true)], { type: "application/json;charset=utf-8" }); window.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime()); diff --git a/src/app/features/dashboard/partials/cloneDashboard.html b/src/app/features/dashboard/partials/cloneDashboard.html new file mode 100644 index 00000000000..dcbea9d1d00 --- /dev/null +++ b/src/app/features/dashboard/partials/cloneDashboard.html @@ -0,0 +1,26 @@ + + diff --git a/src/app/features/grafanaDatasource/datasource.js b/src/app/features/grafanaDatasource/datasource.js index 7afee86096f..b6babaa7a93 100644 --- a/src/app/features/grafanaDatasource/datasource.js +++ b/src/app/features/grafanaDatasource/datasource.js @@ -45,11 +45,6 @@ function (angular, _, kbn) { }; GrafanaDatasource.prototype.saveDashboard = function(dashboard) { - // remove id if title has changed - if (dashboard.title !== dashboard.originalTitle) { - dashboard.id = null; - } - return backendSrv.post('/api/dashboards/db/', { dashboard: dashboard }) .then(function(data) { return { title: dashboard.title, url: '/dashboard/db/' + data.slug }; diff --git a/src/app/partials/dashboard_topnav.html b/src/app/partials/dashboard_topnav.html index 71956a8c461..39264b9fbbe 100644 --- a/src/app/partials/dashboard_topnav.html +++ b/src/app/partials/dashboard_topnav.html @@ -44,6 +44,7 @@
  • Export
  • View JSON
  • Delete dashboard
  • +
  • Clone dashboard
  • diff --git a/src/config.sample.js b/src/config.sample.js index 0c11e4007b2..ad14b7f7520 100644 --- a/src/config.sample.js +++ b/src/config.sample.js @@ -86,12 +86,6 @@ define(['settings'], function(Settings) { // Example: "1m", "1h" playlist_timespan: "1m", - // If you want to specify password before saving, please specify it below - // The purpose of this password is not security, but to stop some users from accidentally changing dashboards - admin: { - password: '' - }, - // Change window title prefix from 'Grafana - ' window_title_prefix: 'Grafana - ', diff --git a/src/css/less/forms.less b/src/css/less/forms.less index aa9381e74ff..b5e866e8045 100644 --- a/src/css/less/forms.less +++ b/src/css/less/forms.less @@ -1,7 +1,8 @@ input[type=text].input-fluid { width: 100%; box-sizing: border-box; - padding: 14px; + padding: 10px; + font-size: 16px; -moz-box-sizing: border-box; height: 100%; } diff --git a/src/css/less/tightform.less b/src/css/less/tightform.less index 22efcda2fcf..5266a81b901 100644 --- a/src/css/less/tightform.less +++ b/src/css/less/tightform.less @@ -9,7 +9,7 @@ padding: 0; margin: 0; } - &:last-child { + &:last-child, &.last { border-bottom: 1px solid @grafanaTargetBorder; } } diff --git a/src/test/specs/sharePanelCtrl-specs.js b/src/test/specs/sharePanelCtrl-specs.js index 6cb0a732d6e..acfc849db25 100644 --- a/src/test/specs/sharePanelCtrl-specs.js +++ b/src/test/specs/sharePanelCtrl-specs.js @@ -20,7 +20,6 @@ define([ describe('shareUrl with current time range and panel', function() { - it('should generate share url relative time', function() { ctx.$location.path('/test'); ctx.scope.panel = { id: 22 };