From 614b3beef94d57022b6c2cf5e6d367812ed12708 Mon Sep 17 00:00:00 2001
From: psjostrom <per.sjostrom@symphony.com>
Date: Thu, 1 Apr 2021 15:34:02 +0200
Subject: [PATCH] SDA-3033 Add ability to close all windows from SFE-Lite

---
 spec/mainApiHandler.spec.ts  | 10 +++++++
 src/app/main-api-handler.ts  |  4 +++
 src/app/window-handler.ts    | 11 +++----
 src/app/window-utils.ts      |  6 ++--
 src/common/api-interface.ts  |  1 +
 src/renderer/app-bridge.ts   |  2 ++
 src/renderer/notification.ts | 58 +++++++-----------------------------
 src/renderer/preload-main.ts |  2 ++
 src/renderer/ssf-api.ts      |  9 ++++++
 9 files changed, 46 insertions(+), 57 deletions(-)

diff --git a/spec/mainApiHandler.spec.ts b/spec/mainApiHandler.spec.ts
index 09294be9..b72b68d9 100644
--- a/spec/mainApiHandler.spec.ts
+++ b/spec/mainApiHandler.spec.ts
@@ -38,6 +38,7 @@ jest.mock('../src/app/window-actions', () => {
 jest.mock('../src/app/window-handler', () => {
   return {
     windowHandler: {
+      closeAllWindows: jest.fn(),
       closeWindow: jest.fn(),
       createNotificationSettingsWindow: jest.fn(),
       createScreenPickerWindow: jest.fn(),
@@ -458,5 +459,14 @@ describe('main api handler', () => {
         expect(windowHandler.appMenu.buildMenu).not.toBeCalled();
       }
     });
+
+    it('should call closeAllWindows on windowHandler correctly', () => {
+      const spy = jest.spyOn(windowHandler, 'closeAllWindows');
+      const value = {
+        cmd: apiCmds.closeAllWrapperWindows,
+      };
+      ipcMain.send(apiName.symphonyApi, value);
+      expect(spy).toBeCalled();
+    });
   });
 });
diff --git a/src/app/main-api-handler.ts b/src/app/main-api-handler.ts
index 98b22e26..90311e82 100644
--- a/src/app/main-api-handler.ts
+++ b/src/app/main-api-handler.ts
@@ -35,6 +35,7 @@ import {
 /**
  * Handle API related ipc messages from renderers. Only messages from windows
  * we have created are allowed.
+ * Used mainly for Mana to communicate with SDA
  */
 ipcMain.on(
   apiName.symphonyApi,
@@ -270,6 +271,9 @@ ipcMain.on(
           await notificationHelper.closeNotification(arg.notificationId);
         }
         break;
+      case apiCmds.closeAllWrapperWindows:
+        windowHandler.closeAllWindows();
+        break;
       default:
         break;
     }
diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts
index 04779089..d60a8bf1 100644
--- a/src/app/window-handler.ts
+++ b/src/app/window-handler.ts
@@ -607,7 +607,7 @@ export class WindowHandler {
       if (isWindowsOS || isMac) {
         this.execCmd(this.screenShareIndicatorFrameUtil, []);
       }
-      this.closeAllWindow();
+      this.closeAllWindows();
       this.destroyAllWindows();
     });
 
@@ -796,18 +796,14 @@ export class WindowHandler {
   /**
    * Finds all the child window and closes it
    */
-  public async closeAllWindow(): Promise<void> {
+  public closeAllWindows(): void {
     const browserWindows = BrowserWindow.getAllWindows();
-    await notification.cleanUp();
     if (browserWindows && browserWindows.length) {
       browserWindows.forEach((win) => {
         const browserWindow = win as ICustomBrowserWindow;
         if (browserWindow && windowExists(browserWindow)) {
           // Closes only child windows
-          if (
-            browserWindow.winName !== apiName.mainWindowName &&
-            browserWindow.winName !== apiName.notificationWindowName
-          ) {
+          if (browserWindow.winName !== apiName.mainWindowName) {
             if (browserWindow.closable) {
               browserWindow.close();
             } else {
@@ -817,6 +813,7 @@ export class WindowHandler {
         }
       });
     }
+    notification.cleanUp();
   }
 
   /**
diff --git a/src/app/window-utils.ts b/src/app/window-utils.ts
index 9dc97820..ec7ab5b3 100644
--- a/src/app/window-utils.ts
+++ b/src/app/window-utils.ts
@@ -323,7 +323,7 @@ export const showPopupMenu = (opts: Electron.PopupOptions): void => {
  *
  * @param windowName {string}
  */
-export const sanitize = async (windowName: string): Promise<void> => {
+export const sanitize = (windowName: string): void => {
   // To make sure the reload event is from the main window
   const mainWindow = windowHandler.getMainWindow();
   if (mainWindow && windowName === mainWindow.winName) {
@@ -335,7 +335,7 @@ export const sanitize = async (windowName: string): Promise<void> => {
       screenSnippet.killChildProcess();
     }
     // Closes all the child windows
-    await windowHandler.closeAllWindow();
+    windowHandler.closeAllWindows();
   }
 };
 
@@ -675,7 +675,7 @@ export const reloadWindow = (browserWindow: ICustomBrowserWindow) => {
     logger.info(`window-utils: reloading the main window`);
     browserWindow.reload();
 
-    windowHandler.closeAllWindow();
+    windowHandler.closeAllWindows();
 
     windowHandler.execCmd(windowHandler.screenShareIndicatorFrameUtil, []);
 
diff --git a/src/common/api-interface.ts b/src/common/api-interface.ts
index 4872190b..7d1685e6 100644
--- a/src/common/api-interface.ts
+++ b/src/common/api-interface.ts
@@ -45,6 +45,7 @@ export enum apiCmds {
   restartApp = 'restart-app',
   setIsMana = 'set-is-mana',
   showNotification = 'show-notification',
+  closeAllWrapperWindows = 'close-all-windows',
 }
 
 export enum apiName {
diff --git a/src/renderer/app-bridge.ts b/src/renderer/app-bridge.ts
index 7365b947..72ca849d 100644
--- a/src/renderer/app-bridge.ts
+++ b/src/renderer/app-bridge.ts
@@ -94,6 +94,8 @@ export class AppBridge {
    * Switch case that validates and handle
    * incoming messages from postMessage
    *
+   * Is only used for 1.5.
+   *
    * @param event
    */
   private async handleMessage(event): Promise<void> {
diff --git a/src/renderer/notification.ts b/src/renderer/notification.ts
index 2dc69138..17be5b49 100644
--- a/src/renderer/notification.ts
+++ b/src/renderer/notification.ts
@@ -18,7 +18,6 @@ import { isNodeEnv, isWindowsOS } from '../common/env';
 import { logger } from '../common/logger';
 import NotificationHandler from './notification-handler';
 
-// const MAX_QUEUE_SIZE = 30;
 const CLEAN_UP_INTERVAL = 60 * 1000; // Closes inactive notification
 const animationQueue = new AnimationQueue();
 const CONTAINER_HEIGHT_WITH_INPUT = 120; // Notification container height
@@ -68,8 +67,8 @@ class Notification extends NotificationHandler {
       this.onMouseLeave(windowId, isInputHidden),
     onShowReply: (_event, windowId) => this.onShowReply(windowId),
   };
-  private activeNotifications: Electron.BrowserWindow[] = [];
-  private inactiveWindows: Electron.BrowserWindow[] = [];
+  private activeNotifications: ICustomBrowserWindow[] = [];
+  private inactiveWindows: ICustomBrowserWindow[] = [];
   private cleanUpTimer: NodeJS.Timer;
   private notificationQueue: INotificationData[] = [];
 
@@ -150,15 +149,13 @@ class Notification extends NotificationHandler {
       }
 
       for (const window of this.activeNotifications) {
-        const notificationWin = window as ICustomBrowserWindow;
-        const winHeight =
-          windowExists(notificationWin) && notificationWin.getBounds().height;
+        const winHeight = windowExists(window) && window.getBounds().height;
         if (
           window &&
-          notificationWin.notificationData.tag === data.tag &&
+          window.notificationData.tag === data.tag &&
           winHeight < CONTAINER_HEIGHT_WITH_INPUT
         ) {
-          this.setNotificationContent(notificationWin, data);
+          this.setNotificationContent(window, data);
           return;
         }
       }
@@ -175,7 +172,7 @@ class Notification extends NotificationHandler {
 
     // Checks for the cashed window and use them
     if (this.inactiveWindows.length > 0) {
-      const inactiveWin = this.inactiveWindows[0] as ICustomBrowserWindow;
+      const inactiveWin = this.inactiveWindows[0];
       if (windowExists(inactiveWin)) {
         this.inactiveWindows.splice(0, 1);
         this.renderNotification(inactiveWin, data);
@@ -398,14 +395,9 @@ class Notification extends NotificationHandler {
   public getNotificationWindow(
     clientId: number,
   ): ICustomBrowserWindow | undefined {
-    const index: number = this.activeNotifications.findIndex((win) => {
-      const notificationWindow = win as ICustomBrowserWindow;
-      return notificationWindow.clientId === clientId;
-    });
-    if (index === -1) {
-      return;
-    }
-    return this.activeNotifications[index] as ICustomBrowserWindow;
+    return this.activeNotifications.find(
+      (notification) => notification.clientId === clientId,
+    );
   }
 
   /**
@@ -426,35 +418,9 @@ class Notification extends NotificationHandler {
   /**
    * Closes all the notification windows and resets some configurations
    */
-  public async cleanUp(): Promise<void> {
+  public cleanUp(): void {
     animationQueue.clear();
     this.notificationQueue = [];
-    const activeNotificationWindows = {
-      ...[],
-      ...this.activeNotifications,
-    };
-    const inactiveNotificationWindows = { ...[], ...this.inactiveWindows };
-    if (activeNotificationWindows && Array.isArray(activeNotificationWindows)) {
-      for (const activeWindow of activeNotificationWindows) {
-        if (activeWindow && windowExists(activeWindow)) {
-          await this.hideNotification(
-            (activeWindow as ICustomBrowserWindow).clientId,
-          );
-        }
-      }
-    }
-
-    if (
-      inactiveNotificationWindows &&
-      Array.isArray(inactiveNotificationWindows)
-    ) {
-      for (const inactiveWindow of inactiveNotificationWindows) {
-        if (inactiveWindow && windowExists(inactiveWindow)) {
-          inactiveWindow.close();
-        }
-      }
-    }
-
     this.activeNotifications = [];
     this.inactiveWindows = [];
   }
@@ -464,9 +430,7 @@ class Notification extends NotificationHandler {
    * issue: ELECTRON-1382
    */
   public moveNotificationToTop(): void {
-    const notificationWindows = this
-      .activeNotifications as ICustomBrowserWindow[];
-    notificationWindows
+    this.activeNotifications
       .filter(
         (browserWindow) =>
           typeof browserWindow.notificationData === 'object' &&
diff --git a/src/renderer/preload-main.ts b/src/renderer/preload-main.ts
index 9a1bfb63..7b14d4cb 100644
--- a/src/renderer/preload-main.ts
+++ b/src/renderer/preload-main.ts
@@ -49,6 +49,7 @@ createAPI();
 
 if (ssfWindow.ssf) {
   // New context bridge api that exposes all the methods on to window object
+  // For Mana to communicate with SDA
   contextBridge.exposeInMainWorld('manaSSF', {
     setIsMana: ssfWindow.ssf.setIsMana,
     CryptoLib: ssfWindow.ssf.CryptoLib,
@@ -85,6 +86,7 @@ if (ssfWindow.ssf) {
     showNotification: ssfWindow.ssf.showNotification,
     closeNotification: ssfWindow.ssf.closeNotification,
     restartApp: ssfWindow.ssf.restartApp,
+    closeAllWrapperWindows: ssfWindow.ssf.closeAllWrapperWindows,
   });
 }
 
diff --git a/src/renderer/ssf-api.ts b/src/renderer/ssf-api.ts
index 9373bae9..df26a323 100644
--- a/src/renderer/ssf-api.ts
+++ b/src/renderer/ssf-api.ts
@@ -627,6 +627,15 @@ export class SSFApi {
     });
   }
 
+  /**
+   * Closes all browser windows on SDA side, such as notifications, Screen snippet window, popped out chats etc
+   */
+  public closeAllWrapperWindows(): void {
+    ipcRenderer.send(apiName.symphonyApi, {
+      cmd: apiCmds.closeAllWrapperWindows,
+    });
+  }
+
   /**
    * Displays a notification from the main process
    * @param notificationOpts {INotificationData}