From 5604120d5516258dbfc086ed9c68db98d13c90d2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 11:42:35 -0800 Subject: [PATCH 01/14] [Create] Use duplicate at end of Save ...for unpersisted objects. Ensures that they share the persistence space of their parent. #656. --- .../commonUI/edit/src/actions/SaveAction.js | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 073beeb4df..2833f5f357 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -36,7 +36,18 @@ define( * @implements {Action} * @memberof platform/commonUI/edit */ - function SaveAction($q, $location, $injector, urlService, navigationService, policyService, dialogService, creationService, context) { + function SaveAction( + $q, + $location, + $injector, + urlService, + navigationService, + policyService, + dialogService, + creationService, + copyService, + context + ) { this.domainObject = (context || {}).domainObject; this.$location = $location; this.injectObjectService = function(){ @@ -47,6 +58,7 @@ define( this.policyService = policyService; this.dialogService = dialogService; this.creationService = creationService; + this.copyService = copyService; this.$q = $q; } @@ -69,6 +81,7 @@ define( var domainObject = this.domainObject, $location = this.$location, urlService = this.urlService, + copyService = this.copyService, self = this; function resolveWith(object){ @@ -88,7 +101,6 @@ define( }); } - function persistObject(object){ //Persist first to mark dirty @@ -129,14 +141,11 @@ define( // yet. if (!domainObject.getModel().persisted){ 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()); - }) + .then(doWizardSave) + .then(copyService.perform.bind( + copyService, + [ domainObject ] + )) .catch(doNothing); } else { return domainObject.getCapability("editor").save() From 8c602025d46a50349166c4623568ff6ad93f23bb Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 11:59:17 -0800 Subject: [PATCH 02/14] [Create] Avoid navigation warning ...when navigating to a clone created via Save As. --- platform/commonUI/edit/bundle.js | 3 ++- platform/commonUI/edit/src/actions/SaveAction.js | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js index 00815faa1c..726a14bc07 100644 --- a/platform/commonUI/edit/bundle.js +++ b/platform/commonUI/edit/bundle.js @@ -163,7 +163,8 @@ define([ "navigationService", "policyService", "dialogService", - "creationService" + "creationService", + "copyService" ], "priority": "mandatory" }, diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 2833f5f357..00dd5bb639 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -132,6 +132,11 @@ define( return false; } + function cancelEditingAfterClone(clonedObject) { + return domainObject.getCapability("editor").cancel() + .then(resolveWith(clonedObject)); + } + // Invoke any save behavior introduced by the editor capability; // this is introduced by EditableDomainObject which is // used to insulate underlying objects from changes made @@ -142,10 +147,9 @@ define( if (!domainObject.getModel().persisted){ return getParent(domainObject) .then(doWizardSave) - .then(copyService.perform.bind( - copyService, - [ domainObject ] - )) + .then(getParent) + .then(copyService.perform.bind(copyService, domainObject)) + .then(cancelEditingAfterClone) .catch(doNothing); } else { return domainObject.getCapability("editor").save() From 88750d92ef19eca883f9e09716b3abae394f1296 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 12:05:01 -0800 Subject: [PATCH 03/14] [Create] Remove unused code, dependencies --- .../commonUI/edit/src/actions/SaveAction.js | 52 +++++-------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 00dd5bb639..56923d1d51 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -37,11 +37,7 @@ define( * @memberof platform/commonUI/edit */ function SaveAction( - $q, - $location, $injector, - urlService, - navigationService, policyService, dialogService, creationService, @@ -49,17 +45,13 @@ define( 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.copyService = copyService; - this.$q = $q; } SaveAction.prototype.getObjectService = function(){ @@ -79,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){ @@ -120,18 +106,6 @@ 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 doNothing() { - // Create cancelled, do nothing - return false; - } - function cancelEditingAfterClone(clonedObject) { return domainObject.getCapability("editor").cancel() .then(resolveWith(clonedObject)); @@ -150,7 +124,7 @@ define( .then(getParent) .then(copyService.perform.bind(copyService, domainObject)) .then(cancelEditingAfterClone) - .catch(doNothing); + .catch(resolveWith(false)); } else { return domainObject.getCapability("editor").save() .then(resolveWith(domainObject.getOriginalObject())); @@ -161,7 +135,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; } From c43929f1c663c3bdaaca89940ca9abf01894f2a4 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 12:07:45 -0800 Subject: [PATCH 04/14] [Create] Add specificity to check Explicitly check if an object has a persistence timestamp at all (avoids false-positives due to falsiness of zero.) --- platform/commonUI/edit/bundle.js | 4 ---- platform/commonUI/edit/src/actions/SaveAction.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js index 726a14bc07..f5142031e6 100644 --- a/platform/commonUI/edit/bundle.js +++ b/platform/commonUI/edit/bundle.js @@ -156,11 +156,7 @@ define([ "name": "Save", "description": "Save changes made to these objects.", "depends": [ - "$q", - "$location", "$injector", - "urlService", - "navigationService", "policyService", "dialogService", "creationService", diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 56923d1d51..3fb376e6fb 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -118,7 +118,7 @@ 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(getParent) From b37b82133e7ec7e79fe790e8c7487c12e4dc0c71 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 12:23:10 -0800 Subject: [PATCH 05/14] [Create] Return cloned object in context ...to allow copyService to be used in the context of a Save As action, with an appropriate navigation change. --- platform/entanglement/src/services/CopyTask.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/platform/entanglement/src/services/CopyTask.js b/platform/entanglement/src/services/CopyTask.js index 693acc2df3..1c4a27c620 100644 --- a/platform/entanglement/src/services/CopyTask.js +++ b/platform/entanglement/src/services/CopyTask.js @@ -101,9 +101,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.getId()) + .then(function (addedClone) { + return self.parent.getCapability("persistence").persist() + .then(function () { + return addedClone; + }); + }); } /** From f602aa9247007ada8569e34741280c8988221200 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 13:29:56 -0800 Subject: [PATCH 06/14] [Create] Add filter to copyService Add an optional parameter to method signature of copyService, used to determine if a domain object should or should not be cloned. This will be used to support usages of copyService where links should remain links; https://github.com/nasa/openmctweb/pull/666/files#r52525612 --- .../entanglement/src/services/CopyService.js | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/platform/entanglement/src/services/CopyService.js b/platform/entanglement/src/services/CopyService.js index bc825c0394..7cdd769018 100644 --- a/platform/entanglement/src/services/CopyService.js +++ b/platform/entanglement/src/services/CopyService.js @@ -54,16 +54,33 @@ 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) { + CopyService.prototype.perform = function (domainObject, parent, filter) { var $q = this.$q, copyTask = new CopyTask(domainObject, parent, this.policyService, this.$q); if (this.validate(domainObject, parent)) { From 72df464f0ff31bfc20d50f1e2849ce0097551295 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 13:38:53 -0800 Subject: [PATCH 07/14] [Create] Utilize passed-in filter ...when determining which objects should be cloned. --- .../entanglement/src/services/CopyService.js | 19 ++++++++++++++++--- .../entanglement/src/services/CopyTask.js | 15 +++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/platform/entanglement/src/services/CopyService.js b/platform/entanglement/src/services/CopyService.js index 7cdd769018..0df33de71c 100644 --- a/platform/entanglement/src/services/CopyService.js +++ b/platform/entanglement/src/services/CopyService.js @@ -81,10 +81,23 @@ define( * domainObject when the duplication is successful. */ CopyService.prototype.perform = function (domainObject, parent, filter) { - var $q = this.$q, - copyTask = new CopyTask(domainObject, parent, this.policyService, this.$q); + var policyService = this.policyService; + + function completeFilter(domainObject) { + return (!filter || filter(domainObject)) && + policyService.allow( + "creation", + domainObject.getCapability("type") + ); + } + if (this.validate(domainObject, parent)) { - return copyTask.perform(); + return new CopyTask( + domainObject, + parent, + completeFilter, + this.$q + ).perform(); } else { throw new Error( "Tried to copy objects without validating first." diff --git a/platform/entanglement/src/services/CopyTask.js b/platform/entanglement/src/services/CopyTask.js index 1c4a27c620..15407f6db1 100644 --- a/platform/entanglement/src/services/CopyTask.js +++ b/platform/entanglement/src/services/CopyTask.js @@ -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 = {}; @@ -198,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 From 314666083345d5e52bfea08a024d5d1e393477b4 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 13:46:19 -0800 Subject: [PATCH 08/14] [Create] Utilize filtering during clone --- platform/commonUI/edit/src/actions/SaveAction.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 3fb376e6fb..21542bb2ad 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -106,6 +106,14 @@ define( return fetchObject(object.getModel().location); } + function isOriginal(domainObject) { + return domainObject.getCapability('location').isOriginal(); + } + + function cloneIntoParent(parent) { + return copyService.perform(domainObject, parent, isOriginal); + } + function cancelEditingAfterClone(clonedObject) { return domainObject.getCapability("editor").cancel() .then(resolveWith(clonedObject)); @@ -122,7 +130,7 @@ define( return getParent(domainObject) .then(doWizardSave) .then(getParent) - .then(copyService.perform.bind(copyService, domainObject)) + .then(cloneIntoParent) .then(cancelEditingAfterClone) .catch(resolveWith(false)); } else { From 0bdf05e61c3da7f972adab4faba9e967ae7ea591 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 13:49:15 -0800 Subject: [PATCH 09/14] [Create] Always allow cloning self Always allow cloning the newly-created object itself when saving a newly-created domain object. --- platform/commonUI/edit/src/actions/SaveAction.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 21542bb2ad..1415a6ed4b 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -106,12 +106,13 @@ define( return fetchObject(object.getModel().location); } - function isOriginal(domainObject) { - return domainObject.getCapability('location').isOriginal(); + function allowClone(objectToClone) { + return (objectToClone.getId() === domainObject.getId()) || + objectToClone.getCapability('location').isOriginal(); } function cloneIntoParent(parent) { - return copyService.perform(domainObject, parent, isOriginal); + return copyService.perform(domainObject, parent, allowClone); } function cancelEditingAfterClone(clonedObject) { From 0f231838ec109445bc69b42b1ec96f9162910552 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 14:05:04 -0800 Subject: [PATCH 10/14] [Create] Update test inputs to CopyTask ...to reflect changes for #656 --- .../entanglement/test/services/CopyTaskSpec.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/platform/entanglement/test/services/CopyTaskSpec.js b/platform/entanglement/test/services/CopyTaskSpec.js index b63c72d6d2..a66fb185ce 100644 --- a/platform/entanglement/test/services/CopyTaskSpec.js +++ b/platform/entanglement/test/services/CopyTaskSpec.js @@ -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 ); From cb53e1aaee2b062617c973661b02756f598e8ef1 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 14:17:36 -0800 Subject: [PATCH 11/14] [Create] Add object, not ID Add domain object, and not its identifier, when suing add method of composition from CopyTask, for consistency with test expectations. --- platform/entanglement/src/services/CopyTask.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/entanglement/src/services/CopyTask.js b/platform/entanglement/src/services/CopyTask.js index 15407f6db1..4906d84b2e 100644 --- a/platform/entanglement/src/services/CopyTask.js +++ b/platform/entanglement/src/services/CopyTask.js @@ -105,7 +105,7 @@ define( */ function addClonesToParent(self) { return self.parent.getCapability("composition") - .add(self.firstClone.getId()) + .add(self.firstClone) .then(function (addedClone) { return self.parent.getCapability("persistence").persist() .then(function () { From 99a454f9430f6aa5dc40ea4b8ed073bc294168fd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 14:21:09 -0800 Subject: [PATCH 12/14] [Create] Update CopyService spec ...to reflect API usage after #656 --- platform/entanglement/test/services/CopyServiceSpec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/entanglement/test/services/CopyServiceSpec.js b/platform/entanglement/test/services/CopyServiceSpec.js index 3d4ebf147e..e1849ec60c 100644 --- a/platform/entanglement/test/services/CopyServiceSpec.js +++ b/platform/entanglement/test/services/CopyServiceSpec.js @@ -162,6 +162,7 @@ define( 'compositionCapability', ['invoke', 'add'] ); + compositionCapability.add.andCallFake(synchronousPromise); locationCapability = jasmine.createSpyObj( 'locationCapability', @@ -401,8 +402,8 @@ 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); }); }); }); From 53a49a671b027189dd9a9dbd700759908bd4a1bc Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 10 Feb 2016 14:31:56 -0800 Subject: [PATCH 13/14] [Create] Test optional filter parameter --- .../test/services/CopyServiceSpec.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/platform/entanglement/test/services/CopyServiceSpec.js b/platform/entanglement/test/services/CopyServiceSpec.js index e1849ec60c..fb5092ba65 100644 --- a/platform/entanglement/test/services/CopyServiceSpec.js +++ b/platform/entanglement/test/services/CopyServiceSpec.js @@ -388,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){ @@ -406,6 +407,31 @@ define( .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); + }); + }); }); describe("on invalid inputs", function () { From 43d497e069052e96265e80eb4c0089acda13e5b8 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 11 Feb 2016 09:49:26 -0800 Subject: [PATCH 14/14] [Create] Clarify function naming Per review feedback, https://github.com/nasa/openmctweb/pull/666#discussion_r52625960 --- platform/entanglement/src/services/CopyService.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/entanglement/src/services/CopyService.js b/platform/entanglement/src/services/CopyService.js index 0df33de71c..56155f0b77 100644 --- a/platform/entanglement/src/services/CopyService.js +++ b/platform/entanglement/src/services/CopyService.js @@ -83,7 +83,9 @@ define( CopyService.prototype.perform = function (domainObject, parent, filter) { var policyService = this.policyService; - function completeFilter(domainObject) { + // Combines caller-provided filter (if any) with the + // baseline behavior of respecting creation policy. + function filterWithPolicy(domainObject) { return (!filter || filter(domainObject)) && policyService.allow( "creation", @@ -95,7 +97,7 @@ define( return new CopyTask( domainObject, parent, - completeFilter, + filterWithPolicy, this.$q ).perform(); } else {