UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

374 lines (372 loc) 14.1 kB
import { EMPTY, ReplaySubject } from 'rxjs'; import { Globalization } from '../data/globalization'; import { Net } from '../data/net'; import { LogLevel } from '../diagnostics/log-level'; import { Logging } from '../diagnostics/logging'; import { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry'; import { RpcNotificationSubjectServer } from '../rpc/notification/rpc-notification-subject-server'; import { RpcWorkItemFindSubjectServer } from '../rpc/work-item-find/rpc-work-item-find-subject-server'; import { Notification, NotificationChangeEvent } from './notification'; import { NotificationState } from './notification-state'; /** * Mock the IFrameService class in app folder */ export class IFrameService { getActiveToolIFrameData; } /** * Notification manager class. */ export class NotificationManager { rpc; collection; psSessionIdToNotificationIdMap = new Map(); notificationIdToPsSessionIdMap = new Map(); rpcNotifySubscription; rpcQuerySubscription; changedEventSubject; rpcWorkItemFindSubjectServer; rpcNotificationSubjectServer; iFrameService; /** * Initializes a new instance of the NotificationManager class. * * @param rpc the RPC object. */ constructor(rpc) { this.rpc = rpc; this.changedEventSubject = new ReplaySubject(1); this.initialize(); } /** * register iframe service from shell * @param iFrameService the iframe service from shell */ registerIFrameService(iFrameService) { this.iFrameService = iFrameService; } /** * Gets the items from current notification collection including dismissed. */ get items() { const items = []; for (const item in this.collection) { if (this.collection.hasOwnProperty(item)) { items.push(this.collection[item]); } } return items; } /** * Gets the subject of notification changed event. */ get changed() { return this.changedEventSubject; } /** * Initializes the rpc notification call. */ initialize() { this.collection = {}; // notification request from rpc... this.rpcNotificationSubjectServer = new RpcNotificationSubjectServer(this.rpc); this.rpcNotifySubscription = this.rpcNotificationSubjectServer.subject .subscribe({ next: item => { this.notify(item.data).toPromise().then(item.deferred.resolve, item.deferred.reject); }, error: error => { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.NotificationRpcInitialization.message; Logging.log({ source: 'Notification', level: LogLevel.Error, message: message.format(Net.getErrorMessage(error)) }); } }); this.rpcWorkItemFindSubjectServer = new RpcWorkItemFindSubjectServer(this.rpc); this.rpcQuerySubscription = this.rpcWorkItemFindSubjectServer.subject .subscribe({ next: item => { item.deferred.resolve(this.workItemFind(item.data)); }, error: error => { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.NotificationRpcInitialization.message; Logging.log({ source: 'Notification', level: LogLevel.Error, message: message.format(Net.getErrorMessage(error)) }); } }); this.addEvent(NotificationChangeEvent.Initialized); } /** * Stop the notification manager. */ uninitialize() { if (this.rpcNotifySubscription) { this.rpcNotifySubscription.unsubscribe(); this.rpcNotifySubscription = null; } if (this.rpcQuerySubscription) { this.rpcQuerySubscription.unsubscribe(); this.rpcQuerySubscription = null; } } /** * Find a notification. * * @param id the notification id. */ find(id) { const notificationId = this.psSessionIdToNotificationIdMap[id] || id; return this.collection[notificationId]; } /** * Remove a notification. * There is no dismiss API on the gateway, this just remove from the list. * Don't remove active notification. Use dismiss api instead, so it doesn't displays to .items property. * * @param id the session id (notification id). * @return boolean true if removed. */ remove(id) { const notification = this.find(id); if (notification) { const psSessionId = this.notificationIdToPsSessionIdMap[id]; delete this.psSessionIdToNotificationIdMap[psSessionId]; delete this.notificationIdToPsSessionIdMap[id]; delete this.collection[id]; this.addEvent(NotificationChangeEvent.Remove, notification); return true; } return false; } /** * Dismiss a notification to mark dismiss property. * * @param id the session id (notification id). * @return boolean true if dismissed. */ dismiss(id) { const notification = this.find(id); if (notification) { notification.dismissed = true; this.addEvent(NotificationChangeEvent.Remove, notification); return true; } return false; } /** * Set dismissed to false for notification updated that was previously dismissed * * @param id the session id (notification id). * @return boolean true if undismissed. */ undismiss(id) { const notification = this.find(id); if (notification) { notification.dismissed = false; this.addEvent(NotificationChangeEvent.Change, notification); return true; } return false; } /** * Add notification from WorkItem. * * @param psSessionId the psSession ID. * @param workItem the RPC work item. * @param state the initial state. * @param object the object from query result. * @return notification the notification object. */ addFromWorkItem(notificationId, workItem, state) { const notification = Notification.createFromWorkItem(notificationId, workItem, state, this.iFrameService); const existingNotification = this.find(notificationId); this.collection[notificationId] = notification; if (!notification.isDisabled) { if (existingNotification) { this.addEvent(NotificationChangeEvent.Change, notification); } else { this.addEvent(NotificationChangeEvent.Add, notification); } } } /** * Update an existing work item with psSession Id information. * * @param notificationId the id of the notification. * @param psSessionId the psSession ID. * @param workItem the work item. * @param state the state of the work item. * @param object the object from query result. */ updateWorkItemWithPsSession(notificationId, psSessionId, workItem, state, object) { const notification = this.find(notificationId); this.psSessionIdToNotificationIdMap[psSessionId] = notificationId; this.notificationIdToPsSessionIdMap[notificationId] = psSessionId; if (notification) { if (notification.updateFromWorkItem(notificationId, workItem, state, object)) { this.addEvent(NotificationChangeEvent.Change, notification); } return true; } return false; } /** * Add notification from Recover. * * @param id the notification ID. * @param workItem the RPC work item. * @param state the initial state. * @param object the object from query result. * @return notification the notification object. */ addFromRecover(recover) { const notification = Notification.createFromRecover(recover, this.iFrameService); this.collection[recover.id] = notification; this.psSessionIdToNotificationIdMap[recover.id] = recover.id; this.notificationIdToPsSessionIdMap[recover.id] = recover.id; this.addEvent(NotificationChangeEvent.Add, notification); } /** * Add initial notification for Message Notification. * * @param id the notification ID. * @param workItem the RPC work item. * @param state the initial state. * @param object the object from query result. * @return notification the notification object. */ addForNotificationMessage(state, message) { if (this.collection[message.id]) { return false; } const notification = new Notification(message.id); const now = new Date(); notification.isFromRecover = true; notification.state = state; notification.object = {}; notification.nodeName = message.sourceName; notification.moduleDisplayName = message.sourceName; notification.startTimestamp = Globalization.timeOnly(now); notification.changedTimestamp = Globalization.timeOnly(now); notification.changedTimestampValue = now.getTime(); notification.description = null; notification.typeId = null; notification.title = message.title; notification.message = message.message; this.collection[message.id] = notification; this.psSessionIdToNotificationIdMap[message.id] = message.id; this.notificationIdToPsSessionIdMap[message.id] = message.id; this.addEvent(NotificationChangeEvent.Add, notification); return true; } /** * Update notification from socket message. * * @param psSessionId the psSession ID. * @param message the socket message. */ updateFromMessage(psSessionId, message) { const notificationId = this.psSessionIdToNotificationIdMap[psSessionId]; const notification = this.find(notificationId); if (notification) { if (notification.updateFromMessage(message)) { this.addEvent(NotificationChangeEvent.Change, notification); } return true; } return false; } /** * Update notification from socket message. * * @param psSessionId the psSession ID. * @param message the socket message. */ updateFromNotificationMessage(state, item) { const notification = this.find(item.id); if (notification) { notification.updateFromNotificationMessage(state, item); this.addEvent(NotificationChangeEvent.Change, notification); return true; } return false; } /** * Add or update client notification. * * @param clientNotification the client notification object. * @param Observable the observable of void. */ notify(clientNotification) { // convert alert into notification if (MsftSme.isNullOrWhiteSpace(clientNotification.title)) { clientNotification.title = clientNotification.message; clientNotification.message = null; } SmeWebTelemetry.traceClientNotification(clientNotification); let notification = this.find(clientNotification.id); if (notification) { if (notification.updateFromClient(clientNotification)) { this.addEvent(NotificationChangeEvent.Change, notification); } return EMPTY; } notification = Notification.createFromClient(clientNotification, this.iFrameService); this.collection[clientNotification.id] = notification; this.addEvent(NotificationChangeEvent.Add, notification); return EMPTY; } /** * Find current work item by the typeId/sourceName/nodeName. * * @param workItemFind the query notification object. * @param RpcWorkItemFindResult the result of query. */ workItemFind(workItemFind) { const keys = Object.keys(this.collection); const results = keys .map(key => ({ key: key, notification: this.collection[key] })) .filter(data => data.notification.moduleName === workItemFind.moduleName && data.notification.nodeName === workItemFind.nodeName && data.notification.typeId === workItemFind.typeId) .map(data => ({ id: data.key, state: data.notification.state, percent: data.notification.percent, error: data.notification.error, object: data.notification.object })); const notificationResult = { results: results, typeId: workItemFind.typeId, moduleName: workItemFind.moduleName, nodeName: workItemFind.nodeName }; return notificationResult; } /** * Add an event to report the change of notification data or collection. * * @param changeEvent the changed event. * @param notification the notification object. (optional) */ addEvent(changeEvent, notification) { // need to copy otherwise every change to original notification will be shown on UI without event const notificationCopy = {}; if (notification) { MsftSme.shallowCopyFromObject(notificationCopy, notification); } this.changedEventSubject.next({ notification: notificationCopy, changeEvent: changeEvent }); // no localization. Logging.logVerbose('Notification', notification ? 'addEvent: {0}/{1}\n{2}\n{3}\n{4}'.format(NotificationChangeEvent[changeEvent], NotificationState[notification.state], notification.title, notification.message, notification.link) : 'addEvent: {0}'.format(NotificationChangeEvent[changeEvent])); } } //# sourceMappingURL=notification-manager.js.map