LP#1750894 Server prefs view/migration options
authorBill Erickson <berickxx@gmail.com>
Tue, 22 May 2018 20:45:19 +0000 (16:45 -0400)
committerBill Erickson <berickxx@gmail.com>
Tue, 29 May 2018 14:13:36 +0000 (10:13 -0400)
Adds a "Server Prefs" tab to the Stored User Preferences user interface.

Adds options for migrating workstation settings to server settings, both
in test mode and delete-local-once-complete mode.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/templates/staff/admin/workstation/index.tt2
Open-ILS/src/templates/staff/admin/workstation/t_splash.tt2
Open-ILS/src/templates/staff/admin/workstation/t_stored_prefs.tt2
Open-ILS/web/js/ui/default/staff/admin/workstation/app.js
Open-ILS/web/js/ui/default/staff/services/hatch.js

index 44842ea..97472cf 100644 (file)
@@ -23,6 +23,8 @@ angular.module('egCoreMod').run(['egStrings', function(s) {
   s.PRINT_TEMPLATES_FAIL_IMPORT = "[% l('Failed to import any print template(s)') %]";
   s.HATCH_SETTINGS_MIGRATION_SUCCESS = "[% l('Settings successfully migrated') %]";
   s.HATCH_SETTINGS_MIGRATION_FAILURE = "[% l('Settings migration failed') %]";
+  s.HATCH_SERVER_SETTINGS_MIGRATION_CONFIRM = 
+    "[% l('This will delete the local version all settings configured to live on the server.  Continue?') %]"
 }]);
 </script>
 [% END %]
index 345f7db..50a60ef 100644 (file)
@@ -82,6 +82,7 @@
         </div>
       </div>
 
+
     </div><!-- left column -->
     <div class="col-md-6"><!-- right column -->
 
         </div>
       </div>
 
+      <div class="row new-entry">
+        <div class="col-md-12">
+          <label>
+            [% l('Experimental: Migrate Workstation Settings to Server') %]
+          </label>
+          <p>[% | l %]Settings may be migrated to the server using the first
+option below as many times as needed for testing and verification.  Once 
+local settings are deleted via the second option, the migration will be 
+marked as complete and no more migration attempts may occur.[% END %]
+          </p>
+          <ol>
+            <li class="pad-vert">
+              <button class="btn btn-default" ng-click="migrateServerSettings()">
+                [% l('Migrate and Keep Local Settings (for testing)') %]
+              </button>
+            </li>
+            <li>
+              <button class="btn btn-warning" 
+                ng-click="migrateServerSettings(true)">
+                [% l('Migrate and Delete Local Settings') %]
+              </button>
+            </li>
+          </ol>
+        </div>
+      </div>
+
+
     </div><!-- col -->
   </div><!-- row -->
 
index dc031b4..e4c34c9 100644 (file)
 [% |l %]
 Preference values are stored as JSON strings.  
 Click on a preference to view the stored value.
-Click on the delete (X) button to remove a preference's value.
+Click on the delete (X) button to remove a preference value.
 [% END %]
       </div>
     </div>
   </div>
 
   <div class="row">
+    <div class="col-md-12">
+      <div class="panel panel-info">
+        <div class="panel-heading">
+          <h3 class="panel-title">
+            [% l('Experimental: Migrate Workstation Settings to Server') %]
+          </h3>
+        </div>
+        <div class="panel-body">
+          <p>
+[% | l %]Settings may be migrated to the server using the first option below 
+as many times as needed for testing and verification.  Once local settings 
+are deleted via the second option, no settings will remain to migrate, unless
+they are added back through some external mechanism.[% END %]
+          </p>
+          <p>
+[% | l %]Note that just because a setting exists under "Server Prefs" below
+does not mean it has been migrated.  Check the value by clicking on the 
+setting name to be sure.[% END %]
+          </p>
+          <div class="row pad-left">
+            <button class="btn btn-success pad-right" 
+              ng-click="migrateServerSettings()">
+              [% l('#1 Migrate and Keep Local Settings (Testing)') %]
+            </button>
+            <button class="btn btn-warning pad-left" 
+              ng-click="migrateServerSettings(true)">
+              [% l('#2 Migrate and Delete Local Settings') %]
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <div class="row">
     <div class="col-md-4">
 
       <ul class="nav nav-tabs">
@@ -29,7 +64,10 @@ Click on the delete (X) button to remove a preference's value.
           <a href='' ng-click="setContext('local')">[% l('Local Prefs') %]</a>
         </li>
         <li ng-class="{active : context == 'remote'}">
-          <a href='' ng-click="setContext('remote')">[% l('Remote Prefs') %]</a>
+          <a href='' ng-click="setContext('remote')">[% l('Hatch Prefs') %]</a>
+        </li>
+        <li ng-class="{active : context == 'server'}">
+          <a href='' ng-click="setContext('server')">[% l('Server Prefs') %]</a>
         </li>
       </ul>
       <div class="tab-content">
index f599bc0..fa0df89 100644 (file)
@@ -728,8 +728,8 @@ function($scope , $q , egCore , ngToast) {
 }])
 
 .controller('StoredPrefsCtrl',
-       ['$scope','$q','egCore','egConfirmDialog',
-function($scope , $q , egCore , egConfirmDialog) {
+       ['$scope','$q','egCore','egConfirmDialog','egProgressDialog','$timeout',
+function($scope , $q , egCore , egConfirmDialog , egProgressDialog , $timeout) {
     console.log('StoredPrefsCtrl');
 
     $scope.setContext = function(ctx) {
@@ -745,7 +745,7 @@ function($scope , $q , egCore , egConfirmDialog) {
     // fetch the keys
 
     function refreshKeys() {
-        $scope.keys = {local : [], remote : []};
+        $scope.keys = {local : [], remote : [], server: []};
 
         if (egCore.hatch.hatchAvailable) {
             egCore.hatch.getRemoteKeys().then(
@@ -754,6 +754,10 @@ function($scope , $q , egCore , egConfirmDialog) {
     
         // local calls are non-async
         $scope.keys.local = egCore.hatch.getLocalKeys();
+
+        egCore.hatch.getServerKeys().then(function(keys) {
+            $scope.keys.server = keys;
+        });
     }
     refreshKeys();
 
@@ -763,6 +767,11 @@ function($scope , $q , egCore , egConfirmDialog) {
 
         if ($scope.context == 'local') {
             $scope.currentKeyContent = egCore.hatch.getLocalItem(key);
+        } else if ($scope.context === 'server') {
+            egCore.hatch.getServerItem(key)
+            .then(function(content) {
+                $scope.currentKeyContent = content
+            });
         } else {
             egCore.hatch.getRemoteItem(key)
             .then(function(content) {
@@ -783,6 +792,9 @@ function($scope , $q , egCore , egConfirmDialog) {
                     if ($scope.context == 'local') {
                         egCore.hatch.removeLocalItem(key);
                         refreshKeys();
+                    } else if ($scope.context == 'server') {
+                        egCore.hatch.removeServerItem(key)
+                        .then(function() { refreshKeys() });
                     } else {
                         egCore.hatch.removeItem(key)
                         .then(function() { refreshKeys() });
@@ -792,6 +804,33 @@ function($scope , $q , egCore , egConfirmDialog) {
             }
         );
     }
+
+    $scope.migrateServerSettings = function(deleteLocal) {
+
+        var promise = !deleteLocal ? $q.when() : 
+            egConfirmDialog.open(
+                egCore.strings.HATCH_SERVER_SETTINGS_MIGRATION_CONFIRM, '', {}
+            ).result;
+
+        promise.then(function() {
+            egProgressDialog.open();
+            // timeout added because closing a progress dialog too quickly
+            // (before it's registered that it's opened) can leave the
+            // dialog stranded open.  This is only an issue when no local
+            // settings data exists to migrate, causing the migration to 
+            // be instantaneous.
+            $timeout(function() {
+                egCore.hatch.migrateServerSettings(deleteLocal).then(
+                    function() {},
+                    function() {},
+                    function() {
+                        egProgressDialog.increment();
+                    }
+                )['finally'](egProgressDialog.close);
+            }, 100);
+        });
+    }
+
 }])
 
 .controller('WSRegCtrl',
index 973f145..6fa8ae2 100644 (file)
@@ -33,6 +33,7 @@ angular.module('egCoreMod')
     service.messages = {};
     service.hatchAvailable = false;
     service.auth = null;  // ref to egAuth loaded on-demand to avoid circular ref.
+    service.disableServerSettings = false;
 
     // key/value cache -- avoid unnecessary Hatch extension requests.
     // Only affects *RemoteItem calls.
@@ -90,6 +91,11 @@ angular.module('egCoreMod')
     ];
 
     service.keyStoredOnServer = function(key) {
+
+        if (service.disableServerSettings) {
+            return false;
+        }
+
         var browserOnly = false;
         angular.forEach(service.browserOnlyPrefixes, function(pfx) {
             if (key.match(new RegExp('^' + pfx))) 
@@ -368,7 +374,7 @@ angular.module('egCoreMod')
         });
     }
 
-    service.migrateServerSettings = function() {
+    service.migrateServerSettings = function(deleteLocal) {
 
         if (!service.auth) service.auth = $injector.get('egAuth');
         if (!service.auth.token()) return $q.reject('no authtoken');
@@ -376,45 +382,46 @@ angular.module('egCoreMod')
         var deferred = $q.defer();
         var settings = service.serverSettings.slice(0); // clone
 
+        // Allow get/remove calls to fall back to local options
+        // during migration.
+        service.disableServerSettings = true;
+
         function migrateNext(key) {
+
             if (!key) {
+                service.disableServerSettings = false;
                 return deferred.resolve();
             }
 
-            service.migrateOneServerSetting(key).then(
+            service.migrateOneServerSetting(key, deleteLocal).then(
                 function() {
                     deferred.notify('migrated ' + key);
                     migrateNext(settings.shift());
                 },
                 function() {
+                    service.disableServerSettings = false;
                     deferred.reject(
                         'Something failed during settings migration');
                 }
             );
-
         }
 
+        migrateNext(settings.shift());
         return deferred.promise;
     }
 
-    service.migrateOneServerSetting = function(key) {
-        console.log('migrating server setting ' + key);
+    service.migrateOneServerSetting = function(key, deleteLocal) {
         var deferred = $q.defer();
 
-        function remove(key) {
-            return service.useSettings() ? 
-                service.removeRemoteItem(key) :
-                $q.when(service.removeLocalItem(key));
-        }
-
-        var prom = service.useSettings() ? 
-            service.getRemoteItem(key) :
-            $q.when(service.getLocalItem(key));
-
-        prom.then(function(value) {
+        service.getItem(key).then(function(value) {
 
             if (value === undefined || value === null) {
-                remove(key); // for good measure.
+                console.log(key + ' has no value to migrate');
+                // Nothing to migrate.
+                if (deleteLocal) {
+                    // for good measure.
+                    service.removeItem(key); 
+                }
                 return deferred.resolve();
             }
 
@@ -423,9 +430,13 @@ angular.module('egCoreMod')
                     console.debug(
                         'setting ' + key + ' successfully stored on server');
 
-                    remove(key).then(function() {
+                    if (!deleteLocal) {
+                        return deferred.resolve();
+                    }
+
+                    service.removeItem(key).then(function() {
                         console.debug(
-                            'setting ' + key + ' removed from local storage');
+                            'setting ' + key + ' removed from workstation');
                         deferred.resolve();
                     });
                 },
@@ -551,7 +562,7 @@ angular.module('egCoreMod')
     // remove a stored item
     service.removeItem = function(key) {
         if (service.keyStoredOnServer(key))
-            return service.setServerItem(key, null);
+            return service.removeServerItem(key);
 
         if (!service.useSettings())
             return $q.when(service.removeLocalItem(key));
@@ -570,6 +581,10 @@ angular.module('egCoreMod')
         return $q.reject();
     }
 
+    service.removeServerItem = function(key) {
+        return service.setServerItem(key, null);
+    }
+
     service.removeRemoteItem = function(key) {
         delete service.keyCache[key];
         return service.attemptHatchDelivery({
@@ -617,6 +632,20 @@ angular.module('egCoreMod')
         });
     }
 
+    service.getServerKeys = function(prefix) {
+        var keys = [];
+        var idx = 0;
+        service.serverSettings.forEach(function(k) {
+            // key prefix match test
+            if (prefix && k.substr(0, prefix.length) != prefix) {
+                return;
+            }
+            keys.push(k);
+        });
+        // these may eventually come from the server, so return a promise.
+        return $q.when(keys);
+    }
+
     service.getLocalKeys = function(prefix) {
         var keys = [];
         var idx = 0;