mirror of
https://github.com/nasa/openmct.git
synced 2024-12-27 16:38:51 +00:00
Merge branch 'open338' into rems_data
This commit is contained in:
commit
7fad2f6f2e
@ -102,6 +102,12 @@
|
|||||||
"implementation": "navigation/NavigationService.js"
|
"implementation": "navigation/NavigationService.js"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"implementation": "creation/CreationPolicy.js",
|
||||||
|
"category": "creation"
|
||||||
|
}
|
||||||
|
],
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
"key": "navigate",
|
"key": "navigate",
|
||||||
|
@ -69,7 +69,7 @@ define(
|
|||||||
|
|
||||||
// Introduce one create action per type
|
// Introduce one create action per type
|
||||||
return this.typeService.listTypes().filter(function (type) {
|
return this.typeService.listTypes().filter(function (type) {
|
||||||
return type.hasFeature("creation");
|
return self.policyService.allow("creation", type);
|
||||||
}).map(function (type) {
|
}).map(function (type) {
|
||||||
return new CreateAction(
|
return new CreateAction(
|
||||||
type,
|
type,
|
||||||
|
49
platform/commonUI/browse/src/creation/CreationPolicy.js
Normal file
49
platform/commonUI/browse/src/creation/CreationPolicy.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A policy for determining whether objects of a certain type can be
|
||||||
|
* created.
|
||||||
|
* @returns {{allow: Function}}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function CreationPolicy() {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Only allow creation of object types that have the
|
||||||
|
* Creation capability
|
||||||
|
*/
|
||||||
|
allow: function (type) {
|
||||||
|
return type.hasFeature("creation");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreationPolicy;
|
||||||
|
}
|
||||||
|
);
|
@ -33,6 +33,9 @@ define(
|
|||||||
var mockTypeService,
|
var mockTypeService,
|
||||||
mockDialogService,
|
mockDialogService,
|
||||||
mockCreationService,
|
mockCreationService,
|
||||||
|
mockPolicyService,
|
||||||
|
mockCreationPolicy,
|
||||||
|
mockPolicyMap = {},
|
||||||
mockTypes,
|
mockTypes,
|
||||||
provider;
|
provider;
|
||||||
|
|
||||||
@ -67,14 +70,32 @@ define(
|
|||||||
"creationService",
|
"creationService",
|
||||||
[ "createObject" ]
|
[ "createObject" ]
|
||||||
);
|
);
|
||||||
|
mockPolicyService = jasmine.createSpyObj(
|
||||||
|
"policyService",
|
||||||
|
[ "allow" ]
|
||||||
|
);
|
||||||
|
|
||||||
mockTypes = [ "A", "B", "C" ].map(createMockType);
|
mockTypes = [ "A", "B", "C" ].map(createMockType);
|
||||||
|
|
||||||
|
mockTypes.forEach(function(type){
|
||||||
|
mockPolicyMap[type.getName()] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mockCreationPolicy = function(type){
|
||||||
|
return mockPolicyMap[type.getName()];
|
||||||
|
};
|
||||||
|
|
||||||
|
mockPolicyService.allow.andCallFake(function(category, type){
|
||||||
|
return category === "creation" && mockCreationPolicy(type) ? true : false;
|
||||||
|
});
|
||||||
|
|
||||||
mockTypeService.listTypes.andReturn(mockTypes);
|
mockTypeService.listTypes.andReturn(mockTypes);
|
||||||
|
|
||||||
provider = new CreateActionProvider(
|
provider = new CreateActionProvider(
|
||||||
mockTypeService,
|
mockTypeService,
|
||||||
mockDialogService,
|
mockDialogService,
|
||||||
mockCreationService
|
mockCreationService,
|
||||||
|
mockPolicyService
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -94,15 +115,15 @@ define(
|
|||||||
|
|
||||||
it("does not expose non-creatable types", function () {
|
it("does not expose non-creatable types", function () {
|
||||||
// One of the types won't have the creation feature...
|
// One of the types won't have the creation feature...
|
||||||
mockTypes[1].hasFeature.andReturn(false);
|
mockPolicyMap[mockTypes[0].getName()] = false;
|
||||||
// ...so it should have been filtered out.
|
// ...so it should have been filtered out.
|
||||||
expect(provider.getActions({
|
expect(provider.getActions({
|
||||||
key: "create",
|
key: "create",
|
||||||
domainObject: {}
|
domainObject: {}
|
||||||
}).length).toEqual(2);
|
}).length).toEqual(2);
|
||||||
// Make sure it was creation which was used to check
|
// Make sure it was creation which was used to check
|
||||||
expect(mockTypes[1].hasFeature)
|
expect(mockPolicyService.allow)
|
||||||
.toHaveBeenCalledWith("creation");
|
.toHaveBeenCalledWith("creation", mockTypes[0]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
53
platform/commonUI/browse/test/creation/CreationPolicySpec.js
Normal file
53
platform/commonUI/browse/test/creation/CreationPolicySpec.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
["../../src/creation/CreationPolicy"],
|
||||||
|
function (CreationPolicy) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The creation policy", function () {
|
||||||
|
var mockType,
|
||||||
|
policy;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockType = jasmine.createSpyObj(
|
||||||
|
'type',
|
||||||
|
['hasFeature']
|
||||||
|
);
|
||||||
|
|
||||||
|
policy = new CreationPolicy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows creation of types with the creation feature", function () {
|
||||||
|
mockType.hasFeature.andReturn(true);
|
||||||
|
expect(policy.allow(mockType)).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("disallows creation of types without the creation feature", function () {
|
||||||
|
mockType.hasFeature.andReturn(false);
|
||||||
|
expect(policy.allow(mockType)).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -8,6 +8,7 @@
|
|||||||
"creation/CreateMenuController",
|
"creation/CreateMenuController",
|
||||||
"creation/CreateWizard",
|
"creation/CreateWizard",
|
||||||
"creation/CreationService",
|
"creation/CreationService",
|
||||||
|
"creation/CreationPolicy",
|
||||||
"creation/LocatorController",
|
"creation/LocatorController",
|
||||||
"navigation/NavigateAction",
|
"navigation/NavigateAction",
|
||||||
"navigation/NavigationService",
|
"navigation/NavigationService",
|
||||||
|
@ -28,9 +28,7 @@ define(
|
|||||||
|
|
||||||
var DISALLOWED_ACTIONS = [
|
var DISALLOWED_ACTIONS = [
|
||||||
"move",
|
"move",
|
||||||
"copy",
|
"copy"
|
||||||
"link",
|
|
||||||
"compose"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,7 +71,7 @@ define(
|
|||||||
*/
|
*/
|
||||||
CopyService.prototype.perform = function (domainObject, parent) {
|
CopyService.prototype.perform = function (domainObject, parent) {
|
||||||
var $q = this.$q,
|
var $q = this.$q,
|
||||||
copyTask = new CopyTask(domainObject, parent, this.persistenceService, this.$q, this.now);
|
copyTask = new CopyTask(domainObject, parent, this.persistenceService, this.policyService, this.$q, this.now);
|
||||||
if (this.validate(domainObject, parent)) {
|
if (this.validate(domainObject, parent)) {
|
||||||
return copyTask.perform();
|
return copyTask.perform();
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,12 +38,14 @@ define(
|
|||||||
* @param now
|
* @param now
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CopyTask (domainObject, parent, persistenceService, $q, now){
|
function CopyTask (domainObject, parent, persistenceService, policyService, $q, now){
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.$q = $q;
|
this.$q = $q;
|
||||||
this.deferred = undefined;
|
this.deferred = undefined;
|
||||||
this.persistenceService = persistenceService;
|
this.persistenceService = persistenceService;
|
||||||
|
this.policyService = policyService;
|
||||||
|
this.persistenceSpace = parent.getCapability("persistence") && parent.getCapability("persistence").getSpace();
|
||||||
this.persisted = 0;
|
this.persisted = 0;
|
||||||
this.now = now;
|
this.now = now;
|
||||||
this.clones = [];
|
this.clones = [];
|
||||||
@ -52,17 +54,31 @@ define(
|
|||||||
function composeChild(child, parent) {
|
function composeChild(child, parent) {
|
||||||
//Once copied, associate each cloned
|
//Once copied, associate each cloned
|
||||||
// composee with its parent clone
|
// composee with its parent clone
|
||||||
child.model.location = parent.id;
|
|
||||||
parent.model.composition = parent.model.composition || [];
|
parent.getModel().composition.push(child.getId());
|
||||||
return parent.model.composition.push(child.id);
|
|
||||||
|
//Check if the object being composed is a link
|
||||||
|
if (!child.getCapability("location").isLink()) {
|
||||||
|
child.getModel().location = parent.getId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneObjectModel(objectModel) {
|
function cloneObjectModel(objectModel) {
|
||||||
var clone = JSON.parse(JSON.stringify(objectModel));
|
var clone = JSON.parse(JSON.stringify(objectModel));
|
||||||
|
|
||||||
delete clone.composition;
|
/**
|
||||||
|
* Reset certain fields.
|
||||||
|
*/
|
||||||
|
//If has a composition, set it to an empty array. Will be
|
||||||
|
// recomposed later with the ids of its cloned children.
|
||||||
|
if (clone.composition) {
|
||||||
|
//Important to set it to an empty array here, otherwise
|
||||||
|
// hasCapability("composition") returns false;
|
||||||
|
clone.composition = [];
|
||||||
|
}
|
||||||
delete clone.persisted;
|
delete clone.persisted;
|
||||||
delete clone.modified;
|
delete clone.modified;
|
||||||
|
delete clone.location;
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
@ -73,13 +89,10 @@ define(
|
|||||||
* result in automatic request batching by the browser.
|
* result in automatic request batching by the browser.
|
||||||
*/
|
*/
|
||||||
function persistObjects(self) {
|
function persistObjects(self) {
|
||||||
|
|
||||||
return self.$q.all(self.clones.map(function(clone){
|
return self.$q.all(self.clones.map(function(clone){
|
||||||
clone.model.persisted = self.now();
|
return clone.getCapability("persistence").persist().then(function(){
|
||||||
return self.persistenceService.createObject(clone.persistenceSpace, clone.id, clone.model)
|
self.deferred.notify({phase: "copying", totalObjects: self.clones.length, processed: ++self.persisted});
|
||||||
.then(function(){
|
});
|
||||||
self.deferred.notify({phase: "copying", totalObjects: self.clones.length, processed: ++self.persisted});
|
|
||||||
});
|
|
||||||
})).then(function(){
|
})).then(function(){
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
@ -91,15 +104,13 @@ define(
|
|||||||
function addClonesToParent(self) {
|
function addClonesToParent(self) {
|
||||||
var parentClone = self.clones[self.clones.length-1];
|
var parentClone = self.clones[self.clones.length-1];
|
||||||
|
|
||||||
if (!self.parent.hasCapability('composition')){
|
//self.persistenceService
|
||||||
return self.$q.reject();
|
// .updateObject(self.persistenceSpace,
|
||||||
}
|
// parentClone.id, parentClone.model)
|
||||||
|
return parentClone.getCapability("persistence").persist()
|
||||||
return self.persistenceService
|
.then(function(){self.parent.getCapability("composition").add(parentClone.getId())})
|
||||||
.updateObject(parentClone.persistenceSpace, parentClone.id, parentClone.model)
|
.then(function(){return self.parent.getCapability("persistence").persist();})
|
||||||
.then(function(){return self.parent.getCapability("composition").add(parentClone.id);})
|
.then(function(){return parentClone;});
|
||||||
.then(function(){return self.parent.getCapability("persistence").persist();})
|
|
||||||
.then(function(){return parentClone;});
|
|
||||||
// Ensure the clone of the original domainObject is returned
|
// Ensure the clone of the original domainObject is returned
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +129,7 @@ define(
|
|||||||
return promise.then(function(){
|
return promise.then(function(){
|
||||||
// ...to recursively copy it (and its children)
|
// ...to recursively copy it (and its children)
|
||||||
return self.copy(composee, originalParent).then(function(composee){
|
return self.copy(composee, originalParent).then(function(composee){
|
||||||
composeChild(composee, clonedParent);
|
return composeChild(composee, clonedParent);
|
||||||
});
|
});
|
||||||
});}, self.$q.when(undefined)
|
});}, self.$q.when(undefined)
|
||||||
);
|
);
|
||||||
@ -137,23 +148,37 @@ define(
|
|||||||
*/
|
*/
|
||||||
CopyTask.prototype.copy = function(originalObject, originalParent) {
|
CopyTask.prototype.copy = function(originalObject, originalParent) {
|
||||||
var self = this,
|
var self = this,
|
||||||
modelClone = {
|
clone;
|
||||||
id: uuid(),
|
|
||||||
model: cloneObjectModel(originalObject.getModel()),
|
|
||||||
persistenceSpace: originalParent.hasCapability('persistence') && originalParent.getCapability('persistence').getSpace()
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.$q.when(originalObject.useCapability('composition')).then(function(composees){
|
//Check if the type of the object being copied allows for
|
||||||
self.deferred.notify({phase: "preparing"});
|
// creation of new instances. If it does not, then a link to the
|
||||||
//Duplicate the object's children, and their children, and
|
// original will be created instead.
|
||||||
// so on down to the leaf nodes of the tree.
|
if (this.policyService.allow("creation", originalObject.getCapability("type"))){
|
||||||
return self.copyComposees(composees, modelClone, originalObject).then(function (){
|
//create a new clone of the original object. Use the
|
||||||
//Add the clone to the list of clones that will
|
// creation capability of the targetParent to create the
|
||||||
//be returned by this function
|
// new clone. This will ensure that the correct persistence
|
||||||
self.clones.push(modelClone);
|
// space is used.
|
||||||
return modelClone;
|
clone = this.parent.hasCapability("instantiation") && originalParent.useCapability("instantiation", cloneObjectModel(originalObject.getModel()));
|
||||||
|
|
||||||
|
//Iterate through child tree
|
||||||
|
return this.$q.when(originalObject.useCapability('composition')).then(function(composees){
|
||||||
|
self.deferred.notify({phase: "preparing"});
|
||||||
|
//Duplicate the object's children, and their children, and
|
||||||
|
// so on down to the leaf nodes of the tree.
|
||||||
|
//If it is a link, don't both with children
|
||||||
|
return self.copyComposees(composees, clone, originalObject).then(function (){
|
||||||
|
//Add the clone to the list of clones that will
|
||||||
|
//be returned by this function
|
||||||
|
self.clones.push(clone);
|
||||||
|
return clone;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
} else {
|
||||||
|
//Creating a link, no need to iterate children
|
||||||
|
return $q.when(originalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,6 +210,10 @@ define(
|
|||||||
CopyTask.prototype.perform = function(){
|
CopyTask.prototype.perform = function(){
|
||||||
this.deferred = this.$q.defer();
|
this.deferred = this.$q.defer();
|
||||||
|
|
||||||
|
if (!this.parent.hasCapability('composition')){
|
||||||
|
return self.$q.reject();
|
||||||
|
}
|
||||||
|
|
||||||
this.buildCopyPlan()
|
this.buildCopyPlan()
|
||||||
.then(persistObjects)
|
.then(persistObjects)
|
||||||
.then(addClonesToParent)
|
.then(addClonesToParent)
|
||||||
|
@ -72,7 +72,7 @@ define(
|
|||||||
policy = new CrossSpacePolicy();
|
policy = new CrossSpacePolicy();
|
||||||
});
|
});
|
||||||
|
|
||||||
['move', 'copy', 'link', 'compose'].forEach(function (key) {
|
['move', 'copy'].forEach(function (key) {
|
||||||
describe("for " + key + " actions", function () {
|
describe("for " + key + " actions", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
testActionMetadata.key = key;
|
testActionMetadata.key = key;
|
||||||
|
Loading…
Reference in New Issue
Block a user