[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:
Jamie V 2023-03-16 13:53:25 -07:00 committed by GitHub
parent 3714958627
commit 25c0dab346
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 55 deletions

View File

@ -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);
}

View File

@ -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) => {

View File

@ -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() {

View File

@ -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);
});
});
});