mirror of
https://github.com/nasa/openmct.git
synced 2025-02-21 01:42:31 +00:00
Merge pull request #666 from nasa/open656b
[Create] Utilize copyService during Save As
This commit is contained in:
commit
42ce2aa7cf
@ -156,14 +156,11 @@ define([
|
||||
"name": "Save",
|
||||
"description": "Save changes made to these objects.",
|
||||
"depends": [
|
||||
"$q",
|
||||
"$location",
|
||||
"$injector",
|
||||
"urlService",
|
||||
"navigationService",
|
||||
"policyService",
|
||||
"dialogService",
|
||||
"creationService"
|
||||
"creationService",
|
||||
"copyService"
|
||||
],
|
||||
"priority": "mandatory"
|
||||
},
|
||||
|
@ -36,18 +36,22 @@ define(
|
||||
* @implements {Action}
|
||||
* @memberof platform/commonUI/edit
|
||||
*/
|
||||
function SaveAction($q, $location, $injector, urlService, navigationService, policyService, dialogService, creationService, context) {
|
||||
function SaveAction(
|
||||
$injector,
|
||||
policyService,
|
||||
dialogService,
|
||||
creationService,
|
||||
copyService,
|
||||
context
|
||||
) {
|
||||
this.domainObject = (context || {}).domainObject;
|
||||
this.$location = $location;
|
||||
this.injectObjectService = function(){
|
||||
this.objectService = $injector.get("objectService");
|
||||
};
|
||||
this.urlService = urlService;
|
||||
this.navigationService = navigationService;
|
||||
this.policyService = policyService;
|
||||
this.dialogService = dialogService;
|
||||
this.creationService = creationService;
|
||||
this.$q = $q;
|
||||
this.copyService = copyService;
|
||||
}
|
||||
|
||||
SaveAction.prototype.getObjectService = function(){
|
||||
@ -67,35 +71,29 @@ define(
|
||||
*/
|
||||
SaveAction.prototype.perform = function () {
|
||||
var domainObject = this.domainObject,
|
||||
$location = this.$location,
|
||||
urlService = this.urlService,
|
||||
copyService = this.copyService,
|
||||
self = this;
|
||||
|
||||
function resolveWith(object){
|
||||
return function() {
|
||||
return function () {
|
||||
return object;
|
||||
};
|
||||
}
|
||||
|
||||
function doWizardSave(parent) {
|
||||
var context = domainObject.getCapability("context"),
|
||||
wizard = new CreateWizard(domainObject, parent, self.policyService);
|
||||
wizard = new CreateWizard(
|
||||
domainObject,
|
||||
parent,
|
||||
self.policyService
|
||||
);
|
||||
|
||||
return self.dialogService
|
||||
.getUserInput(wizard.getFormStructure(true), wizard.getInitialFormValue())
|
||||
.then(function(formValue){
|
||||
return wizard.populateObjectFromInput(formValue, domainObject);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function persistObject(object){
|
||||
|
||||
//Persist first to mark dirty
|
||||
return object.getCapability('persistence').persist().then(function(){
|
||||
//then save permanently
|
||||
return object.getCapability('editor').save();
|
||||
});
|
||||
.getUserInput(
|
||||
wizard.getFormStructure(true),
|
||||
wizard.getInitialFormValue()
|
||||
)
|
||||
.then(wizard.populateObjectFromInput.bind(wizard));
|
||||
}
|
||||
|
||||
function fetchObject(objectId){
|
||||
@ -108,16 +106,18 @@ define(
|
||||
return fetchObject(object.getModel().location);
|
||||
}
|
||||
|
||||
function locateObjectInParent(parent){
|
||||
parent.getCapability('composition').add(domainObject.getId());
|
||||
return parent.getCapability('persistence').persist().then(function() {
|
||||
return parent;
|
||||
});
|
||||
function allowClone(objectToClone) {
|
||||
return (objectToClone.getId() === domainObject.getId()) ||
|
||||
objectToClone.getCapability('location').isOriginal();
|
||||
}
|
||||
|
||||
function doNothing() {
|
||||
// Create cancelled, do nothing
|
||||
return false;
|
||||
function cloneIntoParent(parent) {
|
||||
return copyService.perform(domainObject, parent, allowClone);
|
||||
}
|
||||
|
||||
function cancelEditingAfterClone(clonedObject) {
|
||||
return domainObject.getCapability("editor").cancel()
|
||||
.then(resolveWith(clonedObject));
|
||||
}
|
||||
|
||||
// Invoke any save behavior introduced by the editor capability;
|
||||
@ -127,17 +127,13 @@ define(
|
||||
function doSave() {
|
||||
//This is a new 'virtual object' that has not been persisted
|
||||
// yet.
|
||||
if (!domainObject.getModel().persisted){
|
||||
if (domainObject.getModel().persisted === undefined){
|
||||
return getParent(domainObject)
|
||||
.then(doWizardSave)
|
||||
.then(persistObject)
|
||||
.then(getParent)//Parent may have changed based
|
||||
// on user selection
|
||||
.then(locateObjectInParent)
|
||||
.then(function(){
|
||||
return fetchObject(domainObject.getId());
|
||||
})
|
||||
.catch(doNothing);
|
||||
.then(doWizardSave)
|
||||
.then(getParent)
|
||||
.then(cloneIntoParent)
|
||||
.then(cancelEditingAfterClone)
|
||||
.catch(resolveWith(false));
|
||||
} else {
|
||||
return domainObject.getCapability("editor").save()
|
||||
.then(resolveWith(domainObject.getOriginalObject()));
|
||||
@ -148,7 +144,7 @@ define(
|
||||
// UI, which will have been pushed atop the Browse UI.)
|
||||
function returnToBrowse(object) {
|
||||
if (object) {
|
||||
self.navigationService.setNavigation(object);
|
||||
object.getCapability("action").perform("navigate");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
@ -54,20 +54,52 @@ define(
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* A function used to check if a domain object should be cloned
|
||||
* or not.
|
||||
* @callback platform/entanglement.CopyService~filter
|
||||
* @param {DomainObject} domainObject the object to be cloned
|
||||
* @returns {boolean} true if the object should be cloned; false
|
||||
* if it should be linked
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a duplicate of the object tree starting at domainObject to
|
||||
* the new parent specified.
|
||||
* @param domainObject
|
||||
* @param parent
|
||||
* @param progress
|
||||
*
|
||||
* Any domain objects which cannot be created will not be cloned;
|
||||
* instead, these will appear as links. If a filtering function
|
||||
* is provided, any objects which fail that check will also be
|
||||
* linked instead of cloned
|
||||
*
|
||||
* @param {DomainObject} domainObject the object to duplicate
|
||||
* @param {DomainObject} parent the destination for the clone
|
||||
* @param {platform/entanglement.CopyService~filter} [filter]
|
||||
* an optional function used to filter out objects from
|
||||
* the cloning process
|
||||
* @returns a promise that will be completed with the clone of
|
||||
* domainObject when the duplication is successful.
|
||||
*/
|
||||
CopyService.prototype.perform = function (domainObject, parent) {
|
||||
var $q = this.$q,
|
||||
copyTask = new CopyTask(domainObject, parent, this.policyService, this.$q);
|
||||
CopyService.prototype.perform = function (domainObject, parent, filter) {
|
||||
var policyService = this.policyService;
|
||||
|
||||
// Combines caller-provided filter (if any) with the
|
||||
// baseline behavior of respecting creation policy.
|
||||
function filterWithPolicy(domainObject) {
|
||||
return (!filter || filter(domainObject)) &&
|
||||
policyService.allow(
|
||||
"creation",
|
||||
domainObject.getCapability("type")
|
||||
);
|
||||
}
|
||||
|
||||
if (this.validate(domainObject, parent)) {
|
||||
return copyTask.perform();
|
||||
return new CopyTask(
|
||||
domainObject,
|
||||
parent,
|
||||
filterWithPolicy,
|
||||
this.$q
|
||||
).perform();
|
||||
} else {
|
||||
throw new Error(
|
||||
"Tried to copy objects without validating first."
|
||||
|
@ -31,18 +31,21 @@ define(
|
||||
* This class encapsulates the process of copying a domain object
|
||||
* and all of its children.
|
||||
*
|
||||
* @param domainObject The object to copy
|
||||
* @param parent The new location of the cloned object tree
|
||||
* @param $q
|
||||
* @param {DomainObject} domainObject The object to copy
|
||||
* @param {DomainObject} parent The new location of the cloned object tree
|
||||
* @param {platform/entanglement.CopyService~filter} filter
|
||||
* a function used to filter out objects from
|
||||
* the cloning process
|
||||
* @param $q Angular's $q, for promises
|
||||
* @constructor
|
||||
*/
|
||||
function CopyTask (domainObject, parent, policyService, $q){
|
||||
function CopyTask (domainObject, parent, filter, $q){
|
||||
this.domainObject = domainObject;
|
||||
this.parent = parent;
|
||||
this.firstClone = undefined;
|
||||
this.$q = $q;
|
||||
this.deferred = undefined;
|
||||
this.policyService = policyService;
|
||||
this.filter = filter;
|
||||
this.persisted = 0;
|
||||
this.clones = [];
|
||||
this.idMap = {};
|
||||
@ -101,9 +104,14 @@ define(
|
||||
* Will add a list of clones to the specified parent's composition
|
||||
*/
|
||||
function addClonesToParent(self) {
|
||||
self.parent.getCapability("composition").add(self.firstClone.getId());
|
||||
return self.parent.getCapability("persistence").persist()
|
||||
.then(function(){return self.firstClone;});
|
||||
return self.parent.getCapability("composition")
|
||||
.add(self.firstClone)
|
||||
.then(function (addedClone) {
|
||||
return self.parent.getCapability("persistence").persist()
|
||||
.then(function () {
|
||||
return addedClone;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,7 +201,7 @@ define(
|
||||
//Check if the type of the object being copied allows for
|
||||
// creation of new instances. If it does not, then a link to the
|
||||
// original will be created instead.
|
||||
if (this.policyService.allow("creation", originalObject.getCapability("type"))){
|
||||
if (this.filter(originalObject)) {
|
||||
//create a new clone of the original object. Use the
|
||||
// creation capability of the targetParent to create the
|
||||
// new clone. This will ensure that the correct persistence
|
||||
|
@ -162,6 +162,7 @@ define(
|
||||
'compositionCapability',
|
||||
['invoke', 'add']
|
||||
);
|
||||
compositionCapability.add.andCallFake(synchronousPromise);
|
||||
|
||||
locationCapability = jasmine.createSpyObj(
|
||||
'locationCapability',
|
||||
@ -387,6 +388,7 @@ define(
|
||||
expect(childObjectClone.getModel().location).toEqual(objectClone.getId());
|
||||
});
|
||||
});
|
||||
|
||||
describe("when cloning non-creatable objects", function() {
|
||||
beforeEach(function () {
|
||||
policyService.allow.andCallFake(function(category){
|
||||
@ -401,8 +403,33 @@ define(
|
||||
it ("creates link instead of clone", function() {
|
||||
var copiedObject = copyFinished.calls[0].args[0];
|
||||
expect(copiedObject).toBe(object);
|
||||
expect(compositionCapability.add).toHaveBeenCalledWith(copiedObject.getId());
|
||||
//expect(newParent.getModel().composition).toContain(copiedObject.getId());
|
||||
expect(compositionCapability.add)
|
||||
.toHaveBeenCalledWith(copiedObject);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when provided a filtering function", function () {
|
||||
function accept() {
|
||||
return true;
|
||||
}
|
||||
function reject() {
|
||||
return false;
|
||||
}
|
||||
|
||||
it("does not create new instances of objects " +
|
||||
"rejected by the filter", function() {
|
||||
copyService.perform(object, newParent, reject)
|
||||
.then(copyFinished);
|
||||
expect(copyFinished.mostRecentCall.args[0])
|
||||
.toBe(object);
|
||||
});
|
||||
|
||||
it("does create new instances of objects " +
|
||||
"accepted by the filter", function() {
|
||||
copyService.perform(object, newParent, accept)
|
||||
.then(copyFinished);
|
||||
expect(copyFinished.mostRecentCall.args[0])
|
||||
.not.toBe(object);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -44,11 +44,10 @@ define(
|
||||
describe("CopyTask", function () {
|
||||
var mockDomainObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockFilter,
|
||||
mockQ,
|
||||
mockDeferred,
|
||||
testModel,
|
||||
mockCallback,
|
||||
counter,
|
||||
cloneIds,
|
||||
task;
|
||||
@ -119,17 +118,14 @@ define(
|
||||
mockParentObject = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities()
|
||||
});
|
||||
mockPolicyService = jasmine.createSpyObj(
|
||||
'policyService',
|
||||
[ 'allow' ]
|
||||
);
|
||||
mockFilter = jasmine.createSpy('filter');
|
||||
mockQ = jasmine.createSpyObj('$q', ['when', 'defer', 'all']);
|
||||
mockDeferred = jasmine.createSpyObj(
|
||||
'deferred',
|
||||
[ 'notify', 'resolve', 'reject' ]
|
||||
);
|
||||
|
||||
mockPolicyService.allow.andReturn(true);
|
||||
mockFilter.andReturn(true);
|
||||
|
||||
mockQ.when.andCallFake(synchronousPromise);
|
||||
mockQ.defer.andReturn(mockDeferred);
|
||||
@ -156,7 +152,7 @@ define(
|
||||
task = new CopyTask(
|
||||
mockDomainObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockFilter,
|
||||
mockQ
|
||||
);
|
||||
|
||||
@ -218,7 +214,7 @@ define(
|
||||
task = new CopyTask(
|
||||
mockComposingObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockFilter,
|
||||
mockQ
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user