Move action (#3356)

* WIP: added new move action plugin, added to default plugins in mct.js

* WIP: removed old move action and references, added new root action, working, needs tess

* added tests for move action

* removing focused tests

* WIP

* using composition collection now, optimized some calls

* removed test for removed function

* minor spec change, format only

* updated for new action registration and 3 dot

* removing comments

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
This commit is contained in:
Jamie V
2020-11-24 14:37:28 -08:00
committed by GitHub
parent d1656f8561
commit acea18fa70
11 changed files with 284 additions and 897 deletions

View File

@ -0,0 +1,166 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
export default class MoveAction {
constructor(openmct) {
this.name = 'Move';
this.key = 'move';
this.description = 'Move this object from its containing object to another object.';
this.cssClass = "icon-move";
this.group = "action";
this.priority = 7;
this.openmct = openmct;
}
async invoke(objectPath) {
let object = objectPath[0];
let inNavigationPath = this.inNavigationPath(object);
let oldParent = objectPath[1];
let dialogService = this.openmct.$injector.get('dialogService');
let dialogForm = this.getDialogForm(object, oldParent);
let userInput = await dialogService.getUserInput(dialogForm, { name: object.name });
// if we need to update name
if (object.name !== userInput.name) {
this.openmct.objects.mutate(object, 'name', userInput.name);
}
let parentContext = userInput.location.getCapability('context');
let newParent = await this.openmct.objects.get(parentContext.domainObject.id);
if (inNavigationPath && this.openmct.editor.isEditing()) {
this.openmct.editor.save();
}
this.addToNewParent(object, newParent);
this.removeFromOldParent(oldParent, object);
if (inNavigationPath) {
let newObjectPath = await this.openmct.objects.getOriginalPath(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) {
newObjectPath.pop(); // remove ROOT
}
this.navigateTo(newObjectPath);
}
}
inNavigationPath(object) {
return this.openmct.router.path
.some(objectInPath => this.openmct.objects.areIdsEqual(objectInPath.identifier, object.identifier));
}
navigateTo(objectPath) {
let urlPath = objectPath.reverse()
.map(object => this.openmct.objects.makeKeyString(object.identifier))
.join("/");
window.location.href = '#/browse/' + urlPath;
}
addToNewParent(child, newParent) {
let newParentKeyString = this.openmct.objects.makeKeyString(newParent.identifier);
let compositionCollection = this.openmct.composition.get(newParent);
this.openmct.objects.mutate(child, 'location', newParentKeyString);
compositionCollection.add(child);
}
removeFromOldParent(parent, child) {
let compositionCollection = this.openmct.composition.get(parent);
compositionCollection.remove(child);
}
getDialogForm(object, parent) {
return {
name: "Move Item",
sections: [
{
rows: [
{
key: "name",
control: "textfield",
name: "Folder Name",
pattern: "\\S+",
required: true,
cssClass: "l-input-lg"
},
{
name: "location",
control: "locator",
validate: this.validate(object, parent),
key: 'location'
}
]
}
]
};
}
validate(object, currentParent) {
return (parentCandidate) => {
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.getId());
let objectKeystring = this.openmct.objects.makeKeyString(object.identifier);
if (!parentCandidateKeystring || !currentParentKeystring) {
return false;
}
if (parentCandidateKeystring === currentParentKeystring) {
return false;
}
if (parentCandidateKeystring === objectKeystring) {
return false;
}
if (parentCandidate.getModel().composition.indexOf(objectKeystring) !== -1) {
return false;
}
return this.openmct.composition.checkPolicy(
parentCandidate.useCapability('adapter'),
object
);
};
}
appliesTo(objectPath) {
let parent = objectPath[1];
let parentType = parent && this.openmct.types.get(parent.type);
let child = objectPath[0];
if (child.locked || (parent && parent.locked)) {
return false;
}
return parentType
&& parentType.definition.creatable
&& Array.isArray(parent.composition);
}
}

View File

@ -0,0 +1,28 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import MoveAction from "./MoveAction";
export default function () {
return function (openmct) {
openmct.actions.register(new MoveAction(openmct));
};
}

View File

@ -0,0 +1,110 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import MoveActionPlugin from './plugin.js';
import MoveAction from './MoveAction.js';
import {
createOpenMct,
resetApplicationState,
getMockObjects
} from 'utils/testing';
describe("The Move Action plugin", () => {
let openmct;
let moveAction;
let childObject;
let parentObject;
let anotherParentObject;
// this setups up the app
beforeEach((done) => {
const appHolder = document.createElement('div');
appHolder.style.width = '640px';
appHolder.style.height = '480px';
openmct = createOpenMct();
childObject = getMockObjects({
objectKeyStrings: ['folder'],
overwrite: {
folder: {
name: "Child Folder",
identifier: {
namespace: "",
key: "child-folder-object"
}
}
}
}).folder;
parentObject = getMockObjects({
objectKeyStrings: ['folder'],
overwrite: {
folder: {
name: "Parent Folder",
composition: [childObject.identifier]
}
}
}).folder;
anotherParentObject = getMockObjects({
objectKeyStrings: ['folder'],
overwrite: {
folder: {
name: "Another Parent Folder"
}
}
}).folder;
// already installed by default, but never hurts, just adds to context menu
openmct.install(MoveActionPlugin());
openmct.on('start', done);
openmct.startHeadless(appHolder);
});
afterEach(() => {
resetApplicationState(openmct);
});
it("should be defined", () => {
expect(MoveActionPlugin).toBeDefined();
});
describe("when moving an object to a new parent and removing from the old parent", () => {
beforeEach(() => {
moveAction = new MoveAction(openmct);
moveAction.addToNewParent(childObject, anotherParentObject);
moveAction.removeFromOldParent(parentObject, childObject);
});
it("the child object's identifier should be in the new parent's composition", () => {
let newParentChild = anotherParentObject.composition[0];
expect(newParentChild).toEqual(childObject.identifier);
});
it("the child object's identifier should be removed from the old parent's composition", () => {
let oldParentComposition = parentObject.composition;
expect(oldParentComposition.length).toEqual(0);
});
});
});