Worked on clone dashboard feature, #1488

This commit is contained in:
Torkel Ödegaard 2015-02-18 10:44:36 +01:00
parent 5c9ef9d9da
commit 596ce18aeb
12 changed files with 79 additions and 34 deletions

View File

@ -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 #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 #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 #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** **Enhancements**
- [Issue #1297](https://github.com/grafana/grafana/issues/1297). Graphite: Added cumulative and minimumBelow graphite functions - [Issue #1297](https://github.com/grafana/grafana/issues/1297). Graphite: Added cumulative and minimumBelow graphite functions

View File

@ -27,7 +27,6 @@ function (_, crypto) {
playlist_timespan: "1m", playlist_timespan: "1m",
unsaved_changes_warning: true, unsaved_changes_warning: true,
search: { max_results: 100 }, search: { max_results: 100 },
admin: {},
appSubUrl: "" appSubUrl: ""
}; };

View File

@ -1,6 +1,7 @@
define([ define([
'./dashboardCtrl', './dashboardCtrl',
'./dashboardNavCtrl', './dashboardNavCtrl',
'./cloneDashboardCtrl',
'./playlistCtrl', './playlistCtrl',
'./rowCtrl', './rowCtrl',
'./sharePanelCtrl', './sharePanelCtrl',

View File

@ -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]);
});
};
});
});

View File

@ -65,27 +65,11 @@ function (angular, _, moment, config, store) {
window.sessionStorage["grafanaAdminPassword"] = pwd; 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.openSearch = function() {
$scope.appEvent('show-dash-search'); $scope.appEvent('show-dash-search');
}; };
$scope.saveDashboard = function() { $scope.saveDashboard = function() {
if (!$scope.isAdmin()) { return false; }
var clone = angular.copy($scope.dashboard); var clone = angular.copy($scope.dashboard);
$scope.db.saveDashboard(clone) $scope.db.saveDashboard(clone)
.then(function(result) { .then(function(result) {
@ -96,7 +80,7 @@ function (angular, _, moment, config, store) {
$location.path(result.url); $location.path(result.url);
} }
$rootScope.$emit('dashboard-saved', $scope.dashboard); $scope.appEvent('dashboard-saved', $scope.dashboard);
}, function(err) { }, function(err) {
$scope.appEvent('alert-error', ['Save failed', err]); $scope.appEvent('alert-error', ['Save failed', err]);
@ -104,8 +88,6 @@ function (angular, _, moment, config, store) {
}; };
$scope.deleteDashboard = function() { $scope.deleteDashboard = function() {
if (!$scope.isAdmin()) { return false; }
$scope.appEvent('confirm-modal', { $scope.appEvent('confirm-modal', {
title: 'Delete dashboard', title: 'Delete dashboard',
text: 'Do you want to delete dashboard ' + $scope.dashboard.title + '?', 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() { $scope.exportDashboard = function() {
var blob = new Blob([angular.toJson($scope.dashboard, true)], { type: "application/json;charset=utf-8" }); var blob = new Blob([angular.toJson($scope.dashboard, true)], { type: "application/json;charset=utf-8" });
window.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime()); window.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime());

View File

@ -0,0 +1,26 @@
<div class="modal-body gf-box gf-box-no-margin" ng-controller="CloneDashboardCtrl" ng-init="init();">
<div class="gf-box-header">
<div class="gf-box-title">
<i class="fa fa-copy"></i>
Clone Dashboard
</div>
<button class="gf-box-header-close-btn" ng-click="dismiss();">
<i class="fa fa-remove"></i>
</button>
</div>
<div class="gf-box-body">
<div class="text-center">
<h4>New title</h4>
<input type="text" class="input input-fluid" ng-model="clone.title">
<br>
<br>
<button class="btn btn-success" ng-click="saveClone();">Clone</button>
<button class="btn btn-inverse" ng-click="dismiss();">Cancel</button>
</div>
</div>
</div>

View File

@ -45,11 +45,6 @@ function (angular, _, kbn) {
}; };
GrafanaDatasource.prototype.saveDashboard = function(dashboard) { 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 }) return backendSrv.post('/api/dashboards/db/', { dashboard: dashboard })
.then(function(data) { .then(function(data) {
return { title: dashboard.title, url: '/dashboard/db/' + data.slug }; return { title: dashboard.title, url: '/dashboard/db/' + data.slug };

View File

@ -44,6 +44,7 @@
<li><a class="pointer" ng-click="exportDashboard();">Export</a></li> <li><a class="pointer" ng-click="exportDashboard();">Export</a></li>
<li><a class="pointer" ng-click="editJson();">View JSON</a></li> <li><a class="pointer" ng-click="editJson();">View JSON</a></li>
<li><a class="pointer" ng-click="deleteDashboard();">Delete dashboard</a></li> <li><a class="pointer" ng-click="deleteDashboard();">Delete dashboard</a></li>
<li><a class="pointer" ng-click="cloneDashboard();">Clone dashboard</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@ -86,12 +86,6 @@ define(['settings'], function(Settings) {
// Example: "1m", "1h" // Example: "1m", "1h"
playlist_timespan: "1m", 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 - <dashboard title>' // Change window title prefix from 'Grafana - <dashboard title>'
window_title_prefix: 'Grafana - ', window_title_prefix: 'Grafana - ',

View File

@ -1,7 +1,8 @@
input[type=text].input-fluid { input[type=text].input-fluid {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
padding: 14px; padding: 10px;
font-size: 16px;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
height: 100%; height: 100%;
} }

View File

@ -9,7 +9,7 @@
padding: 0; margin: 0; padding: 0; margin: 0;
} }
&:last-child { &:last-child, &.last {
border-bottom: 1px solid @grafanaTargetBorder; border-bottom: 1px solid @grafanaTargetBorder;
} }
} }

View File

@ -20,7 +20,6 @@ define([
describe('shareUrl with current time range and panel', function() { describe('shareUrl with current time range and panel', function() {
it('should generate share url relative time', function() { it('should generate share url relative time', function() {
ctx.$location.path('/test'); ctx.$location.path('/test');
ctx.scope.panel = { id: 22 }; ctx.scope.panel = { id: 22 };