Compare commits
4 Commits
fix-duplic
...
notebook-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ade4d6f77a | ||
|
|
80d4c10fea | ||
|
|
aa6d509fde | ||
|
|
a1c6168c91 |
@@ -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());
|
||||
|
||||
@@ -187,7 +187,7 @@ export default class ObjectAPI {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get a domain object.
|
||||
* Force remote get for a domain object. Don't return dirty objects.
|
||||
*
|
||||
* @method get
|
||||
* @memberof module:openmct.ObjectProvider#
|
||||
@@ -196,23 +196,8 @@ 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) {
|
||||
let keystring = this.makeKeyString(identifier);
|
||||
|
||||
if (this.cache[keystring] !== undefined) {
|
||||
return this.cache[keystring];
|
||||
}
|
||||
|
||||
identifier = utils.parseKeyString(identifier);
|
||||
|
||||
if (this.isTransactionActive()) {
|
||||
let dirtyObject = this.transaction.getDirtyObject(identifier);
|
||||
|
||||
if (dirtyObject) {
|
||||
return Promise.resolve(dirtyObject);
|
||||
}
|
||||
}
|
||||
|
||||
remoteGet(identifier, abortSignal) {
|
||||
const keystring = this.makeKeyString(identifier);
|
||||
const provider = this.getProvider(identifier);
|
||||
|
||||
if (!provider) {
|
||||
@@ -225,7 +210,6 @@ export default class ObjectAPI {
|
||||
|
||||
let objectPromise = provider.get(identifier, abortSignal).then(result => {
|
||||
delete this.cache[keystring];
|
||||
|
||||
result = this.applyGetInterceptors(identifier, result);
|
||||
if (result.isMutable) {
|
||||
result.$refresh(result);
|
||||
@@ -250,6 +234,36 @@ export default class ObjectAPI {
|
||||
return objectPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a domain object.
|
||||
*
|
||||
* @method get
|
||||
* @memberof module:openmct.ObjectProvider#
|
||||
* @param {string} key the key for the domain object to load
|
||||
* @param {AbortController.signal} abortSignal (optional) signal to abort fetch requests
|
||||
* @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) {
|
||||
const keystring = this.makeKeyString(identifier);
|
||||
|
||||
if (this.cache[keystring] !== undefined) {
|
||||
return this.cache[keystring];
|
||||
}
|
||||
|
||||
identifier = utils.parseKeyString(identifier);
|
||||
|
||||
if (this.isTransactionActive()) {
|
||||
let dirtyObject = this.transaction.getDirtyObject(identifier);
|
||||
|
||||
if (dirtyObject) {
|
||||
return Promise.resolve(dirtyObject);
|
||||
}
|
||||
}
|
||||
|
||||
return this.remoteGet(identifier, abortSignal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for domain objects.
|
||||
*
|
||||
@@ -355,6 +369,7 @@ export default class ObjectAPI {
|
||||
* has been saved, or be rejected if it cannot be saved
|
||||
*/
|
||||
async save(domainObject) {
|
||||
console.log('save', JSON.parse(JSON.stringify(domainObject)));
|
||||
const provider = this.getProvider(domainObject.identifier);
|
||||
let result;
|
||||
let lastPersistedTime;
|
||||
@@ -399,7 +414,7 @@ export default class ObjectAPI {
|
||||
savedObjectPromise.then(response => {
|
||||
savedResolve(response);
|
||||
}).catch((error) => {
|
||||
if (lastPersistedTime !== undefined) {
|
||||
if (!isNewObject) {
|
||||
this.#mutate(domainObject, 'persisted', lastPersistedTime);
|
||||
}
|
||||
|
||||
@@ -411,7 +426,9 @@ export default class ObjectAPI {
|
||||
}
|
||||
|
||||
return result.catch((error) => {
|
||||
if (error instanceof this.errors.Conflict) {
|
||||
// suppress conflict error notifications for remotely synced items
|
||||
// (possibly just for notebook and restricted-notebook as they have conflic resolution)
|
||||
if (error instanceof this.errors.Conflict && !this.SYNCHRONIZED_OBJECT_TYPES.includes(domainObject.type)) {
|
||||
this.openmct.notifications.error(`Conflict detected while saving ${this.makeKeyString(domainObject.identifier)}`);
|
||||
}
|
||||
|
||||
@@ -559,6 +576,7 @@ export default class ObjectAPI {
|
||||
this.#mutate(domainObject, path, value);
|
||||
|
||||
if (this.isTransactionActive()) {
|
||||
console.log('objectAPI: mutate', JSON.parse(JSON.stringify(domainObject)), path, value);
|
||||
this.transaction.add(domainObject);
|
||||
} else {
|
||||
this.save(domainObject);
|
||||
@@ -590,6 +608,7 @@ export default class ObjectAPI {
|
||||
let unobserve = provider.observe(identifier, (updatedModel) => {
|
||||
// modified can sometimes be undefined, so make it 0 in this case
|
||||
const mutableObjectModification = mutableObject.modified ?? Number.MIN_SAFE_INTEGER;
|
||||
|
||||
if (updatedModel.persisted > mutableObjectModification) {
|
||||
//Don't replace with a stale model. This can happen on slow connections when multiple mutations happen
|
||||
//in rapid succession and intermediate persistence states are returned by the observe function.
|
||||
|
||||
@@ -41,6 +41,7 @@ export default class Transaction {
|
||||
const save = this.objectAPI.save.bind(this.objectAPI);
|
||||
|
||||
Object.values(this.dirtyObjects).forEach(object => {
|
||||
console.log('transaction: commit, objects', object);
|
||||
promiseArray.push(this.createDirtyObjectPromise(object, save));
|
||||
});
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -69,6 +69,7 @@
|
||||
@toggleNav="toggleNav"
|
||||
/>
|
||||
<div class="c-notebook__page-view">
|
||||
|
||||
<div class="c-notebook__page-view__header">
|
||||
<button
|
||||
class="c-notebook__toggle-nav-button c-icon-button c-icon-button--major icon-menu-hamburger"
|
||||
@@ -124,6 +125,7 @@
|
||||
<div
|
||||
v-if="selectedPage && !selectedPage.isLocked"
|
||||
class="c-notebook__drag-area icon-plus"
|
||||
:class="{ 'disabled': activeTransaction }"
|
||||
@click="newEntry()"
|
||||
@dragover="dragOver"
|
||||
@drop.capture="dropCapture"
|
||||
@@ -133,6 +135,11 @@
|
||||
To start a new entry, click here or drag and drop any object
|
||||
</span>
|
||||
</div>
|
||||
<progress-bar
|
||||
v-if="savingTransaction"
|
||||
class="c-telemetry-table__progress-bar"
|
||||
:model="{ progressPerc: undefined }"
|
||||
/>
|
||||
<div
|
||||
v-if="selectedPage && selectedPage.isLocked"
|
||||
class="c-notebook__page-locked"
|
||||
@@ -183,6 +190,7 @@ import NotebookEntry from './NotebookEntry.vue';
|
||||
import Search from '@/ui/components/search.vue';
|
||||
import SearchResults from './SearchResults.vue';
|
||||
import Sidebar from './Sidebar.vue';
|
||||
import ProgressBar from '../../../ui/components/ProgressBar.vue';
|
||||
import { clearDefaultNotebook, getDefaultNotebook, setDefaultNotebook, setDefaultNotebookSectionId, setDefaultNotebookPageId } from '../utils/notebook-storage';
|
||||
import { addNotebookEntry, createNewEmbed, getEntryPosById, getNotebookEntries, mutateObject } from '../utils/notebook-entries';
|
||||
import { saveNotebookImageDomainObject, updateNamespaceOfDomainObject } from '../utils/notebook-image';
|
||||
@@ -200,7 +208,8 @@ export default {
|
||||
NotebookEntry,
|
||||
Search,
|
||||
SearchResults,
|
||||
Sidebar
|
||||
Sidebar,
|
||||
ProgressBar
|
||||
},
|
||||
inject: ['agent', 'openmct', 'snapshotContainer'],
|
||||
props: {
|
||||
@@ -225,7 +234,9 @@ export default {
|
||||
showNav: false,
|
||||
sidebarCoversEntries: false,
|
||||
filteredAndSortedEntries: [],
|
||||
notebookAnnotations: {}
|
||||
notebookAnnotations: {},
|
||||
activeTransaction: false,
|
||||
savingTransaction: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -274,9 +285,27 @@ export default {
|
||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
||||
|
||||
return entries && entries.length > 0 && this.isRestricted && !this.selectedPage.isLocked;
|
||||
},
|
||||
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;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeTransaction() {
|
||||
console.log('Active Transaction changed', this.activeTransaction);
|
||||
},
|
||||
search() {
|
||||
this.getSearchResults();
|
||||
},
|
||||
@@ -300,7 +329,7 @@ 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) {
|
||||
@@ -327,6 +356,12 @@ export default {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
startObservingEntries() {
|
||||
this.unobserveEntries = this.openmct.objects.observe(this.domainObject, '*', this.filterAndSortEntries);
|
||||
},
|
||||
stopObservingEntries() {
|
||||
this.unobserveEntries();
|
||||
},
|
||||
changeSectionPage(newParams, oldParams, changedParams) {
|
||||
if (isNotebookViewType(newParams.view)) {
|
||||
return;
|
||||
@@ -496,10 +531,10 @@ export default {
|
||||
{
|
||||
label: "Ok",
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
callback: async () => {
|
||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
||||
entries.splice(entryPos, 1);
|
||||
this.updateEntries(entries);
|
||||
await this.updateEntries(entries);
|
||||
this.filterAndSortEntries();
|
||||
this.removeAnnotations(entryId);
|
||||
dialog.dismiss();
|
||||
@@ -749,10 +784,12 @@ export default {
|
||||
return section.id;
|
||||
},
|
||||
async newEntry(embed = null) {
|
||||
this.startTransaction();
|
||||
this.resetSearch();
|
||||
const notebookStorage = this.createNotebookStorageObject();
|
||||
this.updateDefaultNotebook(notebookStorage);
|
||||
const id = await addNotebookEntry(this.openmct, this.domainObject, notebookStorage, embed);
|
||||
console.log('newEntry, id, entries', id, JSON.parse(JSON.stringify(this.domainObject.configuration.entries)));
|
||||
this.focusEntryId = id;
|
||||
this.filterAndSortEntries();
|
||||
},
|
||||
@@ -835,21 +872,23 @@ export default {
|
||||
|
||||
setDefaultNotebookSectionId(defaultNotebookSectionId);
|
||||
},
|
||||
updateEntry(entry) {
|
||||
async updateEntry(entry) {
|
||||
console.log('update entry', entry);
|
||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
||||
const entryPos = getEntryPosById(entry.id, this.domainObject, this.selectedSection, this.selectedPage);
|
||||
console.log('entry pos', entry, entryPos);
|
||||
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;
|
||||
@@ -890,21 +929,45 @@ export default {
|
||||
this.filterAndSortEntries();
|
||||
},
|
||||
startTransaction() {
|
||||
console.log('notebook: startTransaction');
|
||||
if (!this.openmct.objects.isTransactionActive()) {
|
||||
this.stopObservingEntries();
|
||||
this.activeTransaction = true;
|
||||
console.log('notebook: startTransaction - starting a new transaction');
|
||||
this.transaction = this.openmct.objects.startTransaction();
|
||||
}
|
||||
},
|
||||
async saveTransaction() {
|
||||
if (this.transaction !== undefined) {
|
||||
await this.transaction.commit();
|
||||
this.openmct.objects.endTransaction();
|
||||
console.log('notebook: saveTransaction');
|
||||
if (this.activeTransaction) {
|
||||
this.savingTransaction = true;
|
||||
console.log('notebook: saveTransaction - saving a transaction');
|
||||
|
||||
try {
|
||||
await this.transaction.commit();
|
||||
} catch (error) {
|
||||
console.log('error committing', error);
|
||||
}
|
||||
|
||||
console.log('notebook: saveTransaction - done saving');
|
||||
this.endTransaction();
|
||||
}
|
||||
},
|
||||
async cancelTransaction() {
|
||||
if (this.transaction !== undefined) {
|
||||
console.log('notebook: cancelTransaction');
|
||||
if (this.activeTransaction) {
|
||||
this.savingTransaction = true;
|
||||
console.log('notebook: cancelTransaction - canceling a transaction');
|
||||
await this.transaction.cancel();
|
||||
this.openmct.objects.endTransaction();
|
||||
this.endTransaction();
|
||||
}
|
||||
},
|
||||
endTransaction() {
|
||||
this.openmct.objects.endTransaction();
|
||||
this.activeTransaction = false;
|
||||
this.transaction = undefined;
|
||||
this.savingTransaction = false;
|
||||
this.startObservingEntries();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -283,7 +283,7 @@ export default {
|
||||
await this.addNewEmbed(objectPath);
|
||||
}
|
||||
|
||||
this.timestampAndUpdate();
|
||||
await this.timestampAndUpdate();
|
||||
},
|
||||
findPositionInArray(array, id) {
|
||||
let position = -1;
|
||||
@@ -316,14 +316,14 @@ export default {
|
||||
pageId: null
|
||||
});
|
||||
},
|
||||
removeEmbed(id) {
|
||||
async removeEmbed(id) {
|
||||
const embedPosition = this.findPositionInArray(this.entry.embeds, id);
|
||||
// TODO: remove notebook snapshot object using object remove API
|
||||
this.entry.embeds.splice(embedPosition, 1);
|
||||
|
||||
this.timestampAndUpdate();
|
||||
await this.timestampAndUpdate();
|
||||
},
|
||||
updateEmbed(newEmbed) {
|
||||
async updateEmbed(newEmbed) {
|
||||
this.entry.embeds.some(e => {
|
||||
const found = (e.id === newEmbed.id);
|
||||
if (found) {
|
||||
@@ -333,7 +333,7 @@ export default {
|
||||
return found;
|
||||
});
|
||||
|
||||
this.timestampAndUpdate();
|
||||
await this.timestampAndUpdate();
|
||||
},
|
||||
async timestampAndUpdate() {
|
||||
const user = await this.openmct.user.getCurrentUser();
|
||||
@@ -347,14 +347,17 @@ export default {
|
||||
this.$emit('updateEntry', this.entry);
|
||||
},
|
||||
editingEntry() {
|
||||
console.log('nb entry: editingEntry');
|
||||
this.$emit('editingEntry');
|
||||
},
|
||||
updateEntryValue($event) {
|
||||
async updateEntryValue($event) {
|
||||
const value = $event.target.innerText;
|
||||
if (value !== this.entry.text && value.match(/\S/)) {
|
||||
console.log('nb entry: updateEntryValue - prev val is empty, new val', this.entry.text === '', value);
|
||||
this.entry.text = value;
|
||||
this.timestampAndUpdate();
|
||||
await this.timestampAndUpdate();
|
||||
} else {
|
||||
console.log('nb entry: updateEntryValue, same value not updating');
|
||||
this.$emit('cancelEdit');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,43 +4,52 @@ import _ from 'lodash';
|
||||
export default function (openmct) {
|
||||
const apiSave = openmct.objects.save.bind(openmct.objects);
|
||||
|
||||
openmct.objects.save = async (domainObject) => {
|
||||
if (!isNotebookOrAnnotationType(domainObject)) {
|
||||
return apiSave(domainObject);
|
||||
openmct.objects.save = async (saveObject) => {
|
||||
let domainObject = cloneObject(saveObject);
|
||||
if (!isNotebookOrAnnotationType(saveObject)) {
|
||||
return apiSave(saveObject);
|
||||
}
|
||||
|
||||
const isNewMutable = !domainObject.isMutable;
|
||||
const localMutable = openmct.objects.toMutable(domainObject);
|
||||
// const isNewMutable = !domainObject.isMutable;
|
||||
// const localMutable = openmct.objects.toMutable(domainObject);
|
||||
let result;
|
||||
|
||||
try {
|
||||
result = await apiSave(localMutable);
|
||||
console.log('monkeypatch save');
|
||||
result = await apiSave(saveObject);
|
||||
// result = await apiSave(localMutable);
|
||||
} catch (error) {
|
||||
console.log('monkeypatch save error', error);
|
||||
if (error instanceof openmct.objects.errors.Conflict) {
|
||||
result = await resolveConflicts(domainObject, localMutable, openmct);
|
||||
console.log('we got ourselves a conflict');
|
||||
result = await resolveConflicts(domainObject, openmct);
|
||||
// result = await resolveConflicts(domainObject, localMutable, openmct);
|
||||
} else {
|
||||
result = Promise.reject(error);
|
||||
}
|
||||
} finally {
|
||||
if (isNewMutable) {
|
||||
openmct.objects.destroyMutable(localMutable);
|
||||
}
|
||||
// if (isNewMutable) {
|
||||
// openmct.objects.destroyMutable(localMutable);
|
||||
// }
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function resolveConflicts(domainObject, localMutable, openmct) {
|
||||
// function resolveConflicts(domainObject, localMutable, openmct) {
|
||||
function resolveConflicts(domainObject, openmct) {
|
||||
if (isNotebookType(domainObject)) {
|
||||
return resolveNotebookEntryConflicts(localMutable, openmct);
|
||||
return resolveNotebookEntryConflicts(domainObject, openmct);
|
||||
// return resolveNotebookEntryConflicts(localMutable, openmct);
|
||||
} else if (isAnnotationType(domainObject)) {
|
||||
return resolveNotebookTagConflicts(localMutable, openmct);
|
||||
return resolveNotebookTagConflicts(domainObject, openmct);
|
||||
// return resolveNotebookTagConflicts(localMutable, openmct);
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveNotebookTagConflicts(localAnnotation, openmct) {
|
||||
const localClonedAnnotation = structuredClone(localAnnotation);
|
||||
const localClonedAnnotation = cloneObject(localAnnotation);
|
||||
const remoteMutable = await openmct.objects.getMutable(localClonedAnnotation.identifier);
|
||||
|
||||
// should only be one annotation per targetID, entryID, and tag; so for sanity, ensure we have the
|
||||
@@ -72,32 +81,40 @@ async function resolveNotebookTagConflicts(localAnnotation, openmct) {
|
||||
return true;
|
||||
}
|
||||
|
||||
async function resolveNotebookEntryConflicts(localMutable, openmct) {
|
||||
if (localMutable.configuration.entries) {
|
||||
const localEntries = structuredClone(localMutable.configuration.entries);
|
||||
const remoteMutable = await openmct.objects.getMutable(localMutable.identifier);
|
||||
applyLocalEntries(remoteMutable, localEntries, openmct);
|
||||
openmct.objects.destroyMutable(remoteMutable);
|
||||
// async function resolveNotebookEntryConflicts(localMutable, openmct) {
|
||||
async function resolveNotebookEntryConflicts(domainObject, openmct) {
|
||||
if (domainObject.configuration.entries) {
|
||||
// if (localMutable.configuration.entries) {
|
||||
// const localEntries = structuredClone(localMutable.configuration.entries);
|
||||
// const remoteObject = await openmct.objects.remoteGet(localMutable.identifier);
|
||||
const localEntries = domainObject.configuration.entries;
|
||||
const remoteObject = await openmct.objects.remoteGet(domainObject.identifier);
|
||||
|
||||
return applyLocalEntries(remoteObject, localEntries, openmct);
|
||||
// openmct.objects.destroyMutable(remoteMutable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function applyLocalEntries(mutable, entries, openmct) {
|
||||
function applyLocalEntries(remoteObject, entries, openmct) {
|
||||
console.log('apply local entries', entries, 'and remote entries', remoteObject.configuration.entries);
|
||||
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;
|
||||
let shouldSave = false;
|
||||
|
||||
const locallyAddedEntries = _.differenceBy(localEntries, remoteEntries, 'id');
|
||||
const locallyModifiedEntries = _.differenceWith(localEntries, remoteEntries, (localEntry, remoteEntry) => {
|
||||
return localEntry.id === remoteEntry.id && localEntry.text === remoteEntry.text;
|
||||
});
|
||||
|
||||
console.log('locally added', locallyAddedEntries);
|
||||
console.log('locally modified', locallyModifiedEntries);
|
||||
locallyAddedEntries.forEach((localEntry) => {
|
||||
mergedEntries.push(localEntry);
|
||||
shouldMutate = true;
|
||||
shouldSave = true;
|
||||
});
|
||||
|
||||
locallyModifiedEntries.forEach((locallyModifiedEntry) => {
|
||||
@@ -105,13 +122,25 @@ function applyLocalEntries(mutable, entries, openmct) {
|
||||
if (mergedEntry !== undefined
|
||||
&& locallyModifiedEntry.text.match(/\S/)) {
|
||||
mergedEntry.text = locallyModifiedEntry.text;
|
||||
shouldMutate = true;
|
||||
shouldSave = true;
|
||||
}
|
||||
});
|
||||
console.log('mergedEntries', mergedEntries);
|
||||
|
||||
if (shouldMutate) {
|
||||
openmct.objects.mutate(mutable, `configuration.entries.${sectionKey}.${pageKey}`, mergedEntries);
|
||||
if (shouldSave) {
|
||||
remoteObject.configuration.entries = mergedEntries;
|
||||
console.log('save this one', remoteObject);
|
||||
return openmct.objects.save(remoteObject);
|
||||
// openmct.objects.save(remoteObject, `configuration.entries.${sectionKey}.${pageKey}`, mergedEntries);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cloneObject(object) {
|
||||
if (typeof window.structuredClone === 'function') {
|
||||
return structuredClone(object);
|
||||
} else {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ class CouchObjectProvider {
|
||||
if (observersForObject) {
|
||||
observersForObject.forEach(async (observer) => {
|
||||
const updatedObject = await this.get(objectIdentifier);
|
||||
|
||||
if (this.isSynchronizedObject(updatedObject)) {
|
||||
observer(updatedObject);
|
||||
}
|
||||
@@ -184,6 +185,7 @@ class CouchObjectProvider {
|
||||
}
|
||||
|
||||
async request(subPath, method, body, signal) {
|
||||
console.log('couchobjectprovider.js: request', subPath, method, body, signal);
|
||||
let fetchOptions = {
|
||||
method,
|
||||
body,
|
||||
@@ -219,7 +221,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;
|
||||
}
|
||||
@@ -234,7 +241,7 @@ class CouchObjectProvider {
|
||||
#handleResponseCode(status, json, fetchOptions) {
|
||||
this.indicator.setIndicatorToState(this.#statusCodeToIndicatorState(status));
|
||||
if (status === CouchObjectProvider.HTTP_CONFLICT) {
|
||||
throw new this.openmct.objects.errors.Conflict(`Conflict persisting ${fetchOptions.body.name}`);
|
||||
throw new this.openmct.objects.errors.Conflict(`Conflict persisting ${JSON.parse(fetchOptions.body).name}`);
|
||||
} else if (status >= CouchObjectProvider.HTTP_BAD_REQUEST) {
|
||||
if (!json.error || !json.reason) {
|
||||
throw new Error(`CouchDB Error ${status}`);
|
||||
@@ -253,7 +260,7 @@ class CouchObjectProvider {
|
||||
*/
|
||||
#checkResponse(response, intermediateResponse, key) {
|
||||
let requestSuccess = false;
|
||||
const id = response ? response.id : undefined;
|
||||
const id = response?.id;
|
||||
let rev;
|
||||
|
||||
if (response && response.ok) {
|
||||
@@ -291,6 +298,13 @@ class CouchObjectProvider {
|
||||
}
|
||||
|
||||
if (isNotebookOrAnnotationType(object)) {
|
||||
// check if the object is currently being edited, if so, don't update revision so a conflict will be thrown
|
||||
// and handled with our notebook conflict resolution
|
||||
if (this.openmct.objects.isTransactionActive()
|
||||
&& this.openmct.objects.transaction.getDirtyObject(object.identifier)) {
|
||||
return object;
|
||||
}
|
||||
|
||||
//Temporary measure until object sync is supported for all object types
|
||||
//Always update notebook revision number because we have realtime sync, so always assume it's the latest.
|
||||
this.objectQueue[key].updateRevision(response[REV]);
|
||||
@@ -684,6 +698,7 @@ class CouchObjectProvider {
|
||||
}
|
||||
|
||||
update(model) {
|
||||
console.log('couchobjectprovider.js: update', model);
|
||||
let intermediateResponse = this.#getIntermediateResponse();
|
||||
const key = model.identifier.key;
|
||||
model = this.toPersistableModel(model);
|
||||
|
||||
Reference in New Issue
Block a user