Use Composition API to add/remove from composition (#5941)
* Use composition API in RemoveAction
* refactor: ScatterPlotView to use composition API
* fix: initialize transaction to null and reset
* fix: remove seriesKey and correct found condition
* refactor: Gauge to use composition API
* refactor: DisplayLayout to use composition API
* test: RemoveAction starts and ends transactions
* test: add ScatterPlot add/remove telemetry test
* test: fix e2e test and add annotation
* test: remove unnecessary awaits
* test: make some displayLayout tests stable
* test{displayLayout}: navigate to objects via url
* test(gauge): add test for add/remove telemetry
* fix(#3117): init layoutItems within transaction
* refactor: add clearSelection() method
* test: remove unstable tag
* fix(#3117): init frames and use transactions
- fixes #3117 for flexible layouts by syncing frames and composition
- also uses transactions now to avoid race condition
* test(flexibleLayout): removing items via context menu
- add test for removing items via context menu while focusing the layout
- add test for removing items via context menu while not focusing the layout
* fix(e2e): use pluginFixtures
* refactor(e2e): improve selectors
* refactor: use async/await for saving transactions
* docs(e2e): fix comments
* test: use soft expects
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
This commit is contained in:
@@ -56,17 +56,12 @@ export default class Editor extends EventEmitter {
|
||||
* Save any unsaved changes from this editing session. This will
|
||||
* end the current transaction.
|
||||
*/
|
||||
save() {
|
||||
async save() {
|
||||
const transaction = this.openmct.objects.getActiveTransaction();
|
||||
|
||||
return transaction.commit()
|
||||
.then(() => {
|
||||
this.editing = false;
|
||||
this.emit('isEditing', false);
|
||||
this.openmct.objects.endTransaction();
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
await transaction.commit();
|
||||
this.editing = false;
|
||||
this.emit('isEditing', false);
|
||||
this.openmct.objects.endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,11 +112,7 @@ export default {
|
||||
}
|
||||
},
|
||||
removeFromComposition(telemetryObject) {
|
||||
let composition = this.domainObject.composition.filter(id =>
|
||||
!this.openmct.objects.areIdsEqual(id, telemetryObject.identifier)
|
||||
);
|
||||
|
||||
this.openmct.objects.mutate(this.domainObject, 'composition', composition);
|
||||
this.composition.remove(telemetryObject);
|
||||
},
|
||||
addTelemetryObject(telemetryObject) {
|
||||
// grab information we need from the added telmetry object
|
||||
|
||||
@@ -104,10 +104,14 @@ export default {
|
||||
this.$set(this.plotSeries, this.plotSeries.length, series);
|
||||
this.setAxesLabels();
|
||||
},
|
||||
removeSeries(series) {
|
||||
const index = this.plotSeries.findIndex(plotSeries => this.openmct.objects.areIdsEqual(series.identifier, plotSeries.identifier));
|
||||
if (index !== undefined) {
|
||||
this.$delete(this.plotSeries, index);
|
||||
removeSeries(seriesKey) {
|
||||
const seriesIndex = this.plotSeries.findIndex(
|
||||
plotSeries => this.openmct.objects.areIdsEqual(seriesKey, plotSeries.identifier)
|
||||
);
|
||||
|
||||
const foundSeries = seriesIndex > -1;
|
||||
if (foundSeries) {
|
||||
this.$delete(this.plotSeries, seriesIndex);
|
||||
this.setAxesLabels();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -245,6 +245,9 @@ export default {
|
||||
});
|
||||
this.gridDimensions = [wMax * this.gridSize[0], hMax * this.gridSize[1]];
|
||||
},
|
||||
clearSelection() {
|
||||
this.$el.click();
|
||||
},
|
||||
watchDisplayResize() {
|
||||
const resizeObserver = new ResizeObserver(() => this.updateGrid());
|
||||
|
||||
@@ -478,7 +481,7 @@ export default {
|
||||
});
|
||||
_.pullAt(this.layoutItems, indices);
|
||||
this.mutate("configuration.items", this.layoutItems);
|
||||
this.$el.click();
|
||||
this.clearSelection();
|
||||
},
|
||||
untrackItem(item) {
|
||||
if (!item.identifier) {
|
||||
@@ -504,15 +507,11 @@ export default {
|
||||
}
|
||||
|
||||
if (!telemetryViewCount && !objectViewCount) {
|
||||
this.removeFromComposition(keyString);
|
||||
this.removeFromComposition(item);
|
||||
}
|
||||
},
|
||||
removeFromComposition(keyString) {
|
||||
let composition = this.domainObject.composition ? this.domainObject.composition : [];
|
||||
composition = composition.filter(identifier => {
|
||||
return this.openmct.objects.makeKeyString(identifier) !== keyString;
|
||||
});
|
||||
this.mutate("composition", composition);
|
||||
removeFromComposition(item) {
|
||||
this.composition.remove(item);
|
||||
},
|
||||
initializeItems() {
|
||||
this.telemetryViewMap = {};
|
||||
@@ -529,7 +528,10 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
this.startTransaction();
|
||||
removedItems.forEach(this.removeFromConfiguration);
|
||||
|
||||
return this.endTransaction();
|
||||
},
|
||||
isItemAlreadyTracked(child) {
|
||||
let found = false;
|
||||
@@ -590,7 +592,7 @@ export default {
|
||||
}
|
||||
});
|
||||
this.mutate("configuration.items", layoutItems);
|
||||
this.$el.click();
|
||||
this.clearSelection();
|
||||
},
|
||||
orderItem(position, selectedItems) {
|
||||
let delta = ORDERS[position];
|
||||
@@ -773,7 +775,7 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.openmct.objects.mutate(this.domainObject, "configuration.items", this.layoutItems);
|
||||
this.openmct.objects.mutate(this.domainObject, "configuration.objectStyles", objectStyles);
|
||||
this.$el.click(); //clear selection;
|
||||
this.clearSelection();
|
||||
|
||||
newDomainObjectsArray.forEach(domainObject => {
|
||||
this.composition.add(domainObject);
|
||||
@@ -867,6 +869,20 @@ export default {
|
||||
this.removeItem(selection);
|
||||
this.initSelectIndex = this.layoutItems.length - 1; //restore selection
|
||||
},
|
||||
startTransaction() {
|
||||
if (!this.openmct.objects.isTransactionActive()) {
|
||||
this.transaction = this.openmct.objects.startTransaction();
|
||||
}
|
||||
},
|
||||
async endTransaction() {
|
||||
if (!this.transaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.transaction.commit();
|
||||
this.openmct.objects.endTransaction();
|
||||
this.transaction = null;
|
||||
},
|
||||
toggleGrid() {
|
||||
this.showGrid = !this.showGrid;
|
||||
},
|
||||
|
||||
@@ -185,10 +185,24 @@ export default {
|
||||
this.composition.off('add', this.addFrame);
|
||||
},
|
||||
methods: {
|
||||
containsObject(identifier) {
|
||||
if ('composition' in this.domainObject) {
|
||||
return this.domainObject.composition
|
||||
.some(childId => this.openmct.objects.areIdsEqual(childId, identifier));
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
buildIdentifierMap() {
|
||||
this.containers.forEach(container => {
|
||||
container.frames.forEach(frame => {
|
||||
let keystring = this.openmct.objects.makeKeyString(frame.domainObjectIdentifier);
|
||||
if (!this.containsObject(frame.domainObjectIdentifier)) {
|
||||
this.removeChildObject(frame.domainObjectIdentifier);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const keystring = this.openmct.objects.makeKeyString(frame.domainObjectIdentifier);
|
||||
this.identifierMap[keystring] = true;
|
||||
});
|
||||
});
|
||||
@@ -296,11 +310,14 @@ export default {
|
||||
}
|
||||
},
|
||||
persist(index) {
|
||||
this.startTransaction();
|
||||
if (index) {
|
||||
this.openmct.objects.mutate(this.domainObject, `configuration.containers[${index}]`, this.containers[index]);
|
||||
} else {
|
||||
this.openmct.objects.mutate(this.domainObject, 'configuration.containers', this.containers);
|
||||
}
|
||||
|
||||
return this.endTransaction();
|
||||
},
|
||||
startContainerResizing(index) {
|
||||
let beforeContainer = this.containers[index];
|
||||
@@ -366,6 +383,20 @@ export default {
|
||||
});
|
||||
|
||||
this.persist();
|
||||
},
|
||||
startTransaction() {
|
||||
if (!this.openmct.objects.isTransactionActive()) {
|
||||
this.transaction = this.openmct.objects.startTransaction();
|
||||
}
|
||||
},
|
||||
async endTransaction() {
|
||||
if (!this.transaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.transaction.commit();
|
||||
this.openmct.objects.endTransaction();
|
||||
this.transaction = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class EditPropertiesAction extends PropertiesAction {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onSave(changes) {
|
||||
async _onSave(changes) {
|
||||
if (!this.openmct.objects.isTransactionActive()) {
|
||||
this.openmct.objects.startTransaction();
|
||||
}
|
||||
@@ -70,14 +70,8 @@ export default class EditPropertiesAction extends PropertiesAction {
|
||||
this.openmct.objects.mutate(this.domainObject, key, value);
|
||||
});
|
||||
const transaction = this.openmct.objects.getActiveTransaction();
|
||||
|
||||
return transaction.commit()
|
||||
.catch(error => {
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
this.openmct.objects.endTransaction();
|
||||
});
|
||||
|
||||
await transaction.commit();
|
||||
this.openmct.objects.endTransaction();
|
||||
} catch (error) {
|
||||
this.openmct.notifications.error('Error saving objects');
|
||||
console.error(error);
|
||||
|
||||
@@ -598,11 +598,7 @@ export default {
|
||||
return this.round(((vPercent / 100) * 270) + DIAL_VALUE_DEG_OFFSET, 2);
|
||||
},
|
||||
removeFromComposition(telemetryObject = this.telemetryObject) {
|
||||
let composition = this.domainObject.composition.filter(id =>
|
||||
!this.openmct.objects.areIdsEqual(id, telemetryObject.identifier)
|
||||
);
|
||||
|
||||
this.openmct.objects.mutate(this.domainObject, 'composition', composition);
|
||||
this.composition.remove(telemetryObject);
|
||||
},
|
||||
refreshData(bounds, isTick) {
|
||||
if (!isTick) {
|
||||
|
||||
@@ -894,24 +894,16 @@ export default {
|
||||
this.transaction = this.openmct.objects.startTransaction();
|
||||
}
|
||||
},
|
||||
saveTransaction() {
|
||||
async saveTransaction() {
|
||||
if (this.transaction !== undefined) {
|
||||
this.transaction.commit()
|
||||
.catch(error => {
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
this.openmct.objects.endTransaction();
|
||||
});
|
||||
await this.transaction.commit();
|
||||
this.openmct.objects.endTransaction();
|
||||
}
|
||||
},
|
||||
cancelTransaction() {
|
||||
async cancelTransaction() {
|
||||
if (this.transaction !== undefined) {
|
||||
this.transaction.cancel()
|
||||
.catch(error => {
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
this.openmct.objects.endTransaction();
|
||||
});
|
||||
await this.transaction.cancel();
|
||||
this.openmct.objects.endTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ export default class RemoveAction {
|
||||
this.openmct = openmct;
|
||||
|
||||
this.removeFromComposition = this.removeFromComposition.bind(this); // for access to private transaction variable
|
||||
this.#transaction = null;
|
||||
}
|
||||
|
||||
async invoke(objectPath) {
|
||||
@@ -152,16 +153,13 @@ export default class RemoveAction {
|
||||
}
|
||||
}
|
||||
|
||||
saveTransaction() {
|
||||
async saveTransaction() {
|
||||
if (!this.#transaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.#transaction.commit()
|
||||
.catch(error => {
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
this.openmct.objects.endTransaction();
|
||||
});
|
||||
await this.#transaction.commit();
|
||||
this.openmct.objects.endTransaction();
|
||||
this.#transaction = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,8 @@ describe("The Remove Action plugin", () => {
|
||||
spyOn(removeAction, 'removeFromComposition').and.callThrough();
|
||||
spyOn(removeAction, 'inNavigationPath').and.returnValue(false);
|
||||
spyOn(openmct.objects, 'mutate').and.callThrough();
|
||||
spyOn(openmct.objects, 'startTransaction').and.callThrough();
|
||||
spyOn(openmct.objects, 'endTransaction').and.callThrough();
|
||||
removeAction.removeFromComposition(parentObject, childObject);
|
||||
});
|
||||
|
||||
@@ -90,6 +92,17 @@ describe("The Remove Action plugin", () => {
|
||||
expect(openmct.objects.mutate).toHaveBeenCalled();
|
||||
expect(openmct.objects.mutate.calls.argsFor(0)[0]).toEqual(parentObject);
|
||||
});
|
||||
|
||||
it("it should start a transaction", () => {
|
||||
expect(openmct.objects.startTransaction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("it should end the transaction", (done) => {
|
||||
setTimeout(() => {
|
||||
expect(openmct.objects.endTransaction).toHaveBeenCalled();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when determining the object is applicable", () => {
|
||||
|
||||
Reference in New Issue
Block a user