diff --git a/public/app/features/dashboard/all.ts b/public/app/features/dashboard/all.ts
index a3535c8fb35..fd79b7b1f03 100644
--- a/public/app/features/dashboard/all.ts
+++ b/public/app/features/dashboard/all.ts
@@ -1,18 +1,18 @@
import './dashboard_ctrl';
import './alerting_srv';
import './history/history';
-import './dashboardLoaderSrv';
+import './dashboard_loader_srv';
import './dashnav/dashnav';
import './submenu/submenu';
import './save_as_modal';
import './save_modal';
import './shareModalCtrl';
-import './shareSnapshotCtrl';
+import './share_snapshot_ctrl';
import './dashboard_srv';
import './view_state_srv';
import './validation_srv';
import './time_srv';
-import './unsavedChangesSrv';
+import './unsaved_changes_srv';
import './unsaved_changes_modal';
import './timepicker/timepicker';
import './upload';
diff --git a/public/app/features/dashboard/dashboardLoaderSrv.js b/public/app/features/dashboard/dashboardLoaderSrv.js
deleted file mode 100644
index d5e257de665..00000000000
--- a/public/app/features/dashboard/dashboardLoaderSrv.js
+++ /dev/null
@@ -1,109 +0,0 @@
-define([
- 'angular',
- 'moment',
- 'lodash',
- 'jquery',
- 'app/core/utils/kbn',
- 'app/core/utils/datemath',
- 'app/core/services/impression_srv'
-],
-function (angular, moment, _, $, kbn, dateMath, impressionSrv) {
- 'use strict';
-
- kbn = kbn.default;
- impressionSrv = impressionSrv.default;
-
- var module = angular.module('grafana.services');
-
- module.service('dashboardLoaderSrv', function(backendSrv,
- dashboardSrv,
- datasourceSrv,
- $http, $q, $timeout,
- contextSrv, $routeParams,
- $rootScope) {
- var self = this;
-
- this._dashboardLoadFailed = function(title, snapshot) {
- snapshot = snapshot || false;
- return {
- meta: { canStar: false, isSnapshot: snapshot, canDelete: false, canSave: false, canEdit: false, dashboardNotFound: true },
- dashboard: {title: title }
- };
- };
-
- this.loadDashboard = function(type, slug) {
- var promise;
-
- if (type === 'script') {
- promise = this._loadScriptedDashboard(slug);
- } else if (type === 'snapshot') {
- promise = backendSrv.get('/api/snapshots/' + $routeParams.slug)
- .catch(function() {
- return self._dashboardLoadFailed("Snapshot not found", true);
- });
- } else {
- promise = backendSrv.getDashboard($routeParams.type, $routeParams.slug)
- .then(function(result) {
- if (result.meta.isFolder) {
- $rootScope.appEvent("alert-error", ['Dashboard not found']);
- throw new Error("Dashboard not found");
- }
- return result;
- })
- .catch(function() {
- return self._dashboardLoadFailed("Not found");
- });
- }
-
- promise.then(function(result) {
-
- if (result.meta.dashboardNotFound !== true) {
- impressionSrv.addDashboardImpression(result.dashboard.id);
- }
-
- return result;
- });
-
- return promise;
- };
-
- this._loadScriptedDashboard = function(file) {
- var url = 'public/dashboards/'+file.replace(/\.(?!js)/,"/") + '?' + new Date().getTime();
-
- return $http({ url: url, method: "GET" })
- .then(this._executeScript).then(function(result) {
- return { meta: { fromScript: true, canDelete: false, canSave: false, canStar: false}, dashboard: result.data };
- }, function(err) {
- console.log('Script dashboard error '+ err);
- $rootScope.appEvent('alert-error', ["Script Error", "Please make sure it exists and returns a valid dashboard"]);
- return self._dashboardLoadFailed('Scripted dashboard');
- });
- };
-
- this._executeScript = function(result) {
- var services = {
- dashboardSrv: dashboardSrv,
- datasourceSrv: datasourceSrv,
- $q: $q,
- };
-
- /*jshint -W054 */
- var script_func = new Function('ARGS','kbn','dateMath','_','moment','window','document','$','jQuery', 'services', result.data);
- var script_result = script_func($routeParams, kbn, dateMath, _ , moment, window, document, $, $, services);
-
- // Handle async dashboard scripts
- if (_.isFunction(script_result)) {
- var deferred = $q.defer();
- script_result(function(dashboard) {
- $timeout(function() {
- deferred.resolve({ data: dashboard });
- });
- });
- return deferred.promise;
- }
-
- return { data: script_result };
- };
-
- });
-});
diff --git a/public/app/features/dashboard/dashboard_loader_srv.ts b/public/app/features/dashboard/dashboard_loader_srv.ts
new file mode 100644
index 00000000000..323b5e39177
--- /dev/null
+++ b/public/app/features/dashboard/dashboard_loader_srv.ts
@@ -0,0 +1,158 @@
+import angular from 'angular';
+import moment from 'moment';
+import _ from 'lodash';
+import $ from 'jquery';
+import kbn from 'app/core/utils/kbn';
+import * as dateMath from 'app/core/utils/datemath';
+import impressionSrv from 'app/core/services/impression_srv';
+
+export class DashboardLoaderSrv {
+ /** @ngInject */
+ constructor(
+ private backendSrv,
+ private dashboardSrv,
+ private datasourceSrv,
+ private $http,
+ private $q,
+ private $timeout,
+ contextSrv,
+ private $routeParams,
+ private $rootScope
+ ) {}
+
+ _dashboardLoadFailed(title, snapshot) {
+ snapshot = snapshot || false;
+ return {
+ meta: {
+ canStar: false,
+ isSnapshot: snapshot,
+ canDelete: false,
+ canSave: false,
+ canEdit: false,
+ dashboardNotFound: true,
+ },
+ dashboard: { title: title },
+ };
+ }
+
+ loadDashboard(type, slug) {
+ var promise;
+
+ if (type === 'script') {
+ promise = this._loadScriptedDashboard(slug);
+ } else if (type === 'snapshot') {
+ promise = this.backendSrv
+ .get('/api/snapshots/' + this.$routeParams.slug)
+ .catch(() => {
+ return this._dashboardLoadFailed('Snapshot not found', true);
+ });
+ } else {
+ promise = this.backendSrv
+ .getDashboard(this.$routeParams.type, this.$routeParams.slug)
+ .then(result => {
+ if (result.meta.isFolder) {
+ this.$rootScope.appEvent('alert-error', ['Dashboard not found']);
+ throw new Error('Dashboard not found');
+ }
+ return result;
+ })
+ .catch(() => {
+ return this._dashboardLoadFailed('Not found', true);
+ });
+ }
+
+ promise.then(function(result) {
+ if (result.meta.dashboardNotFound !== true) {
+ impressionSrv.addDashboardImpression(result.dashboard.id);
+ }
+
+ return result;
+ });
+
+ return promise;
+ }
+
+ _loadScriptedDashboard(file) {
+ var url =
+ 'public/dashboards/' +
+ file.replace(/\.(?!js)/, '/') +
+ '?' +
+ new Date().getTime();
+
+ return this.$http({ url: url, method: 'GET' })
+ .then(this._executeScript)
+ .then(
+ function(result) {
+ return {
+ meta: {
+ fromScript: true,
+ canDelete: false,
+ canSave: false,
+ canStar: false,
+ },
+ dashboard: result.data,
+ };
+ },
+ function(err) {
+ console.log('Script dashboard error ' + err);
+ this.$rootScope.appEvent('alert-error', [
+ 'Script Error',
+ 'Please make sure it exists and returns a valid dashboard',
+ ]);
+ return this._dashboardLoadFailed('Scripted dashboard');
+ }
+ );
+ }
+
+ _executeScript(result) {
+ var services = {
+ dashboardSrv: this.dashboardSrv,
+ datasourceSrv: this.datasourceSrv,
+ $q: this.$q,
+ };
+
+ /*jshint -W054 */
+ var script_func = new Function(
+ 'ARGS',
+ 'kbn',
+ 'dateMath',
+ '_',
+ 'moment',
+ 'window',
+ 'document',
+ '$',
+ 'jQuery',
+ 'services',
+ result.data
+ );
+ var script_result = script_func(
+ this.$routeParams,
+ kbn,
+ dateMath,
+ _,
+ moment,
+ window,
+ document,
+ $,
+ $,
+ services
+ );
+
+ // Handle async dashboard scripts
+ if (_.isFunction(script_result)) {
+ var deferred = this.$q.defer();
+ script_result(dashboard => {
+ this.$timeout(() => {
+ deferred.resolve({ data: dashboard });
+ });
+ });
+ return deferred.promise;
+ }
+
+ return { data: script_result };
+ }
+}
+
+angular
+ .module('grafana.services')
+ .service('dashboardLoaderSrv', DashboardLoaderSrv);
diff --git a/public/app/features/dashboard/shareSnapshotCtrl.js b/public/app/features/dashboard/share_snapshot_ctrl.ts
similarity index 61%
rename from public/app/features/dashboard/shareSnapshotCtrl.js
rename to public/app/features/dashboard/share_snapshot_ctrl.ts
index 617e54db59c..7ab583e815a 100644
--- a/public/app/features/dashboard/shareSnapshotCtrl.js
+++ b/public/app/features/dashboard/share_snapshot_ctrl.ts
@@ -1,14 +1,8 @@
-define([
- 'angular',
- 'lodash',
-],
-function (angular, _) {
- 'use strict';
-
- var module = angular.module('grafana.controllers');
-
- module.controller('ShareSnapshotCtrl', function($scope, $rootScope, $location, backendSrv, $timeout, timeSrv) {
+import angular from 'angular';
+import _ from 'lodash';
+export class ShareSnapshotCtrl {
+ constructor($scope, $rootScope, $location, backendSrv, $timeout, timeSrv) {
$scope.snapshot = {
name: $scope.dashboard.title,
expires: 0,
@@ -18,16 +12,16 @@ function (angular, _) {
$scope.step = 1;
$scope.expireOptions = [
- {text: '1 Hour', value: 60*60},
- {text: '1 Day', value: 60*60*24},
- {text: '7 Days', value: 60*60*24*7},
- {text: 'Never', value: 0},
+ { text: '1 Hour', value: 60 * 60 },
+ { text: '1 Day', value: 60 * 60 * 24 },
+ { text: '7 Days', value: 60 * 60 * 24 * 7 },
+ { text: 'Never', value: 0 },
];
$scope.accessOptions = [
- {text: 'Anyone with the link', value: 1},
- {text: 'Organization users', value: 2},
- {text: 'Public on the web', value: 3},
+ { text: 'Anyone with the link', value: 1 },
+ { text: 'Organization users', value: 2 },
+ { text: 'Public on the web', value: 3 },
];
$scope.init = function() {
@@ -42,7 +36,7 @@ function (angular, _) {
$scope.createSnapshot = function(external) {
$scope.dashboard.snapshot = {
- timestamp: new Date()
+ timestamp: new Date(),
};
if (!external) {
@@ -69,31 +63,37 @@ function (angular, _) {
expires: $scope.snapshot.expires,
};
- var postUrl = external ? $scope.externalUrl + $scope.apiUrl : $scope.apiUrl;
+ var postUrl = external
+ ? $scope.externalUrl + $scope.apiUrl
+ : $scope.apiUrl;
- backendSrv.post(postUrl, cmdData).then(function(results) {
- $scope.loading = false;
+ backendSrv.post(postUrl, cmdData).then(
+ function(results) {
+ $scope.loading = false;
- if (external) {
- $scope.deleteUrl = results.deleteUrl;
- $scope.snapshotUrl = results.url;
- $scope.saveExternalSnapshotRef(cmdData, results);
- } else {
- var url = $location.url();
- var baseUrl = $location.absUrl();
+ if (external) {
+ $scope.deleteUrl = results.deleteUrl;
+ $scope.snapshotUrl = results.url;
+ $scope.saveExternalSnapshotRef(cmdData, results);
+ } else {
+ var url = $location.url();
+ var baseUrl = $location.absUrl();
- if (url !== '/') {
- baseUrl = baseUrl.replace(url, '') + '/';
+ if (url !== '/') {
+ baseUrl = baseUrl.replace(url, '') + '/';
+ }
+
+ $scope.snapshotUrl = baseUrl + 'dashboard/snapshot/' + results.key;
+ $scope.deleteUrl =
+ baseUrl + 'api/snapshots-delete/' + results.deleteKey;
}
- $scope.snapshotUrl = baseUrl + 'dashboard/snapshot/' + results.key;
- $scope.deleteUrl = baseUrl + 'api/snapshots-delete/' + results.deleteKey;
+ $scope.step = 2;
+ },
+ function() {
+ $scope.loading = false;
}
-
- $scope.step = 2;
- }, function() {
- $scope.loading = false;
- });
+ );
};
$scope.getSnapshotUrl = function() {
@@ -116,21 +116,22 @@ function (angular, _) {
// remove annotation queries
dash.annotations.list = _.chain(dash.annotations.list)
- .filter(function(annotation) {
- return annotation.enable;
- })
- .map(function(annotation) {
- return {
- name: annotation.name,
- enable: annotation.enable,
- iconColor: annotation.iconColor,
- snapshotData: annotation.snapshotData
- };
- }).value();
+ .filter(function(annotation) {
+ return annotation.enable;
+ })
+ .map(function(annotation) {
+ return {
+ name: annotation.name,
+ enable: annotation.enable,
+ iconColor: annotation.iconColor,
+ snapshotData: annotation.snapshotData,
+ };
+ })
+ .value();
// remove template queries
_.each(dash.templating.list, function(variable) {
- variable.query = "";
+ variable.query = '';
variable.options = variable.current;
variable.refresh = false;
});
@@ -168,7 +169,9 @@ function (angular, _) {
cmdData.deleteKey = results.deleteKey;
backendSrv.post('/api/snapshots/', cmdData);
};
+ }
+}
- });
-
-});
+angular
+ .module('grafana.controllers')
+ .controller('ShareSnapshotCtrl', ShareSnapshotCtrl);
diff --git a/public/app/features/dashboard/specs/unsaved_changes_srv_specs.ts b/public/app/features/dashboard/specs/unsaved_changes_srv_specs.ts
index 79a0a237ca1..b510f76f114 100644
--- a/public/app/features/dashboard/specs/unsaved_changes_srv_specs.ts
+++ b/public/app/features/dashboard/specs/unsaved_changes_srv_specs.ts
@@ -6,14 +6,17 @@ import {
sinon,
angularMocks,
} from 'test/lib/common';
-import 'app/features/dashboard/unsavedChangesSrv';
+import { Tracker } from 'app/features/dashboard/unsaved_changes_srv';
import 'app/features/dashboard/dashboard_srv';
+import { contextSrv } from 'app/core/core';
describe('unsavedChangesSrv', function() {
- var _unsavedChangesSrv;
var _dashboardSrv;
var _contextSrvStub = { isEditor: true };
var _rootScope;
+ var _location;
+ var _timeout;
+ var _window;
var tracker;
var dash;
var scope;
@@ -32,11 +35,15 @@ describe('unsavedChangesSrv', function() {
unsavedChangesSrv,
$location,
$rootScope,
- dashboardSrv
+ dashboardSrv,
+ $timeout,
+ $window
) {
- _unsavedChangesSrv = unsavedChangesSrv;
_dashboardSrv = dashboardSrv;
_rootScope = $rootScope;
+ _location = $location;
+ _timeout = $timeout;
+ _window = $window;
})
);
@@ -54,7 +61,16 @@ describe('unsavedChangesSrv', function() {
scope.appEvent = sinon.spy();
scope.onAppEvent = sinon.spy();
- tracker = new _unsavedChangesSrv.Tracker(dash, scope);
+ tracker = new Tracker(
+ dash,
+ scope,
+ undefined,
+ _location,
+ _window,
+ _timeout,
+ contextSrv,
+ _rootScope
+ );
});
it('No changes should not have changes', function() {
diff --git a/public/app/features/dashboard/unsavedChangesSrv.js b/public/app/features/dashboard/unsavedChangesSrv.js
deleted file mode 100644
index 7ffdb36952e..00000000000
--- a/public/app/features/dashboard/unsavedChangesSrv.js
+++ /dev/null
@@ -1,189 +0,0 @@
-define([
- 'angular',
- 'lodash',
-],
-function(angular, _) {
- 'use strict';
-
- var module = angular.module('grafana.services');
-
- module.service('unsavedChangesSrv', function($rootScope, $q, $location, $timeout, contextSrv, dashboardSrv, $window) {
-
- function Tracker(dashboard, scope, originalCopyDelay) {
- var self = this;
-
- this.current = dashboard;
- this.originalPath = $location.path();
- this.scope = scope;
-
- // register events
- scope.onAppEvent('dashboard-saved', function() {
- this.original = this.current.getSaveModelClone();
- this.originalPath = $location.path();
- }.bind(this));
-
- $window.onbeforeunload = function() {
- if (self.ignoreChanges()) { return; }
- if (self.hasChanges()) {
- return "There are unsaved changes to this dashboard";
- }
- };
-
- scope.$on("$locationChangeStart", function(event, next) {
- // check if we should look for changes
- if (self.originalPath === $location.path()) { return true; }
- if (self.ignoreChanges()) { return true; }
-
- if (self.hasChanges()) {
- event.preventDefault();
- self.next = next;
-
- $timeout(function() {
- self.open_modal();
- });
- }
- });
-
- if (originalCopyDelay) {
- $timeout(function() {
- // wait for different services to patch the dashboard (missing properties)
- self.original = dashboard.getSaveModelClone();
- }, originalCopyDelay);
- } else {
- self.original = dashboard.getSaveModelClone();
- }
- }
-
- var p = Tracker.prototype;
-
- // for some dashboards and users
- // changes should be ignored
- p.ignoreChanges = function() {
- if (!this.original) { return true; }
- if (!contextSrv.isEditor) { return true; }
- if (!this.current || !this.current.meta) { return true; }
-
- var meta = this.current.meta;
- return !meta.canSave || meta.fromScript || meta.fromFile;
- };
-
- // remove stuff that should not count in diff
- p.cleanDashboardFromIgnoredChanges = function(dash) {
- // ignore time and refresh
- dash.time = 0;
- dash.refresh = 0;
- dash.schemaVersion = 0;
-
- // filter row and panels properties that should be ignored
- dash.rows = _.filter(dash.rows, function(row) {
- if (row.repeatRowId) {
- return false;
- }
-
- row.panels = _.filter(row.panels, function(panel) {
- if (panel.repeatPanelId) {
- return false;
- }
-
- // remove scopedVars
- panel.scopedVars = null;
-
- // ignore span changes
- panel.span = null;
-
- // ignore panel legend sort
- if (panel.legend) {
- delete panel.legend.sort;
- delete panel.legend.sortDesc;
- }
-
- return true;
- });
-
- // ignore collapse state
- row.collapse = false;
- return true;
- });
-
- dash.panels = _.filter(dash.panels, function(panel) {
- if (panel.repeatPanelId) {
- return false;
- }
-
- // remove scopedVars
- panel.scopedVars = null;
-
- // ignore panel legend sort
- if (panel.legend) {
- delete panel.legend.sort;
- delete panel.legend.sortDesc;
- }
-
- return true;
- });
-
- // ignore template variable values
- _.each(dash.templating.list, function(value) {
- value.current = null;
- value.options = null;
- value.filters = null;
- });
- };
-
- p.hasChanges = function() {
- var current = this.current.getSaveModelClone();
- var original = this.original;
-
- this.cleanDashboardFromIgnoredChanges(current);
- this.cleanDashboardFromIgnoredChanges(original);
-
- var currentTimepicker = _.find(current.nav, { type: 'timepicker' });
- var originalTimepicker = _.find(original.nav, { type: 'timepicker' });
-
- if (currentTimepicker && originalTimepicker) {
- currentTimepicker.now = originalTimepicker.now;
- }
-
- var currentJson = angular.toJson(current);
- var originalJson = angular.toJson(original);
-
- return currentJson !== originalJson;
- };
-
- p.discardChanges = function() {
- this.original = null;
- this.gotoNext();
- };
-
- p.open_modal = function() {
- $rootScope.appEvent('show-modal', {
- templateHtml: '',
- modalClass: 'modal--narrow confirm-modal'
- });
- };
-
- p.saveChanges = function() {
- var self = this;
- var cancel = $rootScope.$on('dashboard-saved', function() {
- cancel();
- $timeout(function() {
- self.gotoNext();
- });
- });
-
- $rootScope.appEvent('save-dashboard');
- };
-
- p.gotoNext = function() {
- var baseLen = $location.absUrl().length - $location.url().length;
- var nextUrl = this.next.substring(baseLen);
- $location.url(nextUrl);
- };
-
- this.Tracker = Tracker;
- this.init = function(dashboard, scope) {
- this.tracker = new Tracker(dashboard, scope, 1000);
- return this.tracker;
- };
- });
-});
diff --git a/public/app/features/dashboard/unsaved_changes_srv.ts b/public/app/features/dashboard/unsaved_changes_srv.ts
new file mode 100644
index 00000000000..e02466a91e0
--- /dev/null
+++ b/public/app/features/dashboard/unsaved_changes_srv.ts
@@ -0,0 +1,236 @@
+import angular from 'angular';
+import _ from 'lodash';
+
+export class Tracker {
+ current: any;
+ originalPath: any;
+ scope: any;
+ original: any;
+ next: any;
+ $window: any;
+
+ /** @ngInject */
+ constructor(
+ dashboard,
+ scope,
+ originalCopyDelay,
+ private $location,
+ $window,
+ private $timeout,
+ private contextSrv,
+ private $rootScope
+ ) {
+ this.$location = $location;
+ this.$window = $window;
+
+ this.current = dashboard;
+ this.originalPath = $location.path();
+ this.scope = scope;
+
+ // register events
+ scope.onAppEvent('dashboard-saved', () => {
+ this.original = this.current.getSaveModelClone();
+ this.originalPath = $location.path();
+ });
+
+ $window.onbeforeunload = () => {
+ if (this.ignoreChanges()) {
+ return '';
+ }
+ if (this.hasChanges()) {
+ return 'There are unsaved changes to this dashboard';
+ }
+ return '';
+ };
+
+ scope.$on('$locationChangeStart', (event, next) => {
+ // check if we should look for changes
+ if (this.originalPath === $location.path()) {
+ return true;
+ }
+ if (this.ignoreChanges()) {
+ return true;
+ }
+
+ if (this.hasChanges()) {
+ event.preventDefault();
+ this.next = next;
+
+ this.$timeout(() => {
+ this.open_modal();
+ });
+ }
+ return false;
+ });
+
+ if (originalCopyDelay) {
+ this.$timeout(() => {
+ // wait for different services to patch the dashboard (missing properties)
+ this.original = dashboard.getSaveModelClone();
+ }, originalCopyDelay);
+ } else {
+ this.original = dashboard.getSaveModelClone();
+ }
+ }
+
+ // for some dashboards and users
+ // changes should be ignored
+ ignoreChanges() {
+ if (!this.original) {
+ return true;
+ }
+ if (!this.contextSrv.isEditor) {
+ return true;
+ }
+ if (!this.current || !this.current.meta) {
+ return true;
+ }
+
+ var meta = this.current.meta;
+ return !meta.canSave || meta.fromScript || meta.fromFile;
+ }
+
+ // remove stuff that should not count in diff
+ cleanDashboardFromIgnoredChanges(dash) {
+ // ignore time and refresh
+ dash.time = 0;
+ dash.refresh = 0;
+ dash.schemaVersion = 0;
+
+ // filter row and panels properties that should be ignored
+ dash.rows = _.filter(dash.rows, function(row) {
+ if (row.repeatRowId) {
+ return false;
+ }
+
+ row.panels = _.filter(row.panels, function(panel) {
+ if (panel.repeatPanelId) {
+ return false;
+ }
+
+ // remove scopedVars
+ panel.scopedVars = null;
+
+ // ignore span changes
+ panel.span = null;
+
+ // ignore panel legend sort
+ if (panel.legend) {
+ delete panel.legend.sort;
+ delete panel.legend.sortDesc;
+ }
+
+ return true;
+ });
+
+ // ignore collapse state
+ row.collapse = false;
+ return true;
+ });
+
+ dash.panels = _.filter(dash.panels, panel => {
+ if (panel.repeatPanelId) {
+ return false;
+ }
+
+ // remove scopedVars
+ panel.scopedVars = null;
+
+ // ignore panel legend sort
+ if (panel.legend) {
+ delete panel.legend.sort;
+ delete panel.legend.sortDesc;
+ }
+
+ return true;
+ });
+
+ // ignore template variable values
+ _.each(dash.templating.list, function(value) {
+ value.current = null;
+ value.options = null;
+ value.filters = null;
+ });
+ }
+
+ hasChanges() {
+ var current = this.current.getSaveModelClone();
+ var original = this.original;
+
+ this.cleanDashboardFromIgnoredChanges(current);
+ this.cleanDashboardFromIgnoredChanges(original);
+
+ var currentTimepicker = _.find(current.nav, { type: 'timepicker' });
+ var originalTimepicker = _.find(original.nav, { type: 'timepicker' });
+
+ if (currentTimepicker && originalTimepicker) {
+ currentTimepicker.now = originalTimepicker.now;
+ }
+
+ var currentJson = angular.toJson(current);
+ var originalJson = angular.toJson(original);
+
+ return currentJson !== originalJson;
+ }
+
+ discardChanges() {
+ this.original = null;
+ this.gotoNext();
+ }
+
+ open_modal() {
+ this.$rootScope.appEvent('show-modal', {
+ templateHtml:
+ '',
+ modalClass: 'modal--narrow confirm-modal',
+ });
+ }
+
+ saveChanges() {
+ var self = this;
+ var cancel = this.$rootScope.$on('dashboard-saved', () => {
+ cancel();
+ this.$timeout(() => {
+ self.gotoNext();
+ });
+ });
+
+ this.$rootScope.appEvent('save-dashboard');
+ }
+
+ gotoNext() {
+ var baseLen = this.$location.absUrl().length - this.$location.url().length;
+ var nextUrl = this.next.substring(baseLen);
+ this.$location.url(nextUrl);
+ }
+}
+
+/** @ngInject */
+export function unsavedChangesSrv(
+ $rootScope,
+ $q,
+ $location,
+ $timeout,
+ contextSrv,
+ dashboardSrv,
+ $window
+) {
+ this.Tracker = Tracker;
+ this.init = function(dashboard, scope) {
+ this.tracker = new Tracker(
+ dashboard,
+ scope,
+ 1000,
+ $location,
+ $window,
+ $timeout,
+ contextSrv,
+ $rootScope
+ );
+ return this.tracker;
+ };
+}
+
+angular
+ .module('grafana.services')
+ .service('unsavedChangesSrv', unsavedChangesSrv);