Compare commits
4 Commits
bugfix/iss
...
nb-conflic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c25095a801 | ||
|
|
0e3e32f037 | ||
|
|
9f6463105a | ||
|
|
317abfe2c1 |
@@ -75,7 +75,8 @@
|
||||
const TWO_HOURS = ONE_HOUR * 2;
|
||||
const ONE_DAY = ONE_HOUR * 24;
|
||||
|
||||
openmct.install(openmct.plugins.LocalStorage());
|
||||
// openmct.install(openmct.plugins.LocalStorage());
|
||||
openmct.install(openmct.plugins.CouchDB("http://localhost:5984/openmct"));
|
||||
|
||||
openmct.install(openmct.plugins.example.Generator());
|
||||
openmct.install(openmct.plugins.example.EventGeneratorPlugin());
|
||||
|
||||
@@ -196,20 +196,22 @@ export default class ObjectAPI {
|
||||
* @returns {Promise} a promise which will resolve when the domain object
|
||||
* has been saved, or be rejected if it cannot be saved
|
||||
*/
|
||||
get(identifier, abortSignal) {
|
||||
get(identifier, abortSignal = undefined, forceRemote = false) {
|
||||
let keystring = this.makeKeyString(identifier);
|
||||
|
||||
if (this.cache[keystring] !== undefined) {
|
||||
return this.cache[keystring];
|
||||
}
|
||||
if (!forceRemote) {
|
||||
if (this.cache[keystring] !== undefined) {
|
||||
return this.cache[keystring];
|
||||
}
|
||||
|
||||
identifier = utils.parseKeyString(identifier);
|
||||
identifier = utils.parseKeyString(identifier);
|
||||
|
||||
if (this.isTransactionActive()) {
|
||||
let dirtyObject = this.transaction.getDirtyObject(identifier);
|
||||
if (this.isTransactionActive()) {
|
||||
let dirtyObject = this.transaction.getDirtyObject(identifier);
|
||||
|
||||
if (dirtyObject) {
|
||||
return Promise.resolve(dirtyObject);
|
||||
if (dirtyObject) {
|
||||
return Promise.resolve(dirtyObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,7 +401,7 @@ export default class ObjectAPI {
|
||||
savedObjectPromise.then(response => {
|
||||
savedResolve(response);
|
||||
}).catch((error) => {
|
||||
if (lastPersistedTime !== undefined) {
|
||||
if (isNewObject) {
|
||||
this.#mutate(domainObject, 'persisted', lastPersistedTime);
|
||||
}
|
||||
|
||||
@@ -412,7 +414,9 @@ export default class ObjectAPI {
|
||||
|
||||
return result.catch((error) => {
|
||||
if (error instanceof this.errors.Conflict) {
|
||||
this.openmct.notifications.error(`Conflict detected while saving ${this.makeKeyString(domainObject.identifier)}`);
|
||||
if (!this.SYNCHRONIZED_OBJECT_TYPES.includes(domainObject.type)) {
|
||||
this.openmct.notifications.error(`Conflict detected while saving ${this.makeKeyString(domainObject.identifier)}`);
|
||||
}
|
||||
}
|
||||
|
||||
throw error;
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<Sidebar
|
||||
ref="sidebar"
|
||||
class="c-notebook__nav c-sidebar c-drawer c-drawer--align-left"
|
||||
:class="[{'is-expanded': showNav}, {'c-drawer--push': !sidebarCoversEntries}, {'c-drawer--overlays': sidebarCoversEntries}]"
|
||||
:class="sidebarClasses"
|
||||
:default-page-id="defaultPageId"
|
||||
:selected-page-id="getSelectedPageId()"
|
||||
:default-section-id="defaultSectionId"
|
||||
@@ -270,6 +270,20 @@ export default {
|
||||
|
||||
return this.sections[0];
|
||||
},
|
||||
sidebarClasses() {
|
||||
let sidebarClasses = [];
|
||||
if (this.showNav) {
|
||||
sidebarClasses.push('is-expanded');
|
||||
}
|
||||
|
||||
if (this.sidebarCoversEntries) {
|
||||
sidebarClasses.push('c-drawer--overlays');
|
||||
} else {
|
||||
sidebarClasses.push('c-drawer--push');
|
||||
}
|
||||
|
||||
return sidebarClasses;
|
||||
},
|
||||
showLockButton() {
|
||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
||||
|
||||
@@ -300,16 +314,14 @@ export default {
|
||||
window.addEventListener('orientationchange', this.formatSidebar);
|
||||
window.addEventListener('hashchange', this.setSectionAndPageFromUrl);
|
||||
this.filterAndSortEntries();
|
||||
this.unobserveEntries = this.openmct.objects.observe(this.domainObject, '*', this.filterAndSortEntries);
|
||||
this.startObservingEntries();
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.unlisten) {
|
||||
this.unlisten();
|
||||
}
|
||||
|
||||
if (this.unobserveEntries) {
|
||||
this.unobserveEntries();
|
||||
}
|
||||
this.stopObservingEntries();
|
||||
|
||||
Object.keys(this.notebookAnnotations).forEach(entryID => {
|
||||
const notebookAnnotationsForEntry = this.notebookAnnotations[entryID];
|
||||
@@ -327,6 +339,17 @@ export default {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
startObservingEntries() {
|
||||
if (this.unobserveEntries) {
|
||||
this.stopObservingEntries();
|
||||
}
|
||||
|
||||
this.unobserveEntries = this.openmct.objects.observe(this.domainObject, '*', this.filterAndSortEntries);
|
||||
},
|
||||
stopObservingEntries() {
|
||||
this.unobserveEntries();
|
||||
delete this.unobserveEntries;
|
||||
},
|
||||
changeSectionPage(newParams, oldParams, changedParams) {
|
||||
if (isNotebookViewType(newParams.view)) {
|
||||
return;
|
||||
@@ -749,6 +772,7 @@ export default {
|
||||
return section.id;
|
||||
},
|
||||
async newEntry(embed = null) {
|
||||
this.startTransaction();
|
||||
this.resetSearch();
|
||||
const notebookStorage = this.createNotebookStorageObject();
|
||||
this.updateDefaultNotebook(notebookStorage);
|
||||
@@ -835,21 +859,21 @@ export default {
|
||||
|
||||
setDefaultNotebookSectionId(defaultNotebookSectionId);
|
||||
},
|
||||
updateEntry(entry) {
|
||||
async updateEntry(entry) {
|
||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
||||
const entryPos = getEntryPosById(entry.id, this.domainObject, this.selectedSection, this.selectedPage);
|
||||
entries[entryPos] = entry;
|
||||
|
||||
this.updateEntries(entries);
|
||||
await this.updateEntries(entries);
|
||||
},
|
||||
updateEntries(entries) {
|
||||
async updateEntries(entries) {
|
||||
const configuration = this.domainObject.configuration;
|
||||
const notebookEntries = configuration.entries || {};
|
||||
notebookEntries[this.selectedSection.id][this.selectedPage.id] = entries;
|
||||
|
||||
mutateObject(this.openmct, this.domainObject, 'configuration.entries', notebookEntries);
|
||||
|
||||
this.saveTransaction();
|
||||
await this.saveTransaction();
|
||||
},
|
||||
getPageIdFromUrl() {
|
||||
return this.openmct.router.getParams().pageId;
|
||||
@@ -891,20 +915,36 @@ export default {
|
||||
},
|
||||
startTransaction() {
|
||||
if (!this.openmct.objects.isTransactionActive()) {
|
||||
this.stopObservingEntries();
|
||||
this.transaction = this.openmct.objects.startTransaction();
|
||||
}
|
||||
},
|
||||
async saveTransaction() {
|
||||
if (this.transaction !== undefined) {
|
||||
await this.transaction.commit();
|
||||
this.openmct.objects.endTransaction();
|
||||
try {
|
||||
await this.transaction.commit();
|
||||
} catch (error) {
|
||||
console.warn('Error saving Notebook transaction', error);
|
||||
} finally {
|
||||
this.endTransaction();
|
||||
}
|
||||
}
|
||||
},
|
||||
async cancelTransaction() {
|
||||
if (this.transaction !== undefined) {
|
||||
await this.transaction.cancel();
|
||||
this.openmct.objects.endTransaction();
|
||||
try {
|
||||
await this.transaction.cancel();
|
||||
} catch (error) {
|
||||
console.warn('Error canceling Notebook transaction', error);
|
||||
} finally {
|
||||
this.endTransaction();
|
||||
}
|
||||
}
|
||||
},
|
||||
endTransaction() {
|
||||
this.openmct.objects.endTransaction();
|
||||
this.transaction = undefined;
|
||||
this.startObservingEntries();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,21 +74,25 @@ async function resolveNotebookTagConflicts(localAnnotation, openmct) {
|
||||
|
||||
async function resolveNotebookEntryConflicts(localMutable, openmct) {
|
||||
if (localMutable.configuration.entries) {
|
||||
const FORCE_REMOTE = true;
|
||||
const localEntries = structuredClone(localMutable.configuration.entries);
|
||||
const remoteMutable = await openmct.objects.getMutable(localMutable.identifier);
|
||||
applyLocalEntries(remoteMutable, localEntries, openmct);
|
||||
openmct.objects.destroyMutable(remoteMutable);
|
||||
const remoteObject = await openmct.objects.get(localMutable.identifier, undefined, FORCE_REMOTE);
|
||||
|
||||
return applyLocalEntries(remoteObject, localEntries, openmct);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function applyLocalEntries(mutable, entries, openmct) {
|
||||
function applyLocalEntries(remoteObject, entries, openmct) {
|
||||
let shouldSave = false;
|
||||
|
||||
Object.entries(entries).forEach(([sectionKey, pagesInSection]) => {
|
||||
Object.entries(pagesInSection).forEach(([pageKey, localEntries]) => {
|
||||
const remoteEntries = mutable.configuration.entries[sectionKey][pageKey];
|
||||
const remoteEntries = remoteObject.configuration.entries[sectionKey][pageKey];
|
||||
const mergedEntries = [].concat(remoteEntries);
|
||||
let shouldMutate = false;
|
||||
console.log('merging after conflict, remote, local', remoteEntries, entries);
|
||||
|
||||
const locallyAddedEntries = _.differenceBy(localEntries, remoteEntries, 'id');
|
||||
const locallyModifiedEntries = _.differenceWith(localEntries, remoteEntries, (localEntry, remoteEntry) => {
|
||||
@@ -108,10 +112,17 @@ function applyLocalEntries(mutable, entries, openmct) {
|
||||
shouldMutate = true;
|
||||
}
|
||||
});
|
||||
|
||||
console.log('merged entries', mergedEntries);
|
||||
if (shouldMutate) {
|
||||
openmct.objects.mutate(mutable, `configuration.entries.${sectionKey}.${pageKey}`, mergedEntries);
|
||||
shouldSave = true;
|
||||
openmct.objects.mutate(remoteObject, `configuration.entries.${sectionKey}.${pageKey}`, mergedEntries);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (shouldSave) {
|
||||
return openmct.objects.save(remoteObject);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ export default function () {
|
||||
}
|
||||
|
||||
let wrappedFunction = openmct.objects.get;
|
||||
openmct.objects.get = function migrate(identifier) {
|
||||
return wrappedFunction.apply(openmct.objects, [identifier])
|
||||
openmct.objects.get = function migrate() {
|
||||
return wrappedFunction.apply(openmct.objects, [...arguments])
|
||||
.then(function (object) {
|
||||
if (needsMigration(object)) {
|
||||
migrateObject(object)
|
||||
|
||||
@@ -219,7 +219,12 @@ class CouchObjectProvider {
|
||||
console.error(error.message);
|
||||
throw new Error(`CouchDB Error - No response"`);
|
||||
} else {
|
||||
console.error(error.message);
|
||||
if (!isNotebookOrAnnotationType(body.model)) {
|
||||
console.error(error.message);
|
||||
} else {
|
||||
// warn since we handle conflicts for notebooks
|
||||
console.warn(error.message);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
@@ -554,8 +559,9 @@ class CouchObjectProvider {
|
||||
let observersForObject = this.observers[keyString];
|
||||
|
||||
if (observersForObject) {
|
||||
const FORCE_REMOTE = true;
|
||||
observersForObject.forEach(async (observer) => {
|
||||
const updatedObject = await this.get(identifier);
|
||||
const updatedObject = await this.get(identifier, undefined, FORCE_REMOTE);
|
||||
if (this.isSynchronizedObject(updatedObject)) {
|
||||
observer(updatedObject);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user