[Edit] Add notifications to Save & SaveAs (#1258)

* [Edit] Added notifications to SaveAsAction

* [Edit] Added notifications to SaveAction

* [Edit] Update SaveAsActionSpec

* [Edit] No error notif when user cancels SaveAs
This commit is contained in:
Bogdan Alexandru Marginean 2016-12-19 20:59:26 +02:00 committed by Andrew Henry
parent 90a7ca8ae5
commit 532f7a76f9
7 changed files with 132 additions and 26 deletions

View File

@ -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"
},

View File

@ -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);
};
/**

View File

@ -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();

View File

@ -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);
};

View File

@ -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();
});
});
});
});
}
);

View File

@ -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);
});

View File

@ -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();
});
});
});
});
}