Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nasa/openmct.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Mazzella <ozyx@users.noreply.github.com>2022-11-03 23:49:03 +0300
committerGitHub <noreply@github.com>2022-11-03 23:49:03 +0300
commit091f6406a87253fec0418f17eee61756527ef9ff (patch)
tree191fa0ee0d9d0f594d37ccc602c6b01e9770a663
parent42a0e503cca5e368022404ef199a7722bb6c00b7 (diff)
Merge `release/2.1.2` into `master` (#5946)
* Bump version to `2.1.2` * Ensure properties stay in sync and are committed only once (#5717) * Ensure form properties stay in sync * Separate out overlay based forms and custom forms * Use a transaction to save properties * Fix GaugeController to not depend on event emitted from FormsAPI * refactor showForms to call showCustomForm Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Henry <akhenry@gmail.com> * Fix persistence timestamp (#5916) * Calculate persisted timestamp last * Added regression tests * Correct transaction handling code * Code cleanup * Fix typo for publish (#5936) * Add e2e tests to npm package (#5930) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Shefali Joshi <simplyrender@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: John Hill <john.c.hill@nasa.gov>
-rw-r--r--.github/workflows/npm-prerelease.yml2
-rw-r--r--.npmignore8
-rw-r--r--src/api/forms/FormsAPI.js96
-rw-r--r--src/api/forms/FormsAPISpec.js2
-rw-r--r--src/api/forms/components/FormProperties.vue6
-rw-r--r--src/api/objects/MutableDomainObject.js11
-rw-r--r--src/api/objects/ObjectAPI.js8
-rw-r--r--src/api/objects/ObjectAPISpec.js29
-rw-r--r--src/api/overlays/Overlay.js13
-rw-r--r--src/api/overlays/OverlayAPI.js2
-rw-r--r--src/plugins/formActions/CreateAction.js32
-rw-r--r--src/plugins/formActions/EditPropertiesAction.js34
-rw-r--r--src/plugins/formActions/pluginSpec.js60
-rw-r--r--src/plugins/gauge/components/GaugeFormController.vue39
-rw-r--r--src/plugins/notebook/components/Notebook.vue30
15 files changed, 216 insertions, 156 deletions
diff --git a/.github/workflows/npm-prerelease.yml b/.github/workflows/npm-prerelease.yml
index b92d21790..0f141e362 100644
--- a/.github/workflows/npm-prerelease.yml
+++ b/.github/workflows/npm-prerelease.yml
@@ -28,6 +28,6 @@ jobs:
node-version: 16
registry-url: https://registry.npmjs.org/
- run: npm install
- - run: npm publish --access public --tag unstable
+ - run: npm publish --access=public --tag unstable
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.npmignore b/.npmignore
index 57b7d8d12..1bdde6a5f 100644
--- a/.npmignore
+++ b/.npmignore
@@ -21,4 +21,10 @@
!copyright-notice.html
!index.html
!openmct.js
-!SECURITY.md \ No newline at end of file
+!SECURITY.md
+
+# Add e2e tests to npm package
+!/e2e/**/*
+
+# ... except our test-data folder files.
+/e2e/test-data/*.json
diff --git a/src/api/forms/FormsAPI.js b/src/api/forms/FormsAPI.js
index c0bdc78c6..95fc6a3f7 100644
--- a/src/api/forms/FormsAPI.js
+++ b/src/api/forms/FormsAPI.js
@@ -23,13 +23,11 @@
import FormController from './FormController';
import FormProperties from './components/FormProperties.vue';
-import EventEmitter from 'EventEmitter';
import Vue from 'vue';
+import _ from 'lodash';
-export default class FormsAPI extends EventEmitter {
+export default class FormsAPI {
constructor(openmct) {
- super();
-
this.openmct = openmct;
this.formController = new FormController(openmct);
}
@@ -92,29 +90,75 @@ export default class FormsAPI extends EventEmitter {
/**
* Show form inside an Overlay dialog with given form structure
+ * @public
+ * @param {Array<Section>} formStructure a form structure, array of section
+ * @param {Object} options
+ * @property {function} onChange a callback function when any changes detected
+ */
+ showForm(formStructure, {
+ onChange
+ } = {}) {
+ let overlay;
+
+ const self = this;
+
+ const overlayEl = document.createElement('div');
+ overlayEl.classList.add('u-contents');
+
+ overlay = self.openmct.overlays.overlay({
+ element: overlayEl,
+ size: 'dialog'
+ });
+
+ let formSave;
+ let formCancel;
+ const promise = new Promise((resolve, reject) => {
+ formSave = resolve;
+ formCancel = reject;
+ });
+
+ this.showCustomForm(formStructure, {
+ element: overlayEl,
+ onChange
+ })
+ .then((response) => {
+ overlay.dismiss();
+ formSave(response);
+ })
+ .catch((response) => {
+ overlay.dismiss();
+ formCancel(response);
+ });
+
+ return promise;
+ }
+
+ /**
+ * Show form as a child of the element provided with given form structure
*
* @public
* @param {Array<Section>} formStructure a form structure, array of section
* @param {Object} options
* @property {HTMLElement} element Parent Element to render a Form
* @property {function} onChange a callback function when any changes detected
- * @property {function} onSave a callback function when form is submitted
- * @property {function} onDismiss a callback function when form is dismissed
*/
- showForm(formStructure, {
+ showCustomForm(formStructure, {
element,
onChange
} = {}) {
- const changes = {};
- let overlay;
- let onDismiss;
- let onSave;
+ if (element === undefined) {
+ throw Error('Required element parameter not provided');
+ }
const self = this;
+ const changes = {};
+ let formSave;
+ let formCancel;
+
const promise = new Promise((resolve, reject) => {
- onSave = onFormAction(resolve);
- onDismiss = onFormAction(reject);
+ formSave = onFormAction(resolve);
+ formCancel = onFormAction(reject);
});
const vm = new Vue({
@@ -126,26 +170,17 @@ export default class FormsAPI extends EventEmitter {
return {
formStructure,
onChange: onFormPropertyChange,
- onDismiss,
- onSave
+ onCancel: formCancel,
+ onSave: formSave
};
},
- template: '<FormProperties :model="formStructure" @onChange="onChange" @onDismiss="onDismiss" @onSave="onSave"></FormProperties>'
+ template: '<FormProperties :model="formStructure" @onChange="onChange" @onCancel="onCancel" @onSave="onSave"></FormProperties>'
}).$mount();
const formElement = vm.$el;
- if (element) {
- element.append(formElement);
- } else {
- overlay = self.openmct.overlays.overlay({
- element: vm.$el,
- size: 'dialog',
- onDestroy: () => vm.$destroy()
- });
- }
+ element.append(formElement);
function onFormPropertyChange(data) {
- self.emit('onFormPropertyChange', data);
if (onChange) {
onChange(data);
}
@@ -158,17 +193,14 @@ export default class FormsAPI extends EventEmitter {
key = property.join('.');
}
- changes[key] = data.value;
+ _.set(changes, key, data.value);
}
}
function onFormAction(callback) {
return () => {
- if (element) {
- formElement.remove();
- } else {
- overlay.dismiss();
- }
+ formElement.remove();
+ vm.$destroy();
if (callback) {
callback(changes);
diff --git a/src/api/forms/FormsAPISpec.js b/src/api/forms/FormsAPISpec.js
index ac7f0fc9f..362e398da 100644
--- a/src/api/forms/FormsAPISpec.js
+++ b/src/api/forms/FormsAPISpec.js
@@ -133,7 +133,7 @@ describe('The Forms API', () => {
});
it('when container element is provided', (done) => {
- openmct.forms.showForm(formStructure, { element }).catch(() => {
+ openmct.forms.showCustomForm(formStructure, { element }).catch(() => {
done();
});
const titleElement = element.querySelector('.c-overlay__dialog-title');
diff --git a/src/api/forms/components/FormProperties.vue b/src/api/forms/components/FormProperties.vue
index 2ca84d0a7..9f631e108 100644
--- a/src/api/forms/components/FormProperties.vue
+++ b/src/api/forms/components/FormProperties.vue
@@ -73,7 +73,7 @@
tabindex="0"
class="c-button js-cancel-button"
aria-label="Cancel"
- @click="onDismiss"
+ @click="onCancel"
>
{{ cancelLabel }}
</button>
@@ -164,8 +164,8 @@ export default {
this.$emit('onChange', data);
},
- onDismiss() {
- this.$emit('onDismiss');
+ onCancel() {
+ this.$emit('onCancel');
},
onSave() {
this.$emit('onSave');
diff --git a/src/api/objects/MutableDomainObject.js b/src/api/objects/MutableDomainObject.js
index 046f8b069..df0965d3b 100644
--- a/src/api/objects/MutableDomainObject.js
+++ b/src/api/objects/MutableDomainObject.js
@@ -75,11 +75,7 @@ class MutableDomainObject {
return eventOff;
}
$set(path, value) {
- _.set(this, path, value);
-
- if (path !== 'persisted' && path !== 'modified') {
- _.set(this, 'modified', Date.now());
- }
+ MutableDomainObject.mutateObject(this, path, value);
//Emit secret synchronization event first, so that all objects are in sync before subsequent events fired.
this._globalEventEmitter.emit(qualifiedEventName(this, '$_synchronize_model'), this);
@@ -136,8 +132,11 @@ class MutableDomainObject {
}
static mutateObject(object, path, value) {
+ if (path !== 'persisted') {
+ _.set(object, 'modified', Date.now());
+ }
+
_.set(object, path, value);
- _.set(object, 'modified', Date.now());
}
}
diff --git a/src/api/objects/ObjectAPI.js b/src/api/objects/ObjectAPI.js
index 0ebeba5da..986644350 100644
--- a/src/api/objects/ObjectAPI.js
+++ b/src/api/objects/ObjectAPI.js
@@ -363,7 +363,6 @@ export default class ObjectAPI {
} else if (this.#hasAlreadyBeenPersisted(domainObject)) {
result = Promise.resolve(true);
} else {
- const persistedTime = Date.now();
const username = await this.#getCurrentUsername();
const isNewObject = domainObject.persisted === undefined;
let savedResolve;
@@ -375,15 +374,20 @@ export default class ObjectAPI {
savedReject = reject;
});
- this.#mutate(domainObject, 'persisted', persistedTime);
this.#mutate(domainObject, 'modifiedBy', username);
if (isNewObject) {
+ const persistedTime = Date.now();
+
+ this.#mutate(domainObject, 'persisted', persistedTime);
this.#mutate(domainObject, 'created', persistedTime);
this.#mutate(domainObject, 'createdBy', username);
savedObjectPromise = provider.create(domainObject);
} else {
+ const persistedTime = Date.now();
+ this.#mutate(domainObject, 'persisted', persistedTime);
+
savedObjectPromise = provider.update(domainObject);
}
diff --git a/src/api/objects/ObjectAPISpec.js b/src/api/objects/ObjectAPISpec.js
index c15b3c7db..6940b7426 100644
--- a/src/api/objects/ObjectAPISpec.js
+++ b/src/api/objects/ObjectAPISpec.js
@@ -94,6 +94,35 @@ describe("The Object API", () => {
expect(mockProvider.create).not.toHaveBeenCalled();
expect(mockProvider.update).toHaveBeenCalled();
});
+ describe("the persisted timestamp for existing objects", () => {
+ let persistedTimestamp;
+ beforeEach(() => {
+ persistedTimestamp = Date.now() - FIFTEEN_MINUTES;
+ mockDomainObject.persisted = persistedTimestamp;
+ mockDomainObject.modified = Date.now();
+ });
+
+ it("is updated", async () => {
+ await objectAPI.save(mockDomainObject);
+ expect(mockDomainObject.persisted).toBeDefined();
+ expect(mockDomainObject.persisted > persistedTimestamp).toBe(true);
+ });
+ it("is >= modified timestamp", async () => {
+ await objectAPI.save(mockDomainObject);
+ expect(mockDomainObject.persisted >= mockDomainObject.modified).toBe(true);
+ });
+ });
+ describe("the persisted timestamp for new objects", () => {
+ it("is updated", async () => {
+ await objectAPI.save(mockDomainObject);
+ expect(mockDomainObject.persisted).toBeDefined();
+ });
+ it("is >= modified timestamp", async () => {
+ await objectAPI.save(mockDomainObject);
+ expect(mockDomainObject.persisted >= mockDomainObject.modified).toBe(true);
+ });
+ });
+
it("Sets the current user for 'createdBy' on new objects", async () => {
await objectAPI.save(mockDomainObject);
expect(mockDomainObject.createdBy).toBe(USERNAME);
diff --git a/src/api/overlays/Overlay.js b/src/api/overlays/Overlay.js
index c63285a2e..632d881b1 100644
--- a/src/api/overlays/Overlay.js
+++ b/src/api/overlays/Overlay.js
@@ -17,6 +17,7 @@ class Overlay extends EventEmitter {
dismissable = true,
element,
onDestroy,
+ onDismiss,
size
} = {}) {
super();
@@ -32,7 +33,7 @@ class Overlay extends EventEmitter {
OverlayComponent: OverlayComponent
},
provide: {
- dismiss: this.dismiss.bind(this),
+ dismiss: this.notifyAndDismiss.bind(this),
element,
buttons,
dismissable: this.dismissable
@@ -43,6 +44,10 @@ class Overlay extends EventEmitter {
if (onDestroy) {
this.once('destroy', onDestroy);
}
+
+ if (onDismiss) {
+ this.once('dismiss', onDismiss);
+ }
}
dismiss() {
@@ -51,6 +56,12 @@ class Overlay extends EventEmitter {
this.component.$destroy();
}
+ //Ensures that any callers are notified that the overlay is dismissed
+ notifyAndDismiss() {
+ this.emit('dismiss');
+ this.dismiss();
+ }
+
/**
* @private
**/
diff --git a/src/api/overlays/OverlayAPI.js b/src/api/overlays/OverlayAPI.js
index 5587df316..80c6238de 100644
--- a/src/api/overlays/OverlayAPI.js
+++ b/src/api/overlays/OverlayAPI.js
@@ -55,7 +55,7 @@ class OverlayAPI {
dismissLastOverlay() {
let lastOverlay = this.activeOverlays[this.activeOverlays.length - 1];
if (lastOverlay && lastOverlay.dismissable) {
- lastOverlay.dismiss();
+ lastOverlay.notifyAndDismiss();
}
}
diff --git a/src/plugins/formActions/CreateAction.js b/src/plugins/formActions/CreateAction.js
index aa42a611d..f43b523e6 100644
--- a/src/plugins/formActions/CreateAction.js
+++ b/src/plugins/formActions/CreateAction.js
@@ -24,6 +24,7 @@ import PropertiesAction from './PropertiesAction';
import CreateWizard from './CreateWizard';
import { v4 as uuid } from 'uuid';
+import _ from 'lodash';
export default class CreateAction extends PropertiesAction {
constructor(openmct, type, parentDomainObject) {
@@ -50,19 +51,15 @@ export default class CreateAction extends PropertiesAction {
return;
}
- const properties = key.split('.');
- let object = this.domainObject;
- const propertiesLength = properties.length;
- properties.forEach((property, index) => {
- const isComplexProperty = propertiesLength > 1 && index !== propertiesLength - 1;
- if (isComplexProperty && object[property] !== null) {
- object = object[property];
- } else {
- object[property] = value;
- }
- });
-
- object = value;
+ const existingValue = this.domainObject[key];
+ if (!(existingValue instanceof Array) && (typeof existingValue === 'object')) {
+ value = {
+ ...existingValue,
+ ...value
+ };
+ }
+
+ _.set(this.domainObject, key, value);
});
const parentDomainObject = parentDomainObjectPath[0];
@@ -97,6 +94,12 @@ export default class CreateAction extends PropertiesAction {
/**
* @private
*/
+ _onCancel() {
+ //do Nothing
+ }
+ /**
+ * @private
+ */
async _navigateAndEdit(domainObject, parentDomainObjectpath) {
let objectPath;
let self = this;
@@ -151,6 +154,7 @@ export default class CreateAction extends PropertiesAction {
formStructure.title = 'Create a New ' + definition.name;
this.openmct.forms.showForm(formStructure)
- .then(this._onSave.bind(this));
+ .then(this._onSave.bind(this))
+ .catch(this._onCancel.bind(this));
}
}
diff --git a/src/plugins/formActions/EditPropertiesAction.js b/src/plugins/formActions/EditPropertiesAction.js
index 65ceaaadd..f2cb232f5 100644
--- a/src/plugins/formActions/EditPropertiesAction.js
+++ b/src/plugins/formActions/EditPropertiesAction.js
@@ -22,6 +22,7 @@
import PropertiesAction from './PropertiesAction';
import CreateWizard from './CreateWizard';
+
export default class EditPropertiesAction extends PropertiesAction {
constructor(openmct) {
super(openmct);
@@ -52,24 +53,31 @@ export default class EditPropertiesAction extends PropertiesAction {
* @private
*/
_onSave(changes) {
+ if (!this.openmct.objects.isTransactionActive()) {
+ this.openmct.objects.startTransaction();
+ }
+
try {
Object.entries(changes).forEach(([key, value]) => {
- const properties = key.split('.');
- let object = this.domainObject;
- const propertiesLength = properties.length;
- properties.forEach((property, index) => {
- const isComplexProperty = propertiesLength > 1 && index !== propertiesLength - 1;
- if (isComplexProperty && object[property] !== null) {
- object = object[property];
- } else {
- object[property] = value;
- }
- });
+ const existingValue = this.domainObject[key];
+ if (!(Array.isArray(existingValue)) && (typeof existingValue === 'object')) {
+ value = {
+ ...existingValue,
+ ...value
+ };
+ }
- object = value;
this.openmct.objects.mutate(this.domainObject, key, value);
- this.openmct.notifications.info('Save successful');
});
+ const transaction = this.openmct.objects.getActiveTransaction();
+
+ return transaction.commit()
+ .catch(error => {
+ throw error;
+ }).finally(() => {
+ this.openmct.objects.endTransaction();
+ });
+
} catch (error) {
this.openmct.notifications.error('Error saving objects');
console.error(error);
diff --git a/src/plugins/formActions/pluginSpec.js b/src/plugins/formActions/pluginSpec.js
index 232ff0d30..ad5f24472 100644
--- a/src/plugins/formActions/pluginSpec.js
+++ b/src/plugins/formActions/pluginSpec.js
@@ -24,6 +24,7 @@ import {
createOpenMct,
resetApplicationState
} from 'utils/testing';
+import Vue from 'vue';
import { debounce } from 'lodash';
@@ -101,10 +102,15 @@ describe('EditPropertiesAction plugin', () => {
composition: []
};
- const deBouncedFormChange = debounce(handleFormPropertyChange, 500);
- openmct.forms.on('onFormPropertyChange', deBouncedFormChange);
+ editPropertiesAction.invoke([domainObject])
+ .then(() => {
+ done();
+ })
+ .catch(() => {
+ done();
+ });
- function handleFormPropertyChange(data) {
+ Vue.nextTick(() => {
const form = document.querySelector('.js-form');
const title = form.querySelector('input');
expect(title.value).toEqual(domainObject.name);
@@ -118,17 +124,7 @@ describe('EditPropertiesAction plugin', () => {
const clickEvent = createMouseEvent('click');
buttons[1].dispatchEvent(clickEvent);
-
- openmct.forms.off('onFormPropertyChange', deBouncedFormChange);
- }
-
- editPropertiesAction.invoke([domainObject])
- .then(() => {
- done();
- })
- .catch(() => {
- done();
- });
+ });
});
it('edit properties action saves changes', (done) => {
@@ -159,11 +155,9 @@ describe('EditPropertiesAction plugin', () => {
const deBouncedCallback = debounce(callback, 300);
unObserve = openmct.objects.observe(domainObject, '*', deBouncedCallback);
- let changed = false;
- const deBouncedFormChange = debounce(handleFormPropertyChange, 500);
- openmct.forms.on('onFormPropertyChange', deBouncedFormChange);
+ editPropertiesAction.invoke([domainObject]);
- function handleFormPropertyChange(data) {
+ Vue.nextTick(() => {
const form = document.querySelector('.js-form');
const title = form.querySelector('input');
const notes = form.querySelector('textArea');
@@ -172,27 +166,18 @@ describe('EditPropertiesAction plugin', () => {
expect(buttons[0].textContent.trim()).toEqual('OK');
expect(buttons[1].textContent.trim()).toEqual('Cancel');
- if (!changed) {
- expect(title.value).toEqual(domainObject.name);
- expect(notes.value).toEqual(domainObject.notes);
-
- // change input field value and dispatch event for it
- title.focus();
- title.value = newName;
- title.dispatchEvent(new Event('input'));
- title.blur();
-
- changed = true;
- } else {
- // click ok to save form changes
- const clickEvent = createMouseEvent('click');
- buttons[0].dispatchEvent(clickEvent);
+ expect(title.value).toEqual(domainObject.name);
+ expect(notes.value).toEqual(domainObject.notes);
- openmct.forms.off('onFormPropertyChange', deBouncedFormChange);
- }
- }
+ // change input field value and dispatch event for it
+ title.focus();
+ title.value = newName;
+ title.dispatchEvent(new Event('input'));
+ title.blur();
- editPropertiesAction.invoke([domainObject]);
+ const clickEvent = createMouseEvent('click');
+ buttons[0].dispatchEvent(clickEvent);
+ });
});
it('edit properties action discards changes', (done) => {
@@ -217,7 +202,6 @@ describe('EditPropertiesAction plugin', () => {
})
.catch(() => {
expect(domainObject.name).toEqual(name);
-
done();
});
diff --git a/src/plugins/gauge/components/GaugeFormController.vue b/src/plugins/gauge/components/GaugeFormController.vue
index b9556e79b..73a224e31 100644
--- a/src/plugins/gauge/components/GaugeFormController.vue
+++ b/src/plugins/gauge/components/GaugeFormController.vue
@@ -100,6 +100,7 @@ export default {
components: {
ToggleSwitch
},
+ inject: ["openmct"],
props: {
model: {
type: Object,
@@ -107,11 +108,10 @@ export default {
}
},
data() {
+ this.changes = {};
+
return {
isUseTelemetryLimits: this.model.value.isUseTelemetryLimits,
- isDisplayMinMax: this.model.value.isDisplayMinMax,
- isDisplayCurVal: this.model.value.isDisplayCurVal,
- isDisplayUnits: this.model.value.isDisplayUnits,
limitHigh: this.model.value.limitHigh,
limitLow: this.model.value.limitLow,
max: this.model.value.max,
@@ -120,24 +120,15 @@ export default {
},
methods: {
onChange(event) {
- const data = {
- model: this.model,
- value: {
- gaugeType: this.model.value.gaugeType,
- isDisplayMinMax: this.isDisplayMinMax,
- isDisplayCurVal: this.isDisplayCurVal,
- isDisplayUnits: this.isDisplayUnits,
- isUseTelemetryLimits: this.isUseTelemetryLimits,
- limitLow: this.limitLow,
- limitHigh: this.limitHigh,
- max: this.max,
- min: this.min,
- precision: this.model.value.precision
- }
+ let data = {
+ model: {}
};
if (event) {
const target = event.target;
+ const property = target.dataset.fieldName;
+ data.model.property = Array.from(this.model.property).concat([property]);
+ data.value = this[property];
const targetIndicator = target.parentElement.querySelector('.req-indicator');
if (targetIndicator.classList.contains('req')) {
targetIndicator.classList.add('visited');
@@ -160,13 +151,13 @@ export default {
},
toggleUseTelemetryLimits() {
this.isUseTelemetryLimits = !this.isUseTelemetryLimits;
-
- this.onChange();
- },
- toggleMinMax() {
- this.isDisplayMinMax = !this.isDisplayMinMax;
-
- this.onChange();
+ const data = {
+ model: {
+ property: Array.from(this.model.property).concat(['isUseTelemetryLimits'])
+ },
+ value: this.isUseTelemetryLimits
+ };
+ this.$emit('onChange', data);
}
}
};
diff --git a/src/plugins/notebook/components/Notebook.vue b/src/plugins/notebook/components/Notebook.vue
index 14a5cc48f..c242d1356 100644
--- a/src/plugins/notebook/components/Notebook.vue
+++ b/src/plugins/notebook/components/Notebook.vue
@@ -889,32 +889,24 @@ export default {
this.syncUrlWithPageAndSection();
this.filterAndSortEntries();
},
- activeTransaction() {
- return this.openmct.objects.getActiveTransaction();
- },
startTransaction() {
- if (!this.openmct.editor.isEditing()) {
- this.openmct.objects.startTransaction();
+ if (!this.openmct.objects.isTransactionActive()) {
+ this.transaction = this.openmct.objects.startTransaction();
}
},
saveTransaction() {
- const transaction = this.activeTransaction();
-
- if (!transaction || this.openmct.editor.isEditing()) {
- return;
+ if (this.transaction !== undefined) {
+ this.transaction.commit()
+ .catch(error => {
+ throw error;
+ }).finally(() => {
+ this.openmct.objects.endTransaction();
+ });
}
-
- return transaction.commit()
- .catch(error => {
- throw error;
- }).finally(() => {
- this.openmct.objects.endTransaction();
- });
},
cancelTransaction() {
- if (!this.openmct.editor.isEditing()) {
- const transaction = this.activeTransaction();
- transaction.cancel()
+ if (this.transaction !== undefined) {
+ this.transaction.cancel()
.catch(error => {
throw error;
}).finally(() => {