diff --git a/app/assets/javascripts/app/controllers/editor.js b/app/assets/javascripts/app/controllers/editor.js index a4aa8d740..514342e83 100644 --- a/app/assets/javascripts/app/controllers/editor.js +++ b/app/assets/javascripts/app/controllers/editor.js @@ -143,7 +143,7 @@ angular.module('app') } // Lots of dirtying can happen above, so we'll sync - syncManager.sync(); + syncManager.sync("editorMenuOnSelect"); }.bind(this) this.hasAvailableExtensions = function() { diff --git a/app/assets/javascripts/app/controllers/footer.js b/app/assets/javascripts/app/controllers/footer.js index 945aaa9c9..b37b94ff1 100644 --- a/app/assets/javascripts/app/controllers/footer.js +++ b/app/assets/javascripts/app/controllers/footer.js @@ -69,7 +69,7 @@ angular.module('app') this.refreshData = function() { this.isRefreshing = true; - syncManager.sync(function(response){ + syncManager.sync((response) => { $timeout(function(){ this.isRefreshing = false; }.bind(this), 200) @@ -78,7 +78,7 @@ angular.module('app') } else { this.syncUpdated(); } - }.bind(this)); + }, null, "refreshData"); } this.syncUpdated = function() { diff --git a/app/assets/javascripts/app/controllers/home.js b/app/assets/javascripts/app/controllers/home.js index 427afa393..e775c9c4c 100644 --- a/app/assets/javascripts/app/controllers/home.js +++ b/app/assets/javascripts/app/controllers/home.js @@ -9,8 +9,8 @@ angular.module('app') } /* Used to avoid circular dependencies where syncManager cannot be imported but rootScope can */ - $rootScope.sync = function() { - syncManager.sync(); + $rootScope.sync = function(source) { + syncManager.sync("$rootScope.sync - " + source); } $rootScope.lockApplication = function() { @@ -49,7 +49,7 @@ angular.module('app') dbManager.openDatabase(null, function() { // new database, delete syncToken so that items can be refetched entirely from server syncManager.clearSyncToken(); - syncManager.sync(); + syncManager.sync("openDatabase"); }) } @@ -61,10 +61,10 @@ angular.module('app') $rootScope.$broadcast("initial-data-loaded"); - syncManager.sync(null); + syncManager.sync("initiateSync"); // refresh every 30s setInterval(function () { - syncManager.sync(null); + syncManager.sync("timer"); }, 30000); }); } @@ -115,7 +115,7 @@ angular.module('app') } note.setDirty(true); - syncManager.sync(); + syncManager.sync("updateTagsForNote"); } /* @@ -145,7 +145,7 @@ angular.module('app') return; } tag.setDirty(true); - syncManager.sync(callback); + syncManager.sync(callback, null, "tagsSave"); $rootScope.$broadcast("tag-changed"); modelManager.resortTag(tag); } @@ -161,7 +161,7 @@ angular.module('app') syncManager.sync(function(){ // force scope tags to update on sub directives $scope.safeApply(); - }); + }, null, "removeTag"); } } @@ -199,7 +199,7 @@ angular.module('app') callback(true); } } - }) + }, null, "saveNote") } $scope.safeApply = function(fn) { @@ -240,7 +240,7 @@ angular.module('app') } else { $scope.notifyDelete(); } - }); + }, null, "deleteNote"); } diff --git a/app/assets/javascripts/app/directives/views/accountMenu.js b/app/assets/javascripts/app/directives/views/accountMenu.js index 7e65d07f7..aa6a68476 100644 --- a/app/assets/javascripts/app/directives/views/accountMenu.js +++ b/app/assets/javascripts/app/directives/views/accountMenu.js @@ -80,7 +80,7 @@ class AccountMenu { }, 1000) }); }) - }) + }, null, "submitPasswordChange") } $scope.submitMfaForm = function() { @@ -162,7 +162,7 @@ class AccountMenu { var block = function() { $timeout(function(){ $scope.onSuccessfulAuth()(); - syncManager.sync(); + syncManager.sync("onAuthSuccess"); }) } @@ -280,7 +280,7 @@ class AccountMenu { syncManager.sync((response) => { callback(response, errorCount); - }, {additionalFields: ["created_at", "updated_at"]}); + }, {additionalFields: ["created_at", "updated_at"]}, "importJSONData"); }.bind(this) if(data.auth_params) { @@ -443,7 +443,7 @@ class AccountMenu { alert("Your items have been successfully re-encrypted and synced. You must sign out of all other signed in applications (mobile, desktop, web) and sign in again, or else you may corrupt your data.") $scope.newPasswordData = {}; }, 1000) - }); + }, null, "reencryptPressed"); } diff --git a/app/assets/javascripts/app/directives/views/editorMenu.js b/app/assets/javascripts/app/directives/views/editorMenu.js index 51d301fb0..78b9bb66f 100644 --- a/app/assets/javascripts/app/directives/views/editorMenu.js +++ b/app/assets/javascripts/app/directives/views/editorMenu.js @@ -51,7 +51,7 @@ class EditorMenu { } component.setAppDataItem("defaultEditor", true); component.setDirty(true); - syncManager.sync(); + syncManager.sync("makeEditorDefault"); $scope.defaultEditor = component; } @@ -59,7 +59,7 @@ class EditorMenu { $scope.removeEditorDefault = function(component) { component.setAppDataItem("defaultEditor", false); component.setDirty(true); - syncManager.sync(); + syncManager.sync("removeEditorDefault"); $scope.defaultEditor = null; } diff --git a/app/assets/javascripts/app/services/authManager.js b/app/assets/javascripts/app/services/authManager.js index a20fad35b..a72423d01 100644 --- a/app/assets/javascripts/app/services/authManager.js +++ b/app/assets/javascripts/app/services/authManager.js @@ -302,7 +302,7 @@ angular.module('app') var prefs = new Item({content_type: prefsContentType}); modelManager.addItem(prefs); prefs.setDirty(true); - $rootScope.sync(); + $rootScope.sync("authManager singletonCreate"); valueCallback(prefs); }); @@ -312,7 +312,7 @@ angular.module('app') this.syncUserPreferences = function() { this.userPreferences.setDirty(true); - $rootScope.sync(); + $rootScope.sync("syncUserPreferences"); } this.getUserPrefValue = function(key, defaultValue) { diff --git a/app/assets/javascripts/app/services/componentManager.js b/app/assets/javascripts/app/services/componentManager.js index bd7151f26..317b3b4a4 100644 --- a/app/assets/javascripts/app/services/componentManager.js +++ b/app/assets/javascripts/app/services/componentManager.js @@ -425,7 +425,7 @@ class ComponentManager { saveMessage.action = response && response.error ? "save-error" : "save-success"; this.replyToMessage(component, message, {error: response.error}) this.handleMessage(component, saveMessage); - }); + }, null, "handleSaveItemsMessage"); }); } @@ -447,7 +447,7 @@ class ComponentManager { this.modelManager.addItem(item); this.modelManager.resolveReferencesForItem(item); item.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("handleCreateItemMessage"); this.replyToMessage(component, message, {item: this.jsonForItem(item, component)}) }); } @@ -470,7 +470,7 @@ class ComponentManager { this.modelManager.setItemToBeDeleted(model); } - this.syncManager.sync(); + this.syncManager.sync("handleDeleteItemsMessage"); } }); } @@ -486,7 +486,7 @@ class ComponentManager { this.runWithPermissions(component, [], () => { component.componentData = message.data.componentData; component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("handleSetComponentDataMessage"); }); } @@ -569,7 +569,7 @@ class ComponentManager { } } component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("promptForPermissions"); } this.permissionDialogs = this.permissionDialogs.filter((pendingDialog) => { @@ -635,7 +635,7 @@ class ComponentManager { this.modelManager.addItem(component); component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("installComponent"); } activateComponent(component) { @@ -650,7 +650,7 @@ class ComponentManager { if(didChange) { component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("activateComponent"); } if(!this.activeComponents.includes(component)) { @@ -709,7 +709,7 @@ class ComponentManager { if(didChange) { component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("deactivateComponent"); } _.pull(this.activeComponents, component); @@ -729,7 +729,7 @@ class ComponentManager { deleteComponent(component) { this.modelManager.setItemToBeDeleted(component); - this.syncManager.sync(); + this.syncManager.sync("deleteComponent"); } isComponentActive(component) { diff --git a/app/assets/javascripts/app/services/desktopManager.js b/app/assets/javascripts/app/services/desktopManager.js index c63bc4e4c..3454d6e19 100644 --- a/app/assets/javascripts/app/services/desktopManager.js +++ b/app/assets/javascripts/app/services/desktopManager.js @@ -51,14 +51,14 @@ class DesktopManager { console.log("Web|Component Installation Complete", componentData); var component = this.modelManager.mapResponseItemsToLocalModels([componentData], ModelManager.MappingSourceDesktopInstalled)[0]; component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("desktop_onComponentInstallationComplete"); } desktop_updateComponentComplete(componentData) { console.log("Web|Component Update Complete", componentData); var component = this.modelManager.mapResponseItemsToLocalModels([componentData], ModelManager.MappingSourceDesktopInstalled)[0]; component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("desktop_updateComponentComplete"); } /* Used to resolve "sn://" */ diff --git a/app/assets/javascripts/app/services/migrationManager.js b/app/assets/javascripts/app/services/migrationManager.js index 59eb9a2e1..9fec09d65 100644 --- a/app/assets/javascripts/app/services/migrationManager.js +++ b/app/assets/javascripts/app/services/migrationManager.js @@ -50,7 +50,7 @@ class MigrationManager { this.modelManager.setItemToBeDeleted(editor); } - this.syncManager.sync(); + this.syncManager.sync("addEditorToComponentMigrator"); } }) } diff --git a/app/assets/javascripts/app/services/modelManager.js b/app/assets/javascripts/app/services/modelManager.js index f97a3fa49..c1982308d 100644 --- a/app/assets/javascripts/app/services/modelManager.js +++ b/app/assets/javascripts/app/services/modelManager.js @@ -54,6 +54,8 @@ class ModelManager { this.informModelsOfUUIDChangeForItem(newItem, item.uuid, newItem.uuid); + console.log(item.uuid, "-->", newItem.uuid); + var block = () => { this.addItem(newItem); newItem.setDirty(true); diff --git a/app/assets/javascripts/app/services/packageManager.js b/app/assets/javascripts/app/services/packageManager.js index 7c61b2bac..fa0aa837e 100644 --- a/app/assets/javascripts/app/services/packageManager.js +++ b/app/assets/javascripts/app/services/packageManager.js @@ -24,7 +24,7 @@ class PackageManager { this.modelManager.addItem(assembled); assembled.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("installPackage"); console.log("Created assembled", assembled); diff --git a/app/assets/javascripts/app/services/singletonManager.js b/app/assets/javascripts/app/services/singletonManager.js index 4192bab7b..2e8774729 100644 --- a/app/assets/javascripts/app/services/singletonManager.js +++ b/app/assets/javascripts/app/services/singletonManager.js @@ -58,6 +58,7 @@ class SingletonManager { // This way we know there was some action and things need to be resolved. The saved items will come up // in filterItemsWithPredicate(this.modelManager.allItems) and be deleted anyway let savedSingletonItemsCount = this.filterItemsWithPredicate(savedItems, predicate).length; + if(retrievedSingletonItems.length > 0 || savedSingletonItemsCount > 0) { /* Check local inventory and make sure only 1 similar item exists. If more than 1, delete oldest @@ -109,7 +110,7 @@ class SingletonManager { this.modelManager.setItemToBeDeleted(d); } - this.$rootScope.sync(); + this.$rootScope.sync("resolveSingletons"); // Send remaining item to callback singletonHandler.singleton = winningItem; diff --git a/app/assets/javascripts/app/services/syncManager.js b/app/assets/javascripts/app/services/syncManager.js index 1002b9b5b..bf80cd75b 100644 --- a/app/assets/javascripts/app/services/syncManager.js +++ b/app/assets/javascripts/app/services/syncManager.js @@ -189,7 +189,17 @@ class SyncManager { this.$interval.cancel(this.syncStatus.checker); } - sync(callback, options = {}) { + sync(callback, options = {}, source) { + + if(!options) options = {}; + + if(typeof callback == 'string') { + // is source string, used to avoid filling parameters on call + source = callback; + callback = null; + } + + // console.log("Syncing from", source); var allDirtyItems = this.modelManager.getDirtyItems(); @@ -271,6 +281,15 @@ class SyncManager { this.$rootScope.$broadcast("sync:updated_token", this.syncToken); + // Filter retrieved_items to remove any items that may be in saved_items for this complete sync operation + // When signing in, and a user requires many round trips to complete entire retrieval of data, an item may be saved + // on the first trip, then on subsequent trips using cursor_token, this same item may be returned, since it's date is + // greater than cursor_token. We keep track of all saved items in whole sync operation with this.allSavedItems + // We need this because singletonManager looks at retrievedItems as higher precendence than savedItems, but if it comes in both + // then that's problematic. + let allSavedUUIDs = this.allSavedItems.map((item) => {return item.uuid}); + response.retrieved_items = response.retrieved_items.filter((candidate) => {return !allSavedUUIDs.includes(candidate.uuid)}); + // Map retrieved items to local data var retrieved = this.handleItemsResponse(response.retrieved_items, null, ModelManager.MappingSourceRemoteRetrieved); @@ -307,12 +326,12 @@ class SyncManager { if(this.cursorToken || this.syncStatus.needsMoreSync) { setTimeout(function () { - this.sync(callback, options); + this.sync(callback, options, "onSyncSuccess cursorToken || needsMoreSync"); }.bind(this), 10); // wait 10ms to allow UI to update } else if(this.repeatOnCompletion) { this.repeatOnCompletion = false; setTimeout(function () { - this.sync(callback, options); + this.sync(callback, options, "onSyncSuccess repeatOnCompletion"); }.bind(this), 10); // wait 10ms to allow UI to update } else { this.writeItemsToLocalStorage(this.allRetreivedItems, false, null); diff --git a/app/assets/javascripts/app/services/sysExtManager.js b/app/assets/javascripts/app/services/sysExtManager.js index 1ff562653..7ee8c76ea 100644 --- a/app/assets/javascripts/app/services/sysExtManager.js +++ b/app/assets/javascripts/app/services/sysExtManager.js @@ -30,7 +30,7 @@ class SysExtManager { if(needsSync) { resolvedSingleton.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("resolveExtensionsManager"); } }, (valueCallback) => { // Safe to create. Create and return object. @@ -71,7 +71,7 @@ class SysExtManager { this.modelManager.addItem(component); component.setDirty(true); - this.syncManager.sync(); + this.syncManager.sync("resolveExtensionsManager createNew"); valueCallback(component); });