mirror of
https://github.com/grafana/grafana.git
synced 2025-01-18 12:33:37 -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 #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
|
||||||
|
@ -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: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
define([
|
define([
|
||||||
'./dashboardCtrl',
|
'./dashboardCtrl',
|
||||||
'./dashboardNavCtrl',
|
'./dashboardNavCtrl',
|
||||||
|
'./cloneDashboardCtrl',
|
||||||
'./playlistCtrl',
|
'./playlistCtrl',
|
||||||
'./rowCtrl',
|
'./rowCtrl',
|
||||||
'./sharePanelCtrl',
|
'./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;
|
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());
|
||||||
|
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) {
|
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 };
|
||||||
|
@ -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>
|
||||||
|
@ -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 - ',
|
||||||
|
|
||||||
|
@ -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%;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 };
|
||||||
|
Loading…
Reference in New Issue
Block a user