mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 07:16:39 +00:00
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:
parent
d1656f8561
commit
acea18fa70
@ -21,30 +21,24 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
"./src/actions/MoveAction",
|
|
||||||
"./src/actions/LinkAction",
|
"./src/actions/LinkAction",
|
||||||
"./src/actions/SetPrimaryLocationAction",
|
"./src/actions/SetPrimaryLocationAction",
|
||||||
"./src/services/LocatingCreationDecorator",
|
"./src/services/LocatingCreationDecorator",
|
||||||
"./src/services/LocatingObjectDecorator",
|
"./src/services/LocatingObjectDecorator",
|
||||||
"./src/policies/CopyPolicy",
|
"./src/policies/CopyPolicy",
|
||||||
"./src/policies/CrossSpacePolicy",
|
"./src/policies/CrossSpacePolicy",
|
||||||
"./src/policies/MovePolicy",
|
|
||||||
"./src/capabilities/LocationCapability",
|
"./src/capabilities/LocationCapability",
|
||||||
"./src/services/MoveService",
|
|
||||||
"./src/services/LinkService",
|
"./src/services/LinkService",
|
||||||
"./src/services/CopyService",
|
"./src/services/CopyService",
|
||||||
"./src/services/LocationService"
|
"./src/services/LocationService"
|
||||||
], function (
|
], function (
|
||||||
MoveAction,
|
|
||||||
LinkAction,
|
LinkAction,
|
||||||
SetPrimaryLocationAction,
|
SetPrimaryLocationAction,
|
||||||
LocatingCreationDecorator,
|
LocatingCreationDecorator,
|
||||||
LocatingObjectDecorator,
|
LocatingObjectDecorator,
|
||||||
CopyPolicy,
|
CopyPolicy,
|
||||||
CrossSpacePolicy,
|
CrossSpacePolicy,
|
||||||
MovePolicy,
|
|
||||||
LocationCapability,
|
LocationCapability,
|
||||||
MoveService,
|
|
||||||
LinkService,
|
LinkService,
|
||||||
CopyService,
|
CopyService,
|
||||||
LocationService
|
LocationService
|
||||||
@ -58,21 +52,6 @@ define([
|
|||||||
"configuration": {},
|
"configuration": {},
|
||||||
"extensions": {
|
"extensions": {
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
|
||||||
"key": "move",
|
|
||||||
"name": "Move",
|
|
||||||
"description": "Move object to another location.",
|
|
||||||
"cssClass": "icon-move",
|
|
||||||
"category": "contextual",
|
|
||||||
"group": "action",
|
|
||||||
"priority": 9,
|
|
||||||
"implementation": MoveAction,
|
|
||||||
"depends": [
|
|
||||||
"policyService",
|
|
||||||
"locationService",
|
|
||||||
"moveService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "link",
|
"key": "link",
|
||||||
"name": "Create Link",
|
"name": "Create Link",
|
||||||
@ -121,10 +100,6 @@ define([
|
|||||||
{
|
{
|
||||||
"category": "action",
|
"category": "action",
|
||||||
"implementation": CopyPolicy
|
"implementation": CopyPolicy
|
||||||
},
|
|
||||||
{
|
|
||||||
"category": "action",
|
|
||||||
"implementation": MovePolicy
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"capabilities": [
|
"capabilities": [
|
||||||
@ -140,17 +115,6 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"services": [
|
"services": [
|
||||||
{
|
|
||||||
"key": "moveService",
|
|
||||||
"name": "Move Service",
|
|
||||||
"description": "Provides a service for moving objects",
|
|
||||||
"implementation": MoveService,
|
|
||||||
"depends": [
|
|
||||||
"openmct",
|
|
||||||
"linkService",
|
|
||||||
"$q"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "linkService",
|
"key": "linkService",
|
||||||
"name": "Link Service",
|
"name": "Link Service",
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['./AbstractComposeAction'],
|
|
||||||
function (AbstractComposeAction) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The MoveAction is available from context menus and allows a user to
|
|
||||||
* move an object to another location of their choosing.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/entanglement
|
|
||||||
*/
|
|
||||||
function MoveAction(policyService, locationService, moveService, context) {
|
|
||||||
AbstractComposeAction.apply(
|
|
||||||
this,
|
|
||||||
[policyService, locationService, moveService, context, "Move"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveAction.prototype = Object.create(AbstractComposeAction.prototype);
|
|
||||||
|
|
||||||
MoveAction.appliesTo = function (context) {
|
|
||||||
var applicableObject =
|
|
||||||
context.selectedObject || context.domainObject;
|
|
||||||
|
|
||||||
if (applicableObject && applicableObject.model.locked) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Boolean(applicableObject
|
|
||||||
&& applicableObject.hasCapability('context'));
|
|
||||||
};
|
|
||||||
|
|
||||||
return MoveAction;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
function () {
|
|
||||||
/**
|
|
||||||
* MoveService provides an interface for moving objects from one
|
|
||||||
* location to another. It also provides a method for determining if
|
|
||||||
* an object can be copied to a specific location.
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/entanglement
|
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
|
||||||
*/
|
|
||||||
function MoveService(openmct, linkService) {
|
|
||||||
this.openmct = openmct;
|
|
||||||
this.linkService = linkService;
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveService.prototype.validate = function (object, parentCandidate) {
|
|
||||||
var currentParent = object
|
|
||||||
.getCapability('context')
|
|
||||||
.getParent();
|
|
||||||
|
|
||||||
if (!parentCandidate || !parentCandidate.getId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentCandidate.getId() === currentParent.getId()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentCandidate.getId() === object.getId()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.openmct.composition.checkPolicy(
|
|
||||||
parentCandidate.useCapability('adapter'),
|
|
||||||
object.useCapability('adapter')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
MoveService.prototype.perform = function (object, parentObject) {
|
|
||||||
function relocate(objectInNewContext) {
|
|
||||||
var newLocationCapability = objectInNewContext
|
|
||||||
.getCapability('location'),
|
|
||||||
oldLocationCapability = object
|
|
||||||
.getCapability('location');
|
|
||||||
|
|
||||||
if (!newLocationCapability
|
|
||||||
|| !oldLocationCapability) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldLocationCapability.isOriginal()) {
|
|
||||||
return newLocationCapability.setPrimaryLocation(
|
|
||||||
newLocationCapability
|
|
||||||
.getContextualLocation()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.validate(object, parentObject)) {
|
|
||||||
throw new Error(
|
|
||||||
"Tried to move objects without validating first."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.linkService
|
|
||||||
.perform(object, parentObject)
|
|
||||||
.then(relocate)
|
|
||||||
.then(function () {
|
|
||||||
return object
|
|
||||||
.getCapability('action')
|
|
||||||
.perform('remove', true);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return MoveService;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,178 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'../../src/actions/MoveAction',
|
|
||||||
'../services/MockMoveService',
|
|
||||||
'../DomainObjectFactory'
|
|
||||||
],
|
|
||||||
function (MoveAction, MockMoveService, domainObjectFactory) {
|
|
||||||
|
|
||||||
describe("Move Action", function () {
|
|
||||||
|
|
||||||
var moveAction,
|
|
||||||
policyService,
|
|
||||||
locationService,
|
|
||||||
locationServicePromise,
|
|
||||||
moveService,
|
|
||||||
context,
|
|
||||||
selectedObject,
|
|
||||||
selectedObjectContextCapability,
|
|
||||||
currentParent,
|
|
||||||
newParent;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
policyService = jasmine.createSpyObj(
|
|
||||||
'policyService',
|
|
||||||
['allow']
|
|
||||||
);
|
|
||||||
policyService.allow.and.returnValue(true);
|
|
||||||
|
|
||||||
selectedObjectContextCapability = jasmine.createSpyObj(
|
|
||||||
'selectedObjectContextCapability',
|
|
||||||
[
|
|
||||||
'getParent'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
selectedObject = domainObjectFactory({
|
|
||||||
name: 'selectedObject',
|
|
||||||
model: {
|
|
||||||
name: 'selectedObject'
|
|
||||||
},
|
|
||||||
capabilities: {
|
|
||||||
context: selectedObjectContextCapability
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
currentParent = domainObjectFactory({
|
|
||||||
name: 'currentParent'
|
|
||||||
});
|
|
||||||
|
|
||||||
selectedObjectContextCapability
|
|
||||||
.getParent
|
|
||||||
.and.returnValue(currentParent);
|
|
||||||
|
|
||||||
newParent = domainObjectFactory({
|
|
||||||
name: 'newParent'
|
|
||||||
});
|
|
||||||
|
|
||||||
locationService = jasmine.createSpyObj(
|
|
||||||
'locationService',
|
|
||||||
[
|
|
||||||
'getLocationFromUser'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
locationServicePromise = jasmine.createSpyObj(
|
|
||||||
'locationServicePromise',
|
|
||||||
[
|
|
||||||
'then'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
locationService
|
|
||||||
.getLocationFromUser
|
|
||||||
.and.returnValue(locationServicePromise);
|
|
||||||
|
|
||||||
moveService = new MockMoveService();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("with context from context-action", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
context = {
|
|
||||||
domainObject: selectedObject
|
|
||||||
};
|
|
||||||
|
|
||||||
moveAction = new MoveAction(
|
|
||||||
policyService,
|
|
||||||
locationService,
|
|
||||||
moveService,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("initializes happily", function () {
|
|
||||||
expect(moveAction).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when performed it", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
moveAction.perform();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("prompts for location", function () {
|
|
||||||
expect(locationService.getLocationFromUser)
|
|
||||||
.toHaveBeenCalledWith(
|
|
||||||
"Move selectedObject To a New Location",
|
|
||||||
"Move To",
|
|
||||||
jasmine.any(Function),
|
|
||||||
currentParent
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("waits for location and handles cancellation by user", function () {
|
|
||||||
expect(locationServicePromise.then)
|
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("moves object to selected location", function () {
|
|
||||||
locationServicePromise
|
|
||||||
.then
|
|
||||||
.calls.mostRecent()
|
|
||||||
.args[0](newParent);
|
|
||||||
|
|
||||||
expect(moveService.perform)
|
|
||||||
.toHaveBeenCalledWith(selectedObject, newParent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("with context from drag-drop", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
context = {
|
|
||||||
selectedObject: selectedObject,
|
|
||||||
domainObject: newParent
|
|
||||||
};
|
|
||||||
|
|
||||||
moveAction = new MoveAction(
|
|
||||||
policyService,
|
|
||||||
locationService,
|
|
||||||
moveService,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("initializes happily", function () {
|
|
||||||
expect(moveAction).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("performs move immediately", function () {
|
|
||||||
moveAction.perform();
|
|
||||||
expect(moveService.perform)
|
|
||||||
.toHaveBeenCalledWith(selectedObject, newParent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,124 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define([
|
|
||||||
'../../src/policies/MovePolicy',
|
|
||||||
'../DomainObjectFactory'
|
|
||||||
], function (MovePolicy, domainObjectFactory) {
|
|
||||||
|
|
||||||
describe("MovePolicy", function () {
|
|
||||||
var testMetadata,
|
|
||||||
testContext,
|
|
||||||
mockDomainObject,
|
|
||||||
mockParent,
|
|
||||||
mockParentType,
|
|
||||||
mockType,
|
|
||||||
mockAction,
|
|
||||||
policy;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
var mockContextCapability =
|
|
||||||
jasmine.createSpyObj('context', ['getParent']);
|
|
||||||
|
|
||||||
mockType =
|
|
||||||
jasmine.createSpyObj('type', ['hasFeature']);
|
|
||||||
mockParentType =
|
|
||||||
jasmine.createSpyObj('parent-type', ['hasFeature']);
|
|
||||||
|
|
||||||
testMetadata = {};
|
|
||||||
|
|
||||||
mockDomainObject = domainObjectFactory({
|
|
||||||
capabilities: {
|
|
||||||
context: mockContextCapability,
|
|
||||||
type: mockType
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mockParent = domainObjectFactory({
|
|
||||||
capabilities: {
|
|
||||||
type: mockParentType
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mockContextCapability.getParent.and.returnValue(mockParent);
|
|
||||||
|
|
||||||
mockType.hasFeature.and.callFake(function (feature) {
|
|
||||||
return feature === 'creation';
|
|
||||||
});
|
|
||||||
mockParentType.hasFeature.and.callFake(function (feature) {
|
|
||||||
return feature === 'creation';
|
|
||||||
});
|
|
||||||
|
|
||||||
mockAction = jasmine.createSpyObj('action', ['getMetadata']);
|
|
||||||
mockAction.getMetadata.and.returnValue(testMetadata);
|
|
||||||
|
|
||||||
testContext = { domainObject: mockDomainObject };
|
|
||||||
|
|
||||||
policy = new MovePolicy();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("for move actions", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
testMetadata.key = 'move';
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when an object is non-modifiable", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
mockType.hasFeature.and.returnValue(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("disallows the action", function () {
|
|
||||||
expect(policy.allow(mockAction, testContext)).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when a parent is non-modifiable", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
mockParentType.hasFeature.and.returnValue(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("disallows the action", function () {
|
|
||||||
expect(policy.allow(mockAction, testContext)).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when an object and its parent are modifiable", function () {
|
|
||||||
it("allows the action", function () {
|
|
||||||
expect(policy.allow(mockAction, testContext)).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("for other actions", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
testMetadata.key = 'foo';
|
|
||||||
});
|
|
||||||
|
|
||||||
it("simply allows the action", function () {
|
|
||||||
expect(policy.allow(mockAction, testContext)).toBe(true);
|
|
||||||
mockType.hasFeature.and.returnValue(false);
|
|
||||||
expect(policy.allow(mockAction, testContext)).toBe(true);
|
|
||||||
mockParentType.hasFeature.and.returnValue(false);
|
|
||||||
expect(policy.allow(mockAction, testContext)).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,96 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MockMoveService provides the same interface as the moveService,
|
|
||||||
* returning promises where it would normally do so. At it's core,
|
|
||||||
* it is a jasmine spy object, but it also tracks the promises it
|
|
||||||
* returns and provides shortcut methods for resolving those promises
|
|
||||||
* synchronously.
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
*
|
|
||||||
* ```javascript
|
|
||||||
* var moveService = new MockMoveService();
|
|
||||||
*
|
|
||||||
* // validate is a standard jasmine spy.
|
|
||||||
* moveService.validate.and.returnValue(true);
|
|
||||||
* var isValid = moveService.validate(object, parentCandidate);
|
|
||||||
* expect(isValid).toBe(true);
|
|
||||||
*
|
|
||||||
* // perform returns promises and tracks them.
|
|
||||||
* var whenCopied = jasmine.createSpy('whenCopied');
|
|
||||||
* moveService.perform(object, parentObject).then(whenCopied);
|
|
||||||
* expect(whenCopied).not.toHaveBeenCalled();
|
|
||||||
* moveService.perform.calls.mostRecent().resolve('someArg');
|
|
||||||
* expect(whenCopied).toHaveBeenCalledWith('someArg');
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
function MockMoveService() {
|
|
||||||
// track most recent call of a function,
|
|
||||||
// perform automatically returns
|
|
||||||
var mockMoveService = jasmine.createSpyObj(
|
|
||||||
'MockMoveService',
|
|
||||||
[
|
|
||||||
'validate',
|
|
||||||
'perform'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
mockMoveService.perform.and.callFake(() => {
|
|
||||||
var performPromise,
|
|
||||||
callExtensions,
|
|
||||||
spy;
|
|
||||||
|
|
||||||
performPromise = jasmine.createSpyObj(
|
|
||||||
'performPromise',
|
|
||||||
['then']
|
|
||||||
);
|
|
||||||
|
|
||||||
callExtensions = {
|
|
||||||
promise: performPromise,
|
|
||||||
resolve: function (resolveWith) {
|
|
||||||
performPromise.then.calls.all().forEach(function (call) {
|
|
||||||
call.args[0](resolveWith);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
spy = mockMoveService.perform;
|
|
||||||
|
|
||||||
Object.keys(callExtensions).forEach(function (key) {
|
|
||||||
spy.calls.mostRecent()[key] = callExtensions[key];
|
|
||||||
spy.calls.all()[spy.calls.count() - 1][key] = callExtensions[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
return performPromise;
|
|
||||||
});
|
|
||||||
|
|
||||||
return mockMoveService;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MockMoveService;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,260 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'../../src/services/MoveService',
|
|
||||||
'../services/MockLinkService',
|
|
||||||
'../DomainObjectFactory',
|
|
||||||
'../ControlledPromise'
|
|
||||||
],
|
|
||||||
function (
|
|
||||||
MoveService,
|
|
||||||
MockLinkService,
|
|
||||||
domainObjectFactory,
|
|
||||||
ControlledPromise
|
|
||||||
) {
|
|
||||||
|
|
||||||
xdescribe("MoveService", function () {
|
|
||||||
|
|
||||||
var moveService,
|
|
||||||
policyService,
|
|
||||||
object,
|
|
||||||
objectContextCapability,
|
|
||||||
currentParent,
|
|
||||||
parentCandidate,
|
|
||||||
linkService;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
objectContextCapability = jasmine.createSpyObj(
|
|
||||||
'objectContextCapability',
|
|
||||||
[
|
|
||||||
'getParent'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
object = domainObjectFactory({
|
|
||||||
name: 'object',
|
|
||||||
id: 'a',
|
|
||||||
capabilities: {
|
|
||||||
context: objectContextCapability,
|
|
||||||
type: { type: 'object' }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
currentParent = domainObjectFactory({
|
|
||||||
name: 'currentParent',
|
|
||||||
id: 'b'
|
|
||||||
});
|
|
||||||
|
|
||||||
objectContextCapability.getParent.and.returnValue(currentParent);
|
|
||||||
|
|
||||||
parentCandidate = domainObjectFactory({
|
|
||||||
name: 'parentCandidate',
|
|
||||||
model: { composition: [] },
|
|
||||||
id: 'c',
|
|
||||||
capabilities: {
|
|
||||||
type: { type: 'parentCandidate' }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
policyService = jasmine.createSpyObj(
|
|
||||||
'policyService',
|
|
||||||
['allow']
|
|
||||||
);
|
|
||||||
linkService = new MockLinkService();
|
|
||||||
policyService.allow.and.returnValue(true);
|
|
||||||
moveService = new MoveService(policyService, linkService);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("validate", function () {
|
|
||||||
var validate;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
validate = function () {
|
|
||||||
return moveService.validate(object, parentCandidate);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow an invalid parent", function () {
|
|
||||||
parentCandidate = undefined;
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
parentCandidate = {};
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow moving to current parent", function () {
|
|
||||||
parentCandidate.id = currentParent.id = 'xyz';
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow moving to self", function () {
|
|
||||||
object.id = parentCandidate.id = 'xyz';
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow moving to the same location", function () {
|
|
||||||
object.id = 'abc';
|
|
||||||
parentCandidate.model.composition = ['abc'];
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("defers to policyService", function () {
|
|
||||||
|
|
||||||
it("calls policy service with correct args", function () {
|
|
||||||
validate();
|
|
||||||
expect(policyService.allow).toHaveBeenCalledWith(
|
|
||||||
"composition",
|
|
||||||
parentCandidate,
|
|
||||||
object
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("and returns false", function () {
|
|
||||||
policyService.allow.and.returnValue(false);
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("and returns true", function () {
|
|
||||||
policyService.allow.and.returnValue(true);
|
|
||||||
expect(validate()).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("perform", function () {
|
|
||||||
|
|
||||||
var actionCapability,
|
|
||||||
locationCapability,
|
|
||||||
locationPromise,
|
|
||||||
newParent,
|
|
||||||
moveResult;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
newParent = parentCandidate;
|
|
||||||
|
|
||||||
actionCapability = jasmine.createSpyObj(
|
|
||||||
'actionCapability',
|
|
||||||
['perform']
|
|
||||||
);
|
|
||||||
|
|
||||||
locationCapability = jasmine.createSpyObj(
|
|
||||||
'locationCapability',
|
|
||||||
[
|
|
||||||
'isOriginal',
|
|
||||||
'setPrimaryLocation',
|
|
||||||
'getContextualLocation'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
locationPromise = new ControlledPromise();
|
|
||||||
locationCapability.setPrimaryLocation
|
|
||||||
.and.returnValue(locationPromise);
|
|
||||||
|
|
||||||
object = domainObjectFactory({
|
|
||||||
name: 'object',
|
|
||||||
capabilities: {
|
|
||||||
action: actionCapability,
|
|
||||||
location: locationCapability,
|
|
||||||
context: objectContextCapability,
|
|
||||||
type: { type: 'object' }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
moveResult = moveService.perform(object, newParent);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("links object to newParent", function () {
|
|
||||||
expect(linkService.perform).toHaveBeenCalledWith(
|
|
||||||
object,
|
|
||||||
newParent
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns a promise", function () {
|
|
||||||
expect(moveResult.then).toEqual(jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("waits for result of link", function () {
|
|
||||||
expect(linkService.perform.calls.mostRecent().promise.then)
|
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("throws an error when performed on invalid inputs", function () {
|
|
||||||
function perform() {
|
|
||||||
moveService.perform(object, newParent);
|
|
||||||
}
|
|
||||||
|
|
||||||
spyOn(moveService, "validate");
|
|
||||||
moveService.validate.and.returnValue(true);
|
|
||||||
expect(perform).not.toThrow();
|
|
||||||
moveService.validate.and.returnValue(false);
|
|
||||||
expect(perform).toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when moving an original", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
locationCapability.getContextualLocation
|
|
||||||
.and.returnValue('new-location');
|
|
||||||
locationCapability.isOriginal.and.returnValue(true);
|
|
||||||
linkService.perform.calls.mostRecent().promise.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates location", function () {
|
|
||||||
expect(locationCapability.setPrimaryLocation)
|
|
||||||
.toHaveBeenCalledWith('new-location');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("after location update", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
locationPromise.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes object from parent without user warning dialog", function () {
|
|
||||||
expect(actionCapability.perform)
|
|
||||||
.toHaveBeenCalledWith('remove', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when moving a link", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
locationCapability.isOriginal.and.returnValue(false);
|
|
||||||
linkService.perform.calls.mostRecent().promise.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not update location", function () {
|
|
||||||
expect(locationCapability.setPrimaryLocation)
|
|
||||||
.not
|
|
||||||
.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes object from parent without user warning dialog", function () {
|
|
||||||
expect(actionCapability.perform)
|
|
||||||
.toHaveBeenCalledWith('remove', true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -46,6 +46,7 @@ define([
|
|||||||
'./api/Branding',
|
'./api/Branding',
|
||||||
'./plugins/licenses/plugin',
|
'./plugins/licenses/plugin',
|
||||||
'./plugins/remove/plugin',
|
'./plugins/remove/plugin',
|
||||||
|
'./plugins/move/plugin',
|
||||||
'./plugins/duplicate/plugin',
|
'./plugins/duplicate/plugin',
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
@ -74,6 +75,7 @@ define([
|
|||||||
BrandingAPI,
|
BrandingAPI,
|
||||||
LicensesPlugin,
|
LicensesPlugin,
|
||||||
RemoveActionPlugin,
|
RemoveActionPlugin,
|
||||||
|
MoveActionPlugin,
|
||||||
DuplicateActionPlugin,
|
DuplicateActionPlugin,
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
@ -265,6 +267,7 @@ define([
|
|||||||
this.install(LegacyIndicatorsPlugin());
|
this.install(LegacyIndicatorsPlugin());
|
||||||
this.install(LicensesPlugin.default());
|
this.install(LicensesPlugin.default());
|
||||||
this.install(RemoveActionPlugin.default());
|
this.install(RemoveActionPlugin.default());
|
||||||
|
this.install(MoveActionPlugin.default());
|
||||||
this.install(DuplicateActionPlugin.default());
|
this.install(DuplicateActionPlugin.default());
|
||||||
this.install(this.plugins.FolderView());
|
this.install(this.plugins.FolderView());
|
||||||
this.install(this.plugins.Tabs());
|
this.install(this.plugins.Tabs());
|
||||||
|
166
src/plugins/move/MoveAction.js
Normal file
166
src/plugins/move/MoveAction.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -19,45 +19,10 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import MoveAction from "./MoveAction";
|
||||||
|
|
||||||
define([], function () {
|
export default function () {
|
||||||
|
return function (openmct) {
|
||||||
/**
|
openmct.actions.register(new MoveAction(openmct));
|
||||||
* Disallow moves when either the parent or the child are not
|
|
||||||
* modifiable by users.
|
|
||||||
* @constructor
|
|
||||||
* @implements {Policy}
|
|
||||||
* @memberof platform/entanglement
|
|
||||||
*/
|
|
||||||
function MovePolicy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function parentOf(domainObject) {
|
|
||||||
var context = domainObject.getCapability('context');
|
|
||||||
|
|
||||||
return context && context.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
function allowMutation(domainObject) {
|
|
||||||
var type = domainObject && domainObject.getCapability('type');
|
|
||||||
|
|
||||||
return Boolean(type && type.hasFeature('creation'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectedObject(context) {
|
|
||||||
return context.selectedObject || context.domainObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
MovePolicy.prototype.allow = function (action, context) {
|
|
||||||
var key = action.getMetadata().key;
|
|
||||||
|
|
||||||
if (key === 'move') {
|
|
||||||
return allowMutation(selectedObject(context))
|
|
||||||
&& allowMutation(parentOf(selectedObject(context)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
return MovePolicy;
|
|
||||||
});
|
|
110
src/plugins/move/pluginSpec.js
Normal file
110
src/plugins/move/pluginSpec.js
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user