Migrate viewManager to singleton (#2656)
This commit is contained in:
@@ -5,7 +5,7 @@ import {app, dialog} from 'electron';
|
|||||||
|
|
||||||
import CertificateStore from 'main/certificateStore';
|
import CertificateStore from 'main/certificateStore';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import ViewManager from 'main/views/viewManager';
|
||||||
|
|
||||||
import {handleAppWillFinishLaunching, handleAppCertificateError, certificateErrorCallbacks} from 'main/app/app';
|
import {handleAppWillFinishLaunching, handleAppCertificateError, certificateErrorCallbacks} from 'main/app/app';
|
||||||
import {getDeeplinkingURL, openDeepLink} from 'main/app/utils';
|
import {getDeeplinkingURL, openDeepLink} from 'main/app/utils';
|
||||||
@@ -21,13 +21,6 @@ jest.mock('electron', () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('common/config', () => ({
|
|
||||||
teams: [{
|
|
||||||
name: 'test-team',
|
|
||||||
url: 'http://server-1.com',
|
|
||||||
}],
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('main/app/utils', () => ({
|
jest.mock('main/app/utils', () => ({
|
||||||
getDeeplinkingURL: jest.fn(),
|
getDeeplinkingURL: jest.fn(),
|
||||||
openDeepLink: jest.fn(),
|
openDeepLink: jest.fn(),
|
||||||
@@ -46,11 +39,14 @@ jest.mock('main/i18nManager', () => ({
|
|||||||
}));
|
}));
|
||||||
jest.mock('main/tray/tray', () => ({}));
|
jest.mock('main/tray/tray', () => ({}));
|
||||||
jest.mock('main/windows/windowManager', () => ({
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
getViewNameByWebContentsId: jest.fn(),
|
showMainWindow: jest.fn(),
|
||||||
getServerNameByWebContentsId: jest.fn(),
|
}));
|
||||||
viewManager: {
|
jest.mock('main/windows/mainWindow', () => ({
|
||||||
views: new Map(),
|
get: jest.fn(),
|
||||||
},
|
}));
|
||||||
|
jest.mock('main/views/viewManager', () => ({
|
||||||
|
getView: jest.fn(),
|
||||||
|
getViewByWebContentsId: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('main/windows/mainWindow', () => ({
|
jest.mock('main/windows/mainWindow', () => ({
|
||||||
get: jest.fn(),
|
get: jest.fn(),
|
||||||
@@ -71,7 +67,6 @@ describe('main/app/app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
WindowManager.viewManager.views.clear();
|
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -104,10 +99,19 @@ describe('main/app/app', () => {
|
|||||||
const mainWindow = {};
|
const mainWindow = {};
|
||||||
const promise = Promise.resolve({});
|
const promise = Promise.resolve({});
|
||||||
const certificate = {};
|
const certificate = {};
|
||||||
|
const view = {
|
||||||
|
tab: {
|
||||||
|
server: {
|
||||||
|
name: 'test-team',
|
||||||
|
url: new URL(testURL),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
load: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
MainWindow.get.mockReturnValue(mainWindow);
|
MainWindow.get.mockReturnValue(mainWindow);
|
||||||
WindowManager.getServerNameByWebContentsId.mockReturnValue('test-team');
|
ViewManager.getViewByWebContentsId.mockReturnValue(view);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -166,12 +170,9 @@ describe('main/app/app', () => {
|
|||||||
|
|
||||||
it('should load URL using MattermostView when trusting certificate', async () => {
|
it('should load URL using MattermostView when trusting certificate', async () => {
|
||||||
dialog.showMessageBox.mockResolvedValue({response: 0});
|
dialog.showMessageBox.mockResolvedValue({response: 0});
|
||||||
const load = jest.fn();
|
|
||||||
WindowManager.viewManager.views.set('view-name', {load});
|
|
||||||
WindowManager.getViewNameByWebContentsId.mockReturnValue('view-name');
|
|
||||||
await handleAppCertificateError(event, webContents, testURL, 'error-1', certificate, callback);
|
await handleAppCertificateError(event, webContents, testURL, 'error-1', certificate, callback);
|
||||||
expect(callback).toHaveBeenCalledWith(true);
|
expect(callback).toHaveBeenCalledWith(true);
|
||||||
expect(load).toHaveBeenCalledWith(testURL);
|
expect(view.load).toHaveBeenCalledWith(testURL);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should explicitly untrust if user selects More Details and then cancel with the checkbox checked', async () => {
|
it('should explicitly untrust if user selects More Details and then cancel with the checkbox checked', async () => {
|
||||||
|
@@ -5,13 +5,13 @@ import {app, BrowserWindow, Event, dialog, WebContents, Certificate, Details} fr
|
|||||||
|
|
||||||
import {Logger} from 'common/log';
|
import {Logger} from 'common/log';
|
||||||
import urlUtils from 'common/utils/url';
|
import urlUtils from 'common/utils/url';
|
||||||
import Config from 'common/config';
|
|
||||||
|
|
||||||
import updateManager from 'main/autoUpdater';
|
import updateManager from 'main/autoUpdater';
|
||||||
import CertificateStore from 'main/certificateStore';
|
import CertificateStore from 'main/certificateStore';
|
||||||
import {localizeMessage} from 'main/i18nManager';
|
import {localizeMessage} from 'main/i18nManager';
|
||||||
import {destroyTray} from 'main/tray/tray';
|
import {destroyTray} from 'main/tray/tray';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
import {getDeeplinkingURL, openDeepLink, resizeScreen} from './utils';
|
import {getDeeplinkingURL, openDeepLink, resizeScreen} from './utils';
|
||||||
@@ -95,10 +95,9 @@ export async function handleAppCertificateError(event: Event, webContents: WebCo
|
|||||||
// update the callback
|
// update the callback
|
||||||
const errorID = `${origin}:${error}`;
|
const errorID = `${origin}:${error}`;
|
||||||
|
|
||||||
const serverName = WindowManager.getServerNameByWebContentsId(webContents.id);
|
const view = ViewManager.getViewByWebContentsId(webContents.id);
|
||||||
const server = Config.teams.find((team) => team.name === serverName);
|
if (view?.tab.server) {
|
||||||
if (server) {
|
const serverURL = urlUtils.parseURL(view.tab.server.url);
|
||||||
const serverURL = urlUtils.parseURL(server.url);
|
|
||||||
if (serverURL && serverURL.origin !== origin) {
|
if (serverURL && serverURL.origin !== origin) {
|
||||||
log.warn(`Ignoring certificate for unmatched origin ${origin}, will not trust`);
|
log.warn(`Ignoring certificate for unmatched origin ${origin}, will not trust`);
|
||||||
callback(false);
|
callback(false);
|
||||||
@@ -159,10 +158,8 @@ export async function handleAppCertificateError(event: Event, webContents: WebCo
|
|||||||
CertificateStore.save();
|
CertificateStore.save();
|
||||||
certificateErrorCallbacks.get(errorID)(true);
|
certificateErrorCallbacks.get(errorID)(true);
|
||||||
|
|
||||||
const viewName = WindowManager.getViewNameByWebContentsId(webContents.id);
|
if (view) {
|
||||||
if (viewName) {
|
view.load(url);
|
||||||
const view = WindowManager.viewManager?.views.get(viewName);
|
|
||||||
view?.load(url);
|
|
||||||
} else {
|
} else {
|
||||||
webContents.loadURL(url);
|
webContents.loadURL(url);
|
||||||
}
|
}
|
||||||
|
@@ -44,6 +44,9 @@ jest.mock('main/badge', () => ({
|
|||||||
jest.mock('main/tray/tray', () => ({
|
jest.mock('main/tray/tray', () => ({
|
||||||
refreshTrayImages: jest.fn(),
|
refreshTrayImages: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('main/views/viewManager', () => ({
|
||||||
|
reloadConfiguration: jest.fn(),
|
||||||
|
}));
|
||||||
jest.mock('main/views/loadingScreen', () => ({}));
|
jest.mock('main/views/loadingScreen', () => ({}));
|
||||||
jest.mock('main/windows/windowManager', () => ({
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
handleUpdateConfig: jest.fn(),
|
handleUpdateConfig: jest.fn(),
|
||||||
|
@@ -12,6 +12,7 @@ import {Logger, setLoggingLevel} from 'common/log';
|
|||||||
import AutoLauncher from 'main/AutoLauncher';
|
import AutoLauncher from 'main/AutoLauncher';
|
||||||
import {setUnreadBadgeSetting} from 'main/badge';
|
import {setUnreadBadgeSetting} from 'main/badge';
|
||||||
import {refreshTrayImages} from 'main/tray/tray';
|
import {refreshTrayImages} from 'main/tray/tray';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import LoadingScreen from 'main/views/loadingScreen';
|
import LoadingScreen from 'main/views/loadingScreen';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
|
|
||||||
@@ -36,8 +37,8 @@ export function handleConfigUpdate(newConfig: CombinedConfig) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowManager.handleUpdateConfig();
|
|
||||||
if (app.isReady()) {
|
if (app.isReady()) {
|
||||||
|
ViewManager.reloadConfiguration();
|
||||||
WindowManager.sendToRenderer(RELOAD_CONFIGURATION);
|
WindowManager.sendToRenderer(RELOAD_CONFIGURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -162,6 +162,7 @@ jest.mock('main/windows/windowManager', () => ({
|
|||||||
getServerNameByWebContentsId: jest.fn(),
|
getServerNameByWebContentsId: jest.fn(),
|
||||||
getServerURLFromWebContentsId: jest.fn(),
|
getServerURLFromWebContentsId: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('main/views/viewManager', () => ({}));
|
||||||
jest.mock('main/windows/settingsWindow', () => ({
|
jest.mock('main/windows/settingsWindow', () => ({
|
||||||
show: jest.fn(),
|
show: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
@@ -56,6 +56,7 @@ import SettingsWindow from 'main/windows/settingsWindow';
|
|||||||
import TrustedOriginsStore from 'main/trustedOrigins';
|
import TrustedOriginsStore from 'main/trustedOrigins';
|
||||||
import {refreshTrayImages, setupTray} from 'main/tray/tray';
|
import {refreshTrayImages, setupTray} from 'main/tray/tray';
|
||||||
import UserActivityMonitor from 'main/UserActivityMonitor';
|
import UserActivityMonitor from 'main/UserActivityMonitor';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
@@ -238,7 +239,7 @@ function initializeInterCommunicationEventListeners() {
|
|||||||
ipcMain.on(NOTIFY_MENTION, handleMentionNotification);
|
ipcMain.on(NOTIFY_MENTION, handleMentionNotification);
|
||||||
ipcMain.handle('get-app-version', handleAppVersion);
|
ipcMain.handle('get-app-version', handleAppVersion);
|
||||||
ipcMain.on(UPDATE_SHORTCUT_MENU, handleUpdateMenuEvent);
|
ipcMain.on(UPDATE_SHORTCUT_MENU, handleUpdateMenuEvent);
|
||||||
ipcMain.on(FOCUS_BROWSERVIEW, WindowManager.focusBrowserView);
|
ipcMain.on(FOCUS_BROWSERVIEW, ViewManager.focusCurrentView);
|
||||||
ipcMain.on(UPDATE_LAST_ACTIVE, handleUpdateLastActive);
|
ipcMain.on(UPDATE_LAST_ACTIVE, handleUpdateLastActive);
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
@@ -351,7 +352,7 @@ function initializeAfterAppReady() {
|
|||||||
// listen for status updates and pass on to renderer
|
// listen for status updates and pass on to renderer
|
||||||
UserActivityMonitor.on('status', (status) => {
|
UserActivityMonitor.on('status', (status) => {
|
||||||
log.debug('UserActivityMonitor.on(status)', status);
|
log.debug('UserActivityMonitor.on(status)', status);
|
||||||
WindowManager.sendToMattermostViews(USER_ACTIVITY_UPDATE, status);
|
ViewManager.sendToAllViews(USER_ACTIVITY_UPDATE, status);
|
||||||
});
|
});
|
||||||
|
|
||||||
// start monitoring user activity (needs to be started after the app is ready)
|
// start monitoring user activity (needs to be started after the app is ready)
|
||||||
|
@@ -30,6 +30,7 @@ jest.mock('main/utils', () => ({
|
|||||||
getLocalPreload: jest.fn(),
|
getLocalPreload: jest.fn(),
|
||||||
getLocalURLString: jest.fn(),
|
getLocalURLString: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('main/views/viewManager', () => ({}));
|
||||||
jest.mock('main/views/modalManager', () => ({
|
jest.mock('main/views/modalManager', () => ({
|
||||||
addModal: jest.fn(),
|
addModal: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
@@ -14,6 +14,7 @@ import {ping} from 'common/utils/requests';
|
|||||||
import {displayMention} from 'main/notifications';
|
import {displayMention} from 'main/notifications';
|
||||||
import {getLocalPreload, getLocalURLString} from 'main/utils';
|
import {getLocalPreload, getLocalURLString} from 'main/utils';
|
||||||
import ModalManager from 'main/views/modalManager';
|
import ModalManager from 'main/views/modalManager';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ export function handleReloadConfig() {
|
|||||||
log.debug('handleReloadConfig');
|
log.debug('handleReloadConfig');
|
||||||
|
|
||||||
Config.reload();
|
Config.reload();
|
||||||
WindowManager.handleUpdateConfig();
|
ViewManager.reloadConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleAppVersion() {
|
export function handleAppVersion() {
|
||||||
|
@@ -60,6 +60,7 @@ jest.mock('main/server/serverInfo', () => ({
|
|||||||
ServerInfo: jest.fn(),
|
ServerInfo: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('main/tray/tray', () => ({}));
|
jest.mock('main/tray/tray', () => ({}));
|
||||||
|
jest.mock('main/views/viewManager', () => ({}));
|
||||||
jest.mock('main/windows/mainWindow', () => ({}));
|
jest.mock('main/windows/mainWindow', () => ({}));
|
||||||
jest.mock('main/windows/windowManager', () => ({}));
|
jest.mock('main/windows/windowManager', () => ({}));
|
||||||
|
|
||||||
|
@@ -27,6 +27,7 @@ import {createMenu as createAppMenu} from 'main/menus/app';
|
|||||||
import {createMenu as createTrayMenu} from 'main/menus/tray';
|
import {createMenu as createTrayMenu} from 'main/menus/tray';
|
||||||
import {ServerInfo} from 'main/server/serverInfo';
|
import {ServerInfo} from 'main/server/serverInfo';
|
||||||
import {setTrayMenu} from 'main/tray/tray';
|
import {setTrayMenu} from 'main/tray/tray';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ export function handleUpdateMenuEvent() {
|
|||||||
const aMenu = createAppMenu(Config, updateManager);
|
const aMenu = createAppMenu(Config, updateManager);
|
||||||
Menu.setApplicationMenu(aMenu);
|
Menu.setApplicationMenu(aMenu);
|
||||||
aMenu.addListener('menu-will-close', () => {
|
aMenu.addListener('menu-will-close', () => {
|
||||||
WindowManager.focusBrowserView();
|
ViewManager.focusCurrentView();
|
||||||
WindowManager.sendToRenderer(APP_MENU_WILL_CLOSE);
|
WindowManager.sendToRenderer(APP_MENU_WILL_CLOSE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -80,6 +80,7 @@ jest.mock('main/notifications', () => ({}));
|
|||||||
jest.mock('main/windows/windowManager', () => ({
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
sendToRenderer: jest.fn(),
|
sendToRenderer: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('main/views/viewManager', () => ({}));
|
||||||
jest.mock('common/config', () => {
|
jest.mock('common/config', () => {
|
||||||
const original = jest.requireActual('common/config');
|
const original = jest.requireActual('common/config');
|
||||||
return {
|
return {
|
||||||
|
@@ -31,6 +31,7 @@ import {DOWNLOADS_DROPDOWN_AUTOCLOSE_TIMEOUT, DOWNLOADS_DROPDOWN_MAX_ITEMS} from
|
|||||||
import * as Validator from 'common/Validator';
|
import * as Validator from 'common/Validator';
|
||||||
import {localizeMessage} from 'main/i18nManager';
|
import {localizeMessage} from 'main/i18nManager';
|
||||||
import {displayDownloadCompleted} from 'main/notifications';
|
import {displayDownloadCompleted} from 'main/notifications';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
import {doubleSecToMs, getPercentage, isStringWithLength, readFilenameFromContentDispositionHeader, shouldIncrementFilename} from 'main/utils';
|
import {doubleSecToMs, getPercentage, isStringWithLength, readFilenameFromContentDispositionHeader, shouldIncrementFilename} from 'main/utils';
|
||||||
|
|
||||||
@@ -509,7 +510,7 @@ export class DownloadsManager extends JsonFileManager<DownloadedItems> {
|
|||||||
log.debug('doneEventController', {state});
|
log.debug('doneEventController', {state});
|
||||||
|
|
||||||
if (state === 'completed' && !this.open) {
|
if (state === 'completed' && !this.open) {
|
||||||
displayDownloadCompleted(path.basename(item.savePath), item.savePath, WindowManager.getServerNameByWebContentsId(webContents.id) || '');
|
displayDownloadCompleted(path.basename(item.savePath), item.savePath, ViewManager.getViewByWebContentsId(webContents.id)?.tab.server.name ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
const bookmark = this.bookmarks.get(this.getFileId(item));
|
const bookmark = this.bookmarks.get(this.getFileId(item));
|
||||||
|
@@ -49,10 +49,11 @@ jest.mock('macos-notification-state', () => ({
|
|||||||
jest.mock('main/i18nManager', () => ({
|
jest.mock('main/i18nManager', () => ({
|
||||||
localizeMessage: jest.fn(),
|
localizeMessage: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('main/diagnostics', () => ({}));
|
||||||
jest.mock('main/downloadsManager', () => ({
|
jest.mock('main/downloadsManager', () => ({
|
||||||
hasDownloads: jest.fn(),
|
hasDownloads: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('main/diagnostics', () => ({}));
|
jest.mock('main/views/viewManager', () => ({}));
|
||||||
jest.mock('main/windows/windowManager', () => ({
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
getCurrentTeamName: jest.fn(),
|
getCurrentTeamName: jest.fn(),
|
||||||
sendToRenderer: jest.fn(),
|
sendToRenderer: jest.fn(),
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
import {app, ipcMain, Menu, MenuItemConstructorOptions, MenuItem, session, shell, WebContents, clipboard} from 'electron';
|
import {app, ipcMain, Menu, MenuItemConstructorOptions, MenuItem, session, shell, WebContents, clipboard} from 'electron';
|
||||||
import log from 'electron-log';
|
import log from 'electron-log';
|
||||||
|
|
||||||
import {BROWSER_HISTORY_BUTTON, OPEN_TEAMS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication';
|
import {OPEN_TEAMS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication';
|
||||||
import {t} from 'common/utils/util';
|
import {t} from 'common/utils/util';
|
||||||
import {getTabDisplayName, TabType} from 'common/tabs/TabView';
|
import {getTabDisplayName, TabType} from 'common/tabs/TabView';
|
||||||
import {Config} from 'common/config';
|
import {Config} from 'common/config';
|
||||||
@@ -16,6 +16,7 @@ import WindowManager from 'main/windows/windowManager';
|
|||||||
import {UpdateManager} from 'main/autoUpdater';
|
import {UpdateManager} from 'main/autoUpdater';
|
||||||
import downloadsManager from 'main/downloadsManager';
|
import downloadsManager from 'main/downloadsManager';
|
||||||
import Diagnostics from 'main/diagnostics';
|
import Diagnostics from 'main/diagnostics';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import SettingsWindow from 'main/windows/settingsWindow';
|
import SettingsWindow from 'main/windows/settingsWindow';
|
||||||
|
|
||||||
export function createTemplate(config: Config, updateManager: UpdateManager) {
|
export function createTemplate(config: Config, updateManager: UpdateManager) {
|
||||||
@@ -126,20 +127,20 @@ export function createTemplate(config: Config, updateManager: UpdateManager) {
|
|||||||
label: localizeMessage('main.menus.app.view.find', 'Find..'),
|
label: localizeMessage('main.menus.app.view.find', 'Find..'),
|
||||||
accelerator: 'CmdOrCtrl+F',
|
accelerator: 'CmdOrCtrl+F',
|
||||||
click() {
|
click() {
|
||||||
WindowManager.sendToFind();
|
ViewManager.sendToFind();
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
label: localizeMessage('main.menus.app.view.reload', 'Reload'),
|
label: localizeMessage('main.menus.app.view.reload', 'Reload'),
|
||||||
accelerator: 'CmdOrCtrl+R',
|
accelerator: 'CmdOrCtrl+R',
|
||||||
click() {
|
click() {
|
||||||
WindowManager.reload();
|
ViewManager.reload();
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
label: localizeMessage('main.menus.app.view.clearCacheAndReload', 'Clear Cache and Reload'),
|
label: localizeMessage('main.menus.app.view.clearCacheAndReload', 'Clear Cache and Reload'),
|
||||||
accelerator: 'Shift+CmdOrCtrl+R',
|
accelerator: 'Shift+CmdOrCtrl+R',
|
||||||
click() {
|
click() {
|
||||||
session.defaultSession.clearCache();
|
session.defaultSession.clearCache();
|
||||||
WindowManager.reload();
|
ViewManager.reload();
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
role: 'togglefullscreen',
|
role: 'togglefullscreen',
|
||||||
@@ -193,7 +194,7 @@ export function createTemplate(config: Config, updateManager: UpdateManager) {
|
|||||||
}, {
|
}, {
|
||||||
label: localizeMessage('main.menus.app.view.devToolsCurrentServer', 'Developer Tools for Current Server'),
|
label: localizeMessage('main.menus.app.view.devToolsCurrentServer', 'Developer Tools for Current Server'),
|
||||||
click() {
|
click() {
|
||||||
WindowManager.openBrowserViewDevTools();
|
ViewManager.getCurrentView()?.openDevTools();
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@@ -219,21 +220,13 @@ export function createTemplate(config: Config, updateManager: UpdateManager) {
|
|||||||
label: localizeMessage('main.menus.app.history.back', 'Back'),
|
label: localizeMessage('main.menus.app.history.back', 'Back'),
|
||||||
accelerator: process.platform === 'darwin' ? 'Cmd+[' : 'Alt+Left',
|
accelerator: process.platform === 'darwin' ? 'Cmd+[' : 'Alt+Left',
|
||||||
click: () => {
|
click: () => {
|
||||||
const view = WindowManager.viewManager?.getCurrentView();
|
ViewManager.getCurrentView()?.goToOffset(-1);
|
||||||
if (view && view.view.webContents.canGoBack() && !view.isAtRoot) {
|
|
||||||
view.view.webContents.goBack();
|
|
||||||
ipcMain.emit(BROWSER_HISTORY_BUTTON, null, view.name);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
label: localizeMessage('main.menus.app.history.forward', 'Forward'),
|
label: localizeMessage('main.menus.app.history.forward', 'Forward'),
|
||||||
accelerator: process.platform === 'darwin' ? 'Cmd+]' : 'Alt+Right',
|
accelerator: process.platform === 'darwin' ? 'Cmd+]' : 'Alt+Right',
|
||||||
click: () => {
|
click: () => {
|
||||||
const view = WindowManager.viewManager?.getCurrentView();
|
ViewManager.getCurrentView()?.goToOffset(1);
|
||||||
if (view && view.view.webContents.canGoForward()) {
|
|
||||||
view.view.webContents.goForward();
|
|
||||||
ipcMain.emit(BROWSER_HISTORY_BUTTON, null, view.name);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
@@ -75,11 +75,20 @@ jest.mock('windows-focus-assist', () => ({
|
|||||||
jest.mock('macos-notification-state', () => ({
|
jest.mock('macos-notification-state', () => ({
|
||||||
getDoNotDisturb: jest.fn(),
|
getDoNotDisturb: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('../views/viewManager', () => ({
|
||||||
|
getViewByWebContentsId: () => ({
|
||||||
|
id: 'server_id',
|
||||||
|
tab: {
|
||||||
|
server: {
|
||||||
|
name: 'server_name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}));
|
||||||
jest.mock('../windows/mainWindow', () => ({
|
jest.mock('../windows/mainWindow', () => ({
|
||||||
get: jest.fn(),
|
get: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('../windows/windowManager', () => ({
|
jest.mock('../windows/windowManager', () => ({
|
||||||
getServerNameByWebContentsId: () => 'server_name',
|
|
||||||
sendToRenderer: jest.fn(),
|
sendToRenderer: jest.fn(),
|
||||||
flashFrame: jest.fn(),
|
flashFrame: jest.fn(),
|
||||||
switchTab: jest.fn(),
|
switchTab: jest.fn(),
|
||||||
|
@@ -12,6 +12,7 @@ import {PLAY_SOUND} from 'common/communication';
|
|||||||
import {Logger} from 'common/log';
|
import {Logger} from 'common/log';
|
||||||
import {TAB_MESSAGING} from 'common/tabs/TabView';
|
import {TAB_MESSAGING} from 'common/tabs/TabView';
|
||||||
|
|
||||||
|
import ViewManager from '../views/viewManager';
|
||||||
import MainWindow from '../windows/mainWindow';
|
import MainWindow from '../windows/mainWindow';
|
||||||
import WindowManager from '../windows/windowManager';
|
import WindowManager from '../windows/windowManager';
|
||||||
|
|
||||||
@@ -37,7 +38,11 @@ export function displayMention(title: string, body: string, channel: {id: string
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverName = WindowManager.getServerNameByWebContentsId(webcontents.id);
|
const view = ViewManager.getViewByWebContentsId(webcontents.id);
|
||||||
|
if (!view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const serverName = view.tab.server.name;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
title: `${serverName}: ${title}`,
|
title: `${serverName}: ${title}`,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {BrowserView, app, ipcMain} from 'electron';
|
import {BrowserView, app} from 'electron';
|
||||||
import {BrowserViewConstructorOptions, Event, Input} from 'electron/main';
|
import {BrowserViewConstructorOptions, Event, Input} from 'electron/main';
|
||||||
|
|
||||||
import {EventEmitter} from 'events';
|
import {EventEmitter} from 'events';
|
||||||
@@ -15,10 +15,10 @@ import {
|
|||||||
LOAD_FAILED,
|
LOAD_FAILED,
|
||||||
UPDATE_TARGET_URL,
|
UPDATE_TARGET_URL,
|
||||||
IS_UNREAD,
|
IS_UNREAD,
|
||||||
UNREAD_RESULT,
|
|
||||||
TOGGLE_BACK_BUTTON,
|
TOGGLE_BACK_BUTTON,
|
||||||
SET_VIEW_OPTIONS,
|
SET_VIEW_OPTIONS,
|
||||||
LOADSCREEN_END,
|
LOADSCREEN_END,
|
||||||
|
BROWSER_HISTORY_BUTTON,
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
import {MattermostServer} from 'common/servers/MattermostServer';
|
import {MattermostServer} from 'common/servers/MattermostServer';
|
||||||
import {TabView, TabTuple} from 'common/tabs/TabView';
|
import {TabView, TabTuple} from 'common/tabs/TabView';
|
||||||
@@ -234,7 +234,6 @@ export class MattermostView extends EventEmitter {
|
|||||||
WindowManager.sendToRenderer(LOAD_SUCCESS, this.tab.name);
|
WindowManager.sendToRenderer(LOAD_SUCCESS, this.tab.name);
|
||||||
this.maxRetries = MAX_SERVER_RETRIES;
|
this.maxRetries = MAX_SERVER_RETRIES;
|
||||||
if (this.status === Status.LOADING) {
|
if (this.status === Status.LOADING) {
|
||||||
ipcMain.on(UNREAD_RESULT, this.handleFaviconIsUnread);
|
|
||||||
this.updateMentionsFromTitle(this.view.webContents.getTitle());
|
this.updateMentionsFromTitle(this.view.webContents.getTitle());
|
||||||
this.findUnreadState(null);
|
this.findUnreadState(null);
|
||||||
}
|
}
|
||||||
@@ -272,6 +271,32 @@ export class MattermostView extends EventEmitter {
|
|||||||
|
|
||||||
hide = () => this.show(false);
|
hide = () => this.show(false);
|
||||||
|
|
||||||
|
openFind = () => {
|
||||||
|
this.view.webContents.sendInputEvent({type: 'keyDown', keyCode: 'F', modifiers: [process.platform === 'darwin' ? 'cmd' : 'ctrl', 'shift']});
|
||||||
|
}
|
||||||
|
|
||||||
|
goToOffset = (offset: number) => {
|
||||||
|
if (this.view.webContents.canGoToOffset(offset)) {
|
||||||
|
try {
|
||||||
|
this.view.webContents.goToOffset(offset);
|
||||||
|
this.updateHistoryButton();
|
||||||
|
} catch (error) {
|
||||||
|
log.error(error);
|
||||||
|
this.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHistoryButton = () => {
|
||||||
|
if (urlUtils.parseURL(this.view.webContents.getURL())?.toString() === this.tab.url.toString()) {
|
||||||
|
this.view.webContents.clearHistory();
|
||||||
|
this.isAtRoot = true;
|
||||||
|
} else {
|
||||||
|
this.isAtRoot = false;
|
||||||
|
}
|
||||||
|
this.view.webContents.send(BROWSER_HISTORY_BUTTON, this.view.webContents.canGoBack(), this.view.webContents.canGoForward());
|
||||||
|
}
|
||||||
|
|
||||||
setBounds = (boundaries: Electron.Rectangle) => {
|
setBounds = (boundaries: Electron.Rectangle) => {
|
||||||
this.view.setBounds(boundaries);
|
this.view.setBounds(boundaries);
|
||||||
}
|
}
|
||||||
@@ -422,14 +447,4 @@ export class MattermostView extends EventEmitter {
|
|||||||
log.error(err.stack);
|
log.error(err.stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if favicon is null, it means it is the initial load,
|
|
||||||
// so don't memoize as we don't have the favicons and there is no rush to find out.
|
|
||||||
handleFaviconIsUnread = (e: Event, favicon: string, viewName: string, result: boolean) => {
|
|
||||||
log.silly('handleFaviconIsUnread', {favicon, viewName, result});
|
|
||||||
|
|
||||||
if (this.tab && viewName === this.tab.name) {
|
|
||||||
appState.updateUnreads(viewName, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -61,6 +61,10 @@ jest.mock('electron', () => {
|
|||||||
Notification: NotificationMock,
|
Notification: NotificationMock,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
jest.mock('main/downloadsManager', () => ({
|
||||||
|
onOpen: jest.fn(),
|
||||||
|
onClose: jest.fn(),
|
||||||
|
}));
|
||||||
jest.mock('main/windows/mainWindow', () => ({
|
jest.mock('main/windows/mainWindow', () => ({
|
||||||
get: jest.fn(),
|
get: jest.fn(),
|
||||||
getBounds: jest.fn(),
|
getBounds: jest.fn(),
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as WindowManager from '../windows/windowManager';
|
import ViewManager from 'main/views/viewManager';
|
||||||
|
|
||||||
import {ModalManager} from './modalManager';
|
import {ModalManager} from './modalManager';
|
||||||
|
|
||||||
@@ -26,9 +26,11 @@ jest.mock('main/views/webContentEvents', () => ({
|
|||||||
jest.mock('./modalView', () => ({
|
jest.mock('./modalView', () => ({
|
||||||
ModalView: jest.fn(),
|
ModalView: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('../windows/windowManager', () => ({
|
jest.mock('main/views/viewManager', () => ({
|
||||||
|
focusCurrentView: jest.fn(),
|
||||||
|
}));
|
||||||
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
sendToRenderer: jest.fn(),
|
sendToRenderer: jest.fn(),
|
||||||
focusBrowserView: jest.fn(),
|
|
||||||
}));
|
}));
|
||||||
jest.mock('process', () => ({
|
jest.mock('process', () => ({
|
||||||
env: {},
|
env: {},
|
||||||
@@ -161,7 +163,7 @@ describe('main/views/modalManager', () => {
|
|||||||
modalManager.modalQueue.pop();
|
modalManager.modalQueue.pop();
|
||||||
modalManager.modalPromises.delete('test2');
|
modalManager.modalPromises.delete('test2');
|
||||||
modalManager.handleModalFinished('resolve', {sender: {id: 1}}, 'something');
|
modalManager.handleModalFinished('resolve', {sender: {id: 1}}, 'something');
|
||||||
expect(WindowManager.focusBrowserView).toBeCalled();
|
expect(ViewManager.focusCurrentView).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -22,6 +22,7 @@ import {Logger} from 'common/log';
|
|||||||
|
|
||||||
import {getAdjustedWindowBoundaries} from 'main/utils';
|
import {getAdjustedWindowBoundaries} from 'main/utils';
|
||||||
import WebContentsEventManager from 'main/views/webContentEvents';
|
import WebContentsEventManager from 'main/views/webContentEvents';
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
|
|
||||||
import {ModalView} from './modalView';
|
import {ModalView} from './modalView';
|
||||||
@@ -115,7 +116,7 @@ export class ModalManager {
|
|||||||
this.showModal();
|
this.showModal();
|
||||||
} else {
|
} else {
|
||||||
WindowManager.sendToRenderer(MODAL_CLOSE);
|
WindowManager.sendToRenderer(MODAL_CLOSE);
|
||||||
WindowManager.focusBrowserView();
|
ViewManager.focusCurrentView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,7 +7,8 @@
|
|||||||
import {dialog, ipcMain} from 'electron';
|
import {dialog, ipcMain} from 'electron';
|
||||||
import {Tuple as tuple} from '@bloomberg/record-tuple-polyfill';
|
import {Tuple as tuple} from '@bloomberg/record-tuple-polyfill';
|
||||||
|
|
||||||
import {LOAD_SUCCESS, MAIN_WINDOW_SHOWN, BROWSER_HISTORY_PUSH} from 'common/communication';
|
import {BROWSER_HISTORY_PUSH, LOAD_SUCCESS, MAIN_WINDOW_SHOWN} from 'common/communication';
|
||||||
|
import Config from 'common/config';
|
||||||
import {MattermostServer} from 'common/servers/MattermostServer';
|
import {MattermostServer} from 'common/servers/MattermostServer';
|
||||||
import {getTabViewName} from 'common/tabs/TabView';
|
import {getTabViewName} from 'common/tabs/TabView';
|
||||||
import {equalUrlsIgnoringSubpath} from 'common/utils/url';
|
import {equalUrlsIgnoringSubpath} from 'common/utils/url';
|
||||||
@@ -28,9 +29,12 @@ jest.mock('electron', () => ({
|
|||||||
ipcMain: {
|
ipcMain: {
|
||||||
emit: jest.fn(),
|
emit: jest.fn(),
|
||||||
on: jest.fn(),
|
on: jest.fn(),
|
||||||
|
handle: jest.fn(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
jest.mock('common/config', () => ({
|
||||||
|
teams: [],
|
||||||
|
}));
|
||||||
jest.mock('common/tabs/TabView', () => ({
|
jest.mock('common/tabs/TabView', () => ({
|
||||||
getTabViewName: jest.fn((a, b) => `${a}-${b}`),
|
getTabViewName: jest.fn((a, b) => `${a}-${b}`),
|
||||||
TAB_MESSAGING: 'tab',
|
TAB_MESSAGING: 'tab',
|
||||||
@@ -41,6 +45,9 @@ jest.mock('common/servers/MattermostServer', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('common/utils/url', () => ({
|
jest.mock('common/utils/url', () => ({
|
||||||
|
isTeamUrl: jest.fn(),
|
||||||
|
isAdminUrl: jest.fn(),
|
||||||
|
cleanPathName: jest.fn(),
|
||||||
parseURL: (url) => {
|
parseURL: (url) => {
|
||||||
try {
|
try {
|
||||||
return new URL(url);
|
return new URL(url);
|
||||||
@@ -73,6 +80,7 @@ jest.mock('./modalManager', () => ({
|
|||||||
showModal: jest.fn(),
|
showModal: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('./webContentEvents', () => ({}));
|
jest.mock('./webContentEvents', () => ({}));
|
||||||
|
jest.mock('../appState', () => ({}));
|
||||||
|
|
||||||
describe('main/views/viewManager', () => {
|
describe('main/views/viewManager', () => {
|
||||||
describe('loadView', () => {
|
describe('loadView', () => {
|
||||||
@@ -119,12 +127,11 @@ describe('main/views/viewManager', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('reloadViewIfNeeded', () => {
|
describe('handleAppLoggedIn', () => {
|
||||||
const viewManager = new ViewManager({});
|
const viewManager = new ViewManager({});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
viewManager.views = new Map();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reload view when URL is not on subpath of original server URL', () => {
|
it('should reload view when URL is not on subpath of original server URL', () => {
|
||||||
@@ -140,7 +147,7 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
viewManager.views.set('view1', view);
|
viewManager.views.set('view1', view);
|
||||||
viewManager.reloadViewIfNeeded('view1');
|
viewManager.handleAppLoggedIn({}, 'view1');
|
||||||
expect(view.load).toHaveBeenCalledWith(new URL('http://server-1.com/'));
|
expect(view.load).toHaveBeenCalledWith(new URL('http://server-1.com/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -157,7 +164,7 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
viewManager.views.set('view1', view);
|
viewManager.views.set('view1', view);
|
||||||
viewManager.reloadViewIfNeeded('view1');
|
viewManager.handleAppLoggedIn({}, 'view1');
|
||||||
expect(view.load).not.toHaveBeenCalled();
|
expect(view.load).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -174,7 +181,7 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
viewManager.views.set('view1', view);
|
viewManager.views.set('view1', view);
|
||||||
viewManager.reloadViewIfNeeded('view1');
|
viewManager.handleAppLoggedIn({}, 'view1');
|
||||||
expect(view.load).not.toHaveBeenCalled();
|
expect(view.load).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -186,6 +193,7 @@ describe('main/views/viewManager', () => {
|
|||||||
viewManager.loadView = jest.fn();
|
viewManager.loadView = jest.fn();
|
||||||
viewManager.showByName = jest.fn();
|
viewManager.showByName = jest.fn();
|
||||||
viewManager.showInitial = jest.fn();
|
viewManager.showInitial = jest.fn();
|
||||||
|
|
||||||
const mainWindow = {
|
const mainWindow = {
|
||||||
webContents: {
|
webContents: {
|
||||||
send: jest.fn(),
|
send: jest.fn(),
|
||||||
@@ -225,14 +233,7 @@ describe('main/views/viewManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should recycle existing views', () => {
|
it('should recycle existing views', () => {
|
||||||
const makeSpy = jest.spyOn(viewManager, 'makeView');
|
Config.teams = [
|
||||||
const view = new MattermostView({
|
|
||||||
name: 'server1-tab1',
|
|
||||||
urlTypeTuple: tuple(new URL('http://server1.com').href, 'tab1'),
|
|
||||||
server: 'server1',
|
|
||||||
});
|
|
||||||
viewManager.views.set('server1-tab1', view);
|
|
||||||
viewManager.reloadConfiguration([
|
|
||||||
{
|
{
|
||||||
name: 'server1',
|
name: 'server1',
|
||||||
url: 'http://server1.com',
|
url: 'http://server1.com',
|
||||||
@@ -244,14 +245,22 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
const makeSpy = jest.spyOn(viewManager, 'makeView');
|
||||||
|
const view = new MattermostView({
|
||||||
|
name: 'server1-tab1',
|
||||||
|
urlTypeTuple: tuple(new URL('http://server1.com').href, 'tab1'),
|
||||||
|
server: 'server1',
|
||||||
|
});
|
||||||
|
viewManager.views.set('server1-tab1', view);
|
||||||
|
viewManager.reloadConfiguration();
|
||||||
expect(viewManager.views.get('server1-tab1')).toBe(view);
|
expect(viewManager.views.get('server1-tab1')).toBe(view);
|
||||||
expect(makeSpy).not.toHaveBeenCalled();
|
expect(makeSpy).not.toHaveBeenCalled();
|
||||||
makeSpy.mockRestore();
|
makeSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should close tabs that arent open', () => {
|
it('should close tabs that arent open', () => {
|
||||||
viewManager.reloadConfiguration([
|
Config.teams = [
|
||||||
{
|
{
|
||||||
name: 'server1',
|
name: 'server1',
|
||||||
url: 'http://server1.com',
|
url: 'http://server1.com',
|
||||||
@@ -263,13 +272,14 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
viewManager.reloadConfiguration();
|
||||||
expect(viewManager.closedViews.has('server1-tab1')).toBe(true);
|
expect(viewManager.closedViews.has('server1-tab1')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create new views for new tabs', () => {
|
it('should create new views for new tabs', () => {
|
||||||
const makeSpy = jest.spyOn(viewManager, 'makeView');
|
const makeSpy = jest.spyOn(viewManager, 'makeView');
|
||||||
viewManager.reloadConfiguration([
|
Config.teams = [
|
||||||
{
|
{
|
||||||
name: 'server1',
|
name: 'server1',
|
||||||
url: 'http://server1.com',
|
url: 'http://server1.com',
|
||||||
@@ -281,7 +291,8 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
viewManager.reloadConfiguration();
|
||||||
expect(makeSpy).toHaveBeenCalledWith(
|
expect(makeSpy).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
name: 'server1',
|
name: 'server1',
|
||||||
@@ -313,7 +324,7 @@ describe('main/views/viewManager', () => {
|
|||||||
};
|
};
|
||||||
viewManager.currentView = 'server1-tab1';
|
viewManager.currentView = 'server1-tab1';
|
||||||
viewManager.views.set('server1-tab1', view);
|
viewManager.views.set('server1-tab1', view);
|
||||||
viewManager.reloadConfiguration([
|
Config.teams = [
|
||||||
{
|
{
|
||||||
name: 'server1',
|
name: 'server1',
|
||||||
url: 'http://server1.com',
|
url: 'http://server1.com',
|
||||||
@@ -325,7 +336,8 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
viewManager.reloadConfiguration();
|
||||||
expect(viewManager.showByName).toHaveBeenCalledWith('server1-tab1');
|
expect(viewManager.showByName).toHaveBeenCalledWith('server1-tab1');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -342,7 +354,7 @@ describe('main/views/viewManager', () => {
|
|||||||
};
|
};
|
||||||
viewManager.currentView = 'server1-tab1';
|
viewManager.currentView = 'server1-tab1';
|
||||||
viewManager.views.set('server1-tab1', view);
|
viewManager.views.set('server1-tab1', view);
|
||||||
viewManager.reloadConfiguration([
|
Config.teams = [
|
||||||
{
|
{
|
||||||
name: 'server2',
|
name: 'server2',
|
||||||
url: 'http://server2.com',
|
url: 'http://server2.com',
|
||||||
@@ -354,7 +366,8 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
viewManager.reloadConfiguration();
|
||||||
expect(viewManager.showInitial).toBeCalled();
|
expect(viewManager.showInitial).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -368,7 +381,7 @@ describe('main/views/viewManager', () => {
|
|||||||
destroy: jest.fn(),
|
destroy: jest.fn(),
|
||||||
};
|
};
|
||||||
viewManager.views.set('server1-tab1', view);
|
viewManager.views.set('server1-tab1', view);
|
||||||
viewManager.reloadConfiguration([
|
Config.teams = [
|
||||||
{
|
{
|
||||||
name: 'server2',
|
name: 'server2',
|
||||||
url: 'http://server2.com',
|
url: 'http://server2.com',
|
||||||
@@ -380,65 +393,64 @@ describe('main/views/viewManager', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
viewManager.reloadConfiguration();
|
||||||
expect(view.destroy).toBeCalled();
|
expect(view.destroy).toBeCalled();
|
||||||
expect(viewManager.showInitial).toBeCalled();
|
expect(viewManager.showInitial).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('showInitial', () => {
|
describe('showInitial', () => {
|
||||||
const teams = [{
|
|
||||||
name: 'server-1',
|
|
||||||
order: 1,
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
name: 'tab-1',
|
|
||||||
order: 0,
|
|
||||||
isOpen: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-2',
|
|
||||||
order: 2,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-3',
|
|
||||||
order: 1,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
name: 'server-2',
|
|
||||||
order: 0,
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
name: 'tab-1',
|
|
||||||
order: 0,
|
|
||||||
isOpen: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-2',
|
|
||||||
order: 2,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-3',
|
|
||||||
order: 1,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}];
|
|
||||||
const viewManager = new ViewManager({});
|
const viewManager = new ViewManager({});
|
||||||
viewManager.getServers = () => teams.concat();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
Config.teams = [{
|
||||||
|
name: 'server-1',
|
||||||
|
order: 1,
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
name: 'tab-1',
|
||||||
|
order: 0,
|
||||||
|
isOpen: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-2',
|
||||||
|
order: 2,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-3',
|
||||||
|
order: 1,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
name: 'server-2',
|
||||||
|
order: 0,
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
name: 'tab-1',
|
||||||
|
order: 0,
|
||||||
|
isOpen: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-2',
|
||||||
|
order: 2,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-3',
|
||||||
|
order: 1,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}];
|
||||||
viewManager.showByName = jest.fn();
|
viewManager.showByName = jest.fn();
|
||||||
getTabViewName.mockImplementation((server, tab) => `${server}_${tab}`);
|
getTabViewName.mockImplementation((server, tab) => `${server}_${tab}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
viewManager.getServers = () => teams;
|
|
||||||
delete viewManager.lastActiveServer;
|
delete viewManager.lastActiveServer;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -454,7 +466,7 @@ describe('main/views/viewManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show last active tab of first server', () => {
|
it('should show last active tab of first server', () => {
|
||||||
viewManager.getServers = () => [{
|
Config.teams = [{
|
||||||
name: 'server-1',
|
name: 'server-1',
|
||||||
order: 1,
|
order: 1,
|
||||||
tabs: [
|
tabs: [
|
||||||
@@ -501,7 +513,7 @@ describe('main/views/viewManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show next tab when last active tab is closed', () => {
|
it('should show next tab when last active tab is closed', () => {
|
||||||
viewManager.getServers = () => [{
|
Config.teams = [{
|
||||||
name: 'server-1',
|
name: 'server-1',
|
||||||
order: 1,
|
order: 1,
|
||||||
tabs: [
|
tabs: [
|
||||||
@@ -553,7 +565,7 @@ describe('main/views/viewManager', () => {
|
|||||||
send: jest.fn(),
|
send: jest.fn(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
viewManager.getServers = () => [];
|
Config.teams = [];
|
||||||
viewManager.showInitial();
|
viewManager.showInitial();
|
||||||
expect(ipcMain.emit).toHaveBeenCalledWith(MAIN_WINDOW_SHOWN);
|
expect(ipcMain.emit).toHaveBeenCalledWith(MAIN_WINDOW_SHOWN);
|
||||||
});
|
});
|
||||||
@@ -654,8 +666,8 @@ describe('main/views/viewManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getViewByURL', () => {
|
describe('getViewByURL', () => {
|
||||||
const viewManager = new ViewManager({});
|
const viewManager = new ViewManager();
|
||||||
viewManager.getServers = () => [
|
const servers = [
|
||||||
{
|
{
|
||||||
name: 'server-1',
|
name: 'server-1',
|
||||||
url: 'http://server-1.com',
|
url: 'http://server-1.com',
|
||||||
@@ -696,6 +708,7 @@ describe('main/views/viewManager', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
Config.teams = servers.concat();
|
||||||
MattermostServer.mockImplementation((name, url) => ({
|
MattermostServer.mockImplementation((name, url) => ({
|
||||||
name,
|
name,
|
||||||
url: new URL(url),
|
url: new URL(url),
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
import {BrowserView, dialog, ipcMain, IpcMainEvent, IpcMainInvokeEvent} from 'electron';
|
||||||
import {BrowserView, dialog, ipcMain, IpcMainEvent} from 'electron';
|
|
||||||
import {BrowserViewConstructorOptions} from 'electron/main';
|
import {BrowserViewConstructorOptions} from 'electron/main';
|
||||||
|
|
||||||
import {Tuple as tuple} from '@bloomberg/record-tuple-polyfill';
|
import {Tuple as tuple} from '@bloomberg/record-tuple-polyfill';
|
||||||
@@ -20,6 +19,13 @@ import {
|
|||||||
UPDATE_LAST_ACTIVE,
|
UPDATE_LAST_ACTIVE,
|
||||||
UPDATE_URL_VIEW_WIDTH,
|
UPDATE_URL_VIEW_WIDTH,
|
||||||
MAIN_WINDOW_SHOWN,
|
MAIN_WINDOW_SHOWN,
|
||||||
|
RELOAD_CURRENT_VIEW,
|
||||||
|
REACT_APP_INITIALIZED,
|
||||||
|
APP_LOGGED_IN,
|
||||||
|
BROWSER_HISTORY_BUTTON,
|
||||||
|
APP_LOGGED_OUT,
|
||||||
|
UNREAD_RESULT,
|
||||||
|
GET_VIEW_NAME,
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import {Logger} from 'common/log';
|
import {Logger} from 'common/log';
|
||||||
@@ -35,6 +41,7 @@ import {localizeMessage} from 'main/i18nManager';
|
|||||||
import {ServerInfo} from 'main/server/serverInfo';
|
import {ServerInfo} from 'main/server/serverInfo';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
|
import * as appState from '../appState';
|
||||||
import {getLocalURLString, getLocalPreload} from '../utils';
|
import {getLocalURLString, getLocalPreload} from '../utils';
|
||||||
|
|
||||||
import {MattermostView} from './MattermostView';
|
import {MattermostView} from './MattermostView';
|
||||||
@@ -47,32 +54,200 @@ const URL_VIEW_DURATION = 10 * SECOND;
|
|||||||
const URL_VIEW_HEIGHT = 20;
|
const URL_VIEW_HEIGHT = 20;
|
||||||
|
|
||||||
export class ViewManager {
|
export class ViewManager {
|
||||||
lastActiveServer?: number;
|
private closedViews: Map<string, {srv: MattermostServer; tab: Tab}>;
|
||||||
viewOptions: BrowserViewConstructorOptions;
|
private views: Map<string, MattermostView>;
|
||||||
closedViews: Map<string, {srv: MattermostServer; tab: Tab}>;
|
private currentView?: string;
|
||||||
views: Map<string, MattermostView>;
|
|
||||||
currentView?: string;
|
private urlViewCancel?: () => void;
|
||||||
urlView?: BrowserView;
|
|
||||||
urlViewCancel?: () => void;
|
private lastActiveServer?: number;
|
||||||
|
private viewOptions: BrowserViewConstructorOptions;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.lastActiveServer = Config.lastActiveTeam;
|
this.lastActiveServer = Config.lastActiveTeam;
|
||||||
this.viewOptions = {webPreferences: {spellcheck: Config.useSpellChecker}};
|
this.viewOptions = {webPreferences: {spellcheck: Config.useSpellChecker}};
|
||||||
this.views = new Map(); // keep in mind that this doesn't need to hold server order, only tabs on the renderer need that.
|
this.views = new Map(); // keep in mind that this doesn't need to hold server order, only tabs on the renderer need that.
|
||||||
this.closedViews = new Map();
|
this.closedViews = new Map();
|
||||||
|
|
||||||
|
ipcMain.on(REACT_APP_INITIALIZED, this.handleReactAppInitialized);
|
||||||
|
ipcMain.on(BROWSER_HISTORY_PUSH, this.handleBrowserHistoryPush);
|
||||||
|
ipcMain.on(BROWSER_HISTORY_BUTTON, this.handleBrowserHistoryButton);
|
||||||
|
ipcMain.on(APP_LOGGED_IN, this.handleAppLoggedIn);
|
||||||
|
ipcMain.on(APP_LOGGED_OUT, this.handleAppLoggedOut);
|
||||||
|
ipcMain.on(RELOAD_CURRENT_VIEW, this.handleReloadCurrentView);
|
||||||
|
ipcMain.on(UNREAD_RESULT, this.handleFaviconIsUnread);
|
||||||
|
ipcMain.handle(GET_VIEW_NAME, this.handleGetViewName);
|
||||||
}
|
}
|
||||||
|
|
||||||
getServers = () => {
|
init = () => {
|
||||||
return Config.teams.concat();
|
this.getServers().forEach((server) => this.loadServer(server));
|
||||||
|
this.showInitial();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadServer = (server: TeamWithTabs) => {
|
getView = (viewName: string) => {
|
||||||
|
return this.views.get(viewName);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentView = () => {
|
||||||
|
if (this.currentView) {
|
||||||
|
return this.views.get(this.currentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
getViewByWebContentsId = (webContentsId: number) => {
|
||||||
|
return [...this.views.values()].find((view) => view.view.webContents.id === webContentsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
showByName = (name: string) => {
|
||||||
|
log.debug('viewManager.showByName', name);
|
||||||
|
|
||||||
|
const newView = this.views.get(name);
|
||||||
|
if (newView) {
|
||||||
|
if (newView.isVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.currentView && this.currentView !== name) {
|
||||||
|
const previous = this.getCurrentView();
|
||||||
|
if (previous) {
|
||||||
|
previous.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentView = name;
|
||||||
|
if (!newView.isErrored()) {
|
||||||
|
newView.show();
|
||||||
|
if (newView.needsLoadingScreen()) {
|
||||||
|
LoadingScreen.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.tab.server.name, newView.tab.type);
|
||||||
|
ipcMain.emit(SET_ACTIVE_VIEW, true, newView.tab.server.name, newView.tab.type);
|
||||||
|
if (newView.isReady()) {
|
||||||
|
ipcMain.emit(UPDATE_LAST_ACTIVE, true, newView.tab.server.name, newView.tab.type);
|
||||||
|
} else {
|
||||||
|
log.warn(`couldn't show ${name}, not ready`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn(`Couldn't find a view with name: ${name}`);
|
||||||
|
}
|
||||||
|
modalManager.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
focusCurrentView = () => {
|
||||||
|
if (modalManager.isModalDisplayed()) {
|
||||||
|
modalManager.focusCurrentModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const view = this.getCurrentView();
|
||||||
|
if (view) {
|
||||||
|
view.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reload = () => {
|
||||||
|
const currentView = this.getCurrentView();
|
||||||
|
if (currentView) {
|
||||||
|
LoadingScreen.show();
|
||||||
|
currentView.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToAllViews = (channel: string, ...args: unknown[]) => {
|
||||||
|
this.views.forEach((view) => {
|
||||||
|
if (!view.view.webContents.isDestroyed()) {
|
||||||
|
view.view.webContents.send(channel, ...args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToFind = () => {
|
||||||
|
this.getCurrentView()?.openFind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deep linking
|
||||||
|
*/
|
||||||
|
|
||||||
|
handleDeepLink = (url: string | URL) => {
|
||||||
|
// TODO: fix for new tabs
|
||||||
|
if (url) {
|
||||||
|
const parsedURL = urlUtils.parseURL(url)!;
|
||||||
|
const tabView = this.getViewByURL(parsedURL, true);
|
||||||
|
if (tabView) {
|
||||||
|
const urlWithSchema = `${urlUtils.parseURL(tabView.url)?.origin}${parsedURL.pathname}${parsedURL.search}`;
|
||||||
|
if (this.closedViews.has(tabView.name)) {
|
||||||
|
this.openClosedTab(tabView.name, urlWithSchema);
|
||||||
|
} else {
|
||||||
|
const view = this.views.get(tabView.name);
|
||||||
|
if (!view) {
|
||||||
|
log.error(`Couldn't find a view matching the name ${tabView.name}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.isInitialized() && view.serverInfo.remoteInfo.serverVersion && Utils.isVersionGreaterThanOrEqualTo(view.serverInfo.remoteInfo.serverVersion, '6.0.0')) {
|
||||||
|
const pathName = `/${urlWithSchema.replace(view.tab.server.url.toString(), '')}`;
|
||||||
|
view.view.webContents.send(BROWSER_HISTORY_PUSH, pathName);
|
||||||
|
this.deeplinkSuccess(view.name);
|
||||||
|
} else {
|
||||||
|
// attempting to change parsedURL protocol results in it not being modified.
|
||||||
|
view.resetLoadingStatus();
|
||||||
|
view.load(urlWithSchema);
|
||||||
|
view.once(LOAD_SUCCESS, this.deeplinkSuccess);
|
||||||
|
view.once(LOAD_FAILED, this.deeplinkFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dialog.showErrorBox(
|
||||||
|
localizeMessage('main.views.viewManager.handleDeepLink.error.title', 'No matching server'),
|
||||||
|
localizeMessage('main.views.viewManager.handleDeepLink.error.body', 'There is no configured server in the app that matches the requested url: {url}', {url: parsedURL.toString()}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private deeplinkSuccess = (viewName: string) => {
|
||||||
|
log.debug('deeplinkSuccess', viewName);
|
||||||
|
|
||||||
|
const view = this.views.get(viewName);
|
||||||
|
if (!view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.showByName(viewName);
|
||||||
|
view.removeListener(LOAD_FAILED, this.deeplinkFailed);
|
||||||
|
};
|
||||||
|
|
||||||
|
private deeplinkFailed = (viewName: string, err: string, url: string) => {
|
||||||
|
log.error(`[${viewName}] failed to load deeplink ${url}: ${err}`);
|
||||||
|
const view = this.views.get(viewName);
|
||||||
|
if (!view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
view.removeListener(LOAD_SUCCESS, this.deeplinkSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View loading helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
private loadServer = (server: TeamWithTabs) => {
|
||||||
const srv = new MattermostServer(server.name, server.url);
|
const srv = new MattermostServer(server.name, server.url);
|
||||||
const serverInfo = new ServerInfo(srv);
|
const serverInfo = new ServerInfo(srv);
|
||||||
server.tabs.forEach((tab) => this.loadView(srv, serverInfo, tab));
|
server.tabs.forEach((tab) => this.loadView(srv, serverInfo, tab));
|
||||||
}
|
}
|
||||||
|
|
||||||
makeView = (srv: MattermostServer, serverInfo: ServerInfo, tab: Tab, url?: string): MattermostView => {
|
private loadView = (srv: MattermostServer, serverInfo: ServerInfo, tab: Tab, url?: string) => {
|
||||||
|
if (!tab.isOpen) {
|
||||||
|
this.closedViews.set(getTabViewName(srv.name, tab.name), {srv, tab});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const view = this.makeView(srv, serverInfo, tab, url);
|
||||||
|
this.addView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private makeView = (srv: MattermostServer, serverInfo: ServerInfo, tab: Tab, url?: string): MattermostView => {
|
||||||
const tabView = this.getServerView(srv, tab.name);
|
const tabView = this.getServerView(srv, tab.name);
|
||||||
const view = new MattermostView(tabView, serverInfo, this.viewOptions);
|
const view = new MattermostView(tabView, serverInfo, this.viewOptions);
|
||||||
view.once(LOAD_SUCCESS, this.activateView);
|
view.once(LOAD_SUCCESS, this.activateView);
|
||||||
@@ -83,38 +258,153 @@ export class ViewManager {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
addView = (view: MattermostView): void => {
|
private addView = (view: MattermostView): void => {
|
||||||
this.views.set(view.name, view);
|
this.views.set(view.name, view);
|
||||||
if (this.closedViews.has(view.name)) {
|
if (this.closedViews.has(view.name)) {
|
||||||
this.closedViews.delete(view.name);
|
this.closedViews.delete(view.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadView = (srv: MattermostServer, serverInfo: ServerInfo, tab: Tab, url?: string) => {
|
private showInitial = () => {
|
||||||
if (!tab.isOpen) {
|
log.verbose('showInitial');
|
||||||
this.closedViews.set(getTabViewName(srv.name, tab.name), {srv, tab});
|
|
||||||
|
const servers = this.getServers();
|
||||||
|
if (servers.length) {
|
||||||
|
const element = servers.find((e) => e.order === this.lastActiveServer) || servers.find((e) => e.order === 0);
|
||||||
|
if (element && element.tabs.length) {
|
||||||
|
let tab = element.tabs.find((tab) => tab.order === element.lastActiveTab) || element.tabs.find((tab) => tab.order === 0);
|
||||||
|
if (!tab?.isOpen) {
|
||||||
|
const openTabs = element.tabs.filter((tab) => tab.isOpen);
|
||||||
|
tab = openTabs.find((e) => e.order === 0) || openTabs.concat().sort((a, b) => a.order - b.order)[0];
|
||||||
|
}
|
||||||
|
if (tab) {
|
||||||
|
const tabView = getTabViewName(element.name, tab.name);
|
||||||
|
this.showByName(tabView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, null, null);
|
||||||
|
ipcMain.emit(MAIN_WINDOW_SHOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mattermost view event handlers
|
||||||
|
*/
|
||||||
|
|
||||||
|
private activateView = (viewName: string) => {
|
||||||
|
log.debug('activateView', viewName);
|
||||||
|
|
||||||
|
if (this.currentView === viewName) {
|
||||||
|
this.showByName(this.currentView);
|
||||||
|
}
|
||||||
|
const view = this.views.get(viewName);
|
||||||
|
if (!view) {
|
||||||
|
log.error(`Couldn't find a view with the name ${viewName}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const view = this.makeView(srv, serverInfo, tab, url);
|
WebContentsEventManager.addMattermostViewEventListeners(view);
|
||||||
this.addView(view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadViewIfNeeded = (viewName: string) => {
|
private finishLoading = (server: string) => {
|
||||||
const view = this.views.get(viewName);
|
log.debug('finishLoading', server);
|
||||||
if (view && view.view.webContents.getURL() !== view.tab.url.toString() && !view.view.webContents.getURL().startsWith(view.tab.url.toString())) {
|
|
||||||
view.load(view.tab.url);
|
const view = this.views.get(server);
|
||||||
|
if (view && this.getCurrentView() === view) {
|
||||||
|
this.showByName(this.currentView!);
|
||||||
|
LoadingScreen.fade();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
load = () => {
|
private failLoading = (tabName: string) => {
|
||||||
this.getServers().forEach((server) => this.loadServer(server));
|
log.debug('failLoading', tabName);
|
||||||
|
|
||||||
|
LoadingScreen.fade();
|
||||||
|
if (this.currentView === tabName) {
|
||||||
|
this.getCurrentView()?.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private showURLView = (url: URL | string) => {
|
||||||
|
log.silly('showURLView', url);
|
||||||
|
|
||||||
|
const mainWindow = MainWindow.get();
|
||||||
|
if (!mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.urlViewCancel) {
|
||||||
|
this.urlViewCancel();
|
||||||
|
}
|
||||||
|
if (url && url !== '') {
|
||||||
|
const urlString = typeof url === 'string' ? url : url.toString();
|
||||||
|
const preload = getLocalPreload('desktopAPI.js');
|
||||||
|
const urlView = new BrowserView({
|
||||||
|
webPreferences: {
|
||||||
|
preload,
|
||||||
|
|
||||||
|
// Workaround for this issue: https://github.com/electron/electron/issues/30993
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
transparent: true,
|
||||||
|
}});
|
||||||
|
const query = new Map([['url', urlString]]);
|
||||||
|
const localURL = getLocalURLString('urlView.html', query);
|
||||||
|
urlView.webContents.loadURL(localURL);
|
||||||
|
mainWindow.addBrowserView(urlView);
|
||||||
|
const boundaries = this.views.get(this.currentView || '')?.view.getBounds() ?? mainWindow.getBounds();
|
||||||
|
|
||||||
|
const hideView = () => {
|
||||||
|
delete this.urlViewCancel;
|
||||||
|
try {
|
||||||
|
mainWindow.removeBrowserView(urlView);
|
||||||
|
} catch (e) {
|
||||||
|
log.error('Failed to remove URL view', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround to eliminate zombie processes
|
||||||
|
// https://github.com/mattermost/desktop/pull/1519
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
urlView.webContents.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
const adjustWidth = (event: IpcMainEvent, width: number) => {
|
||||||
|
log.silly('showURLView.adjustWidth', width);
|
||||||
|
|
||||||
|
const bounds = {
|
||||||
|
x: 0,
|
||||||
|
y: (boundaries.height + TAB_BAR_HEIGHT) - URL_VIEW_HEIGHT,
|
||||||
|
width: width + 5, // add some padding to ensure that we don't cut off the border
|
||||||
|
height: URL_VIEW_HEIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
|
log.silly('showURLView setBounds', boundaries, bounds);
|
||||||
|
urlView.setBounds(bounds);
|
||||||
|
};
|
||||||
|
|
||||||
|
ipcMain.on(UPDATE_URL_VIEW_WIDTH, adjustWidth);
|
||||||
|
|
||||||
|
const timeout = setTimeout(hideView,
|
||||||
|
URL_VIEW_DURATION);
|
||||||
|
|
||||||
|
this.urlViewCancel = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
ipcMain.removeListener(UPDATE_URL_VIEW_WIDTH, adjustWidth);
|
||||||
|
hideView();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event Handlers
|
||||||
|
*/
|
||||||
|
|
||||||
/** Called when a new configuration is received
|
/** Called when a new configuration is received
|
||||||
* Servers or tabs have been added or edited. We need to
|
* Servers or tabs have been added or edited. We need to
|
||||||
* close, open, or reload tabs, taking care to reuse tabs and
|
* close, open, or reload tabs, taking care to reuse tabs and
|
||||||
* preserve focus on the currently selected tab. */
|
* preserve focus on the currently selected tab. */
|
||||||
reloadConfiguration = (configServers: TeamWithTabs[]) => {
|
reloadConfiguration = () => {
|
||||||
log.debug('reloadConfiguration');
|
log.debug('reloadConfiguration');
|
||||||
|
|
||||||
const focusedTuple: TabTuple | undefined = this.views.get(this.currentView as string)?.urlTypeTuple;
|
const focusedTuple: TabTuple | undefined = this.views.get(this.currentView as string)?.urlTypeTuple;
|
||||||
@@ -127,7 +417,7 @@ export class ViewManager {
|
|||||||
const views: Map<TabTuple, MattermostView> = new Map();
|
const views: Map<TabTuple, MattermostView> = new Map();
|
||||||
const closed: Map<TabTuple, {srv: MattermostServer; tab: Tab; name: string}> = new Map();
|
const closed: Map<TabTuple, {srv: MattermostServer; tab: Tab; name: string}> = new Map();
|
||||||
|
|
||||||
const sortedTabs = configServers.flatMap((x) => [...x.tabs].
|
const sortedTabs = this.getServers().flatMap((x) => [...x.tabs].
|
||||||
sort((a, b) => a.order - b.order).
|
sort((a, b) => a.order - b.order).
|
||||||
map((t): [TeamWithTabs, Tab] => [x, t]));
|
map((t): [TeamWithTabs, Tab] => [x, t]));
|
||||||
|
|
||||||
@@ -167,7 +457,7 @@ export class ViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((focusedTuple && closed.has(focusedTuple)) || (this.currentView && this.closedViews.has(this.currentView))) {
|
if ((focusedTuple && closed.has(focusedTuple)) || (this.currentView && this.closedViews.has(this.currentView))) {
|
||||||
if (configServers.length) {
|
if (this.getServers().length) {
|
||||||
this.currentView = undefined;
|
this.currentView = undefined;
|
||||||
this.showInitial();
|
this.showInitial();
|
||||||
} else {
|
} else {
|
||||||
@@ -188,101 +478,97 @@ export class ViewManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showInitial = () => {
|
private handleAppLoggedIn = (event: IpcMainEvent, viewName: string) => {
|
||||||
log.verbose('showInitial');
|
log.debug('handleAppLoggedIn', viewName);
|
||||||
|
|
||||||
const servers = this.getServers();
|
const view = this.views.get(viewName);
|
||||||
if (servers.length) {
|
if (view && !view.isLoggedIn) {
|
||||||
const element = servers.find((e) => e.order === this.lastActiveServer) || servers.find((e) => e.order === 0);
|
view.isLoggedIn = true;
|
||||||
if (element && element.tabs.length) {
|
if (view.view.webContents.getURL() !== view.tab.url.toString() && !view.view.webContents.getURL().startsWith(view.tab.url.toString())) {
|
||||||
let tab = element.tabs.find((tab) => tab.order === element.lastActiveTab) || element.tabs.find((tab) => tab.order === 0);
|
view.load(view.tab.url);
|
||||||
if (!tab?.isOpen) {
|
|
||||||
const openTabs = element.tabs.filter((tab) => tab.isOpen);
|
|
||||||
tab = openTabs.find((e) => e.order === 0) || openTabs.concat().sort((a, b) => a.order - b.order)[0];
|
|
||||||
}
|
|
||||||
if (tab) {
|
|
||||||
const tabView = getTabViewName(element.name, tab.name);
|
|
||||||
this.showByName(tabView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, null, null);
|
|
||||||
ipcMain.emit(MAIN_WINDOW_SHOWN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showByName = (name: string) => {
|
private handleAppLoggedOut = (event: IpcMainEvent, viewName: string) => {
|
||||||
log.debug('showByName', name);
|
log.debug('handleAppLoggedOut', viewName);
|
||||||
|
|
||||||
const newView = this.views.get(name);
|
const view = this.views.get(viewName);
|
||||||
if (newView) {
|
if (view && view.isLoggedIn) {
|
||||||
if (newView.isVisible) {
|
view.isLoggedIn = false;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.currentView && this.currentView !== name) {
|
|
||||||
const previous = this.getCurrentView();
|
|
||||||
if (previous) {
|
|
||||||
previous.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentView = name;
|
|
||||||
if (!newView.isErrored()) {
|
|
||||||
newView.show();
|
|
||||||
if (newView.needsLoadingScreen()) {
|
|
||||||
LoadingScreen.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.tab.server.name, newView.tab.type);
|
|
||||||
ipcMain.emit(SET_ACTIVE_VIEW, true, newView.tab.server.name, newView.tab.type);
|
|
||||||
if (newView.isReady()) {
|
|
||||||
ipcMain.emit(UPDATE_LAST_ACTIVE, true, newView.tab.server.name, newView.tab.type);
|
|
||||||
} else {
|
|
||||||
log.warn(`couldn't show ${name}, not ready`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.warn(`Couldn't find a view with name: ${name}`);
|
|
||||||
}
|
}
|
||||||
modalManager.showModal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
focus = () => {
|
private handleBrowserHistoryPush = (e: IpcMainEvent, viewName: string, pathName: string) => {
|
||||||
if (modalManager.isModalDisplayed()) {
|
log.debug('handleBrowserHistoryPush', {viewName, pathName});
|
||||||
modalManager.focusCurrentModal();
|
|
||||||
|
const currentView = this.views.get(viewName);
|
||||||
|
const cleanedPathName = urlUtils.cleanPathName(currentView?.tab.server.url.pathname || '', pathName);
|
||||||
|
const redirectedViewName = this.getViewByURL(`${currentView?.tab.server.url.toString().replace(/\/$/, '')}${cleanedPathName}`)?.name || viewName;
|
||||||
|
if (this.closedViews.has(redirectedViewName)) {
|
||||||
|
// If it's a closed view, just open it and stop
|
||||||
|
this.openClosedTab(redirectedViewName, `${currentView?.tab.server.url}${cleanedPathName}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let redirectedView = this.views.get(redirectedViewName) || currentView;
|
||||||
|
if (redirectedView !== currentView && redirectedView?.tab.name === this.currentView && redirectedView?.isLoggedIn) {
|
||||||
|
log.info('redirecting to a new view', redirectedView?.name || viewName);
|
||||||
|
this.showByName(redirectedView?.name || viewName);
|
||||||
|
} else {
|
||||||
|
redirectedView = currentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case check for Channels to not force a redirect to "/", causing a refresh
|
||||||
|
if (!(redirectedView !== currentView && redirectedView?.tab.type === TAB_MESSAGING && cleanedPathName === '/')) {
|
||||||
|
redirectedView?.view.webContents.send(BROWSER_HISTORY_PUSH, cleanedPathName);
|
||||||
|
if (redirectedView) {
|
||||||
|
this.handleBrowserHistoryButton(e, redirectedView.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleBrowserHistoryButton = (e: IpcMainEvent, viewName: string) => {
|
||||||
|
log.debug('handleBrowserHistoryButton', viewName);
|
||||||
|
|
||||||
|
this.getView(viewName)?.updateHistoryButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleReactAppInitialized = (e: IpcMainEvent, viewName: string) => {
|
||||||
|
log.debug('handleReactAppInitialized', viewName);
|
||||||
|
|
||||||
|
const view = this.views.get(viewName);
|
||||||
|
if (view) {
|
||||||
|
view.setInitialized();
|
||||||
|
if (this.getCurrentView() === view) {
|
||||||
|
LoadingScreen.fade();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleReloadCurrentView = () => {
|
||||||
|
log.debug('handleReloadCurrentView');
|
||||||
|
|
||||||
const view = this.getCurrentView();
|
const view = this.getCurrentView();
|
||||||
if (view) {
|
|
||||||
view.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
activateView = (viewName: string) => {
|
|
||||||
log.debug('activateView', viewName);
|
|
||||||
|
|
||||||
if (this.currentView === viewName) {
|
|
||||||
this.showByName(this.currentView);
|
|
||||||
}
|
|
||||||
const view = this.views.get(viewName);
|
|
||||||
if (!view) {
|
if (!view) {
|
||||||
log.error(`Couldn't find a view with the name ${viewName}`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WebContentsEventManager.addMattermostViewEventListeners(view);
|
view?.reload();
|
||||||
|
this.showByName(view?.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
finishLoading = (server: string) => {
|
// if favicon is null, it means it is the initial load,
|
||||||
log.debug('finishLoading', server);
|
// so don't memoize as we don't have the favicons and there is no rush to find out.
|
||||||
|
private handleFaviconIsUnread = (e: Event, favicon: string, viewName: string, result: boolean) => {
|
||||||
|
log.silly('handleFaviconIsUnread', {favicon, viewName, result});
|
||||||
|
|
||||||
const view = this.views.get(server);
|
appState.updateUnreads(viewName, result);
|
||||||
if (view && this.getCurrentView() === view) {
|
|
||||||
this.showByName(this.currentView!);
|
|
||||||
LoadingScreen.fade();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openClosedTab = (name: string, url?: string) => {
|
/**
|
||||||
|
* Helper functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
private openClosedTab = (name: string, url?: string) => {
|
||||||
if (!this.closedViews.has(name)) {
|
if (!this.closedViews.has(name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -299,142 +585,6 @@ export class ViewManager {
|
|||||||
ipcMain.emit(OPEN_TAB, null, srv.name, tab.name);
|
ipcMain.emit(OPEN_TAB, null, srv.name, tab.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
failLoading = (tabName: string) => {
|
|
||||||
log.debug('failLoading', tabName);
|
|
||||||
|
|
||||||
LoadingScreen.fade();
|
|
||||||
if (this.currentView === tabName) {
|
|
||||||
this.getCurrentView()?.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentView() {
|
|
||||||
if (this.currentView) {
|
|
||||||
return this.views.get(this.currentView);
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
openViewDevTools = () => {
|
|
||||||
const view = this.getCurrentView();
|
|
||||||
if (view) {
|
|
||||||
view.openDevTools();
|
|
||||||
} else {
|
|
||||||
log.error(`couldn't find ${this.currentView}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findViewByWebContent(webContentId: number) {
|
|
||||||
let found = null;
|
|
||||||
let view;
|
|
||||||
const entries = this.views.values();
|
|
||||||
|
|
||||||
for (view of entries) {
|
|
||||||
const wc = view.getWebContents();
|
|
||||||
if (wc && wc.id === webContentId) {
|
|
||||||
found = view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
showURLView = (url: URL | string) => {
|
|
||||||
log.silly('showURLView', url);
|
|
||||||
|
|
||||||
if (this.urlViewCancel) {
|
|
||||||
this.urlViewCancel();
|
|
||||||
}
|
|
||||||
if (url && url !== '') {
|
|
||||||
const urlString = typeof url === 'string' ? url : url.toString();
|
|
||||||
const preload = getLocalPreload('desktopAPI.js');
|
|
||||||
const urlView = new BrowserView({
|
|
||||||
webPreferences: {
|
|
||||||
preload,
|
|
||||||
|
|
||||||
// Workaround for this issue: https://github.com/electron/electron/issues/30993
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
transparent: true,
|
|
||||||
}});
|
|
||||||
const query = new Map([['url', urlString]]);
|
|
||||||
const localURL = getLocalURLString('urlView.html', query);
|
|
||||||
urlView.webContents.loadURL(localURL);
|
|
||||||
MainWindow.get()?.addBrowserView(urlView);
|
|
||||||
const boundaries = this.views.get(this.currentView || '')?.view.getBounds() ?? MainWindow.get()!.getBounds();
|
|
||||||
|
|
||||||
const hideView = () => {
|
|
||||||
delete this.urlViewCancel;
|
|
||||||
try {
|
|
||||||
MainWindow.get()?.removeBrowserView(urlView);
|
|
||||||
} catch (e) {
|
|
||||||
log.error('Failed to remove URL view', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// workaround to eliminate zombie processes
|
|
||||||
// https://github.com/mattermost/desktop/pull/1519
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
urlView.webContents.destroy();
|
|
||||||
};
|
|
||||||
|
|
||||||
const adjustWidth = (event: IpcMainEvent, width: number) => {
|
|
||||||
log.silly('showURLView.adjustWidth', width);
|
|
||||||
|
|
||||||
const bounds = {
|
|
||||||
x: 0,
|
|
||||||
y: (boundaries.height + TAB_BAR_HEIGHT) - URL_VIEW_HEIGHT,
|
|
||||||
width: width + 5, // add some padding to ensure that we don't cut off the border
|
|
||||||
height: URL_VIEW_HEIGHT,
|
|
||||||
};
|
|
||||||
|
|
||||||
log.silly('showURLView setBounds', boundaries, bounds);
|
|
||||||
urlView.setBounds(bounds);
|
|
||||||
};
|
|
||||||
|
|
||||||
ipcMain.on(UPDATE_URL_VIEW_WIDTH, adjustWidth);
|
|
||||||
|
|
||||||
const timeout = setTimeout(hideView,
|
|
||||||
URL_VIEW_DURATION);
|
|
||||||
|
|
||||||
this.urlViewCancel = () => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
ipcMain.removeListener(UPDATE_URL_VIEW_WIDTH, adjustWidth);
|
|
||||||
hideView();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setServerInitialized = (server: string) => {
|
|
||||||
const view = this.views.get(server);
|
|
||||||
if (view) {
|
|
||||||
view.setInitialized();
|
|
||||||
if (this.getCurrentView() === view) {
|
|
||||||
LoadingScreen.fade();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deeplinkSuccess = (viewName: string) => {
|
|
||||||
log.debug('deeplinkSuccess', viewName);
|
|
||||||
|
|
||||||
const view = this.views.get(viewName);
|
|
||||||
if (!view) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showByName(viewName);
|
|
||||||
view.removeListener(LOAD_FAILED, this.deeplinkFailed);
|
|
||||||
};
|
|
||||||
|
|
||||||
deeplinkFailed = (viewName: string, err: string, url: string) => {
|
|
||||||
log.error(`[${viewName}] failed to load deeplink ${url}: ${err}`);
|
|
||||||
const view = this.views.get(viewName);
|
|
||||||
if (!view) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
view.removeListener(LOAD_SUCCESS, this.deeplinkSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
getViewByURL = (inputURL: URL | string, ignoreScheme = false) => {
|
getViewByURL = (inputURL: URL | string, ignoreScheme = false) => {
|
||||||
log.silly('getViewByURL', `${inputURL}`, ignoreScheme);
|
log.silly('getViewByURL', `${inputURL}`, ignoreScheme);
|
||||||
|
|
||||||
@@ -449,6 +599,7 @@ export class ViewManager {
|
|||||||
if (!server) {
|
if (!server) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mmServer = new MattermostServer(server.name, server.url);
|
const mmServer = new MattermostServer(server.name, server.url);
|
||||||
let selectedTab = this.getServerView(mmServer, TAB_MESSAGING);
|
let selectedTab = this.getServerView(mmServer, TAB_MESSAGING);
|
||||||
server.tabs.
|
server.tabs.
|
||||||
@@ -462,51 +613,6 @@ export class ViewManager {
|
|||||||
return selectedTab;
|
return selectedTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeepLink = (url: string | URL) => {
|
|
||||||
// TODO: fix for new tabs
|
|
||||||
if (url) {
|
|
||||||
const parsedURL = urlUtils.parseURL(url)!;
|
|
||||||
const tabView = this.getViewByURL(parsedURL, true);
|
|
||||||
if (tabView) {
|
|
||||||
const urlWithSchema = `${urlUtils.parseURL(tabView.url)?.origin}${parsedURL.pathname}${parsedURL.search}`;
|
|
||||||
if (this.closedViews.has(tabView.name)) {
|
|
||||||
this.openClosedTab(tabView.name, urlWithSchema);
|
|
||||||
} else {
|
|
||||||
const view = this.views.get(tabView.name);
|
|
||||||
if (!view) {
|
|
||||||
log.error(`Couldn't find a view matching the name ${tabView.name}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view.isInitialized() && view.serverInfo.remoteInfo.serverVersion && Utils.isVersionGreaterThanOrEqualTo(view.serverInfo.remoteInfo.serverVersion, '6.0.0')) {
|
|
||||||
const pathName = `/${urlWithSchema.replace(view.tab.server.url.toString(), '')}`;
|
|
||||||
view.view.webContents.send(BROWSER_HISTORY_PUSH, pathName);
|
|
||||||
this.deeplinkSuccess(view.name);
|
|
||||||
} else {
|
|
||||||
// attempting to change parsedURL protocol results in it not being modified.
|
|
||||||
view.resetLoadingStatus();
|
|
||||||
view.load(urlWithSchema);
|
|
||||||
view.once(LOAD_SUCCESS, this.deeplinkSuccess);
|
|
||||||
view.once(LOAD_FAILED, this.deeplinkFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dialog.showErrorBox(
|
|
||||||
localizeMessage('main.views.viewManager.handleDeepLink.error.title', 'No matching server'),
|
|
||||||
localizeMessage('main.views.viewManager.handleDeepLink.error.body', 'There is no configured server in the app that matches the requested url: {url}', {url: parsedURL.toString()}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sendToAllViews = (channel: string, ...args: unknown[]) => {
|
|
||||||
this.views.forEach((view) => {
|
|
||||||
if (!view.view.webContents.isDestroyed()) {
|
|
||||||
view.view.webContents.send(channel, ...args);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private getServerView = (srv: MattermostServer, tabName: string) => {
|
private getServerView = (srv: MattermostServer, tabName: string) => {
|
||||||
switch (tabName) {
|
switch (tabName) {
|
||||||
case TAB_MESSAGING:
|
case TAB_MESSAGING:
|
||||||
@@ -519,4 +625,25 @@ export class ViewManager {
|
|||||||
throw new Error('Not implemeneted');
|
throw new Error('Not implemeneted');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getServers = () => {
|
||||||
|
return Config.teams.concat();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGetViewName = (event: IpcMainInvokeEvent) => {
|
||||||
|
return this.getViewByWebContentsId(event.sender.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
setServerInitialized = (server: string) => {
|
||||||
|
const view = this.views.get(server);
|
||||||
|
if (view) {
|
||||||
|
view.setInitialized();
|
||||||
|
if (this.getCurrentView() === view) {
|
||||||
|
LoadingScreen.fade();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const viewManager = new ViewManager();
|
||||||
|
export default viewManager;
|
||||||
|
@@ -25,6 +25,10 @@ jest.mock('electron', () => ({
|
|||||||
jest.mock('main/contextMenu', () => jest.fn());
|
jest.mock('main/contextMenu', () => jest.fn());
|
||||||
|
|
||||||
jest.mock('../allowProtocolDialog', () => ({}));
|
jest.mock('../allowProtocolDialog', () => ({}));
|
||||||
|
jest.mock('main/views/viewManager', () => ({
|
||||||
|
getViewByWebContentsId: jest.fn(),
|
||||||
|
getViewByURL: jest.fn(),
|
||||||
|
}));
|
||||||
jest.mock('../windows/windowManager', () => ({
|
jest.mock('../windows/windowManager', () => ({
|
||||||
getServerURLFromWebContentsId: jest.fn(),
|
getServerURLFromWebContentsId: jest.fn(),
|
||||||
showMainWindow: jest.fn(),
|
showMainWindow: jest.fn(),
|
||||||
|
@@ -18,6 +18,7 @@ import allowProtocolDialog from '../allowProtocolDialog';
|
|||||||
import {composeUserAgent} from '../utils';
|
import {composeUserAgent} from '../utils';
|
||||||
|
|
||||||
import {MattermostView} from './MattermostView';
|
import {MattermostView} from './MattermostView';
|
||||||
|
import ViewManager from './viewManager';
|
||||||
|
|
||||||
type CustomLogin = {
|
type CustomLogin = {
|
||||||
inProgress: boolean;
|
inProgress: boolean;
|
||||||
@@ -249,7 +250,7 @@ export class WebContentsEventManager {
|
|||||||
return {action: 'deny'};
|
return {action: 'deny'};
|
||||||
}
|
}
|
||||||
|
|
||||||
const otherServerURL = WindowManager.viewManager?.getViewByURL(parsedURL);
|
const otherServerURL = ViewManager.getViewByURL(parsedURL);
|
||||||
if (otherServerURL && urlUtils.isTeamUrl(otherServerURL.server.url, parsedURL, true)) {
|
if (otherServerURL && urlUtils.isTeamUrl(otherServerURL.server.url, parsedURL, true)) {
|
||||||
WindowManager.showMainWindow(parsedURL);
|
WindowManager.showMainWindow(parsedURL);
|
||||||
return {action: 'deny'};
|
return {action: 'deny'};
|
||||||
|
@@ -7,8 +7,7 @@
|
|||||||
import {systemPreferences, desktopCapturer} from 'electron';
|
import {systemPreferences, desktopCapturer} from 'electron';
|
||||||
|
|
||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import {getTabViewName, TAB_MESSAGING} from 'common/tabs/TabView';
|
import {getTabViewName} from 'common/tabs/TabView';
|
||||||
import urlUtils from 'common/utils/url';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getAdjustedWindowBoundaries,
|
getAdjustedWindowBoundaries,
|
||||||
@@ -17,6 +16,8 @@ import {
|
|||||||
} from 'main/utils';
|
} from 'main/utils';
|
||||||
import LoadingScreen from '../views/loadingScreen';
|
import LoadingScreen from '../views/loadingScreen';
|
||||||
|
|
||||||
|
import ViewManager from 'main/views/viewManager';
|
||||||
|
|
||||||
import {WindowManager} from './windowManager';
|
import {WindowManager} from './windowManager';
|
||||||
import MainWindow from './mainWindow';
|
import MainWindow from './mainWindow';
|
||||||
import SettingsWindow from './settingsWindow';
|
import SettingsWindow from './settingsWindow';
|
||||||
@@ -52,11 +53,6 @@ jest.mock('electron', () => ({
|
|||||||
|
|
||||||
jest.mock('common/config', () => ({}));
|
jest.mock('common/config', () => ({}));
|
||||||
|
|
||||||
jest.mock('common/utils/url', () => ({
|
|
||||||
isTeamUrl: jest.fn(),
|
|
||||||
isAdminUrl: jest.fn(),
|
|
||||||
cleanPathName: jest.fn(),
|
|
||||||
}));
|
|
||||||
jest.mock('common/tabs/TabView', () => ({
|
jest.mock('common/tabs/TabView', () => ({
|
||||||
getTabViewName: jest.fn(),
|
getTabViewName: jest.fn(),
|
||||||
TAB_MESSAGING: 'tab-messaging',
|
TAB_MESSAGING: 'tab-messaging',
|
||||||
@@ -68,7 +64,16 @@ jest.mock('../utils', () => ({
|
|||||||
resetScreensharePermissionsMacOS: jest.fn(),
|
resetScreensharePermissionsMacOS: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('../views/viewManager', () => ({
|
jest.mock('../views/viewManager', () => ({
|
||||||
ViewManager: jest.fn(),
|
isLoadingScreenHidden: jest.fn(),
|
||||||
|
getView: jest.fn(),
|
||||||
|
getViewByWebContentsId: jest.fn(),
|
||||||
|
getCurrentView: jest.fn(),
|
||||||
|
isViewClosed: jest.fn(),
|
||||||
|
openClosedTab: jest.fn(),
|
||||||
|
handleDeepLink: jest.fn(),
|
||||||
|
setLoadingScreenBounds: jest.fn(),
|
||||||
|
showByName: jest.fn(),
|
||||||
|
updateMainWindow: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('../CriticalErrorHandler', () => jest.fn());
|
jest.mock('../CriticalErrorHandler', () => jest.fn());
|
||||||
jest.mock('../views/loadingScreen', () => ({
|
jest.mock('../views/loadingScreen', () => ({
|
||||||
@@ -94,27 +99,8 @@ jest.mock('./callsWidgetWindow');
|
|||||||
jest.mock('main/views/webContentEvents', () => ({}));
|
jest.mock('main/views/webContentEvents', () => ({}));
|
||||||
|
|
||||||
describe('main/windows/windowManager', () => {
|
describe('main/windows/windowManager', () => {
|
||||||
describe('handleUpdateConfig', () => {
|
|
||||||
const windowManager = new WindowManager();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
windowManager.viewManager = {
|
|
||||||
reloadConfiguration: jest.fn(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reload config', () => {
|
|
||||||
windowManager.handleUpdateConfig();
|
|
||||||
expect(windowManager.viewManager.reloadConfiguration).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('showMainWindow', () => {
|
describe('showMainWindow', () => {
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.viewManager = {
|
|
||||||
handleDeepLink: jest.fn(),
|
|
||||||
updateMainWindow: jest.fn(),
|
|
||||||
};
|
|
||||||
windowManager.initializeViewManager = jest.fn();
|
windowManager.initializeViewManager = jest.fn();
|
||||||
|
|
||||||
const mainWindow = {
|
const mainWindow = {
|
||||||
@@ -150,7 +136,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
|
|
||||||
it('should open deep link when provided', () => {
|
it('should open deep link when provided', () => {
|
||||||
windowManager.showMainWindow('mattermost://server-1.com/subpath');
|
windowManager.showMainWindow('mattermost://server-1.com/subpath');
|
||||||
expect(windowManager.viewManager.handleDeepLink).toHaveBeenCalledWith('mattermost://server-1.com/subpath');
|
expect(ViewManager.handleDeepLink).toHaveBeenCalledWith('mattermost://server-1.com/subpath');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -167,10 +153,6 @@ describe('main/windows/windowManager', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
windowManager.viewManager = {
|
|
||||||
getCurrentView: () => view,
|
|
||||||
setLoadingScreenBounds: jest.fn(),
|
|
||||||
};
|
|
||||||
const mainWindow = {
|
const mainWindow = {
|
||||||
getContentBounds: () => ({width: 800, height: 600}),
|
getContentBounds: () => ({width: 800, height: 600}),
|
||||||
getSize: () => [1000, 900],
|
getSize: () => [1000, 900],
|
||||||
@@ -182,6 +164,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
MainWindow.get.mockReturnValue(mainWindow);
|
MainWindow.get.mockReturnValue(mainWindow);
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
|
ViewManager.getCurrentView.mockReturnValue(view);
|
||||||
getAdjustedWindowBoundaries.mockImplementation((width, height) => ({width, height}));
|
getAdjustedWindowBoundaries.mockImplementation((width, height) => ({width, height}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -230,11 +213,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
windowManager.viewManager = {
|
|
||||||
getCurrentView: () => view,
|
|
||||||
setLoadingScreenBounds: jest.fn(),
|
|
||||||
loadingScreenState: 3,
|
|
||||||
};
|
|
||||||
windowManager.teamDropdown = {
|
windowManager.teamDropdown = {
|
||||||
updateWindowBounds: jest.fn(),
|
updateWindowBounds: jest.fn(),
|
||||||
};
|
};
|
||||||
@@ -244,13 +223,15 @@ describe('main/windows/windowManager', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
ViewManager.getCurrentView.mockReturnValue(view);
|
||||||
|
ViewManager.isLoadingScreenHidden.mockReturnValue(true);
|
||||||
MainWindow.get.mockReturnValue(mainWindow);
|
MainWindow.get.mockReturnValue(mainWindow);
|
||||||
getAdjustedWindowBoundaries.mockImplementation((width, height) => ({width, height}));
|
getAdjustedWindowBoundaries.mockImplementation((width, height) => ({width, height}));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
windowManager.isResizing = false;
|
windowManager.isResizing = false;
|
||||||
jest.resetAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update loading screen and team dropdown bounds', () => {
|
it('should update loading screen and team dropdown bounds', () => {
|
||||||
@@ -265,6 +246,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
LoadingScreen.isHidden.mockReturnValue(true);
|
LoadingScreen.isHidden.mockReturnValue(true);
|
||||||
const event = {preventDefault: jest.fn()};
|
const event = {preventDefault: jest.fn()};
|
||||||
windowManager.handleWillResizeMainWindow(event, {width: 800, height: 600});
|
windowManager.handleWillResizeMainWindow(event, {width: 800, height: 600});
|
||||||
|
expect(event.preventDefault).toHaveBeenCalled();
|
||||||
expect(view.setBounds).not.toHaveBeenCalled();
|
expect(view.setBounds).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -295,6 +277,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
ViewManager.getCurrentView.mockReturnValue(view);
|
||||||
MainWindow.get.mockReturnValue(mainWindow);
|
MainWindow.get.mockReturnValue(mainWindow);
|
||||||
getAdjustedWindowBoundaries.mockImplementation((width, height) => ({width, height}));
|
getAdjustedWindowBoundaries.mockImplementation((width, height) => ({width, height}));
|
||||||
});
|
});
|
||||||
@@ -304,17 +287,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not handle bounds if no window available', () => {
|
|
||||||
windowManager.handleResizedMainWindow();
|
|
||||||
expect(windowManager.isResizing).toBe(false);
|
|
||||||
expect(view.setBounds).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use getContentBounds when the platform is different to linux', () => {
|
it('should use getContentBounds when the platform is different to linux', () => {
|
||||||
windowManager.viewManager = {
|
|
||||||
getCurrentView: () => view,
|
|
||||||
};
|
|
||||||
|
|
||||||
const originalPlatform = process.platform;
|
const originalPlatform = process.platform;
|
||||||
Object.defineProperty(process, 'platform', {
|
Object.defineProperty(process, 'platform', {
|
||||||
value: 'windows',
|
value: 'windows',
|
||||||
@@ -490,66 +463,63 @@ describe('main/windows/windowManager', () => {
|
|||||||
|
|
||||||
describe('switchServer', () => {
|
describe('switchServer', () => {
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.viewManager = {
|
const servers = [
|
||||||
showByName: jest.fn(),
|
{
|
||||||
};
|
name: 'server-1',
|
||||||
|
order: 1,
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
name: 'tab-1',
|
||||||
|
order: 0,
|
||||||
|
isOpen: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-2',
|
||||||
|
order: 2,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-3',
|
||||||
|
order: 1,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
name: 'server-2',
|
||||||
|
order: 0,
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
name: 'tab-1',
|
||||||
|
order: 0,
|
||||||
|
isOpen: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-2',
|
||||||
|
order: 2,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab-3',
|
||||||
|
order: 1,
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
lastActiveTab: 2,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const map = servers.reduce((arr, item) => {
|
||||||
|
item.tabs.forEach((tab) => {
|
||||||
|
arr.push([`${item.name}_${tab.name}`, {}]);
|
||||||
|
});
|
||||||
|
return arr;
|
||||||
|
}, []);
|
||||||
|
const views = new Map(map);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
getTabViewName.mockImplementation((server, tab) => `${server}_${tab}`);
|
getTabViewName.mockImplementation((server, tab) => `${server}_${tab}`);
|
||||||
|
Config.teams = servers.concat();
|
||||||
Config.teams = [
|
ViewManager.getView.mockImplementation((name) => views.get(name));
|
||||||
{
|
|
||||||
name: 'server-1',
|
|
||||||
order: 1,
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
name: 'tab-1',
|
|
||||||
order: 0,
|
|
||||||
isOpen: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-2',
|
|
||||||
order: 2,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-3',
|
|
||||||
order: 1,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
name: 'server-2',
|
|
||||||
order: 0,
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
name: 'tab-1',
|
|
||||||
order: 0,
|
|
||||||
isOpen: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-2',
|
|
||||||
order: 2,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tab-3',
|
|
||||||
order: 1,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
lastActiveTab: 2,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const map = Config.teams.reduce((arr, item) => {
|
|
||||||
item.tabs.forEach((tab) => {
|
|
||||||
arr.push([`${item.name}_${tab.name}`, {}]);
|
|
||||||
});
|
|
||||||
return arr;
|
|
||||||
}, []);
|
|
||||||
windowManager.viewManager.views = new Map(map);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -566,38 +536,35 @@ describe('main/windows/windowManager', () => {
|
|||||||
it('should do nothing if cannot find the server', () => {
|
it('should do nothing if cannot find the server', () => {
|
||||||
windowManager.switchServer('server-3');
|
windowManager.switchServer('server-3');
|
||||||
expect(getTabViewName).not.toBeCalled();
|
expect(getTabViewName).not.toBeCalled();
|
||||||
expect(windowManager.viewManager.showByName).not.toBeCalled();
|
expect(ViewManager.showByName).not.toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show first open tab in order when last active not defined', () => {
|
it('should show first open tab in order when last active not defined', () => {
|
||||||
windowManager.switchServer('server-1');
|
windowManager.switchServer('server-1');
|
||||||
expect(windowManager.viewManager.showByName).toHaveBeenCalledWith('server-1_tab-3');
|
expect(ViewManager.showByName).toHaveBeenCalledWith('server-1_tab-3');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show last active tab of chosen server', () => {
|
it('should show last active tab of chosen server', () => {
|
||||||
windowManager.switchServer('server-2');
|
windowManager.switchServer('server-2');
|
||||||
expect(windowManager.viewManager.showByName).toHaveBeenCalledWith('server-2_tab-2');
|
expect(ViewManager.showByName).toHaveBeenCalledWith('server-2_tab-2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should wait for view to exist if specified', () => {
|
it('should wait for view to exist if specified', () => {
|
||||||
windowManager.viewManager.views.delete('server-1_tab-3');
|
views.delete('server-1_tab-3');
|
||||||
windowManager.switchServer('server-1', true);
|
windowManager.switchServer('server-1', true);
|
||||||
expect(windowManager.viewManager.showByName).not.toBeCalled();
|
expect(ViewManager.showByName).not.toBeCalled();
|
||||||
|
|
||||||
jest.advanceTimersByTime(200);
|
jest.advanceTimersByTime(200);
|
||||||
expect(windowManager.viewManager.showByName).not.toBeCalled();
|
expect(ViewManager.showByName).not.toBeCalled();
|
||||||
|
|
||||||
windowManager.viewManager.views.set('server-1_tab-3', {});
|
views.set('server-1_tab-3', {});
|
||||||
jest.advanceTimersByTime(200);
|
jest.advanceTimersByTime(200);
|
||||||
expect(windowManager.viewManager.showByName).toBeCalledWith('server-1_tab-3');
|
expect(ViewManager.showByName).toBeCalledWith('server-1_tab-3');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('handleHistory', () => {
|
describe('handleHistory', () => {
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.viewManager = {
|
|
||||||
getCurrentView: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should only go to offset if it can', () => {
|
it('should only go to offset if it can', () => {
|
||||||
const view = {
|
const view = {
|
||||||
@@ -608,12 +575,12 @@ describe('main/windows/windowManager', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
windowManager.viewManager.getCurrentView.mockReturnValue(view);
|
ViewManager.getCurrentView.mockReturnValue(view);
|
||||||
|
|
||||||
windowManager.handleHistory(null, 1);
|
windowManager.handleHistory(null, 1);
|
||||||
expect(view.view.webContents.goToOffset).not.toBeCalled();
|
expect(view.view.webContents.goToOffset).not.toBeCalled();
|
||||||
|
|
||||||
windowManager.viewManager.getCurrentView.mockReturnValue({
|
ViewManager.getCurrentView.mockReturnValue({
|
||||||
...view,
|
...view,
|
||||||
view: {
|
view: {
|
||||||
...view.view,
|
...view.view,
|
||||||
@@ -644,7 +611,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
view.view.webContents.goToOffset.mockImplementation(() => {
|
view.view.webContents.goToOffset.mockImplementation(() => {
|
||||||
throw new Error('hi');
|
throw new Error('hi');
|
||||||
});
|
});
|
||||||
windowManager.viewManager.getCurrentView.mockReturnValue(view);
|
ViewManager.getCurrentView.mockReturnValue(view);
|
||||||
|
|
||||||
windowManager.handleHistory(null, 1);
|
windowManager.handleHistory(null, 1);
|
||||||
expect(view.load).toBeCalledWith('http://server-1.com');
|
expect(view.load).toBeCalledWith('http://server-1.com');
|
||||||
@@ -653,9 +620,6 @@ describe('main/windows/windowManager', () => {
|
|||||||
|
|
||||||
describe('selectTab', () => {
|
describe('selectTab', () => {
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.viewManager = {
|
|
||||||
getCurrentView: jest.fn(),
|
|
||||||
};
|
|
||||||
windowManager.switchTab = jest.fn();
|
windowManager.switchTab = jest.fn();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -690,7 +654,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should select next server when open', () => {
|
it('should select next server when open', () => {
|
||||||
windowManager.viewManager.getCurrentView.mockReturnValue({
|
ViewManager.getCurrentView.mockReturnValue({
|
||||||
tab: {
|
tab: {
|
||||||
server: {
|
server: {
|
||||||
name: 'server-1',
|
name: 'server-1',
|
||||||
@@ -704,7 +668,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should select previous server when open', () => {
|
it('should select previous server when open', () => {
|
||||||
windowManager.viewManager.getCurrentView.mockReturnValue({
|
ViewManager.getCurrentView.mockReturnValue({
|
||||||
tab: {
|
tab: {
|
||||||
server: {
|
server: {
|
||||||
name: 'server-1',
|
name: 'server-1',
|
||||||
@@ -718,7 +682,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should skip over closed tab', () => {
|
it('should skip over closed tab', () => {
|
||||||
windowManager.viewManager.getCurrentView.mockReturnValue({
|
ViewManager.getCurrentView.mockReturnValue({
|
||||||
tab: {
|
tab: {
|
||||||
server: {
|
server: {
|
||||||
name: 'server-1',
|
name: 'server-1',
|
||||||
@@ -731,183 +695,8 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('handleBrowserHistoryPush', () => {
|
|
||||||
const windowManager = new WindowManager();
|
|
||||||
const view1 = {
|
|
||||||
name: 'server-1_tab-messaging',
|
|
||||||
isLoggedIn: true,
|
|
||||||
tab: {
|
|
||||||
type: TAB_MESSAGING,
|
|
||||||
server: {
|
|
||||||
url: 'http://server-1.com',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
view: {
|
|
||||||
webContents: {
|
|
||||||
send: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const view2 = {
|
|
||||||
...view1,
|
|
||||||
name: 'server-1_other_type_1',
|
|
||||||
tab: {
|
|
||||||
...view1.tab,
|
|
||||||
type: 'other_type_1',
|
|
||||||
},
|
|
||||||
view: {
|
|
||||||
webContents: {
|
|
||||||
send: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const view3 = {
|
|
||||||
...view1,
|
|
||||||
name: 'server-1_other_type_2',
|
|
||||||
tab: {
|
|
||||||
...view1.tab,
|
|
||||||
type: 'other_type_2',
|
|
||||||
},
|
|
||||||
view: {
|
|
||||||
webContents: {
|
|
||||||
send: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
windowManager.viewManager = {
|
|
||||||
views: new Map([
|
|
||||||
['server-1_tab-messaging', view1],
|
|
||||||
['server-1_other_type_1', view2],
|
|
||||||
]),
|
|
||||||
closedViews: new Map([
|
|
||||||
['server-1_other_type_2', view3],
|
|
||||||
]),
|
|
||||||
openClosedTab: jest.fn(),
|
|
||||||
showByName: jest.fn(),
|
|
||||||
getViewByURL: jest.fn(),
|
|
||||||
};
|
|
||||||
windowManager.handleBrowserHistoryButton = jest.fn();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
Config.teams = [
|
|
||||||
{
|
|
||||||
name: 'server-1',
|
|
||||||
url: 'http://server-1.com',
|
|
||||||
order: 0,
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
name: 'tab-messaging',
|
|
||||||
order: 0,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'other_type_1',
|
|
||||||
order: 2,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'other_type_2',
|
|
||||||
order: 1,
|
|
||||||
isOpen: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
urlUtils.cleanPathName.mockImplementation((base, path) => path);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
Config.teams = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should open closed view if pushing to it', () => {
|
|
||||||
windowManager.viewManager.getViewByURL.mockReturnValue({name: 'server-1_other_type_2'});
|
|
||||||
windowManager.viewManager.openClosedTab.mockImplementation((name) => {
|
|
||||||
const view = windowManager.viewManager.closedViews.get(name);
|
|
||||||
windowManager.viewManager.closedViews.delete(name);
|
|
||||||
windowManager.viewManager.views.set(name, view);
|
|
||||||
});
|
|
||||||
|
|
||||||
windowManager.handleBrowserHistoryPush(null, 'server-1_tab-messaging', '/other_type_2/subpath');
|
|
||||||
expect(windowManager.viewManager.openClosedTab).toBeCalledWith('server-1_other_type_2', 'http://server-1.com/other_type_2/subpath');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should open redirect view if different from current view', () => {
|
|
||||||
windowManager.viewManager.getViewByURL.mockReturnValue({name: 'server-1_other_type_1'});
|
|
||||||
windowManager.handleBrowserHistoryPush(null, 'server-1_tab-messaging', '/other_type_1/subpath');
|
|
||||||
expect(windowManager.viewManager.showByName).toBeCalledWith('server-1_other_type_1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should ignore redirects to "/" to Messages from other tabs', () => {
|
|
||||||
windowManager.viewManager.getViewByURL.mockReturnValue({name: 'server-1_tab-messaging'});
|
|
||||||
windowManager.handleBrowserHistoryPush(null, 'server-1_other_type_1', '/');
|
|
||||||
expect(view1.view.webContents.send).not.toBeCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('handleBrowserHistoryButton', () => {
|
|
||||||
const windowManager = new WindowManager();
|
|
||||||
const view1 = {
|
|
||||||
name: 'server-1_tab-messaging',
|
|
||||||
isLoggedIn: true,
|
|
||||||
isAtRoot: true,
|
|
||||||
tab: {
|
|
||||||
type: TAB_MESSAGING,
|
|
||||||
server: {
|
|
||||||
url: 'http://server-1.com',
|
|
||||||
},
|
|
||||||
url: new URL('http://server-1.com'),
|
|
||||||
},
|
|
||||||
view: {
|
|
||||||
webContents: {
|
|
||||||
canGoBack: jest.fn(),
|
|
||||||
canGoForward: jest.fn(),
|
|
||||||
clearHistory: jest.fn(),
|
|
||||||
send: jest.fn(),
|
|
||||||
getURL: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
windowManager.viewManager = {
|
|
||||||
views: new Map([
|
|
||||||
['server-1_tab-messaging', view1],
|
|
||||||
]),
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
Config.teams = [
|
|
||||||
{
|
|
||||||
name: 'server-1',
|
|
||||||
url: 'http://server-1.com',
|
|
||||||
order: 0,
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
name: 'tab-messaging',
|
|
||||||
order: 0,
|
|
||||||
isOpen: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
Config.teams = [];
|
|
||||||
view1.isAtRoot = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should erase history and set isAtRoot when navigating to root URL', () => {
|
|
||||||
view1.isAtRoot = false;
|
|
||||||
view1.view.webContents.getURL.mockReturnValue(view1.tab.url.toString());
|
|
||||||
windowManager.handleBrowserHistoryButton(null, 'server-1_tab-messaging');
|
|
||||||
expect(view1.view.webContents.clearHistory).toHaveBeenCalled();
|
|
||||||
expect(view1.isAtRoot).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('createCallsWidgetWindow', () => {
|
describe('createCallsWidgetWindow', () => {
|
||||||
|
const windowManager = new WindowManager();
|
||||||
const view = {
|
const view = {
|
||||||
name: 'server-1_tab-messaging',
|
name: 'server-1_tab-messaging',
|
||||||
serverInfo: {
|
serverInfo: {
|
||||||
@@ -927,19 +716,13 @@ describe('main/windows/windowManager', () => {
|
|||||||
close: jest.fn(),
|
close: jest.fn(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
ViewManager.getView.mockReturnValue(view);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
const windowManager = new WindowManager();
|
|
||||||
windowManager.viewManager = {
|
|
||||||
views: new Map([
|
|
||||||
['server-1_tab-messaging', view],
|
|
||||||
]),
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should create calls widget window', async () => {
|
it('should create calls widget window', async () => {
|
||||||
expect(windowManager.callsWidgetWindow).toBeUndefined();
|
expect(windowManager.callsWidgetWindow).toBeUndefined();
|
||||||
await windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'});
|
await windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'});
|
||||||
@@ -965,10 +748,6 @@ describe('main/windows/windowManager', () => {
|
|||||||
|
|
||||||
describe('handleGetDesktopSources', () => {
|
describe('handleGetDesktopSources', () => {
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.viewManager = {
|
|
||||||
showByName: jest.fn(),
|
|
||||||
getCurrentView: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
CallsWidgetWindow.mockImplementation(() => {
|
CallsWidgetWindow.mockImplementation(() => {
|
||||||
@@ -1031,7 +810,8 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
return arr;
|
return arr;
|
||||||
}, []);
|
}, []);
|
||||||
windowManager.viewManager.views = new Map(map);
|
const views = new Map(map);
|
||||||
|
ViewManager.getView.mockImplementation((name) => views.get(name));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -1058,7 +838,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
|
|
||||||
await windowManager.handleGetDesktopSources('server-1_tab-1', null);
|
await windowManager.handleGetDesktopSources('server-1_tab-1', null);
|
||||||
|
|
||||||
expect(windowManager.viewManager.views.get('server-1_tab-1').view.webContents.send).toHaveBeenCalledWith('desktop-sources-result', [
|
expect(ViewManager.getView('server-1_tab-1').view.webContents.send).toHaveBeenCalledWith('desktop-sources-result', [
|
||||||
{
|
{
|
||||||
id: 'screen0',
|
id: 'screen0',
|
||||||
},
|
},
|
||||||
@@ -1074,7 +854,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||||
err: 'screen-permissions',
|
err: 'screen-permissions',
|
||||||
});
|
});
|
||||||
expect(windowManager.viewManager.views.get('server-2_tab-1').view.webContents.send).toHaveBeenCalledWith('calls-error', {
|
expect(ViewManager.getView('server-2_tab-1').view.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||||
err: 'screen-permissions',
|
err: 'screen-permissions',
|
||||||
});
|
});
|
||||||
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||||
@@ -1097,10 +877,10 @@ describe('main/windows/windowManager', () => {
|
|||||||
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||||
err: 'screen-permissions',
|
err: 'screen-permissions',
|
||||||
});
|
});
|
||||||
expect(windowManager.viewManager.views.get('server-1_tab-1').view.webContents.send).toHaveBeenCalledWith('calls-error', {
|
expect(ViewManager.getView('server-1_tab-1').view.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||||
err: 'screen-permissions',
|
err: 'screen-permissions',
|
||||||
});
|
});
|
||||||
expect(windowManager.viewManager.views.get('server-1_tab-1').view.webContents.send).toHaveBeenCalledTimes(1);
|
expect(ViewManager.getView('server-1_tab-1').view.webContents.send).toHaveBeenCalledTimes(1);
|
||||||
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1128,7 +908,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
expect(windowManager.callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||||
err: 'screen-permissions',
|
err: 'screen-permissions',
|
||||||
});
|
});
|
||||||
expect(windowManager.viewManager.views.get('server-1_tab-1').view.webContents.send).toHaveBeenCalledWith('calls-error', {
|
expect(ViewManager.getView('server-1_tab-1').view.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||||
err: 'screen-permissions',
|
err: 'screen-permissions',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1146,10 +926,6 @@ describe('main/windows/windowManager', () => {
|
|||||||
describe('handleDesktopSourcesModalRequest', () => {
|
describe('handleDesktopSourcesModalRequest', () => {
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.switchServer = jest.fn();
|
windowManager.switchServer = jest.fn();
|
||||||
windowManager.viewManager = {
|
|
||||||
showByName: jest.fn(),
|
|
||||||
getCurrentView: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
CallsWidgetWindow.mockImplementation(() => {
|
CallsWidgetWindow.mockImplementation(() => {
|
||||||
@@ -1206,7 +982,8 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
return arr;
|
return arr;
|
||||||
}, []);
|
}, []);
|
||||||
windowManager.viewManager.views = new Map(map);
|
const views = new Map(map);
|
||||||
|
ViewManager.getView.mockImplementation((name) => views.get(name));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -1224,10 +1001,6 @@ describe('main/windows/windowManager', () => {
|
|||||||
describe('handleCallsWidgetChannelLinkClick', () => {
|
describe('handleCallsWidgetChannelLinkClick', () => {
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.switchServer = jest.fn();
|
windowManager.switchServer = jest.fn();
|
||||||
windowManager.viewManager = {
|
|
||||||
showByName: jest.fn(),
|
|
||||||
getCurrentView: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
CallsWidgetWindow.mockImplementation(() => {
|
CallsWidgetWindow.mockImplementation(() => {
|
||||||
@@ -1285,7 +1058,8 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
return arr;
|
return arr;
|
||||||
}, []);
|
}, []);
|
||||||
windowManager.viewManager.views = new Map(map);
|
const views = new Map(map);
|
||||||
|
ViewManager.getView.mockImplementation((name) => views.get(name));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -1347,11 +1121,6 @@ describe('main/windows/windowManager', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
windowManager.viewManager = {
|
|
||||||
views: new Map([
|
|
||||||
['server-1_tab-messaging', view1],
|
|
||||||
]),
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
CallsWidgetWindow.mockImplementation(() => {
|
CallsWidgetWindow.mockImplementation(() => {
|
||||||
@@ -1360,6 +1129,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
getMainView: jest.fn().mockReturnValue(view1),
|
getMainView: jest.fn().mockReturnValue(view1),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
ViewManager.getView.mockReturnValue(view1);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -1376,23 +1146,10 @@ describe('main/windows/windowManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getServerURLFromWebContentsId', () => {
|
describe('getServerURLFromWebContentsId', () => {
|
||||||
const view = {
|
|
||||||
name: 'server-1_tab-messaging',
|
|
||||||
serverInfo: {
|
|
||||||
server: {
|
|
||||||
url: new URL('http://server-1.com'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const windowManager = new WindowManager();
|
const windowManager = new WindowManager();
|
||||||
windowManager.viewManager = {
|
|
||||||
views: new Map([
|
|
||||||
['server-1_tab-messaging', view],
|
|
||||||
]),
|
|
||||||
findViewByWebContent: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should return calls widget URL', () => {
|
it('should return calls widget URL', () => {
|
||||||
|
ViewManager.getView.mockReturnValue({name: 'server-1_tab-messaging'});
|
||||||
CallsWidgetWindow.mockImplementation(() => {
|
CallsWidgetWindow.mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
on: jest.fn(),
|
on: jest.fn(),
|
||||||
|
@@ -16,20 +16,14 @@ import {
|
|||||||
import {
|
import {
|
||||||
MAXIMIZE_CHANGE,
|
MAXIMIZE_CHANGE,
|
||||||
HISTORY,
|
HISTORY,
|
||||||
REACT_APP_INITIALIZED,
|
|
||||||
FOCUS_THREE_DOT_MENU,
|
FOCUS_THREE_DOT_MENU,
|
||||||
GET_DARK_MODE,
|
GET_DARK_MODE,
|
||||||
UPDATE_SHORTCUT_MENU,
|
UPDATE_SHORTCUT_MENU,
|
||||||
BROWSER_HISTORY_PUSH,
|
BROWSER_HISTORY_PUSH,
|
||||||
APP_LOGGED_IN,
|
|
||||||
GET_VIEW_NAME,
|
|
||||||
GET_VIEW_WEBCONTENTS_ID,
|
GET_VIEW_WEBCONTENTS_ID,
|
||||||
RESIZE_MODAL,
|
RESIZE_MODAL,
|
||||||
APP_LOGGED_OUT,
|
|
||||||
BROWSER_HISTORY_BUTTON,
|
|
||||||
DISPATCH_GET_DESKTOP_SOURCES,
|
DISPATCH_GET_DESKTOP_SOURCES,
|
||||||
DESKTOP_SOURCES_RESULT,
|
DESKTOP_SOURCES_RESULT,
|
||||||
RELOAD_CURRENT_VIEW,
|
|
||||||
VIEW_FINISHED_RESIZING,
|
VIEW_FINISHED_RESIZING,
|
||||||
CALLS_JOIN_CALL,
|
CALLS_JOIN_CALL,
|
||||||
CALLS_LEAVE_CALL,
|
CALLS_LEAVE_CALL,
|
||||||
@@ -39,10 +33,9 @@ import {
|
|||||||
CALLS_LINK_CLICK,
|
CALLS_LINK_CLICK,
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
import {Logger} from 'common/log';
|
import {Logger} from 'common/log';
|
||||||
import urlUtils from 'common/utils/url';
|
|
||||||
import {SECOND} from 'common/utils/constants';
|
import {SECOND} from 'common/utils/constants';
|
||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import {getTabViewName, TAB_MESSAGING} from 'common/tabs/TabView';
|
import {getTabViewName} from 'common/tabs/TabView';
|
||||||
|
|
||||||
import downloadsManager from 'main/downloadsManager';
|
import downloadsManager from 'main/downloadsManager';
|
||||||
import {MattermostView} from 'main/views/MattermostView';
|
import {MattermostView} from 'main/views/MattermostView';
|
||||||
@@ -54,7 +47,7 @@ import {
|
|||||||
openScreensharePermissionsSettingsMacOS,
|
openScreensharePermissionsSettingsMacOS,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
import {ViewManager} from '../views/viewManager';
|
import ViewManager from '../views/viewManager';
|
||||||
import LoadingScreen from '../views/loadingScreen';
|
import LoadingScreen from '../views/loadingScreen';
|
||||||
import TeamDropdownView from '../views/teamDropdownView';
|
import TeamDropdownView from '../views/teamDropdownView';
|
||||||
import DownloadsDropdownView from '../views/downloadsDropdownView';
|
import DownloadsDropdownView from '../views/downloadsDropdownView';
|
||||||
@@ -72,7 +65,6 @@ export class WindowManager {
|
|||||||
assetsDir: string;
|
assetsDir: string;
|
||||||
|
|
||||||
callsWidgetWindow?: CallsWidgetWindow;
|
callsWidgetWindow?: CallsWidgetWindow;
|
||||||
viewManager?: ViewManager;
|
|
||||||
teamDropdown?: TeamDropdownView;
|
teamDropdown?: TeamDropdownView;
|
||||||
downloadsDropdown?: DownloadsDropdownView;
|
downloadsDropdown?: DownloadsDropdownView;
|
||||||
downloadsDropdownMenu?: DownloadsDropdownMenuView;
|
downloadsDropdownMenu?: DownloadsDropdownMenuView;
|
||||||
@@ -84,14 +76,7 @@ export class WindowManager {
|
|||||||
|
|
||||||
ipcMain.on(HISTORY, this.handleHistory);
|
ipcMain.on(HISTORY, this.handleHistory);
|
||||||
ipcMain.handle(GET_DARK_MODE, this.handleGetDarkMode);
|
ipcMain.handle(GET_DARK_MODE, this.handleGetDarkMode);
|
||||||
ipcMain.on(REACT_APP_INITIALIZED, this.handleReactAppInitialized);
|
|
||||||
ipcMain.on(BROWSER_HISTORY_PUSH, this.handleBrowserHistoryPush);
|
|
||||||
ipcMain.on(BROWSER_HISTORY_BUTTON, this.handleBrowserHistoryButton);
|
|
||||||
ipcMain.on(APP_LOGGED_IN, this.handleAppLoggedIn);
|
|
||||||
ipcMain.on(APP_LOGGED_OUT, this.handleAppLoggedOut);
|
|
||||||
ipcMain.handle(GET_VIEW_NAME, this.handleGetViewName);
|
|
||||||
ipcMain.handle(GET_VIEW_WEBCONTENTS_ID, this.handleGetWebContentsId);
|
ipcMain.handle(GET_VIEW_WEBCONTENTS_ID, this.handleGetWebContentsId);
|
||||||
ipcMain.on(RELOAD_CURRENT_VIEW, this.handleReloadCurrentView);
|
|
||||||
ipcMain.on(VIEW_FINISHED_RESIZING, this.handleViewFinishedResizing);
|
ipcMain.on(VIEW_FINISHED_RESIZING, this.handleViewFinishedResizing);
|
||||||
|
|
||||||
// Calls handlers
|
// Calls handlers
|
||||||
@@ -104,12 +89,6 @@ export class WindowManager {
|
|||||||
ipcMain.on(CALLS_LINK_CLICK, this.genCallsEventHandler(this.handleCallsLinkClick));
|
ipcMain.on(CALLS_LINK_CLICK, this.genCallsEventHandler(this.handleCallsLinkClick));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUpdateConfig = () => {
|
|
||||||
if (this.viewManager) {
|
|
||||||
this.viewManager.reloadConfiguration(Config.teams || []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genCallsEventHandler = (handler: CallsEventHandler) => {
|
genCallsEventHandler = (handler: CallsEventHandler) => {
|
||||||
return (event: IpcMainEvent, viewName: string, msg?: any) => {
|
return (event: IpcMainEvent, viewName: string, msg?: any) => {
|
||||||
if (this.callsWidgetWindow && !this.callsWidgetWindow.isAllowedEvent(event)) {
|
if (this.callsWidgetWindow && !this.callsWidgetWindow.isAllowedEvent(event)) {
|
||||||
@@ -132,7 +111,7 @@ export class WindowManager {
|
|||||||
// window to be fully closed.
|
// window to be fully closed.
|
||||||
await this.callsWidgetWindow.close();
|
await this.callsWidgetWindow.close();
|
||||||
}
|
}
|
||||||
const currentView = this.viewManager?.views.get(viewName);
|
const currentView = ViewManager.getView(viewName);
|
||||||
if (!currentView) {
|
if (!currentView) {
|
||||||
log.error('unable to create calls widget window: currentView is missing');
|
log.error('unable to create calls widget window: currentView is missing');
|
||||||
return;
|
return;
|
||||||
@@ -209,7 +188,7 @@ export class WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (deeplinkingURL) {
|
if (deeplinkingURL) {
|
||||||
this.viewManager?.handleDeepLink(deeplinkingURL);
|
ViewManager.handleDeepLink(deeplinkingURL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +206,7 @@ export class WindowManager {
|
|||||||
}
|
}
|
||||||
mainWindow.on('will-resize', this.handleWillResizeMainWindow);
|
mainWindow.on('will-resize', this.handleWillResizeMainWindow);
|
||||||
mainWindow.on('resized', this.handleResizedMainWindow);
|
mainWindow.on('resized', this.handleResizedMainWindow);
|
||||||
mainWindow.on('focus', this.focusBrowserView);
|
mainWindow.on('focus', ViewManager.focusCurrentView);
|
||||||
mainWindow.on('enter-full-screen', () => this.sendToRenderer('enter-full-screen'));
|
mainWindow.on('enter-full-screen', () => this.sendToRenderer('enter-full-screen'));
|
||||||
mainWindow.on('leave-full-screen', () => this.sendToRenderer('leave-full-screen'));
|
mainWindow.on('leave-full-screen', () => this.sendToRenderer('leave-full-screen'));
|
||||||
|
|
||||||
@@ -255,7 +234,7 @@ export class WindowManager {
|
|||||||
handleWillResizeMainWindow = (event: Event, newBounds: Electron.Rectangle) => {
|
handleWillResizeMainWindow = (event: Event, newBounds: Electron.Rectangle) => {
|
||||||
log.silly('handleWillResizeMainWindow');
|
log.silly('handleWillResizeMainWindow');
|
||||||
|
|
||||||
if (!(this.viewManager && MainWindow.get())) {
|
if (!MainWindow.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +247,7 @@ export class WindowManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isResizing && LoadingScreen.isHidden() && this.viewManager.getCurrentView()) {
|
if (this.isResizing && LoadingScreen.isHidden() && ViewManager.getCurrentView()) {
|
||||||
log.debug('prevented resize');
|
log.debug('prevented resize');
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return;
|
return;
|
||||||
@@ -310,7 +289,7 @@ export class WindowManager {
|
|||||||
handleResizeMainWindow = () => {
|
handleResizeMainWindow = () => {
|
||||||
log.silly('handleResizeMainWindow');
|
log.silly('handleResizeMainWindow');
|
||||||
|
|
||||||
if (!(this.viewManager && MainWindow.get())) {
|
if (!MainWindow.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.isResizing) {
|
if (this.isResizing) {
|
||||||
@@ -333,7 +312,7 @@ export class WindowManager {
|
|||||||
setCurrentViewBounds = (bounds: {width: number; height: number}) => {
|
setCurrentViewBounds = (bounds: {width: number; height: number}) => {
|
||||||
log.debug('setCurrentViewBounds', {bounds});
|
log.debug('setCurrentViewBounds', {bounds});
|
||||||
|
|
||||||
const currentView = this.viewManager?.getCurrentView();
|
const currentView = ViewManager.getCurrentView();
|
||||||
if (currentView) {
|
if (currentView) {
|
||||||
const adjustedBounds = getAdjustedWindowBoundaries(bounds.width, bounds.height, shouldHaveBackBar(currentView.tab.url, currentView.view.webContents.getURL()));
|
const adjustedBounds = getAdjustedWindowBoundaries(bounds.width, bounds.height, shouldHaveBackBar(currentView.tab.url, currentView.view.webContents.getURL()));
|
||||||
this.setBoundsFunction(currentView, adjustedBounds);
|
this.setBoundsFunction(currentView, adjustedBounds);
|
||||||
@@ -393,12 +372,6 @@ export class WindowManager {
|
|||||||
// TODO: should we include popups?
|
// TODO: should we include popups?
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToMattermostViews = (channel: string, ...args: unknown[]) => {
|
|
||||||
if (this.viewManager) {
|
|
||||||
this.viewManager.sendToAllViews(channel, ...args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
restoreMain = () => {
|
restoreMain = () => {
|
||||||
log.info('restoreMain');
|
log.info('restoreMain');
|
||||||
|
|
||||||
@@ -457,12 +430,8 @@ export class WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initializeViewManager = () => {
|
initializeViewManager = () => {
|
||||||
if (!this.viewManager && Config) {
|
ViewManager.init();
|
||||||
this.viewManager = new ViewManager();
|
this.initializeCurrentServerName();
|
||||||
this.viewManager.load();
|
|
||||||
this.viewManager.showInitial();
|
|
||||||
this.initializeCurrentServerName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCurrentServerName = () => {
|
initializeCurrentServerName = () => {
|
||||||
@@ -488,13 +457,13 @@ export class WindowManager {
|
|||||||
const tabViewName = getTabViewName(serverName, nextTab.name);
|
const tabViewName = getTabViewName(serverName, nextTab.name);
|
||||||
if (waitForViewToExist) {
|
if (waitForViewToExist) {
|
||||||
const timeout = setInterval(() => {
|
const timeout = setInterval(() => {
|
||||||
if (this.viewManager?.views.has(tabViewName)) {
|
if (ViewManager.getView(tabViewName)) {
|
||||||
this.viewManager?.showByName(tabViewName);
|
ViewManager.showByName(tabViewName);
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
} else {
|
} else {
|
||||||
this.viewManager?.showByName(tabViewName);
|
ViewManager.showByName(tabViewName);
|
||||||
}
|
}
|
||||||
ipcMain.emit(UPDATE_SHORTCUT_MENU);
|
ipcMain.emit(UPDATE_SHORTCUT_MENU);
|
||||||
}
|
}
|
||||||
@@ -503,23 +472,7 @@ export class WindowManager {
|
|||||||
log.debug('switchTab');
|
log.debug('switchTab');
|
||||||
this.showMainWindow();
|
this.showMainWindow();
|
||||||
const tabViewName = getTabViewName(serverName, tabName);
|
const tabViewName = getTabViewName(serverName, tabName);
|
||||||
this.viewManager?.showByName(tabViewName);
|
ViewManager.showByName(tabViewName);
|
||||||
}
|
|
||||||
|
|
||||||
focusBrowserView = () => {
|
|
||||||
log.debug('focusBrowserView');
|
|
||||||
|
|
||||||
if (this.viewManager) {
|
|
||||||
this.viewManager.focus();
|
|
||||||
} else {
|
|
||||||
log.error('Trying to call focus when the viewManager has not yet been initialized');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openBrowserViewDevTools = () => {
|
|
||||||
if (this.viewManager) {
|
|
||||||
this.viewManager.openViewDevTools();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
focusThreeDotMenu = () => {
|
focusThreeDotMenu = () => {
|
||||||
@@ -533,24 +486,6 @@ export class WindowManager {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReactAppInitialized = (e: IpcMainEvent, view: string) => {
|
|
||||||
log.debug('handleReactAppInitialized', view);
|
|
||||||
|
|
||||||
if (this.viewManager) {
|
|
||||||
this.viewManager.setServerInitialized(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getViewNameByWebContentsId = (webContentsId: number) => {
|
|
||||||
const view = this.viewManager?.findViewByWebContent(webContentsId);
|
|
||||||
return view?.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
getServerNameByWebContentsId = (webContentsId: number) => {
|
|
||||||
const view = this.viewManager?.findViewByWebContent(webContentsId);
|
|
||||||
return view?.tab.server.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
close = () => {
|
close = () => {
|
||||||
const focused = BrowserWindow.getFocusedWindow();
|
const focused = BrowserWindow.getFocusedWindow();
|
||||||
focused?.close();
|
focused?.close();
|
||||||
@@ -578,7 +513,7 @@ export class WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reload = () => {
|
reload = () => {
|
||||||
const currentView = this.viewManager?.getCurrentView();
|
const currentView = ViewManager.getCurrentView();
|
||||||
if (currentView) {
|
if (currentView) {
|
||||||
LoadingScreen.show();
|
LoadingScreen.show();
|
||||||
currentView.reload();
|
currentView.reload();
|
||||||
@@ -586,7 +521,7 @@ export class WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendToFind = () => {
|
sendToFind = () => {
|
||||||
const currentView = this.viewManager?.getCurrentView();
|
const currentView = ViewManager.getCurrentView();
|
||||||
if (currentView) {
|
if (currentView) {
|
||||||
currentView.view.webContents.sendInputEvent({type: 'keyDown', keyCode: 'F', modifiers: [process.platform === 'darwin' ? 'cmd' : 'ctrl', 'shift']});
|
currentView.view.webContents.sendInputEvent({type: 'keyDown', keyCode: 'F', modifiers: [process.platform === 'darwin' ? 'cmd' : 'ctrl', 'shift']});
|
||||||
}
|
}
|
||||||
@@ -595,15 +530,13 @@ export class WindowManager {
|
|||||||
handleHistory = (event: IpcMainEvent, offset: number) => {
|
handleHistory = (event: IpcMainEvent, offset: number) => {
|
||||||
log.debug('handleHistory', offset);
|
log.debug('handleHistory', offset);
|
||||||
|
|
||||||
if (this.viewManager) {
|
const activeView = ViewManager.getCurrentView();
|
||||||
const activeView = this.viewManager.getCurrentView();
|
if (activeView && activeView.view.webContents.canGoToOffset(offset)) {
|
||||||
if (activeView && activeView.view.webContents.canGoToOffset(offset)) {
|
try {
|
||||||
try {
|
activeView.view.webContents.goToOffset(offset);
|
||||||
activeView.view.webContents.goToOffset(offset);
|
} catch (error) {
|
||||||
} catch (error) {
|
log.error(error);
|
||||||
log.error(error);
|
activeView.load(activeView.tab.url);
|
||||||
activeView.load(activeView.tab.url);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -617,7 +550,7 @@ export class WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectTab = (fn: (order: number, length: number) => number) => {
|
selectTab = (fn: (order: number, length: number) => number) => {
|
||||||
const currentView = this.viewManager?.getCurrentView();
|
const currentView = ViewManager.getCurrentView();
|
||||||
if (!currentView) {
|
if (!currentView) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -645,76 +578,10 @@ export class WindowManager {
|
|||||||
return Config.darkMode;
|
return Config.darkMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBrowserHistoryPush = (e: IpcMainEvent, viewName: string, pathName: string) => {
|
|
||||||
log.debug('handleBrowserHistoryPush', {viewName, pathName});
|
|
||||||
|
|
||||||
const currentView = this.viewManager?.views.get(viewName);
|
|
||||||
const cleanedPathName = urlUtils.cleanPathName(currentView?.tab.server.url.pathname || '', pathName);
|
|
||||||
const redirectedViewName = this.viewManager?.getViewByURL(`${currentView?.tab.server.url.toString().replace(/\/$/, '')}${cleanedPathName}`)?.name || viewName;
|
|
||||||
if (this.viewManager?.closedViews.has(redirectedViewName)) {
|
|
||||||
// If it's a closed view, just open it and stop
|
|
||||||
this.viewManager.openClosedTab(redirectedViewName, `${currentView?.tab.server.url}${cleanedPathName}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let redirectedView = this.viewManager?.views.get(redirectedViewName) || currentView;
|
|
||||||
if (redirectedView !== currentView && redirectedView?.tab.server.name === this.currentServerName && redirectedView?.isLoggedIn) {
|
|
||||||
log.info('redirecting to a new view', redirectedView?.name || viewName);
|
|
||||||
this.viewManager?.showByName(redirectedView?.name || viewName);
|
|
||||||
} else {
|
|
||||||
redirectedView = currentView;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case check for Channels to not force a redirect to "/", causing a refresh
|
|
||||||
if (!(redirectedView !== currentView && redirectedView?.tab.type === TAB_MESSAGING && cleanedPathName === '/')) {
|
|
||||||
redirectedView?.view.webContents.send(BROWSER_HISTORY_PUSH, cleanedPathName);
|
|
||||||
if (redirectedView) {
|
|
||||||
this.handleBrowserHistoryButton(e, redirectedView.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBrowserHistoryButton = (e: IpcMainEvent, viewName: string) => {
|
|
||||||
log.debug('handleBrowserHistoryButton', viewName);
|
|
||||||
|
|
||||||
const currentView = this.viewManager?.views.get(viewName);
|
|
||||||
if (currentView) {
|
|
||||||
if (currentView.view.webContents.getURL() === currentView.tab.url.toString()) {
|
|
||||||
currentView.view.webContents.clearHistory();
|
|
||||||
currentView.isAtRoot = true;
|
|
||||||
} else {
|
|
||||||
currentView.isAtRoot = false;
|
|
||||||
}
|
|
||||||
currentView?.view.webContents.send(BROWSER_HISTORY_BUTTON, currentView.view.webContents.canGoBack(), currentView.view.webContents.canGoForward());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentTeamName = () => {
|
getCurrentTeamName = () => {
|
||||||
return this.currentServerName;
|
return this.currentServerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAppLoggedIn = (event: IpcMainEvent, viewName: string) => {
|
|
||||||
log.debug('handleAppLoggedIn', viewName);
|
|
||||||
|
|
||||||
const view = this.viewManager?.views.get(viewName);
|
|
||||||
if (view && !view.isLoggedIn) {
|
|
||||||
view.isLoggedIn = true;
|
|
||||||
this.viewManager?.reloadViewIfNeeded(viewName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAppLoggedOut = (event: IpcMainEvent, viewName: string) => {
|
|
||||||
log.debug('handleAppLoggedOut', viewName);
|
|
||||||
|
|
||||||
const view = this.viewManager?.views.get(viewName);
|
|
||||||
if (view && view.isLoggedIn) {
|
|
||||||
view.isLoggedIn = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleGetViewName = (event: IpcMainInvokeEvent) => {
|
|
||||||
return this.getViewNameByWebContentsId(event.sender.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleGetWebContentsId = (event: IpcMainInvokeEvent) => {
|
handleGetWebContentsId = (event: IpcMainInvokeEvent) => {
|
||||||
return event.sender.id;
|
return event.sender.id;
|
||||||
}
|
}
|
||||||
@@ -722,7 +589,7 @@ export class WindowManager {
|
|||||||
handleGetDesktopSources = async (viewName: string, opts: Electron.SourcesOptions) => {
|
handleGetDesktopSources = async (viewName: string, opts: Electron.SourcesOptions) => {
|
||||||
log.debug('handleGetDesktopSources', {viewName, opts});
|
log.debug('handleGetDesktopSources', {viewName, opts});
|
||||||
|
|
||||||
const view = this.viewManager?.views.get(viewName);
|
const view = ViewManager.getView(viewName);
|
||||||
if (!view) {
|
if (!view) {
|
||||||
log.error('handleGetDesktopSources: view not found');
|
log.error('handleGetDesktopSources: view not found');
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -784,27 +651,12 @@ export class WindowManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReloadCurrentView = () => {
|
|
||||||
log.debug('handleReloadCurrentView');
|
|
||||||
|
|
||||||
const view = this.viewManager?.getCurrentView();
|
|
||||||
if (!view) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
view?.reload();
|
|
||||||
this.viewManager?.showByName(view?.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getServerURLFromWebContentsId = (id: number) => {
|
getServerURLFromWebContentsId = (id: number) => {
|
||||||
if (this.callsWidgetWindow && (id === this.callsWidgetWindow.getWebContentsId() || id === this.callsWidgetWindow.getPopOutWebContentsId())) {
|
if (this.callsWidgetWindow && (id === this.callsWidgetWindow.getWebContentsId() || id === this.callsWidgetWindow.getPopOutWebContentsId())) {
|
||||||
return this.callsWidgetWindow.getURL();
|
return this.callsWidgetWindow.getURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewName = this.getViewNameByWebContentsId(id);
|
return ViewManager.getViewByWebContentsId(id)?.tab.server.url;
|
||||||
if (!viewName) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return this.viewManager?.views.get(viewName)?.tab.server.url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user