diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js index a5b5fb463f..8b9aad6d21 100644 --- a/platform/commonUI/edit/bundle.js +++ b/platform/commonUI/edit/bundle.js @@ -211,7 +211,8 @@ define([ "cssclass": "icon-save labeled", "description": "Save changes made to these objects.", "depends": [ - "dialogService" + "dialogService", + "notificationService" ] }, { @@ -222,7 +223,8 @@ define([ "cssclass": "icon-save labeled", "description": "Save changes made to these objects.", "depends": [ - "dialogService" + "dialogService", + "notificationService" ] }, { @@ -236,7 +238,8 @@ define([ "$injector", "policyService", "dialogService", - "copyService" + "copyService", + "notificationService" ], "priority": "mandatory" }, diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 8d3ea7f509..1e0b6f72d9 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -33,10 +33,12 @@ define( */ function SaveAction( dialogService, + notificationService, context ) { this.domainObject = (context || {}).domainObject; this.dialogService = dialogService; + this.notificationService = notificationService; } /** @@ -47,7 +49,8 @@ define( * @memberof platform/commonUI/edit.SaveAction# */ SaveAction.prototype.perform = function () { - var domainObject = this.domainObject, + var self = this, + domainObject = this.domainObject, dialog = new SaveInProgressDialog(this.dialogService); // Invoke any save behavior introduced by the editor capability; @@ -58,15 +61,21 @@ define( return domainObject.getCapability("editor").save(); } - function hideBlockingDialog() { + function onSuccess() { dialog.hide(); + self.notificationService.info("Save Succeeded"); + } + + function onFailure() { + dialog.hide(); + self.notificationService.error("Save Failed"); } dialog.show(); return doSave() - .then(hideBlockingDialog) - .catch(hideBlockingDialog); + .then(onSuccess) + .catch(onFailure); }; /** diff --git a/platform/commonUI/edit/src/actions/SaveAndStopEditingAction.js b/platform/commonUI/edit/src/actions/SaveAndStopEditingAction.js index a0a0583048..e8591e9ca5 100644 --- a/platform/commonUI/edit/src/actions/SaveAndStopEditingAction.js +++ b/platform/commonUI/edit/src/actions/SaveAndStopEditingAction.js @@ -33,11 +33,13 @@ define( */ function SaveAndStopEditingAction( dialogService, + notificationService, context ) { this.context = context; this.domainObject = (context || {}).domainObject; this.dialogService = dialogService; + this.notificationService = notificationService; } /** @@ -49,7 +51,7 @@ define( */ SaveAndStopEditingAction.prototype.perform = function () { var domainObject = this.domainObject, - saveAction = new SaveAction(this.dialogService, this.context); + saveAction = new SaveAction(this.dialogService, this.notificationService, this.context); function closeEditor() { return domainObject.getCapability("editor").finish(); diff --git a/platform/commonUI/edit/src/actions/SaveAsAction.js b/platform/commonUI/edit/src/actions/SaveAsAction.js index ab10060e93..5120276193 100644 --- a/platform/commonUI/edit/src/actions/SaveAsAction.js +++ b/platform/commonUI/edit/src/actions/SaveAsAction.js @@ -43,6 +43,7 @@ define([ policyService, dialogService, copyService, + notificationService, context ) { this.domainObject = (context || {}).domainObject; @@ -52,6 +53,7 @@ define([ this.policyService = policyService; this.dialogService = dialogService; this.copyService = copyService; + this.notificationService = notificationService; } /** @@ -117,8 +119,10 @@ define([ return self.dialogService .getUserInput(wizard.getFormStructure(true), - wizard.getInitialFormValue() - ).then(wizard.populateObjectFromInput.bind(wizard)); + wizard.getInitialFormValue()) + .then(wizard.populateObjectFromInput.bind(wizard), function (failureReason) { + return Promise.reject("user canceled"); + }); } function showBlockingDialog(object) { @@ -176,8 +180,16 @@ define([ }); } - function onFailure() { + function onSuccess(object) { + self.notificationService.info("Save Succeeded"); + return object; + } + + function onFailure(reason) { hideBlockingDialog(); + if (reason !== "user canceled") { + self.notificationService.error("Save Failed"); + } return false; } @@ -190,6 +202,7 @@ define([ .then(saveAfterClone) .then(finishEditing) .then(hideBlockingDialog) + .then(onSuccess) .catch(onFailure); }; diff --git a/platform/commonUI/edit/test/actions/SaveActionSpec.js b/platform/commonUI/edit/test/actions/SaveActionSpec.js index 7230c09448..3b878e3c04 100644 --- a/platform/commonUI/edit/test/actions/SaveActionSpec.js +++ b/platform/commonUI/edit/test/actions/SaveActionSpec.js @@ -19,6 +19,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ +/*global describe,it,expect,beforeEach,jasmine,waitsFor,runs*/ define( ["../../src/actions/SaveAction"], @@ -28,7 +29,8 @@ define( var mockDomainObject, mockEditorCapability, actionContext, - dialogService, + mockDialogService, + mockNotificationService, mockActionCapability, capabilities = {}, action; @@ -68,11 +70,17 @@ define( actionContext = { domainObject: mockDomainObject }; - dialogService = jasmine.createSpyObj( + + mockDialogService = jasmine.createSpyObj( "dialogService", ["showBlockingMessage"] ); + mockNotificationService = jasmine.createSpyObj( + "notificationService", + ["info", "error"] + ); + mockDomainObject.hasCapability.andReturn(true); mockDomainObject.getCapability.andCallFake(function (capability) { return capabilities[capability]; @@ -81,7 +89,7 @@ define( mockEditorCapability.save.andReturn(mockPromise(true)); mockEditorCapability.isEditContextRoot.andReturn(true); - action = new SaveAction(dialogService, actionContext); + action = new SaveAction(mockDialogService, mockNotificationService, actionContext); }); it("only applies to domain object with an editor capability", function () { @@ -105,30 +113,54 @@ define( expect(mockEditorCapability.save).toHaveBeenCalled(); }); - describe("a blocking dialog", function () { + describe("in order to keep the user in the loop", function () { var mockDialogHandle; beforeEach(function () { mockDialogHandle = jasmine.createSpyObj("dialogHandle", ["dismiss"]); - dialogService.showBlockingMessage.andReturn(mockDialogHandle); + mockDialogService.showBlockingMessage.andReturn(mockDialogHandle); }); - it("shows a dialog while saving", function () { mockEditorCapability.save.andReturn(new Promise(function () { })); action.perform(); - expect(dialogService.showBlockingMessage).toHaveBeenCalled(); + expect(mockDialogService.showBlockingMessage).toHaveBeenCalled(); expect(mockDialogHandle.dismiss).not.toHaveBeenCalled(); }); - it("hides a dialog when saving is complete", function () { + it("hides the dialog when saving is complete", function () { action.perform(); - expect(dialogService.showBlockingMessage).toHaveBeenCalled(); + expect(mockDialogService.showBlockingMessage).toHaveBeenCalled(); expect(mockDialogHandle.dismiss).toHaveBeenCalled(); }); - }); + it("notifies if saving succeeded", function () { + var mockCallback = jasmine.createSpy("callback"); + mockEditorCapability.save.andReturn(Promise.resolve("success")); + action.perform().then(mockCallback); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + runs(function () { + expect(mockNotificationService.info).toHaveBeenCalled(); + expect(mockNotificationService.error).not.toHaveBeenCalled(); + }); + }); + + it("notifies if saving failed", function () { + var mockCallback = jasmine.createSpy("callback"); + mockEditorCapability.save.andReturn(Promise.reject("some failure reason")); + action.perform().then(mockCallback); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + runs(function () { + expect(mockNotificationService.error).toHaveBeenCalled(); + expect(mockNotificationService.info).not.toHaveBeenCalled(); + }); + }); + }); }); } ); diff --git a/platform/commonUI/edit/test/actions/SaveAndStopEditingActionSpec.js b/platform/commonUI/edit/test/actions/SaveAndStopEditingActionSpec.js index 1fb8fa6492..5366bead3f 100644 --- a/platform/commonUI/edit/test/actions/SaveAndStopEditingActionSpec.js +++ b/platform/commonUI/edit/test/actions/SaveAndStopEditingActionSpec.js @@ -19,6 +19,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ +/*global describe,it,expect,beforeEach,jasmine*/ define( ["../../src/actions/SaveAndStopEditingAction"], @@ -35,6 +36,7 @@ define( mockEditorCapability, actionContext, dialogService, + notificationService, mockActionCapability, capabilities = {}, action; @@ -79,6 +81,11 @@ define( ["showBlockingMessage"] ); + notificationService = jasmine.createSpyObj( + "notificationService", + ["info", "error"] + ); + mockDomainObject.hasCapability.andReturn(true); mockDomainObject.getCapability.andCallFake(function (capability) { return capabilities[capability]; @@ -87,7 +94,7 @@ define( mockEditorCapability.save.andReturn(mockPromise(true)); mockEditorCapability.isEditContextRoot.andReturn(true); - action = new SaveAndStopEditingAction(dialogService, actionContext); + action = new SaveAndStopEditingAction(dialogService, notificationService, actionContext); }); diff --git a/platform/commonUI/edit/test/actions/SaveAsActionSpec.js b/platform/commonUI/edit/test/actions/SaveAsActionSpec.js index f87cf4766f..8cb02679ec 100644 --- a/platform/commonUI/edit/test/actions/SaveAsActionSpec.js +++ b/platform/commonUI/edit/test/actions/SaveAsActionSpec.js @@ -32,6 +32,7 @@ define( mockObjectService, mockDialogService, mockCopyService, + mockNotificationService, mockParent, actionContext, capabilities = {}, @@ -112,11 +113,25 @@ define( ] ); + mockNotificationService = jasmine.createSpyObj( + "notificationService", + [ + "info", + "error" + ] + ); + actionContext = { domainObject: mockDomainObject }; - action = new SaveAsAction(undefined, undefined, mockDialogService, mockCopyService, actionContext); + action = new SaveAsAction( + undefined, + undefined, + mockDialogService, + mockCopyService, + mockNotificationService, + actionContext); spyOn(action, "getObjectService"); action.getObjectService.andReturn(mockObjectService); @@ -186,7 +201,7 @@ define( expect(mockDialogService.getUserInput).toHaveBeenCalled(); }); - describe("a blocking dialog", function () { + describe("in order to keep the user in the loop", function () { var mockDialogHandle; beforeEach(function () { @@ -194,14 +209,14 @@ define( mockDialogService.showBlockingMessage.andReturn(mockDialogHandle); }); - it("indicates that a save is taking place", function () { + it("shows a blocking dialog indicating that saving is in progress", function () { mockEditorCapability.save.andReturn(new Promise(function () {})); action.perform(); expect(mockDialogService.showBlockingMessage).toHaveBeenCalled(); expect(mockDialogHandle.dismiss).not.toHaveBeenCalled(); }); - it("is hidden after saving", function () { + it("hides the blocking dialog after saving finishes", function () { var mockCallback = jasmine.createSpy(); action.perform().then(mockCallback); expect(mockDialogService.showBlockingMessage).toHaveBeenCalled(); @@ -212,6 +227,31 @@ define( expect(mockDialogHandle.dismiss).toHaveBeenCalled(); }); }); + + it("notifies if saving succeeded", function () { + var mockCallback = jasmine.createSpy(); + action.perform().then(mockCallback); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + runs(function () { + expect(mockNotificationService.info).toHaveBeenCalled(); + expect(mockNotificationService.error).not.toHaveBeenCalled(); + }); + }); + + it("notifies if saving failed", function () { + mockCopyService.perform.andReturn(Promise.reject("some failure reason")); + var mockCallback = jasmine.createSpy(); + action.perform().then(mockCallback); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + runs(function () { + expect(mockNotificationService.error).toHaveBeenCalled(); + expect(mockNotificationService.info).not.toHaveBeenCalled(); + }); + }); }); }); }