mirror of
https://github.com/grafana/grafana.git
synced 2025-01-18 04:23:33 -06:00
Worked on clone dashboard feature, #1488
This commit is contained in:
parent
5c9ef9d9da
commit
596ce18aeb
@ -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
|
||||
|
@ -27,7 +27,6 @@ function (_, crypto) {
|
||||
playlist_timespan: "1m",
|
||||
unsaved_changes_warning: true,
|
||||
search: { max_results: 100 },
|
||||
admin: {},
|
||||
appSubUrl: ""
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
define([
|
||||
'./dashboardCtrl',
|
||||
'./dashboardNavCtrl',
|
||||
'./cloneDashboardCtrl',
|
||||
'./playlistCtrl',
|
||||
'./rowCtrl',
|
||||
'./sharePanelCtrl',
|
||||
|
33
src/app/features/dashboard/cloneDashboardCtrl.js
Normal file
33
src/app/features/dashboard/cloneDashboardCtrl.js
Normal 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]);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
});
|
@ -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());
|
||||
|
26
src/app/features/dashboard/partials/cloneDashboard.html
Normal file
26
src/app/features/dashboard/partials/cloneDashboard.html
Normal 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>
|
||||
|
@ -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 };
|
||||
|
@ -44,6 +44,7 @@
|
||||
<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="deleteDashboard();">Delete dashboard</a></li>
|
||||
<li><a class="pointer" ng-click="cloneDashboard();">Clone dashboard</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -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 - <dashboard title>'
|
||||
window_title_prefix: 'Grafana - ',
|
||||
|
||||
|
@ -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%;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
padding: 0; margin: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
&:last-child, &.last {
|
||||
border-bottom: 1px solid @grafanaTargetBorder;
|
||||
}
|
||||
}
|
||||
|
@ -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 };
|
||||
|
Loading…
Reference in New Issue
Block a user