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