mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 23:55:47 -06:00
Merge branch 'unsaved_changes_warning' (Closes #324)
This commit is contained in:
commit
035b5163fb
@ -5,6 +5,8 @@
|
|||||||
- Increased resolution for graphite datapoints (maxDataPoints), now equal to panel pixel width. (Closes #5)
|
- Increased resolution for graphite datapoints (maxDataPoints), now equal to panel pixel width. (Closes #5)
|
||||||
- Improvement to influxdb query editor, can now add where clause and alias (Issue #331, thanks @mavimo)
|
- Improvement to influxdb query editor, can now add where clause and alias (Issue #331, thanks @mavimo)
|
||||||
- New config setting for graphite datasource to control if json render request is POST or GET (Issue #345)
|
- New config setting for graphite datasource to control if json render request is POST or GET (Issue #345)
|
||||||
|
- Unsaved changes warning feature (Issue #324)
|
||||||
|
|
||||||
|
|
||||||
# 1.5.3 (2014-04-17)
|
# 1.5.3 (2014-04-17)
|
||||||
- Add support for async scripted dashboards (Issue #274)
|
- Add support for async scripted dashboards (Issue #274)
|
||||||
|
@ -25,6 +25,7 @@ function (_, crypto) {
|
|||||||
grafana_index : 'grafana-dash',
|
grafana_index : 'grafana-dash',
|
||||||
elasticsearch_all_disabled : false,
|
elasticsearch_all_disabled : false,
|
||||||
timezoneOffset : null,
|
timezoneOffset : null,
|
||||||
|
unsaved_changes_warning : true
|
||||||
};
|
};
|
||||||
|
|
||||||
// This initializes a new hash on purpose, to avoid adding parameters to
|
// This initializes a new hash on purpose, to avoid adding parameters to
|
||||||
|
@ -30,7 +30,8 @@ function (angular, $, config, _) {
|
|||||||
var module = angular.module('kibana.controllers');
|
var module = angular.module('kibana.controllers');
|
||||||
|
|
||||||
module.controller('DashCtrl', function(
|
module.controller('DashCtrl', function(
|
||||||
$scope, $rootScope, $route, ejsResource, dashboard, alertSrv, panelMove, keyboardManager, grafanaVersion) {
|
$scope, $rootScope, ejsResource, dashboard,
|
||||||
|
alertSrv, panelMove, keyboardManager, grafanaVersion) {
|
||||||
|
|
||||||
$scope.requiredElasticSearchVersion = ">=0.90.3";
|
$scope.requiredElasticSearchVersion = ">=0.90.3";
|
||||||
|
|
||||||
|
@ -65,23 +65,20 @@ function (angular, _, moment) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.elasticsearch_save = function(type,ttl) {
|
$scope.elasticsearch_save = function(type,ttl) {
|
||||||
dashboard.elasticsearch_save(
|
dashboard.elasticsearch_save(type, dashboard.current.title, ttl)
|
||||||
type,
|
.then(function(result) {
|
||||||
($scope.elasticsearch.title || dashboard.current.title),
|
if(_.isUndefined(result._id)) {
|
||||||
($scope.loader.save_temp_ttl_enable ? ttl : false)
|
alertSrv.set('Save failed','Dashboard could not be saved to Elasticsearch','error',5000);
|
||||||
).then(function(result) {
|
return;
|
||||||
if(_.isUndefined(result._id)) {
|
}
|
||||||
alertSrv.set('Save failed','Dashboard could not be saved to Elasticsearch','error',5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
alertSrv.set('Dashboard Saved', 'This dashboard has been saved to Elasticsearch as "' + result._id + '"','success', 5000);
|
alertSrv.set('Dashboard Saved', 'Dashboard has been saved to Elasticsearch as "' + result._id + '"','success', 5000);
|
||||||
if(type === 'temp') {
|
if(type === 'temp') {
|
||||||
$scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id);
|
$scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rootScope.$emit('dashboard-saved');
|
$rootScope.$emit('dashboard-saved');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.elasticsearch_delete = function(id) {
|
$scope.elasticsearch_delete = function(id) {
|
||||||
|
16
src/app/partials/unsaved-changes.html
Normal file
16
src/app/partials/unsaved-changes.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<div class="modal-header">
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<h3 class="text-center"><i class="icon-warning-sign"></i> Unsaved changes</h3>
|
||||||
|
<div class="row-fluid">
|
||||||
|
<span class="span3"></span>
|
||||||
|
<button type="button" class="btn btn-success span2" ng-click="dismiss()">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-success span2" ng-click="save();dismiss();">Save</button>
|
||||||
|
<button type="button" class="btn btn-warning span2" ng-click="ignore();dismiss();">Ignore</button>
|
||||||
|
<span class="span3"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
@ -8,5 +8,6 @@ define([
|
|||||||
'./keyboardManager',
|
'./keyboardManager',
|
||||||
'./annotationsSrv',
|
'./annotationsSrv',
|
||||||
'./playlistSrv',
|
'./playlistSrv',
|
||||||
|
'./unsavedChangesSrv',
|
||||||
],
|
],
|
||||||
function () {});
|
function () {});
|
@ -63,6 +63,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
$rootScope.$on('$routeChangeSuccess',function(){
|
$rootScope.$on('$routeChangeSuccess',function(){
|
||||||
// Clear the current dashboard to prevent reloading
|
// Clear the current dashboard to prevent reloading
|
||||||
self.current = {};
|
self.current = {};
|
||||||
|
self.original = null;
|
||||||
self.indices = [];
|
self.indices = [];
|
||||||
route();
|
route();
|
||||||
});
|
});
|
||||||
@ -157,16 +158,8 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
// Set the current dashboard
|
// Set the current dashboard
|
||||||
self.current = angular.copy(dashboard);
|
self.current = angular.copy(dashboard);
|
||||||
|
|
||||||
// Delay this until we're sure that querySrv and filterSrv are ready
|
filterSrv = $injector.get('filterSrv');
|
||||||
$timeout(function() {
|
filterSrv.init();
|
||||||
// Ok, now that we've setup the current dashboard, we can inject our services
|
|
||||||
filterSrv = $injector.get('filterSrv');
|
|
||||||
filterSrv.init();
|
|
||||||
|
|
||||||
},0).then(function() {
|
|
||||||
// Call refresh to calculate the indices and notify the panels that we're ready to roll
|
|
||||||
self.refresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
if(dashboard.refresh) {
|
if(dashboard.refresh) {
|
||||||
self.set_interval(dashboard.refresh);
|
self.set_interval(dashboard.refresh);
|
||||||
@ -181,6 +174,10 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
|
|
||||||
$rootScope.$emit('dashboard-loaded');
|
$rootScope.$emit('dashboard-loaded');
|
||||||
|
|
||||||
|
$timeout(function() {
|
||||||
|
self.original = angular.copy(self.current);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -393,6 +390,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
|
|||||||
if(type === 'dashboard') {
|
if(type === 'dashboard') {
|
||||||
$location.path('/dashboard/elasticsearch/'+title);
|
$location.path('/dashboard/elasticsearch/'+title);
|
||||||
}
|
}
|
||||||
|
self.original = angular.copy(self.current);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
// Failure
|
// Failure
|
||||||
|
102
src/app/services/unsavedChangesSrv.js
Normal file
102
src/app/services/unsavedChangesSrv.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'underscore',
|
||||||
|
'config',
|
||||||
|
],
|
||||||
|
function (angular, _, config) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!config.unsaved_changes_warning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var module = angular.module('kibana.services');
|
||||||
|
|
||||||
|
module.service('unsavedChangesSrv', function($rootScope, $modal, dashboard, $q, $location, $timeout) {
|
||||||
|
var self = this;
|
||||||
|
var modalScope = $rootScope.$new();
|
||||||
|
|
||||||
|
window.onbeforeunload = function () {
|
||||||
|
if (self.has_unsaved_changes()) {
|
||||||
|
return "There are unsaved changes to this dashboard";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init = function() {
|
||||||
|
$rootScope.$on("$locationChangeStart", function(event, next) {
|
||||||
|
if (self.has_unsaved_changes()) {
|
||||||
|
event.preventDefault();
|
||||||
|
self.next = next;
|
||||||
|
self.open_modal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.open_modal = function () {
|
||||||
|
var confirmModal = $modal({
|
||||||
|
template: './app/partials/unsaved-changes.html',
|
||||||
|
persist: true,
|
||||||
|
show: false,
|
||||||
|
scope: modalScope,
|
||||||
|
keyboard: false
|
||||||
|
});
|
||||||
|
|
||||||
|
$q.when(confirmModal).then(function(modalEl) {
|
||||||
|
modalEl.modal('show');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.has_unsaved_changes = function () {
|
||||||
|
if (!dashboard.original) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var current = angular.copy(dashboard.current);
|
||||||
|
var original = dashboard.original;
|
||||||
|
|
||||||
|
// ignore timespan changes
|
||||||
|
current.services.filter.time = original.services.filter.time = {};
|
||||||
|
current.refresh = original.refresh;
|
||||||
|
|
||||||
|
var currentTimepicker = _.findWhere(current.nav, { type: 'timepicker' });
|
||||||
|
var originalTimepicker = _.findWhere(original.nav, { type: 'timepicker' });
|
||||||
|
|
||||||
|
if (currentTimepicker && originalTimepicker) {
|
||||||
|
currentTimepicker.now = originalTimepicker.now;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentJson = angular.toJson(current);
|
||||||
|
var originalJson = angular.toJson(original);
|
||||||
|
|
||||||
|
if (currentJson !== originalJson) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.goto_next = function () {
|
||||||
|
var baseLen = $location.absUrl().length - $location.url().length;
|
||||||
|
var nextUrl = self.next.substring(baseLen);
|
||||||
|
$location.url(nextUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
modalScope.ignore = function() {
|
||||||
|
dashboard.original = null;
|
||||||
|
self.goto_next();
|
||||||
|
};
|
||||||
|
|
||||||
|
modalScope.save = function() {
|
||||||
|
var unregister = $rootScope.$on('dashboard-saved', function() {
|
||||||
|
self.goto_next();
|
||||||
|
});
|
||||||
|
|
||||||
|
$timeout(unregister, 2000);
|
||||||
|
|
||||||
|
$rootScope.$emit('save-dashboard');
|
||||||
|
};
|
||||||
|
|
||||||
|
}).run(function(unsavedChangesSrv) {
|
||||||
|
unsavedChangesSrv.init();
|
||||||
|
});
|
||||||
|
});
|
@ -57,8 +57,17 @@ function (Settings) {
|
|||||||
|
|
||||||
timezoneOffset: null,
|
timezoneOffset: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elasticsearch index for storing dashboards
|
||||||
|
*
|
||||||
|
*/
|
||||||
grafana_index: "grafana-dash",
|
grafana_index: "grafana-dash",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to false to disable unsaved changes warning
|
||||||
|
*/
|
||||||
|
unsaved_changes_warning: true,
|
||||||
|
|
||||||
panel_names: [
|
panel_names: [
|
||||||
'text',
|
'text',
|
||||||
'graphite'
|
'graphite'
|
||||||
|
Loading…
Reference in New Issue
Block a user