mirror of
https://github.com/nasa/openmct.git
synced 2025-04-16 15:29:20 +00:00
[Remove Action][Move Action] Update logic when working with locked, aliased domain objects (#6384)
* Allow move action for locked shift logs. * Allow remove action for links to locked shift logs. --------- Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
parent
3714958627
commit
25c0dab346
@ -45,7 +45,7 @@ export default class MoveAction {
|
||||
}
|
||||
|
||||
navigateTo(objectPath) {
|
||||
let urlPath = objectPath.reverse()
|
||||
const urlPath = objectPath.reverse()
|
||||
.map(object => this.openmct.objects.makeKeyString(object.identifier))
|
||||
.join("/");
|
||||
|
||||
@ -53,8 +53,8 @@ export default class MoveAction {
|
||||
}
|
||||
|
||||
addToNewParent(child, newParent) {
|
||||
let newParentKeyString = this.openmct.objects.makeKeyString(newParent.identifier);
|
||||
let compositionCollection = this.openmct.composition.get(newParent);
|
||||
const newParentKeyString = this.openmct.objects.makeKeyString(newParent.identifier);
|
||||
const compositionCollection = this.openmct.composition.get(newParent);
|
||||
|
||||
this.openmct.objects.mutate(child, 'location', newParentKeyString);
|
||||
compositionCollection.add(child);
|
||||
@ -63,11 +63,7 @@ export default class MoveAction {
|
||||
async onSave(changes) {
|
||||
this.startTransaction();
|
||||
|
||||
let inNavigationPath = this.inNavigationPath(this.object);
|
||||
if (inNavigationPath && this.openmct.editor.isEditing()) {
|
||||
this.openmct.editor.save();
|
||||
}
|
||||
|
||||
const inNavigationPath = this.inNavigationPath(this.object);
|
||||
const parentDomainObjectpath = changes.location || [this.parent];
|
||||
const parent = parentDomainObjectpath[0];
|
||||
|
||||
@ -91,12 +87,15 @@ export default class MoveAction {
|
||||
}
|
||||
|
||||
let newObjectPath;
|
||||
|
||||
if (parentDomainObjectpath) {
|
||||
newObjectPath = parentDomainObjectpath && [this.object].concat(parentDomainObjectpath);
|
||||
} else {
|
||||
const root = await this.openmct.objects.getRoot();
|
||||
const rootCompositionCollection = this.openmct.composition.get(root);
|
||||
const rootComposition = await rootCompositionCollection.load();
|
||||
const rootChildCount = rootComposition.length;
|
||||
newObjectPath = await this.openmct.objects.getOriginalPath(this.object.identifier);
|
||||
let root = await this.openmct.objects.getRoot();
|
||||
let rootChildCount = root.composition.length;
|
||||
|
||||
// if not multiple root children, remove root from path
|
||||
if (rootChildCount < 2) {
|
||||
@ -108,8 +107,7 @@ export default class MoveAction {
|
||||
}
|
||||
|
||||
removeFromOldParent(child) {
|
||||
let compositionCollection = this.openmct.composition.get(this.oldParent);
|
||||
|
||||
const compositionCollection = this.openmct.composition.get(this.oldParent);
|
||||
compositionCollection.remove(child);
|
||||
}
|
||||
|
||||
@ -166,9 +164,9 @@ export default class MoveAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||
|
||||
const objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||
const parentCandidateComposition = parentCandidate.composition;
|
||||
|
||||
if (parentCandidateComposition && parentCandidateComposition.indexOf(objectKeystring) !== -1) {
|
||||
return false;
|
||||
}
|
||||
@ -178,20 +176,18 @@ export default class MoveAction {
|
||||
}
|
||||
|
||||
appliesTo(objectPath) {
|
||||
let parent = objectPath[1];
|
||||
let parentType = parent && this.openmct.types.get(parent.type);
|
||||
let child = objectPath[0];
|
||||
let childType = child && this.openmct.types.get(child.type);
|
||||
let isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||
const parent = objectPath[1];
|
||||
const parentType = parent && this.openmct.types.get(parent.type);
|
||||
const child = objectPath[0];
|
||||
const childType = child && this.openmct.types.get(child.type);
|
||||
const isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||
|
||||
if (child.locked || (parent && parent.locked) || !isPersistable) {
|
||||
if (parent?.locked || !isPersistable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parentType
|
||||
&& parentType.definition.creatable
|
||||
&& childType
|
||||
&& childType.definition.creatable
|
||||
return parentType?.definition.creatable
|
||||
&& childType?.definition.creatable
|
||||
&& Array.isArray(parent.composition);
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,8 @@ describe("The Move Action plugin", () => {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "child-folder-object"
|
||||
}
|
||||
},
|
||||
location: "parent-folder-object"
|
||||
}
|
||||
}
|
||||
}).folder;
|
||||
@ -90,6 +91,31 @@ describe("The Move Action plugin", () => {
|
||||
expect(moveAction).toBeDefined();
|
||||
});
|
||||
|
||||
describe("when determining the object is applicable", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(moveAction, 'appliesTo').and.callThrough();
|
||||
});
|
||||
|
||||
it("should be true when the parent is creatable and has composition", () => {
|
||||
let applies = moveAction.appliesTo([childObject, parentObject]);
|
||||
expect(applies).toBe(true);
|
||||
});
|
||||
|
||||
it("should be true when the child is locked and not an alias", () => {
|
||||
childObject.locked = true;
|
||||
let applies = moveAction.appliesTo([childObject, parentObject]);
|
||||
expect(applies).toBe(true);
|
||||
});
|
||||
|
||||
it("should still be true when the child is locked and is an alias", () => {
|
||||
childObject.locked = true;
|
||||
childObject.location = 'another-parent-folder-object';
|
||||
let applies = moveAction.appliesTo([childObject, parentObject]);
|
||||
expect(applies).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when moving an object to a new parent and removing from the old parent", () => {
|
||||
let unObserve;
|
||||
beforeEach((done) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2023, United States Government
|
||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
@ -20,6 +20,8 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
const SPECIAL_MESSAGE_TYPES = ['layout', 'flexible-layout'];
|
||||
|
||||
export default class RemoveAction {
|
||||
#transaction;
|
||||
|
||||
@ -39,28 +41,37 @@ export default class RemoveAction {
|
||||
}
|
||||
|
||||
async invoke(objectPath) {
|
||||
let object = objectPath[0];
|
||||
let parent = objectPath[1];
|
||||
const child = objectPath[0];
|
||||
const parent = objectPath[1];
|
||||
|
||||
try {
|
||||
await this.showConfirmDialog(object);
|
||||
await this.showConfirmDialog(child, parent);
|
||||
} catch (error) {
|
||||
return; // form canceled, exit invoke
|
||||
}
|
||||
|
||||
await this.removeFromComposition(parent, object);
|
||||
await this.removeFromComposition(parent, child, objectPath);
|
||||
|
||||
if (this.inNavigationPath(object)) {
|
||||
if (this.inNavigationPath(child)) {
|
||||
this.navigateTo(objectPath.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
showConfirmDialog(object) {
|
||||
showConfirmDialog(child, parent) {
|
||||
let message = 'Warning! This action will remove this object. Are you sure you want to continue?';
|
||||
|
||||
if (SPECIAL_MESSAGE_TYPES.includes(parent.type)) {
|
||||
const type = this.openmct.types.get(parent.type);
|
||||
const typeName = type.definition.name;
|
||||
|
||||
message = `Warning! This action will remove this item from the ${typeName}. Are you sure you want to continue?`;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let dialog = this.openmct.overlays.dialog({
|
||||
title: `Remove ${object.name}`,
|
||||
const dialog = this.openmct.overlays.dialog({
|
||||
title: `Remove ${child.name}`,
|
||||
iconClass: 'alert',
|
||||
message: 'Warning! This action will remove this object. Are you sure you want to continue?',
|
||||
message,
|
||||
buttons: [
|
||||
{
|
||||
label: 'OK',
|
||||
@ -94,13 +105,13 @@ export default class RemoveAction {
|
||||
this.openmct.router.navigate('#/browse/' + urlPath);
|
||||
}
|
||||
|
||||
async removeFromComposition(parent, child) {
|
||||
async removeFromComposition(parent, child, objectPath) {
|
||||
this.startTransaction();
|
||||
|
||||
const composition = this.openmct.composition.get(parent);
|
||||
composition.remove(child);
|
||||
|
||||
if (!this.isAlias(child, parent)) {
|
||||
if (!this.openmct.objects.isObjectPathToALink(child, objectPath)) {
|
||||
this.openmct.objects.mutate(child, 'location', null);
|
||||
}
|
||||
|
||||
@ -111,18 +122,6 @@ export default class RemoveAction {
|
||||
await this.saveTransaction();
|
||||
}
|
||||
|
||||
isAlias(child, parent) {
|
||||
if (parent === undefined) {
|
||||
// then it's a root item, not an alias
|
||||
return false;
|
||||
}
|
||||
|
||||
const parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
|
||||
const childLocation = child.location;
|
||||
|
||||
return childLocation !== parentKeyString;
|
||||
}
|
||||
|
||||
appliesTo(objectPath) {
|
||||
const parent = objectPath[1];
|
||||
const parentType = parent && this.openmct.types.get(parent.type);
|
||||
@ -130,9 +129,9 @@ export default class RemoveAction {
|
||||
const locked = child.locked ? child.locked : parent && parent.locked;
|
||||
const isEditing = this.openmct.editor.isEditing();
|
||||
const isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||
const isAlias = this.isAlias(child, parent);
|
||||
const isLink = this.openmct.objects.isObjectPathToALink(child, objectPath);
|
||||
|
||||
if (locked || (!isPersistable && !isAlias)) {
|
||||
if (!isLink && (locked || !isPersistable)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -142,9 +141,8 @@ export default class RemoveAction {
|
||||
}
|
||||
}
|
||||
|
||||
return parentType
|
||||
&& parentType.definition.creatable
|
||||
&& Array.isArray(parent.composition);
|
||||
return parentType?.definition.creatable
|
||||
&& Array.isArray(parent?.composition);
|
||||
}
|
||||
|
||||
startTransaction() {
|
||||
|
@ -52,6 +52,10 @@ describe("The Remove Action plugin", () => {
|
||||
objectKeyStrings: ['folder'],
|
||||
overwrite: {
|
||||
folder: {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "parent-folder-object"
|
||||
},
|
||||
name: "Parent Folder",
|
||||
composition: [childObject.identifier]
|
||||
}
|
||||
@ -116,10 +120,18 @@ describe("The Remove Action plugin", () => {
|
||||
expect(applies).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false when the child is locked", () => {
|
||||
it("should be false when the child is locked and not an alias", () => {
|
||||
childObject.locked = true;
|
||||
childObject.location = 'parent-folder-object';
|
||||
let applies = removeAction.appliesTo([childObject, parentObject]);
|
||||
expect(applies).toBe(false);
|
||||
});
|
||||
|
||||
it("should be true when the child is locked and IS an alias", () => {
|
||||
childObject.locked = true;
|
||||
childObject.location = 'other-folder-object';
|
||||
let applies = removeAction.appliesTo([childObject, parentObject]);
|
||||
expect(applies).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user