mirror of
https://github.com/ceph/ceph
synced 2025-01-15 23:43:06 +00:00
Merge pull request #25325 from Devp00l/wip-issue-37469
mgr/dashboard: Notification queue Reviewed-by: Alfonso Martínez <almartin@redhat.com> Reviewed-by: Ernesto Puerta <epuertat@redhat.com> Reviewed-by: Tiago Melo <tmelo@suse.com>
This commit is contained in:
commit
339ff6abf1
@ -1,16 +1,23 @@
|
||||
import { ToastOptions } from 'ng2-toastr';
|
||||
import { NotificationType } from '../enum/notification-type.enum';
|
||||
|
||||
export class CdNotificationConfig {
|
||||
constructor(
|
||||
public type: NotificationType,
|
||||
public title: string,
|
||||
public message?: string, // Use this for error notifications only
|
||||
public options?: any | ToastOptions
|
||||
) {}
|
||||
}
|
||||
|
||||
export class CdNotification {
|
||||
message: string;
|
||||
timestamp: string;
|
||||
title: string;
|
||||
type: NotificationType;
|
||||
|
||||
constructor(type: NotificationType = NotificationType.info, title?: string, message?: string) {
|
||||
this.type = type;
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
|
||||
constructor(
|
||||
public type: NotificationType = NotificationType.info,
|
||||
public title?: string,
|
||||
public message?: string
|
||||
) {
|
||||
/* string representation of the Date object so it can be directly compared
|
||||
with the timestamps parsed from localStorage */
|
||||
this.timestamp = new Date().toJSON();
|
||||
|
@ -5,6 +5,7 @@ import { ToastsManager } from 'ng2-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper';
|
||||
import { NotificationType } from '../enum/notification-type.enum';
|
||||
import { CdNotificationConfig } from '../models/cd-notification';
|
||||
import { FinishedTask } from '../models/finished-task';
|
||||
import { NotificationService } from './notification.service';
|
||||
import { TaskMessageService } from './task-message.service';
|
||||
@ -57,7 +58,7 @@ describe('NotificationService', () => {
|
||||
}));
|
||||
|
||||
it('should create a success notification and save it', fakeAsync(() => {
|
||||
notificationService.show(NotificationType.success, 'Simple test');
|
||||
notificationService.show(new CdNotificationConfig(NotificationType.success, 'Simple test'));
|
||||
tick(100);
|
||||
expect(notificationService['dataSource'].getValue().length).toBe(1);
|
||||
expect(notificationService['dataSource'].getValue()[0].type).toBe(NotificationType.success);
|
||||
@ -71,7 +72,7 @@ describe('NotificationService', () => {
|
||||
}));
|
||||
|
||||
it('should create an info notification and save it', fakeAsync(() => {
|
||||
notificationService.show(NotificationType.info, 'Simple test');
|
||||
notificationService.show(new CdNotificationConfig(NotificationType.info, 'Simple test'));
|
||||
tick(100);
|
||||
expect(notificationService['dataSource'].getValue().length).toBe(1);
|
||||
const notification = notificationService['dataSource'].getValue()[0];
|
||||
@ -122,4 +123,44 @@ describe('NotificationService', () => {
|
||||
expect(notification.title).toBe(`Failed to create RBD 'somePool/someImage'`);
|
||||
expect(notification.message).toBe(`Name is already used by RBD 'somePool/someImage'.`);
|
||||
}));
|
||||
|
||||
describe('notification queue', () => {
|
||||
const n1 = new CdNotificationConfig(NotificationType.success, 'Some success');
|
||||
const n2 = new CdNotificationConfig(NotificationType.info, 'Some info');
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(notificationService, 'show').and.stub();
|
||||
});
|
||||
|
||||
it('filters out duplicated notifications on single call', fakeAsync(() => {
|
||||
notificationService.queueNotifications([n1, n1, n2, n2]);
|
||||
tick(500);
|
||||
expect(notificationService.show).toHaveBeenCalledTimes(2);
|
||||
}));
|
||||
|
||||
it('filters out duplicated notifications presented in different calls', fakeAsync(() => {
|
||||
notificationService.queueNotifications([n1, n2]);
|
||||
notificationService.queueNotifications([n1, n2]);
|
||||
tick(500);
|
||||
expect(notificationService.show).toHaveBeenCalledTimes(2);
|
||||
}));
|
||||
|
||||
it('will reset the timeout on every call', fakeAsync(() => {
|
||||
notificationService.queueNotifications([n1, n2]);
|
||||
tick(400);
|
||||
notificationService.queueNotifications([n1, n2]);
|
||||
tick(100);
|
||||
expect(notificationService.show).toHaveBeenCalledTimes(0);
|
||||
tick(400);
|
||||
expect(notificationService.show).toHaveBeenCalledTimes(2);
|
||||
}));
|
||||
|
||||
it('wont filter out duplicated notifications if timeout was reached before', fakeAsync(() => {
|
||||
notificationService.queueNotifications([n1, n2]);
|
||||
tick(500);
|
||||
notificationService.queueNotifications([n1, n2]);
|
||||
tick(500);
|
||||
expect(notificationService.show).toHaveBeenCalledTimes(4);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@ -5,7 +5,7 @@ import { ToastsManager } from 'ng2-toastr';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { NotificationType } from '../enum/notification-type.enum';
|
||||
import { CdNotification } from '../models/cd-notification';
|
||||
import { CdNotification, CdNotificationConfig } from '../models/cd-notification';
|
||||
import { FinishedTask } from '../models/finished-task';
|
||||
import { ServicesModule } from './services.module';
|
||||
import { TaskMessageService } from './task-message.service';
|
||||
@ -16,10 +16,12 @@ import { TaskMessageService } from './task-message.service';
|
||||
export class NotificationService {
|
||||
// Observable sources
|
||||
private dataSource = new BehaviorSubject<CdNotification[]>([]);
|
||||
private queuedNotifications: CdNotificationConfig[] = [];
|
||||
|
||||
// Observable streams
|
||||
data$ = this.dataSource.asObservable();
|
||||
|
||||
private queueTimeoutId: number;
|
||||
KEY = 'cdNotifications';
|
||||
|
||||
constructor(public toastr: ToastsManager, private taskMessageService: TaskMessageService) {
|
||||
@ -63,6 +65,21 @@ export class NotificationService {
|
||||
localStorage.setItem(this.KEY, JSON.stringify(recent));
|
||||
}
|
||||
|
||||
queueNotifications(notifications: CdNotificationConfig[]) {
|
||||
this.queuedNotifications = this.queuedNotifications.concat(notifications);
|
||||
this.cancel(this.queueTimeoutId);
|
||||
this.queueTimeoutId = window.setTimeout(() => {
|
||||
this.sendQueuedNotifications();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private sendQueuedNotifications() {
|
||||
_.uniqWith(this.queuedNotifications, _.isEqual).forEach((notification) => {
|
||||
this.show(notification);
|
||||
});
|
||||
this.queuedNotifications = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for showing a notification.
|
||||
* @param {NotificationType} type toastr type
|
||||
@ -70,11 +87,23 @@ export class NotificationService {
|
||||
* @param {string} [message] The message to be displayed. Note, use this field
|
||||
* for error notifications only.
|
||||
* @param {*} [options] toastr compatible options, used when creating a toastr
|
||||
* @memberof NotificationService
|
||||
* @returns The timeout ID that is set to be able to cancel the notification.
|
||||
*/
|
||||
show(type: NotificationType, title: string, message?: string, options?: any) {
|
||||
return setTimeout(() => {
|
||||
show(type: NotificationType, title: string, message?: string, options?: any): number;
|
||||
show(config: CdNotificationConfig): number;
|
||||
show(
|
||||
arg: NotificationType | CdNotificationConfig,
|
||||
title?: string,
|
||||
message?: string,
|
||||
options?: any
|
||||
): number {
|
||||
let type;
|
||||
if (_.isObject(arg)) {
|
||||
({ message, type, title, options } = <CdNotificationConfig>arg);
|
||||
} else {
|
||||
type = arg;
|
||||
}
|
||||
return window.setTimeout(() => {
|
||||
this.save(type, title, message);
|
||||
if (!message) {
|
||||
message = '';
|
||||
@ -94,15 +123,20 @@ export class NotificationService {
|
||||
}
|
||||
|
||||
notifyTask(finishedTask: FinishedTask, success: boolean = true) {
|
||||
let notification: CdNotificationConfig;
|
||||
if (finishedTask.success && success) {
|
||||
this.show(NotificationType.success, this.taskMessageService.getSuccessTitle(finishedTask));
|
||||
notification = new CdNotificationConfig(
|
||||
NotificationType.success,
|
||||
this.taskMessageService.getSuccessTitle(finishedTask)
|
||||
);
|
||||
} else {
|
||||
this.show(
|
||||
notification = new CdNotificationConfig(
|
||||
NotificationType.error,
|
||||
this.taskMessageService.getErrorTitle(finishedTask),
|
||||
this.taskMessageService.getErrorMessage(finishedTask)
|
||||
);
|
||||
}
|
||||
this.show(notification);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,6 +144,6 @@ export class NotificationService {
|
||||
* @param {number} timeoutId A number representing the ID of the timeout to be canceled.
|
||||
*/
|
||||
cancel(timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
window.clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user