Commit 035b5163 by Torkel Ödegaard

Merge branch 'unsaved_changes_warning' (Closes #324)

parents 9e4656e4 a1d5e26f
...@@ -5,6 +5,8 @@ ...@@ -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) { ...@@ -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, _) { ...@@ -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) { ...@@ -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) {
......
<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>
\ No newline at end of file
...@@ -8,5 +8,6 @@ define([ ...@@ -8,5 +8,6 @@ define([
'./keyboardManager', './keyboardManager',
'./annotationsSrv', './annotationsSrv',
'./playlistSrv', './playlistSrv',
'./unsavedChangesSrv',
], ],
function () {}); function () {});
\ No newline at end of file
...@@ -63,6 +63,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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
......
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();
});
});
\ No newline at end of file
...@@ -57,8 +57,17 @@ function (Settings) { ...@@ -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'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment