Ver código fonte

A lot of refactoring opf unsaved changes service so it can be unit tested better

Torkel Ödegaard 10 anos atrás
pai
commit
aaea80e053

+ 47 - 0
'

@@ -0,0 +1,47 @@
+define([
+  'features/dashboard/unsavedChangesSrv',
+  'features/dashboard/dashboardSrv'
+], function() {
+  'use strict';
+
+  describe("unsavedChangesSrv", function() {
+    var _unsavedChangesSrv;
+    var _dashboardSrv;
+    var _location;
+    var _contextSrvStub = {
+      isEditor: true
+    };
+    var _rootScope;
+    var tracker;
+
+    beforeEach(module('grafana.services'));
+    beforeEach(module(function($provide) {
+      $provide.value('contextSrv', _contextSrvStub);
+    }));
+
+    beforeEach(inject(function(unsavedChangesSrv, $location, $rootScope, dashboardSrv) {
+      _unsavedChangesSrv = unsavedChangesSrv;
+      _dashboardSrv = dashboardSrv;
+      _location = $location;
+      _rootScope = $rootScope;
+    }));
+
+    describe('when dashboard is modified and route changes', function() {
+
+      beforeEach(function() {
+        var dash = _dashboardSrv.create({});
+        var scope = _rootScope.$new();
+        scope.appEvent = sinon.spy();
+        scope.onAppEvent = sinon.spy();
+        tracker = _unsavedChangesSrv.constructor(dash, scope);
+      });
+
+      it('No changes should not have changes', function() {
+        expect(tracker.hasChanges()).to.be(false);
+      });
+
+    });
+
+  });
+
+});

+ 2 - 0
public/app/features/dashboard/dashboardCtrl.js

@@ -17,6 +17,7 @@ function (angular, $, config) {
       templateValuesSrv,
       templateValuesSrv,
       dynamicDashboardSrv,
       dynamicDashboardSrv,
       dashboardSrv,
       dashboardSrv,
+      unsavedChangesSrv,
       dashboardViewStateSrv,
       dashboardViewStateSrv,
       contextSrv,
       contextSrv,
       $timeout) {
       $timeout) {
@@ -48,6 +49,7 @@ function (angular, $, config) {
       // the rest of the dashboard can load
       // the rest of the dashboard can load
       templateValuesSrv.init(dashboard).finally(function() {
       templateValuesSrv.init(dashboard).finally(function() {
         dynamicDashboardSrv.init(dashboard);
         dynamicDashboardSrv.init(dashboard);
+        unsavedChangesSrv.init(dashboard, $scope);
 
 
         $scope.dashboard = dashboard;
         $scope.dashboard = dashboard;
         $scope.dashboardMeta = dashboard.meta;
         $scope.dashboardMeta = dashboard.meta;

+ 73 - 84
public/app/features/dashboard/unsavedChangesSrv.js

@@ -1,90 +1,68 @@
 define([
 define([
   'angular',
   'angular',
   'lodash',
   'lodash',
-  'config',
 ],
 ],
-function(angular, _, config) {
+function(angular, _) {
   'use strict';
   'use strict';
 
 
-  if (!config.unsaved_changes_warning) {
-    return;
-  }
-
   var module = angular.module('grafana.services');
   var module = angular.module('grafana.services');
 
 
-  module.service('unsavedChangesSrv', function($rootScope, $modal, $q, $location, $timeout, contextSrv) {
+  module.service('unsavedChangesSrv', function($modal, $q, $location, $timeout, contextSrv, $window) {
 
 
-    var self = this;
-    var modalScope = $rootScope.$new();
+    function Tracker(dashboard, scope) {
+      var self = this;
 
 
-    $rootScope.$on("dashboard-loaded", function(event, newDashboard) {
-      // wait for different services to patch the dashboard (missing properties)
-      $timeout(function() {
-        self.original = newDashboard.getSaveModelClone();
-        self.current = newDashboard;
-      }, 1200);
-    });
-
-    $rootScope.$on("dashboard-saved", function(event, savedDashboard) {
-      self.original = savedDashboard.getSaveModelClone();
-      self.current = savedDashboard;
-      self.orignalPath = $location.path();
-    });
-
-    $rootScope.$on("$routeChangeSuccess", function() {
-      self.original = null;
-      self.originalPath = $location.path();
-    });
-
-    this.ignoreChanges = function() {
-      if (!contextSrv.isEditor) { return true; }
-      if (!self.current || !self.current.meta) { return true; }
+      this.original = dashboard.getSaveModelClone();
+      this.current = dashboard;
+      this.originalPath = $location.path();
+      this.scope = scope;
 
 
-      var meta = self.current.meta;
-      return !meta.canSave || meta.fromScript || meta.fromFile;
-    };
+      // register events
+      scope.onAppEvent('dashboard-saved', function() {
+        self.original = self.current.getSaveModelClone();
+        self.originalPath = $location.path();
+      });
 
 
-    window.onbeforeunload = function() {
-      if (self.ignoreChanges()) { return; }
-      if (self.has_unsaved_changes()) {
-        return "There are unsaved changes to this dashboard";
-      }
-    };
+      $window.onbeforeunload = function() {
+        if (self.ignoreChanges()) { return; }
+        if (self.hasChanges()) {
+          return "There are unsaved changes to this dashboard";
+        }
+      };
 
 
-    this.init = function() {
-      $rootScope.$on("$locationChangeStart", function(event, next) {
+      scope.$on("$locationChangeStart", function(event, next) {
         // check if we should look for changes
         // check if we should look for changes
         if (self.originalPath === $location.path()) { return true; }
         if (self.originalPath === $location.path()) { return true; }
         if (self.ignoreChanges()) { return true; }
         if (self.ignoreChanges()) { return true; }
 
 
-        if (self.has_unsaved_changes()) {
+        if (self.hasChanges()) {
           event.preventDefault();
           event.preventDefault();
           self.next = next;
           self.next = next;
 
 
-          $timeout(self.open_modal);
+          $timeout(function() {
+            self.open_modal();
+          });
         }
         }
       });
       });
-    };
+    }
 
 
-    this.open_modal = function() {
-      var confirmModal = $modal({
-        template: './app/partials/unsaved-changes.html',
-        modalClass: 'confirm-modal',
-        persist: true,
-        show: false,
-        scope: modalScope,
-        keyboard: false
-      });
+    var p = Tracker.prototype;
 
 
-      $q.when(confirmModal).then(function(modalEl) {
-        modalEl.modal('show');
-      });
+    // for some dashboards and users
+    // changes should be ignored
+    p.ignoreChanges = function() {
+      if (!this.original) { return false; }
+      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;
     };
     };
 
 
-    this.cleanDashboardFromRepeatedPanelsAndRows = function(dash) {
+    // remove stuff that should not count in diff
+    p.cleanDashboardFromIgnoredChanges = function(dash) {
       dash.rows = _.filter(dash.rows, function(row) {
       dash.rows = _.filter(dash.rows, function(row) {
         if (row.repeatRowId) {
         if (row.repeatRowId) {
-          console.log('filtering out row');
           return false;
           return false;
         }
         }
 
 
@@ -101,13 +79,9 @@ function(angular, _, config) {
       });
       });
     };
     };
 
 
-    this.has_unsaved_changes = function() {
-      if (!self.original) {
-        return false;
-      }
-
-      var current = self.current.getSaveModelClone();
-      var original = self.original;
+    p.hasChanges = function() {
+      var current = this.current.getSaveModelClone();
+      var original = this.original;
 
 
       // ignore timespan changes
       // ignore timespan changes
       current.time = original.time = {};
       current.time = original.time = {};
@@ -126,8 +100,8 @@ function(angular, _, config) {
         }
         }
       });
       });
 
 
-      this.cleanDashboardFromRepeatedPanelsAndRows(current);
-      this.cleanDashboardFromRepeatedPanelsAndRows(original);
+      this.cleanDashboardFromIgnoredChanges(current);
+      this.cleanDashboardFromIgnoredChanges(original);
 
 
       // ignore some panel and row stuff
       // ignore some panel and row stuff
       current.forEachPanel(function(panel, panelIndex, row, rowIndex) {
       current.forEachPanel(function(panel, panelIndex, row, rowIndex) {
@@ -165,28 +139,43 @@ function(angular, _, config) {
       return false;
       return false;
     };
     };
 
 
-    this.goto_next = function() {
-      var baseLen = $location.absUrl().length - $location.url().length;
-      var nextUrl = self.next.substring(baseLen);
-      $location.url(nextUrl);
-    };
+    p.open_modal = function() {
+      var tracker = this;
 
 
-    modalScope.ignore = function() {
-      self.original = null;
-      self.goto_next();
-    };
+      var modalScope = this.scope.$new();
+      modalScope.ignore = function() {
+        tracker.original = null;
+        tracker.goto_next();
+      };
+
+      modalScope.save = function() {
+        tracker.scope.$emit('save-dashboard');
+      };
 
 
-    modalScope.save = function() {
-      var unregister = $rootScope.$on('dashboard-saved', function() {
-        self.goto_next();
+      var confirmModal = $modal({
+        template: './app/partials/unsaved-changes.html',
+        modalClass: 'confirm-modal',
+        persist: false,
+        show: false,
+        scope: modalScope,
+        keyboard: false
       });
       });
 
 
-      $timeout(unregister, 2000);
+      $q.when(confirmModal).then(function(modalEl) {
+        modalEl.modal('show');
+      });
+    };
 
 
-      $rootScope.$emit('save-dashboard');
+    p.goto_next = function() {
+      var baseLen = $location.absUrl().length - $location.url().length;
+      var nextUrl = this.next.substring(baseLen);
+      $location.url(nextUrl);
     };
     };
 
 
-  }).run(function(unsavedChangesSrv) {
-    unsavedChangesSrv.init();
+    this.Tracker = Tracker;
+    this.init = function(dashboard, scope) {
+      // wait for different services to patch the dashboard (missing properties)
+      $timeout(function() { new Tracker(dashboard, scope); }, 1200);
+    };
   });
   });
 });
 });

+ 48 - 0
public/test/specs/unsavedChangesSrv-specs.js

@@ -0,0 +1,48 @@
+define([
+  'features/dashboard/unsavedChangesSrv',
+  'features/dashboard/dashboardSrv'
+], function() {
+  'use strict';
+
+  describe("unsavedChangesSrv", function() {
+    var _unsavedChangesSrv;
+    var _dashboardSrv;
+    var _location;
+    var _contextSrvStub = { isEditor: true };
+    var _rootScope;
+    var tracker;
+    var dash;
+    var scope;
+
+    beforeEach(module('grafana.services'));
+    beforeEach(module(function($provide) {
+      $provide.value('contextSrv', _contextSrvStub);
+    }));
+
+    beforeEach(inject(function(unsavedChangesSrv, $location, $rootScope, dashboardSrv) {
+      _unsavedChangesSrv = unsavedChangesSrv;
+      _dashboardSrv = dashboardSrv;
+      _location = $location;
+      _rootScope = $rootScope;
+    }));
+
+    beforeEach(function() {
+      dash = _dashboardSrv.create({});
+      scope = _rootScope.$new();
+      scope.appEvent = sinon.spy();
+      scope.onAppEvent = sinon.spy();
+
+      tracker = new _unsavedChangesSrv.Tracker(dash, scope);
+    });
+
+    it('No changes should not have changes', function() {
+      expect(tracker.hasChanges()).to.be(false);
+    });
+
+    it('Simple change should be registered', function() {
+      dash.property = "google";
+      expect(tracker.hasChanges()).to.be(true);
+    });
+
+  });
+});

+ 1 - 0
public/test/test-main.js

@@ -141,6 +141,7 @@ require([
     'specs/dashboardViewStateSrv-specs',
     'specs/dashboardViewStateSrv-specs',
     'specs/soloPanelCtrl-specs',
     'specs/soloPanelCtrl-specs',
     'specs/dynamicDashboardSrv-specs',
     'specs/dynamicDashboardSrv-specs',
+    'specs/unsavedChangesSrv-specs',
   ];
   ];
 
 
   var pluginSpecs = (config.plugins.specs || []).map(function (spec) {
   var pluginSpecs = (config.plugins.specs || []).map(function (spec) {