mirror of
https://github.com/nasa/openmct.git
synced 2025-04-09 04:14:32 +00:00
Added more tests, some refactoring
This commit is contained in:
parent
3af23b7bc5
commit
5ff90f7254
@ -23,13 +23,61 @@
|
||||
|
||||
/**
|
||||
* This bundle implements the notification service, which can be used to
|
||||
* show banner notifications to the user.
|
||||
* show banner notifications to the user. Banner notifications
|
||||
* are used to inform users of events in a non-intrusive way. As
|
||||
* much as possible, notifications share a model with blocking
|
||||
* dialogs so that the same information can be provided in a dialog
|
||||
* and then minimized to a banner notification if needed.
|
||||
*
|
||||
* @namespace platform/commonUI/dialog
|
||||
*/
|
||||
define(
|
||||
["./MessageSeverity"],
|
||||
function (MessageSeverity) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A representation of a user action. Actions are provided to
|
||||
* dialogs and notifications and are shown as buttons.
|
||||
*
|
||||
* @typedef {object} NotificationAction
|
||||
* @property {string} label the label to appear on the button for
|
||||
* this action
|
||||
* @property {function} action a callback function to be invoked
|
||||
* when the button is clicked
|
||||
*/
|
||||
|
||||
/**
|
||||
* A representation of a banner notification. Banner notifications
|
||||
* are used to inform users of events in a non-intrusive way. As
|
||||
* much as possible, notifications share a model with blocking
|
||||
* dialogs so that the same information can be provided in a dialog
|
||||
* and then minimized to a banner notification if needed.
|
||||
*
|
||||
* @typedef {object} Notification
|
||||
* @property {string} title The title of the message
|
||||
* @property {number} progress The completion status of a task
|
||||
* represented numerically
|
||||
* @property {MessageSeverity} messageSeverity The importance of the
|
||||
* message (eg. error, success)
|
||||
* @property {boolean} unknownProgress a boolean indicating that the
|
||||
* progress of the underlying task is unknown. This will result in a
|
||||
* visually distinct progress bar.
|
||||
* @property {boolean | number} autoDismiss If truthy, dialog will
|
||||
* be automatically minimized or dismissed (depending on severity).
|
||||
* Additionally, if the provided value is a number, it will be used
|
||||
* as the delay period before being dismissed.
|
||||
* @property {NotificationAction} primaryAction the default user
|
||||
* response to
|
||||
* this message. Will be represented as a button with the provided
|
||||
* label and action. May be used by banner notifications to display
|
||||
* only the most important option to users.
|
||||
* @property {NotificationAction[]} additionalActions any additional
|
||||
* actions
|
||||
* that the user can take. Will be represented as additional buttons
|
||||
* that may or may not be available from a banner.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The notification service is responsible for informing the user of
|
||||
* events via the use of banner notifications.
|
||||
@ -41,69 +89,51 @@ define(
|
||||
this.$timeout = $timeout;
|
||||
this.DEFAULT_AUTO_DISMISS = DEFAULT_AUTO_DISMISS;
|
||||
|
||||
/**
|
||||
* Exposes the current "active" notification. This is a
|
||||
* notification that is of current highest importance that has
|
||||
* not been dismissed. The deinition of what is of highest
|
||||
* importance might be a little nuanced and require tweaking.
|
||||
* For example, if an important error message is visible and a
|
||||
* success message is triggered, it may be desirable to
|
||||
* temporarily show the success message and then auto-dismiss it.
|
||||
* @type {{notification: undefined}}
|
||||
/*
|
||||
* A context in which to hold the active notification and a
|
||||
* handle to its timeout.
|
||||
*/
|
||||
this.active = {
|
||||
};
|
||||
}
|
||||
/**
|
||||
var model = {
|
||||
title: string,
|
||||
progress: number,
|
||||
severity: MessageSeverity,
|
||||
unknownProgress: boolean,
|
||||
minimized: boolean,
|
||||
autoDismiss: boolean | number,
|
||||
actions: {
|
||||
label: string,
|
||||
action: function
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Possibly refactor this out to a provider?
|
||||
* @constructor
|
||||
* Returns the notification that is currently visible in the banner area
|
||||
* @returns {Notification}
|
||||
*/
|
||||
function Notification (model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
Notification.prototype.minimize = function (setValue) {
|
||||
if (typeof setValue !== undefined){
|
||||
this.model.minimized = setValue;
|
||||
} else {
|
||||
return this.model.minimized;
|
||||
}
|
||||
};
|
||||
|
||||
NotificationService.prototype.getActiveNotification = function (){
|
||||
return this.active.notification;
|
||||
}
|
||||
|
||||
/**
|
||||
* model = {
|
||||
*
|
||||
* }
|
||||
* @param model
|
||||
* A convenience method for success notifications. Notifications
|
||||
* created via this method will be auto-dismissed after a default
|
||||
* wait period
|
||||
* @param {Notification} notification The notification to display
|
||||
*/
|
||||
NotificationService.prototype.notify = function (model) {
|
||||
var notification = new Notification(model),
|
||||
that=this;
|
||||
NotificationService.prototype.success = function (notification) {
|
||||
notification.autoDismiss = notification.autoDismiss || true;
|
||||
NotificationService.prototype.notify(notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the user of an event. If there is a banner notification
|
||||
* already active, then it will be dismissed or minimized automatically,
|
||||
* and the provided notification displayed in its place.
|
||||
*
|
||||
* @param {Notification} notification The notification to display
|
||||
*/
|
||||
NotificationService.prototype.notify = function (notification) {
|
||||
/*var notification = new Notification(model),
|
||||
that=this; */
|
||||
var that = this;
|
||||
|
||||
this.notifications.push(notification);
|
||||
/*
|
||||
Check if there is already an active (ie. visible) notification
|
||||
*/
|
||||
if (!this.active.notification){
|
||||
setActiveNotification.call(this, notification);
|
||||
this.setActiveNotification(notification);
|
||||
|
||||
} else if (!this.active.timeout){
|
||||
/*
|
||||
@ -122,28 +152,42 @@ define(
|
||||
|
||||
};
|
||||
|
||||
function setActiveNotification (notification) {
|
||||
var that = this;
|
||||
this.active.notification = notification;
|
||||
/*
|
||||
If autoDismiss has been specified, setup a timeout to
|
||||
dismiss the dialog.
|
||||
/**
|
||||
* Used internally by the NotificationService
|
||||
* @private
|
||||
*/
|
||||
NotificationService.prototype.setActiveNotification =
|
||||
function (notification) {
|
||||
|
||||
If there are other notifications pending in the queue, set this
|
||||
one to auto-dismiss
|
||||
*/
|
||||
if (notification.model.autoDismiss
|
||||
|| selectNextNotification.call(this)) {
|
||||
var timeout = isNaN(notification.model.autoDismiss) ?
|
||||
this.DEFAULT_AUTO_DISMISS : notification.model.autoDismiss;
|
||||
var that = this;
|
||||
this.active.notification = notification;
|
||||
/*
|
||||
If autoDismiss has been specified, setup a timeout to
|
||||
dismiss the dialog.
|
||||
|
||||
this.active.timeout = this.$timeout(function () {
|
||||
that.dismissOrMinimize(notification);
|
||||
}, timeout);
|
||||
}
|
||||
}
|
||||
If there are other notifications pending in the queue, set this
|
||||
one to auto-dismiss
|
||||
*/
|
||||
if (notification && (notification.autoDismiss
|
||||
|| this.selectNextNotification())) {
|
||||
var timeout = isNaN(notification.autoDismiss) ?
|
||||
this.DEFAULT_AUTO_DISMISS :
|
||||
notification.autoDismiss;
|
||||
|
||||
function selectNextNotification () {
|
||||
this.active.timeout = this.$timeout(function () {
|
||||
that.dismissOrMinimize(notification);
|
||||
}, timeout);
|
||||
} else {
|
||||
delete this.active.timeout;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally by the NotificationService
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
NotificationService.prototype.selectNextNotification = function () {
|
||||
/*
|
||||
Loop through the notifications queue and find the first one that
|
||||
has not already been minimized (manually or otherwise).
|
||||
@ -151,7 +195,7 @@ define(
|
||||
for (var i=0; i< this.notifications.length; i++) {
|
||||
var notification = this.notifications[i];
|
||||
|
||||
if (!notification.model.minimized
|
||||
if (!notification.minimized
|
||||
&& notification!= this.activeNotification) {
|
||||
|
||||
return notification;
|
||||
@ -162,8 +206,9 @@ define(
|
||||
/**
|
||||
* Minimize a notification. The notification will still be available
|
||||
* from the notification list. Typically notifications with a
|
||||
* severity of SUCCESS should not be minimized, but rather
|
||||
* dismissed.
|
||||
* severity of 'success' should not be minimized, but rather
|
||||
* dismissed. If you're not sure which is appropriate,
|
||||
* use {@link NotificationService#dismissOrMinimize}
|
||||
* @see dismiss
|
||||
* @see dismissOrMinimize
|
||||
* @param notification
|
||||
@ -172,19 +217,17 @@ define(
|
||||
//Check this is a known notification
|
||||
var index = this.notifications.indexOf(notification);
|
||||
if (index >= 0) {
|
||||
notification.minimize(true);
|
||||
delete this.active.notification;
|
||||
delete this.active.timeout;
|
||||
setActiveNotification.call(this, selectNextNotification.call(this));
|
||||
notification.minimized=true;
|
||||
this.setActiveNotification(this.selectNextNotification());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Completely remove a notification. This will dismiss it from the
|
||||
* Completely removes a notification. This will dismiss it from the
|
||||
* message banner and remove it from the list of notifications.
|
||||
* Typically only notifications with a severity of SUCCESS should be
|
||||
* Typically only notifications with a severity of success should be
|
||||
* dismissed. If you're not sure whether to dismiss or minimize a
|
||||
* notification, use the dismissOrMinimize method.
|
||||
* notification, use {@link NotificationService#dismissOrMinimize}.
|
||||
* dismiss
|
||||
* @see dismissOrMinimize
|
||||
* @param notification The notification to dismiss
|
||||
@ -194,11 +237,7 @@ define(
|
||||
var index = this.notifications.indexOf(notification);
|
||||
if (index >= 0) {
|
||||
this.notifications.splice(index, 1);
|
||||
|
||||
delete this.active.notification;
|
||||
delete this.active.timeout;
|
||||
|
||||
setActiveNotification.call(this, selectNextNotification.call(this));
|
||||
this.setActiveNotification(this.selectNextNotification());
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,7 +249,7 @@ define(
|
||||
* @param notification
|
||||
*/
|
||||
NotificationService.prototype.dismissOrMinimize = function (notification){
|
||||
if (notification.model.severity > MessageSeverity.SUCCESS){
|
||||
if (notification.severity > MessageSeverity.SUCCESS){
|
||||
this.minimize(notification);
|
||||
} else {
|
||||
this.dismiss(notification);
|
||||
|
@ -30,24 +30,18 @@ define(
|
||||
var notificationService,
|
||||
mockTimeout,
|
||||
mockAutoDismiss,
|
||||
successModel = {
|
||||
title: "Mock Success Notification",
|
||||
severity: MessageSeverity.SUCCESS
|
||||
},
|
||||
errorModel = {
|
||||
title: "Mock Error Notification",
|
||||
severity: MessageSeverity.ERROR
|
||||
};
|
||||
successModel,
|
||||
errorModel;
|
||||
|
||||
/**
|
||||
* 1) Calling .notify results in a new notification being created
|
||||
* with the provided model and set to the active notification
|
||||
* with the provided model and set to the active notification. DONE
|
||||
*
|
||||
* 2) Calling .notify with autoDismiss results in a SUCCESS notification
|
||||
* becoming dismissed after timeout has elapsed
|
||||
* becoming dismissed after timeout has elapsed DONE
|
||||
*
|
||||
* 3) Calling .notify with autoDismiss results in an ERROR notification
|
||||
* being MINIMIZED after a timeout has elapsed
|
||||
* being MINIMIZED after a timeout has elapsed DONE
|
||||
*
|
||||
* 4) Calling .notify with an active success notification results in that
|
||||
* notification being auto-dismissed, and the new notification becoming
|
||||
@ -84,17 +78,49 @@ define(
|
||||
mockAutoDismiss = 0;
|
||||
notificationService = new NotificationService(
|
||||
mockTimeout, mockAutoDismiss);
|
||||
successModel = {
|
||||
title: "Mock Success Notification",
|
||||
severity: MessageSeverity.SUCCESS
|
||||
};
|
||||
errorModel = {
|
||||
title: "Mock Error Notification",
|
||||
severity: MessageSeverity.ERROR
|
||||
};
|
||||
});
|
||||
|
||||
it("Calls the notification service with a new notification, making" +
|
||||
it("gets a new success notification, making" +
|
||||
" the notification active", function() {
|
||||
var activeNotification;
|
||||
notificationService.notify(successModel);
|
||||
activeNotification = notificationService.getActiveNotification();
|
||||
expect(activeNotification.model).toBe(successModel);
|
||||
expect(activeNotification).toBe(successModel);
|
||||
});
|
||||
|
||||
describe(" called with multiple notifications", function(){
|
||||
it("gets a new success notification with" +
|
||||
" numerical auto-dismiss specified. ", function() {
|
||||
var activeNotification;
|
||||
successModel.autoDismiss = 1000;
|
||||
notificationService.notify(successModel);
|
||||
activeNotification = notificationService.getActiveNotification();
|
||||
expect(activeNotification).toBe(successModel);
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
activeNotification = notificationService.getActiveNotification();
|
||||
expect(activeNotification).toBeUndefined();
|
||||
});
|
||||
|
||||
it("gets a new notification with" +
|
||||
" boolean auto-dismiss specified. ", function() {
|
||||
var activeNotification;
|
||||
successModel.autoDismiss = true;
|
||||
notificationService.notify(successModel);
|
||||
activeNotification = notificationService.getActiveNotification();
|
||||
expect(activeNotification).toBe(successModel);
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
activeNotification = notificationService.getActiveNotification();
|
||||
expect(activeNotification).toBeUndefined();
|
||||
});
|
||||
|
||||
describe(" gets called with multiple notifications", function(){
|
||||
it("auto-dismisses the previously active notification, making" +
|
||||
" the new notification active", function() {
|
||||
var activeNotification;
|
||||
@ -103,14 +129,14 @@ define(
|
||||
activeNotification =
|
||||
notificationService.getActiveNotification();
|
||||
//Initially expect the active notification to be success
|
||||
expect(activeNotification.model).toBe(successModel);
|
||||
expect(activeNotification).toBe(successModel);
|
||||
//Then notify of an error
|
||||
notificationService.notify(errorModel);
|
||||
//But it should be auto-dismissed and replaced with the
|
||||
// error notification
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
activeNotification = notificationService.getActiveNotification();
|
||||
expect(activeNotification.model).toBe(errorModel);
|
||||
expect(activeNotification).toBe(errorModel);
|
||||
});
|
||||
it("auto-dismisses an active success notification, removing" +
|
||||
" it completely", function() {
|
||||
@ -125,9 +151,9 @@ define(
|
||||
});
|
||||
it("auto-minimizes an active error notification", function() {
|
||||
var activeNotification;
|
||||
//First pre-load with a success message
|
||||
//First pre-load with an error message
|
||||
notificationService.notify(errorModel);
|
||||
//Then notify of an error
|
||||
//Then notify of success
|
||||
notificationService.notify(successModel);
|
||||
expect(notificationService.notifications.length).toEqual(2);
|
||||
//Mock the auto-minimize
|
||||
@ -137,8 +163,42 @@ define(
|
||||
expect(notificationService.notifications.length).toEqual(2);
|
||||
activeNotification =
|
||||
notificationService.getActiveNotification();
|
||||
expect(activeNotification.model).toBe(successModel);
|
||||
expect(activeNotification).toBe(successModel);
|
||||
expect(errorModel.minimized).toEqual(true);
|
||||
});
|
||||
it("auto-minimizes errors when a number of them arrive in" +
|
||||
" short succession ", function() {
|
||||
var activeNotification;
|
||||
var error2 = {
|
||||
title: "Second Mock Error Notification",
|
||||
severity: MessageSeverity.ERROR
|
||||
}
|
||||
var error3 = {
|
||||
title: "Third Mock Error Notification",
|
||||
severity: MessageSeverity.ERROR
|
||||
}
|
||||
//First pre-load with a success message
|
||||
notificationService.notify(errorModel);
|
||||
//Then notify of a third error
|
||||
notificationService.notify(error2);
|
||||
notificationService.notify(error3);
|
||||
expect(notificationService.notifications.length).toEqual(3);
|
||||
//Mock the auto-minimize
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
//Previous error message should be minimized, not
|
||||
// dismissed
|
||||
expect(notificationService.notifications.length).toEqual(3);
|
||||
activeNotification =
|
||||
notificationService.getActiveNotification();
|
||||
expect(activeNotification).toBe(error2);
|
||||
expect(errorModel.minimized).toEqual(true);
|
||||
|
||||
//Mock the second auto-minimize
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
activeNotification =
|
||||
notificationService.getActiveNotification();
|
||||
expect(activeNotification).toBe(error3);
|
||||
expect(error2.minimized).toEqual(true);
|
||||
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user