Work in progress on Synchronizer notification
diff --git a/views/ngXosLib/xosHelpers/spec/notification.test.js b/views/ngXosLib/xosHelpers/spec/notification.test.js
new file mode 100644
index 0000000..cbc1e56
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/notification.test.js
@@ -0,0 +1,63 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xosNotification service', () => {
+
+      let service, scope;
+
+      const options = {icon: 'icon', body: 'message'};
+
+      let notificationMock = {
+        requestPermission: () => {
+          return {
+            then: cb => cb('granted')
+          }
+        },
+        permission: 'granted'
+      }
+
+
+      // load the application module
+      beforeEach(module('xos.helpers', ($provide) => {
+        $provide.value('Notification', notificationMock);
+      }));
+
+      // inject the cartService
+      beforeEach(inject(function (_xosNotification_, $rootScope) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _xosNotification_;
+        scope = $rootScope;
+        spyOn(service, 'sendNotification');
+        spyOn(service, 'checkPermission').and.callThrough();
+        spyOn(notificationMock, 'requestPermission').and.callThrough();
+      }));
+
+      it('should exist', () => {
+        expect(service).toBeDefined();
+      });
+
+      describe('when permission are granted', () => {
+        it('should send the notification', () => {
+          service.notify('Test', options);
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+      describe('when permission are not granted', () => {
+        beforeEach(() => {
+          notificationMock.permission = false;
+        });
+
+        it('should request permission', () => {
+          service.notify('Test', options);
+          expect(service.checkPermission).toHaveBeenCalled();
+          scope.$apply(); // this resolve the promise
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/notification.service.js b/views/ngXosLib/xosHelpers/src/services/notification.service.js
new file mode 100644
index 0000000..7c4154b
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/notification.service.js
@@ -0,0 +1,62 @@
+(function() {
+  'use strict';
+
+
+  angular
+  .module('xos.helpers')
+  .factory('Notification', function(){
+    return window.Notification;
+  })
+  /**
+  * @ngdoc service
+  * @name xos.helpers.xosNotification
+  * @description This factory define a set of helper function to trigger desktop notification
+  **/
+  .service('xosNotification', function($q, $log, Notification) {
+
+    this.checkPermission = () => {
+      const deferred = $q.defer();
+      Notification.requestPermission()
+      .then(permission => {
+        if (permission === 'granted') {
+          deferred.resolve(permission);
+        }
+        else {
+          deferred.reject(permission);
+        }
+      });
+      return deferred.promise;
+    };
+
+    this.sendNotification = (title, options) => {
+      const notification = new Notification(title, options);
+      notification.onerror = function(err){
+        $log.error(err);
+      };
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.xosNotification#notify
+    * @methodOf xos.helpers.xosNotification
+    * @description
+    * This method will check for user permission and if granted will send a browser notification.
+    * @param {string} title The notification title
+    * @param {object} options The notification options: `{icon: 'url', body: 'Notification body'}`
+    **/
+
+    this.notify = (title, options) => {
+      if (!('Notification' in window)) {
+        $log.info('This browser does not support desktop notification');
+      }
+      else if (Notification.permission !== 'granted') {
+        this.checkPermission()
+        .then(() => this.sendNotification(title, options));
+      }
+      else if (Notification.permission === 'granted') {
+        this.sendNotification(title, options);
+      }
+    }
+
+  })
+})();
diff --git a/views/ngXosViews/synchronizerNotifier/src/js/main.js b/views/ngXosViews/synchronizerNotifier/src/js/main.js
index 93b8191..1d7de32 100644
--- a/views/ngXosViews/synchronizerNotifier/src/js/main.js
+++ b/views/ngXosViews/synchronizerNotifier/src/js/main.js
@@ -50,6 +50,8 @@
     diags.forEach(d => {
       let status = JSON.parse(d.backend_register);
       status.last_run = new Date(status.last_run * 1000);
+      status.last_synchronizer_start = new Date(status.last_synchronizer_start * 1000);
+      status.last_syncrecord_start = status.last_syncrecord_start ? new Date(status.last_syncrecord_start * 1000) : null;
       $rootScope.$broadcast(`diag`, {
         name: d.name,
         updated: d.updated,
@@ -77,11 +79,23 @@
 
     let gap = 5 * 60 * 1000; /* ms */
     // let gap = 2;
-
-    if (((new Date()) - status.last_run) > gap){
-      return false;
+    if(status.last_run > status.last_synchronizer_start){
+      // the synchronizer has finished
+      return true;
     }
-    return true;
+    else {
+      // the synchronizer is running
+      if(!status.last_syncrecord_start){
+        // but no step have been completed
+        return false;
+      }
+      else if (((new Date()) - status.last_syncrecord_start) > gap){
+        return false;
+      }
+      else{
+        return true;
+      }
+    }
   }
 
   $interval(() => {
@@ -105,13 +119,15 @@
     templateUrl: 'templates/sync-status.tpl.html',
     controller: function($log, $rootScope, Diag){
       Diag.start();
-      // this.showNotificationPanel = true;
+      this.showNotificationPanel = true;
       this.synchronizers = {};
 
       this.showNoSync = true;
 
       $rootScope.$on('diag', (e, d) => {
-        // $log.info('Received event: ', d);
+        if(d.name === 'vcpe'){
+          $log.info('Received event: ', d.info.last_run, d.info.last_synchronizer_start);
+        }
         this.synchronizers[d.name] = d;
         this.showNoSync = false;
         if(Object.keys(this.synchronizers).length === 0){
diff --git a/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html b/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html
index 58524e7..84c8e4b 100644
--- a/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html
+++ b/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html
@@ -3,7 +3,7 @@
     <i class="glyphicon glyphicon-inbox"></i>
   </div>
   <div class="notification-panel panel panel-default" ng-show="vm.showNotificationPanel">
-    <ul class="list-group" ng-show="vm.showNoSync">
+    <ul class="list-group" ng-show="!vm.showNoSync">
       <li class="list-group-item" ng-repeat="(syncName, syncStatus) in vm.synchronizers">
         <span class="badge" ng-class="{success: syncStatus.status, danger: !syncStatus.status}">
           <span ng-show="syncStatus.status"><i class="glyphicon glyphicon-ok"></i></span>