]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/services/notification.service.ts
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / services / notification.service.ts
1 import { Injectable } from '@angular/core';
2
3 import * as _ from 'lodash';
4 import { ToastOptions, ToastsManager } from 'ng2-toastr';
5 import { BehaviorSubject } from 'rxjs';
6
7 import { NotificationType } from '../enum/notification-type.enum';
8 import { CdNotification, CdNotificationConfig } from '../models/cd-notification';
9 import { FinishedTask } from '../models/finished-task';
10 import { CdDatePipe } from '../pipes/cd-date.pipe';
11 import { ServicesModule } from './services.module';
12 import { TaskMessageService } from './task-message.service';
13
14 @Injectable({
15 providedIn: ServicesModule
16 })
17 export class NotificationService {
18 private hideToasties = false;
19
20 // Observable sources
21 private dataSource = new BehaviorSubject<CdNotification[]>([]);
22 private queuedNotifications: CdNotificationConfig[] = [];
23
24 // Observable streams
25 data$ = this.dataSource.asObservable();
26
27 private queueTimeoutId: number;
28 KEY = 'cdNotifications';
29
30 constructor(
31 public toastr: ToastsManager,
32 private taskMessageService: TaskMessageService,
33 private cdDatePipe: CdDatePipe
34 ) {
35 const stringNotifications = localStorage.getItem(this.KEY);
36 let notifications: CdNotification[] = [];
37
38 if (_.isString(stringNotifications)) {
39 notifications = JSON.parse(stringNotifications, (_key, value) => {
40 if (_.isPlainObject(value)) {
41 return _.assign(new CdNotification(), value);
42 }
43 return value;
44 });
45 }
46
47 this.dataSource.next(notifications);
48 }
49
50 /**
51 * Removes all current saved notifications
52 */
53 removeAll() {
54 localStorage.removeItem(this.KEY);
55 this.dataSource.next([]);
56 }
57
58 /**
59 * Method used for saving a shown notification (check show() method).
60 */
61 save(notification: CdNotification) {
62 const recent = this.dataSource.getValue();
63 recent.push(notification);
64 while (recent.length > 10) {
65 recent.shift();
66 }
67 this.dataSource.next(recent);
68 localStorage.setItem(this.KEY, JSON.stringify(recent));
69 }
70
71 queueNotifications(notifications: CdNotificationConfig[]) {
72 this.queuedNotifications = this.queuedNotifications.concat(notifications);
73 this.cancel(this.queueTimeoutId);
74 this.queueTimeoutId = window.setTimeout(() => {
75 this.sendQueuedNotifications();
76 }, 500);
77 }
78
79 private sendQueuedNotifications() {
80 _.uniqWith(this.queuedNotifications, _.isEqual).forEach((notification) => {
81 this.show(notification);
82 });
83 this.queuedNotifications = [];
84 }
85
86 /**
87 * Method for showing a notification.
88 * @param {NotificationType} type toastr type
89 * @param {string} title
90 * @param {string} [message] The message to be displayed. Note, use this field
91 * for error notifications only.
92 * @param {*} [options] toastr compatible options, used when creating a toastr
93 * @param {string} [application] Only needed if notification comes from an external application
94 * @returns The timeout ID that is set to be able to cancel the notification.
95 */
96 show(
97 type: NotificationType,
98 title: string,
99 message?: string,
100 options?: any | ToastOptions,
101 application?: string
102 ): number;
103 show(config: CdNotificationConfig | (() => CdNotificationConfig)): number;
104 show(
105 arg: NotificationType | CdNotificationConfig | (() => CdNotificationConfig),
106 title?: string,
107 message?: string,
108 options?: any | ToastOptions,
109 application?: string
110 ): number {
111 return window.setTimeout(() => {
112 let config: CdNotificationConfig;
113 if (_.isFunction(arg)) {
114 config = arg() as CdNotificationConfig;
115 } else if (_.isObject(arg)) {
116 config = arg as CdNotificationConfig;
117 } else {
118 config = new CdNotificationConfig(
119 arg as NotificationType,
120 title,
121 message,
122 options,
123 application
124 );
125 }
126 const notification = new CdNotification(config);
127 this.save(notification);
128 this.showToasty(notification);
129 }, 10);
130 }
131
132 private showToasty(notification: CdNotification) {
133 // Exit immediately if no toasty should be displayed.
134 if (this.hideToasties) {
135 return;
136 }
137 this.toastr[['error', 'info', 'success'][notification.type]](
138 (notification.message ? notification.message + '<br>' : '') +
139 this.renderTimeAndApplicationHtml(notification),
140 notification.title,
141 notification.options
142 );
143 }
144
145 renderTimeAndApplicationHtml(notification: CdNotification): string {
146 return `<small class="date">${this.cdDatePipe.transform(
147 notification.timestamp
148 )}</small><i class="pull-right custom-icon ${notification.applicationClass}" title="${
149 notification.application
150 }"></i>`;
151 }
152
153 notifyTask(finishedTask: FinishedTask, success: boolean = true): number {
154 let notification: CdNotificationConfig;
155 if (finishedTask.success && success) {
156 notification = new CdNotificationConfig(
157 NotificationType.success,
158 this.taskMessageService.getSuccessTitle(finishedTask)
159 );
160 } else {
161 notification = new CdNotificationConfig(
162 NotificationType.error,
163 this.taskMessageService.getErrorTitle(finishedTask),
164 this.taskMessageService.getErrorMessage(finishedTask)
165 );
166 }
167 return this.show(notification);
168 }
169
170 /**
171 * Prevent the notification from being shown.
172 * @param {number} timeoutId A number representing the ID of the timeout to be canceled.
173 */
174 cancel(timeoutId) {
175 window.clearTimeout(timeoutId);
176 }
177
178 /**
179 * Suspend showing the notification toasties.
180 * @param {boolean} suspend Set to ``true`` to disable/hide toasties.
181 */
182 suspendToasties(suspend: boolean) {
183 this.hideToasties = suspend;
184 }
185 }