From 923df7c18744211a84337485f2402a78616f42ce Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:43:22 -0400 Subject: [PATCH] [MM-46634] Force window to be focused after navigation on notification click (#3051) --- src/main/notifications/index.test.ts | 22 +++++++++++++++++++--- src/main/notifications/index.ts | 17 +++++++++++------ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/main/notifications/index.test.ts b/src/main/notifications/index.test.ts index 5acc963f..93ecb71c 100644 --- a/src/main/notifications/index.test.ts +++ b/src/main/notifications/index.test.ts @@ -4,8 +4,8 @@ 'use strict'; import notMockedCP from 'child_process'; -import type {BrowserWindow, WebContents} from 'electron'; -import {Notification as NotMockedNotification, shell, app} from 'electron'; +import type {BrowserWindow, IpcMain, IpcMainEvent, WebContents} from 'electron'; +import {Notification as NotMockedNotification, shell, app, ipcMain as NotMockedIpcMain} from 'electron'; import {getDoNotDisturb as notMockedGetDarwinDoNotDisturb} from 'macos-notification-state'; import {getFocusAssist as notMockedGetFocusAssist} from 'windows-focus-assist'; @@ -28,6 +28,7 @@ const Config = jest.mocked(notMockedConfig); const MainWindow = jest.mocked(notMockedMainWindow); const localizeMessage = jest.mocked(notMockedLocalizeMessage); const cp = jest.mocked(notMockedCP); +const ipcMain = jest.mocked(NotMockedIpcMain); const mentions: Array<{body: string; value: any}> = []; @@ -69,6 +70,10 @@ jest.mock('electron', () => { bounce: jest.fn(), }, }, + ipcMain: { + on: jest.fn(), + off: jest.fn(), + }, Notification: NotificationMock, shell: { showItemInFolder: jest.fn(), @@ -273,7 +278,12 @@ describe('main/notifications', () => { }); }); - it('should switch view when clicking on notification', async () => { + it('should switch view when clicking on notification, but after the navigation has happened', async () => { + let listener: (event: IpcMainEvent, ...args: any[]) => void; + ipcMain.on.mockImplementation((channel: string, cb: (event: IpcMainEvent, ...args: any[]) => void): IpcMain => { + listener = cb; + return ipcMain; + }); await NotificationManager.displayMention( 'click_test', 'mention_click_body', @@ -286,6 +296,12 @@ describe('main/notifications', () => { ); const mention = mentions.find((m) => m.body === 'mention_click_body'); mention?.value.click(); + expect(MainWindow.show).not.toHaveBeenCalled(); + expect(ViewManager.showById).not.toHaveBeenCalledWith('server_id'); + + // @ts-expect-error "Set by the click handler" + listener?.({} as unknown as IpcMainEvent); + expect(MainWindow.show).toHaveBeenCalled(); expect(ViewManager.showById).toHaveBeenCalledWith('server_id'); }); diff --git a/src/main/notifications/index.ts b/src/main/notifications/index.ts index 2a1d2daa..7e55c7d4 100644 --- a/src/main/notifications/index.ts +++ b/src/main/notifications/index.ts @@ -1,11 +1,11 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {app, shell, Notification} from 'electron'; +import {app, shell, Notification, ipcMain} from 'electron'; import isDev from 'electron-is-dev'; import {getDoNotDisturb as getDarwinDoNotDisturb} from 'macos-notification-state'; -import {PLAY_SOUND, NOTIFICATION_CLICKED} from 'common/communication'; +import {PLAY_SOUND, NOTIFICATION_CLICKED, BROWSER_HISTORY_PUSH} from 'common/communication'; import Config from 'common/config'; import {Logger} from 'common/log'; @@ -70,11 +70,16 @@ class NotificationManager { log.debug('notification click', serverName, mention.uId); this.allActiveNotifications.delete(mention.uId); - MainWindow.show(); - if (serverName) { + + // Show the window after navigation has finished to avoid the focus handler + // being called before the current channel has updated + const focus = () => { + MainWindow.show(); ViewManager.showById(view.id); - webcontents.send(NOTIFICATION_CLICKED, channelId, teamId, url); - } + ipcMain.off(BROWSER_HISTORY_PUSH, focus); + }; + ipcMain.on(BROWSER_HISTORY_PUSH, focus); + webcontents.send(NOTIFICATION_CLICKED, channelId, teamId, url); }); mention.on('close', () => {