[MM-14093] Rename 'team' to 'server' and 'tab' to 'view' in most cases, some additional cleanup (#2711)
* Rename MattermostTeam -> UniqueServer, MattermostTab -> UniqueView * Rename 'team' to 'server' * Some further cleanup * Rename weirdly named function * Rename 'tab' to 'view' in most instances * Fix i18n * PR feedback
This commit is contained in:
@@ -95,9 +95,9 @@ describe('main/app/app', () => {
|
||||
const promise = Promise.resolve({});
|
||||
const certificate = {};
|
||||
const view = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
name: 'test-team',
|
||||
name: 'test-server',
|
||||
url: new URL(testURL),
|
||||
},
|
||||
},
|
||||
@@ -163,7 +163,7 @@ describe('main/app/app', () => {
|
||||
expect(CertificateStore.save).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load URL using MattermostView when trusting certificate', async () => {
|
||||
it('should load URL using MattermostBrowserView when trusting certificate', async () => {
|
||||
dialog.showMessageBox.mockResolvedValue({response: 0});
|
||||
await handleAppCertificateError(event, webContents, testURL, 'error-1', certificate, callback);
|
||||
expect(callback).toHaveBeenCalledWith(true);
|
||||
|
@@ -96,8 +96,8 @@ export async function handleAppCertificateError(event: Event, webContents: WebCo
|
||||
const errorID = `${parsedURL.origin}:${error}`;
|
||||
|
||||
const view = ViewManager.getViewByWebContentsId(webContents.id);
|
||||
if (view?.tab.server) {
|
||||
const serverURL = parseURL(view.tab.server.url);
|
||||
if (view?.view.server) {
|
||||
const serverURL = parseURL(view.view.server.url);
|
||||
if (serverURL && serverURL.origin !== parsedURL.origin) {
|
||||
log.warn(`Ignoring certificate for unmatched origin ${parsedURL.origin}, will not trust`);
|
||||
callback(false);
|
||||
|
@@ -93,14 +93,14 @@ describe('main/app/config', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should recheck teams after config update if registry data is pulled in', () => {
|
||||
it('should recheck servers after config update if registry data is pulled in', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'win32',
|
||||
});
|
||||
Config.registryConfigData = {};
|
||||
|
||||
handleConfigUpdate({teams: []});
|
||||
handleConfigUpdate({servers: []});
|
||||
expect(handleMainWindowIsShown).toHaveBeenCalled();
|
||||
|
||||
Object.defineProperty(process, 'platform', {
|
||||
|
@@ -6,7 +6,7 @@
|
||||
import {initialize} from './initialize';
|
||||
|
||||
// TODO: Singletons, we need DI :D
|
||||
import('main/views/teamDropdownView');
|
||||
import('main/views/serverDropdownView');
|
||||
import('main/views/downloadsDropdownMenuView');
|
||||
import('main/views/downloadsDropdownView');
|
||||
|
||||
|
@@ -278,7 +278,7 @@ describe('main/app/initialize', () => {
|
||||
|
||||
it('should allow permission requests for supported types from trusted URLs', async () => {
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
url: new URL('http://server-1.com'),
|
||||
},
|
||||
|
@@ -14,8 +14,8 @@ import {
|
||||
SHOW_NEW_SERVER_MODAL,
|
||||
NOTIFY_MENTION,
|
||||
SWITCH_TAB,
|
||||
CLOSE_TAB,
|
||||
OPEN_TAB,
|
||||
CLOSE_VIEW,
|
||||
OPEN_VIEW,
|
||||
SHOW_EDIT_SERVER_MODAL,
|
||||
SHOW_REMOVE_SERVER_MODAL,
|
||||
UPDATE_SHORTCUT_MENU,
|
||||
@@ -100,8 +100,8 @@ import {
|
||||
switchServer,
|
||||
} from './servers';
|
||||
import {
|
||||
handleCloseTab, handleGetLastActive, handleGetOrderedTabsForServer, handleOpenTab,
|
||||
} from './tabs';
|
||||
handleCloseView, handleGetLastActive, handleGetOrderedViewsForServer, handleOpenView,
|
||||
} from './views';
|
||||
import {
|
||||
clearAppCache,
|
||||
getDeeplinkingURL,
|
||||
@@ -279,8 +279,8 @@ function initializeInterCommunicationEventListeners() {
|
||||
|
||||
ipcMain.on(SWITCH_SERVER, (event, serverId) => switchServer(serverId));
|
||||
ipcMain.on(SWITCH_TAB, (event, viewId) => ViewManager.showById(viewId));
|
||||
ipcMain.on(CLOSE_TAB, handleCloseTab);
|
||||
ipcMain.on(OPEN_TAB, handleOpenTab);
|
||||
ipcMain.on(CLOSE_VIEW, handleCloseView);
|
||||
ipcMain.on(OPEN_VIEW, handleOpenView);
|
||||
|
||||
ipcMain.on(QUIT, handleQuit);
|
||||
|
||||
@@ -296,10 +296,10 @@ function initializeInterCommunicationEventListeners() {
|
||||
ipcMain.on(UPDATE_CONFIGURATION, updateConfiguration);
|
||||
|
||||
ipcMain.on(UPDATE_SERVER_ORDER, (event, serverOrder) => ServerManager.updateServerOrder(serverOrder));
|
||||
ipcMain.on(UPDATE_TAB_ORDER, (event, serverId, tabOrder) => ServerManager.updateTabOrder(serverId, tabOrder));
|
||||
ipcMain.on(UPDATE_TAB_ORDER, (event, serverId, viewOrder) => ServerManager.updateTabOrder(serverId, viewOrder));
|
||||
ipcMain.handle(GET_LAST_ACTIVE, handleGetLastActive);
|
||||
ipcMain.handle(GET_ORDERED_SERVERS, () => ServerManager.getOrderedServers().map((srv) => srv.toMattermostTeam()));
|
||||
ipcMain.handle(GET_ORDERED_TABS_FOR_SERVER, handleGetOrderedTabsForServer);
|
||||
ipcMain.handle(GET_ORDERED_SERVERS, () => ServerManager.getOrderedServers().map((srv) => srv.toUniqueServer()));
|
||||
ipcMain.handle(GET_ORDERED_TABS_FOR_SERVER, handleGetOrderedViewsForServer);
|
||||
|
||||
ipcMain.handle(GET_DARK_MODE, handleGetDarkMode);
|
||||
ipcMain.on(WINDOW_CLOSE, handleClose);
|
||||
@@ -453,7 +453,7 @@ async function initializeAfterAppReady() {
|
||||
}
|
||||
|
||||
const requestingURL = webContents.getURL();
|
||||
const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.tab.server.url;
|
||||
const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.view.server.url;
|
||||
|
||||
if (!serverURL) {
|
||||
callback(false);
|
||||
|
@@ -16,14 +16,14 @@ jest.mock('common/config', () => ({
|
||||
}));
|
||||
jest.mock('main/notifications', () => ({}));
|
||||
jest.mock('common/servers/serverManager', () => ({
|
||||
setTabIsOpen: jest.fn(),
|
||||
setViewIsOpen: jest.fn(),
|
||||
getAllServers: jest.fn(),
|
||||
hasServers: jest.fn(),
|
||||
addServer: jest.fn(),
|
||||
editServer: jest.fn(),
|
||||
removeServer: jest.fn(),
|
||||
getServer: jest.fn(),
|
||||
getTab: jest.fn(),
|
||||
getView: jest.fn(),
|
||||
getLastActiveTabForServer: jest.fn(),
|
||||
}));
|
||||
jest.mock('main/utils', () => ({
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
import {app, IpcMainEvent, IpcMainInvokeEvent, Menu} from 'electron';
|
||||
|
||||
import {MattermostTeam} from 'types/config';
|
||||
import {UniqueServer} from 'types/config';
|
||||
import {MentionData} from 'types/notification';
|
||||
|
||||
import {Logger} from 'common/log';
|
||||
@@ -93,11 +93,11 @@ export function handleWelcomeScreenModal() {
|
||||
if (!mainWindow) {
|
||||
return;
|
||||
}
|
||||
const modalPromise = ModalManager.addModal<MattermostTeam[], MattermostTeam>('welcomeScreen', html, preload, ServerManager.getAllServers().map((team) => team.toMattermostTeam()), mainWindow, !ServerManager.hasServers());
|
||||
const modalPromise = ModalManager.addModal<UniqueServer[], UniqueServer>('welcomeScreen', html, preload, ServerManager.getAllServers().map((server) => server.toUniqueServer()), mainWindow, !ServerManager.hasServers());
|
||||
if (modalPromise) {
|
||||
modalPromise.then((data) => {
|
||||
const newTeam = ServerManager.addServer(data);
|
||||
switchServer(newTeam.id, true);
|
||||
const newServer = ServerManager.addServer(data);
|
||||
switchServer(newServer.id, true);
|
||||
}).catch((e) => {
|
||||
// e is undefined for user cancellation
|
||||
if (e) {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import {getDefaultConfigTeamFromTeam} from 'common/tabs/TabView';
|
||||
import {getDefaultViewsForConfigServer} from 'common/views/View';
|
||||
|
||||
import ModalManager from 'main/views/modalManager';
|
||||
import {getLocalURLString, getLocalPreload} from 'main/utils';
|
||||
@@ -18,19 +18,19 @@ jest.mock('electron', () => ({
|
||||
}));
|
||||
|
||||
jest.mock('common/servers/serverManager', () => ({
|
||||
setTabIsOpen: jest.fn(),
|
||||
setViewIsOpen: jest.fn(),
|
||||
getAllServers: jest.fn(),
|
||||
hasServers: jest.fn(),
|
||||
addServer: jest.fn(),
|
||||
editServer: jest.fn(),
|
||||
removeServer: jest.fn(),
|
||||
getServer: jest.fn(),
|
||||
getTab: jest.fn(),
|
||||
getView: jest.fn(),
|
||||
getLastActiveTabForServer: jest.fn(),
|
||||
getServerLog: jest.fn(),
|
||||
}));
|
||||
jest.mock('common/tabs/TabView', () => ({
|
||||
getDefaultConfigTeamFromTeam: jest.fn(),
|
||||
jest.mock('common/views/View', () => ({
|
||||
getDefaultViewsForConfigServer: jest.fn(),
|
||||
}));
|
||||
jest.mock('main/views/modalManager', () => ({
|
||||
addModal: jest.fn(),
|
||||
@@ -50,22 +50,22 @@ jest.mock('main/views/viewManager', () => ({
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: 'tab-1',
|
||||
name: 'view-1',
|
||||
order: 0,
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
name: 'tab-2',
|
||||
name: 'view-2',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
{
|
||||
name: 'tab-3',
|
||||
name: 'view-3',
|
||||
order: 1,
|
||||
isOpen: true,
|
||||
},
|
||||
];
|
||||
const teams = [
|
||||
const servers = [
|
||||
{
|
||||
id: 'server-1',
|
||||
name: 'server-1',
|
||||
@@ -77,9 +77,9 @@ const teams = [
|
||||
describe('main/app/servers', () => {
|
||||
describe('switchServer', () => {
|
||||
const views = new Map([
|
||||
['tab-1', {id: 'tab-1'}],
|
||||
['tab-2', {id: 'tab-2'}],
|
||||
['tab-3', {id: 'tab-3'}],
|
||||
['view-1', {id: 'view-1'}],
|
||||
['view-2', {id: 'view-2'}],
|
||||
['view-3', {id: 'view-3'}],
|
||||
]);
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -119,69 +119,69 @@ describe('main/app/servers', () => {
|
||||
expect(ViewManager.showById).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should show first open tab in order when last active not defined', () => {
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-3'});
|
||||
it('should show first open view in order when last active not defined', () => {
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-3'});
|
||||
Servers.switchServer('server-1');
|
||||
expect(ViewManager.showById).toHaveBeenCalledWith('tab-3');
|
||||
expect(ViewManager.showById).toHaveBeenCalledWith('view-3');
|
||||
});
|
||||
|
||||
it('should show last active tab of chosen server', () => {
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-2'});
|
||||
it('should show last active view of chosen server', () => {
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-2'});
|
||||
Servers.switchServer('server-2');
|
||||
expect(ViewManager.showById).toHaveBeenCalledWith('tab-2');
|
||||
expect(ViewManager.showById).toHaveBeenCalledWith('view-2');
|
||||
});
|
||||
|
||||
it('should wait for view to exist if specified', () => {
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-3'});
|
||||
views.delete('tab-3');
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-3'});
|
||||
views.delete('view-3');
|
||||
Servers.switchServer('server-1', true);
|
||||
expect(ViewManager.showById).not.toBeCalled();
|
||||
|
||||
jest.advanceTimersByTime(200);
|
||||
expect(ViewManager.showById).not.toBeCalled();
|
||||
|
||||
views.set('tab-3', {});
|
||||
views.set('view-3', {});
|
||||
jest.advanceTimersByTime(200);
|
||||
expect(ViewManager.showById).toBeCalledWith('tab-3');
|
||||
expect(ViewManager.showById).toBeCalledWith('view-3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleNewServerModal', () => {
|
||||
let teamsCopy;
|
||||
let serversCopy;
|
||||
|
||||
beforeEach(() => {
|
||||
getLocalURLString.mockReturnValue('/some/index.html');
|
||||
getLocalPreload.mockReturnValue('/some/preload.js');
|
||||
MainWindow.get.mockReturnValue({});
|
||||
|
||||
teamsCopy = JSON.parse(JSON.stringify(teams));
|
||||
serversCopy = JSON.parse(JSON.stringify(servers));
|
||||
ServerManager.getAllServers.mockReturnValue([]);
|
||||
ServerManager.addServer.mockImplementation(() => {
|
||||
const newTeam = {
|
||||
const newServer = {
|
||||
id: 'server-1',
|
||||
name: 'new-team',
|
||||
url: 'http://new-team.com',
|
||||
name: 'new-server',
|
||||
url: 'http://new-server.com',
|
||||
tabs,
|
||||
};
|
||||
teamsCopy = [
|
||||
...teamsCopy,
|
||||
newTeam,
|
||||
serversCopy = [
|
||||
...serversCopy,
|
||||
newServer,
|
||||
];
|
||||
return newTeam;
|
||||
return newServer;
|
||||
});
|
||||
ServerManager.hasServers.mockReturnValue(Boolean(teamsCopy.length));
|
||||
ServerManager.hasServers.mockReturnValue(Boolean(serversCopy.length));
|
||||
ServerManager.getServerLog.mockReturnValue({debug: jest.fn(), error: jest.fn()});
|
||||
|
||||
getDefaultConfigTeamFromTeam.mockImplementation((team) => ({
|
||||
...team,
|
||||
getDefaultViewsForConfigServer.mockImplementation((server) => ({
|
||||
...server,
|
||||
tabs,
|
||||
}));
|
||||
});
|
||||
|
||||
it('should add new team to the config', async () => {
|
||||
it('should add new server to the config', async () => {
|
||||
const data = {
|
||||
name: 'new-team',
|
||||
url: 'http://new-team.com',
|
||||
name: 'new-server',
|
||||
url: 'http://new-server.com',
|
||||
};
|
||||
const promise = Promise.resolve(data);
|
||||
ModalManager.addModal.mockReturnValue(promise);
|
||||
@@ -190,10 +190,10 @@ describe('main/app/servers', () => {
|
||||
await promise;
|
||||
|
||||
expect(ServerManager.addServer).toHaveBeenCalledWith(data);
|
||||
expect(teamsCopy).toContainEqual(expect.objectContaining({
|
||||
expect(serversCopy).toContainEqual(expect.objectContaining({
|
||||
id: 'server-1',
|
||||
name: 'new-team',
|
||||
url: 'http://new-team.com',
|
||||
name: 'new-server',
|
||||
url: 'http://new-server.com',
|
||||
tabs,
|
||||
}));
|
||||
|
||||
@@ -203,31 +203,31 @@ describe('main/app/servers', () => {
|
||||
});
|
||||
|
||||
describe('handleEditServerModal', () => {
|
||||
let teamsCopy;
|
||||
let serversCopy;
|
||||
|
||||
beforeEach(() => {
|
||||
getLocalURLString.mockReturnValue('/some/index.html');
|
||||
getLocalPreload.mockReturnValue('/some/preload.js');
|
||||
MainWindow.get.mockReturnValue({});
|
||||
|
||||
teamsCopy = JSON.parse(JSON.stringify(teams));
|
||||
serversCopy = JSON.parse(JSON.stringify(servers));
|
||||
ServerManager.getServer.mockImplementation((id) => {
|
||||
if (id !== teamsCopy[0].id) {
|
||||
if (id !== serversCopy[0].id) {
|
||||
return undefined;
|
||||
}
|
||||
return {...teamsCopy[0], toMattermostTeam: jest.fn()};
|
||||
return {...serversCopy[0], toUniqueServer: jest.fn()};
|
||||
});
|
||||
ServerManager.editServer.mockImplementation((id, team) => {
|
||||
if (id !== teamsCopy[0].id) {
|
||||
ServerManager.editServer.mockImplementation((id, server) => {
|
||||
if (id !== serversCopy[0].id) {
|
||||
return;
|
||||
}
|
||||
const newTeam = {
|
||||
...teamsCopy[0],
|
||||
...team,
|
||||
const newServer = {
|
||||
...serversCopy[0],
|
||||
...server,
|
||||
};
|
||||
teamsCopy = [newTeam];
|
||||
serversCopy = [newServer];
|
||||
});
|
||||
ServerManager.getAllServers.mockReturnValue(teamsCopy.map((team) => ({...team, toMattermostTeam: jest.fn()})));
|
||||
ServerManager.getAllServers.mockReturnValue(serversCopy.map((server) => ({...server, toUniqueServer: jest.fn()})));
|
||||
});
|
||||
|
||||
it('should do nothing when the server cannot be found', () => {
|
||||
@@ -235,58 +235,58 @@ describe('main/app/servers', () => {
|
||||
expect(ModalManager.addModal).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should edit the existing team', async () => {
|
||||
it('should edit the existing server', async () => {
|
||||
const promise = Promise.resolve({
|
||||
name: 'new-team',
|
||||
url: 'http://new-team.com',
|
||||
name: 'new-server',
|
||||
url: 'http://new-server.com',
|
||||
});
|
||||
ModalManager.addModal.mockReturnValue(promise);
|
||||
|
||||
Servers.handleEditServerModal(null, 'server-1');
|
||||
await promise;
|
||||
expect(teamsCopy).not.toContainEqual(expect.objectContaining({
|
||||
expect(serversCopy).not.toContainEqual(expect.objectContaining({
|
||||
id: 'server-1',
|
||||
name: 'server-1',
|
||||
url: 'http://server-1.com',
|
||||
tabs,
|
||||
}));
|
||||
expect(teamsCopy).toContainEqual(expect.objectContaining({
|
||||
expect(serversCopy).toContainEqual(expect.objectContaining({
|
||||
id: 'server-1',
|
||||
name: 'new-team',
|
||||
url: 'http://new-team.com',
|
||||
name: 'new-server',
|
||||
url: 'http://new-server.com',
|
||||
tabs,
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleRemoveServerModal', () => {
|
||||
let teamsCopy;
|
||||
let serversCopy;
|
||||
|
||||
beforeEach(() => {
|
||||
getLocalURLString.mockReturnValue('/some/index.html');
|
||||
getLocalPreload.mockReturnValue('/some/preload.js');
|
||||
MainWindow.get.mockReturnValue({});
|
||||
|
||||
teamsCopy = JSON.parse(JSON.stringify(teams));
|
||||
serversCopy = JSON.parse(JSON.stringify(servers));
|
||||
ServerManager.getServer.mockImplementation((id) => {
|
||||
if (id !== teamsCopy[0].id) {
|
||||
if (id !== serversCopy[0].id) {
|
||||
return undefined;
|
||||
}
|
||||
return teamsCopy[0];
|
||||
return serversCopy[0];
|
||||
});
|
||||
ServerManager.removeServer.mockImplementation(() => {
|
||||
teamsCopy = [];
|
||||
serversCopy = [];
|
||||
});
|
||||
ServerManager.getAllServers.mockReturnValue(teamsCopy);
|
||||
ServerManager.getAllServers.mockReturnValue(serversCopy);
|
||||
});
|
||||
|
||||
it('should remove the existing team', async () => {
|
||||
it('should remove the existing server', async () => {
|
||||
const promise = Promise.resolve(true);
|
||||
ModalManager.addModal.mockReturnValue(promise);
|
||||
|
||||
Servers.handleRemoveServerModal(null, 'server-1');
|
||||
await promise;
|
||||
expect(teamsCopy).not.toContainEqual(expect.objectContaining({
|
||||
expect(serversCopy).not.toContainEqual(expect.objectContaining({
|
||||
id: 'server-1',
|
||||
name: 'server-1',
|
||||
url: 'http://server-1.com',
|
||||
@@ -294,11 +294,11 @@ describe('main/app/servers', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('should not remove the existing team when clicking Cancel', async () => {
|
||||
it('should not remove the existing server when clicking Cancel', async () => {
|
||||
const promise = Promise.resolve(false);
|
||||
ModalManager.addModal.mockReturnValue(promise);
|
||||
|
||||
expect(teamsCopy).toContainEqual(expect.objectContaining({
|
||||
expect(serversCopy).toContainEqual(expect.objectContaining({
|
||||
id: 'server-1',
|
||||
name: 'server-1',
|
||||
url: 'http://server-1.com',
|
||||
@@ -307,7 +307,7 @@ describe('main/app/servers', () => {
|
||||
|
||||
Servers.handleRemoveServerModal(null, 'server-1');
|
||||
await promise;
|
||||
expect(teamsCopy).toContainEqual(expect.objectContaining({
|
||||
expect(serversCopy).toContainEqual(expect.objectContaining({
|
||||
id: 'server-1',
|
||||
name: 'server-1',
|
||||
url: 'http://server-1.com',
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
import {IpcMainEvent, ipcMain} from 'electron';
|
||||
|
||||
import {MattermostTeam, Team} from 'types/config';
|
||||
import {UniqueServer, Server} from 'types/config';
|
||||
|
||||
import {UPDATE_SHORTCUT_MENU} from 'common/communication';
|
||||
import {Logger} from 'common/log';
|
||||
@@ -24,16 +24,16 @@ export const switchServer = (serverId: string, waitForViewToExist = false) => {
|
||||
ServerManager.getServerLog(serverId, 'WindowManager').error('Cannot find server in config');
|
||||
return;
|
||||
}
|
||||
const nextTab = ServerManager.getLastActiveTabForServer(serverId);
|
||||
const nextView = ServerManager.getLastActiveTabForServer(serverId);
|
||||
if (waitForViewToExist) {
|
||||
const timeout = setInterval(() => {
|
||||
if (ViewManager.getView(nextTab.id)) {
|
||||
ViewManager.showById(nextTab.id);
|
||||
if (ViewManager.getView(nextView.id)) {
|
||||
ViewManager.showById(nextView.id);
|
||||
clearInterval(timeout);
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
ViewManager.showById(nextTab.id);
|
||||
ViewManager.showById(nextView.id);
|
||||
}
|
||||
ipcMain.emit(UPDATE_SHORTCUT_MENU);
|
||||
};
|
||||
@@ -49,11 +49,11 @@ export const handleNewServerModal = () => {
|
||||
if (!mainWindow) {
|
||||
return;
|
||||
}
|
||||
const modalPromise = ModalManager.addModal<MattermostTeam[], Team>('newServer', html, preload, ServerManager.getAllServers().map((team) => team.toMattermostTeam()), mainWindow, !ServerManager.hasServers());
|
||||
const modalPromise = ModalManager.addModal<UniqueServer[], Server>('newServer', html, preload, ServerManager.getAllServers().map((server) => server.toUniqueServer()), mainWindow, !ServerManager.hasServers());
|
||||
if (modalPromise) {
|
||||
modalPromise.then((data) => {
|
||||
const newTeam = ServerManager.addServer(data);
|
||||
switchServer(newTeam.id, true);
|
||||
const newServer = ServerManager.addServer(data);
|
||||
switchServer(newServer.id, true);
|
||||
}).catch((e) => {
|
||||
// e is undefined for user cancellation
|
||||
if (e) {
|
||||
@@ -80,13 +80,13 @@ export const handleEditServerModal = (e: IpcMainEvent, id: string) => {
|
||||
if (!server) {
|
||||
return;
|
||||
}
|
||||
const modalPromise = ModalManager.addModal<{currentTeams: MattermostTeam[]; team: MattermostTeam}, Team>(
|
||||
const modalPromise = ModalManager.addModal<{currentServers: UniqueServer[]; server: UniqueServer}, Server>(
|
||||
'editServer',
|
||||
html,
|
||||
preload,
|
||||
{
|
||||
currentTeams: ServerManager.getAllServers().map((team) => team.toMattermostTeam()),
|
||||
team: server.toMattermostTeam(),
|
||||
currentServers: ServerManager.getAllServers().map((server) => server.toUniqueServer()),
|
||||
server: server.toUniqueServer(),
|
||||
},
|
||||
mainWindow);
|
||||
if (modalPromise) {
|
||||
|
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
|
||||
import {
|
||||
handleCloseTab,
|
||||
handleOpenTab,
|
||||
} from './tabs';
|
||||
|
||||
jest.mock('common/servers/serverManager', () => ({
|
||||
setTabIsOpen: jest.fn(),
|
||||
getTab: jest.fn(),
|
||||
getLastActiveTabForServer: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('main/views/viewManager', () => ({
|
||||
showById: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('main/app/tabs', () => {
|
||||
describe('handleCloseTab', () => {
|
||||
it('should close the specified tab and switch to the next open tab', () => {
|
||||
ServerManager.getTab.mockReturnValue({server: {id: 'server-1'}});
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-2'});
|
||||
handleCloseTab(null, 'tab-3');
|
||||
expect(ServerManager.setTabIsOpen).toBeCalledWith('tab-3', false);
|
||||
expect(ViewManager.showById).toBeCalledWith('tab-2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleOpenTab', () => {
|
||||
it('should open the specified tab', () => {
|
||||
handleOpenTab(null, 'tab-1');
|
||||
expect(ViewManager.showById).toBeCalledWith('tab-1');
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,73 +0,0 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {IpcMainEvent, IpcMainInvokeEvent} from 'electron';
|
||||
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import {Logger} from 'common/log';
|
||||
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
|
||||
const log = new Logger('App.Tabs');
|
||||
|
||||
export const handleCloseTab = (event: IpcMainEvent, tabId: string) => {
|
||||
log.debug('handleCloseTab', {tabId});
|
||||
|
||||
const tab = ServerManager.getTab(tabId);
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
ServerManager.setTabIsOpen(tabId, false);
|
||||
const nextTab = ServerManager.getLastActiveTabForServer(tab.server.id);
|
||||
ViewManager.showById(nextTab.id);
|
||||
};
|
||||
|
||||
export const handleOpenTab = (event: IpcMainEvent, tabId: string) => {
|
||||
log.debug('handleOpenTab', {tabId});
|
||||
|
||||
ServerManager.setTabIsOpen(tabId, true);
|
||||
ViewManager.showById(tabId);
|
||||
};
|
||||
|
||||
export const selectNextTab = () => {
|
||||
selectTab((order) => order + 1);
|
||||
};
|
||||
|
||||
export const selectPreviousTab = () => {
|
||||
selectTab((order, length) => (length + (order - 1)));
|
||||
};
|
||||
|
||||
export const handleGetOrderedTabsForServer = (event: IpcMainInvokeEvent, serverId: string) => {
|
||||
return ServerManager.getOrderedTabsForServer(serverId).map((tab) => tab.toMattermostTab());
|
||||
};
|
||||
|
||||
export const handleGetLastActive = () => {
|
||||
const server = ServerManager.getCurrentServer();
|
||||
const tab = ServerManager.getLastActiveTabForServer(server.id);
|
||||
return {server: server.id, tab: tab.id};
|
||||
};
|
||||
|
||||
const selectTab = (fn: (order: number, length: number) => number) => {
|
||||
const currentView = ViewManager.getCurrentView();
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentTeamTabs = ServerManager.getOrderedTabsForServer(currentView.tab.server.id).map((tab, index) => ({tab, index}));
|
||||
const filteredTabs = currentTeamTabs?.filter((tab) => tab.tab.isOpen);
|
||||
const currentTab = currentTeamTabs?.find((tab) => tab.tab.type === currentView.tab.type);
|
||||
if (!currentTeamTabs || !currentTab || !filteredTabs) {
|
||||
return;
|
||||
}
|
||||
|
||||
let currentOrder = currentTab.index;
|
||||
let nextIndex = -1;
|
||||
while (nextIndex === -1) {
|
||||
const nextOrder = (fn(currentOrder, currentTeamTabs.length) % currentTeamTabs.length);
|
||||
nextIndex = filteredTabs.findIndex((tab) => tab.index === nextOrder);
|
||||
currentOrder = nextOrder;
|
||||
}
|
||||
|
||||
const newTab = filteredTabs[nextIndex].tab;
|
||||
ViewManager.showById(newTab.id);
|
||||
};
|
39
src/main/app/views.test.js
Normal file
39
src/main/app/views.test.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
|
||||
import {
|
||||
handleCloseView,
|
||||
handleOpenView,
|
||||
} from './views';
|
||||
|
||||
jest.mock('common/servers/serverManager', () => ({
|
||||
setViewIsOpen: jest.fn(),
|
||||
getView: jest.fn(),
|
||||
getLastActiveTabForServer: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('main/views/viewManager', () => ({
|
||||
showById: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('main/app/views', () => {
|
||||
describe('handleCloseView', () => {
|
||||
it('should close the specified view and switch to the next open view', () => {
|
||||
ServerManager.getView.mockReturnValue({server: {id: 'server-1'}});
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-2'});
|
||||
handleCloseView(null, 'view-3');
|
||||
expect(ServerManager.setViewIsOpen).toBeCalledWith('view-3', false);
|
||||
expect(ViewManager.showById).toBeCalledWith('view-2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleOpenView', () => {
|
||||
it('should open the specified view', () => {
|
||||
handleOpenView(null, 'view-1');
|
||||
expect(ViewManager.showById).toBeCalledWith('view-1');
|
||||
});
|
||||
});
|
||||
});
|
73
src/main/app/views.ts
Normal file
73
src/main/app/views.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {IpcMainEvent, IpcMainInvokeEvent} from 'electron';
|
||||
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import {Logger} from 'common/log';
|
||||
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
|
||||
const log = new Logger('App.Views');
|
||||
|
||||
export const handleCloseView = (event: IpcMainEvent, viewId: string) => {
|
||||
log.debug('handleCloseView', {viewId});
|
||||
|
||||
const view = ServerManager.getView(viewId);
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
ServerManager.setViewIsOpen(viewId, false);
|
||||
const nextView = ServerManager.getLastActiveTabForServer(view.server.id);
|
||||
ViewManager.showById(nextView.id);
|
||||
};
|
||||
|
||||
export const handleOpenView = (event: IpcMainEvent, viewId: string) => {
|
||||
log.debug('handleOpenView', {viewId});
|
||||
|
||||
ServerManager.setViewIsOpen(viewId, true);
|
||||
ViewManager.showById(viewId);
|
||||
};
|
||||
|
||||
export const selectNextView = () => {
|
||||
selectView((order) => order + 1);
|
||||
};
|
||||
|
||||
export const selectPreviousView = () => {
|
||||
selectView((order, length) => (length + (order - 1)));
|
||||
};
|
||||
|
||||
export const handleGetOrderedViewsForServer = (event: IpcMainInvokeEvent, serverId: string) => {
|
||||
return ServerManager.getOrderedTabsForServer(serverId).map((view) => view.toUniqueView());
|
||||
};
|
||||
|
||||
export const handleGetLastActive = () => {
|
||||
const server = ServerManager.getCurrentServer();
|
||||
const view = ServerManager.getLastActiveTabForServer(server.id);
|
||||
return {server: server.id, view: view.id};
|
||||
};
|
||||
|
||||
const selectView = (fn: (order: number, length: number) => number) => {
|
||||
const currentView = ViewManager.getCurrentView();
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentServerViews = ServerManager.getOrderedTabsForServer(currentView.view.server.id).map((view, index) => ({view, index}));
|
||||
const filteredViews = currentServerViews?.filter((view) => view.view.isOpen);
|
||||
const currentServerView = currentServerViews?.find((view) => view.view.type === currentView.view.type);
|
||||
if (!currentServerViews || !currentServerView || !filteredViews) {
|
||||
return;
|
||||
}
|
||||
|
||||
let currentOrder = currentServerView.index;
|
||||
let nextIndex = -1;
|
||||
while (nextIndex === -1) {
|
||||
const nextOrder = (fn(currentOrder, currentServerViews.length) % currentServerViews.length);
|
||||
nextIndex = filteredViews.findIndex((view) => view.index === nextOrder);
|
||||
currentOrder = nextOrder;
|
||||
}
|
||||
|
||||
const newView = filteredViews[nextIndex].view;
|
||||
ViewManager.showById(newView.id);
|
||||
};
|
@@ -7,54 +7,6 @@ import MainWindow from 'main/windows/mainWindow';
|
||||
import ModalManager from 'main/views/modalManager';
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
|
||||
jest.mock('common/config', () => ({
|
||||
teams: [{
|
||||
name: 'example',
|
||||
url: 'http://example.com',
|
||||
order: 0,
|
||||
tabs: [
|
||||
{
|
||||
name: 'TAB_MESSAGING',
|
||||
order: 0,
|
||||
isOpen: true,
|
||||
},
|
||||
{
|
||||
name: 'TAB_FOCALBOARD',
|
||||
order: 1,
|
||||
isOpen: true,
|
||||
},
|
||||
{
|
||||
name: 'TAB_PLAYBOOKS',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
],
|
||||
lastActiveTab: 0,
|
||||
}, {
|
||||
name: 'github',
|
||||
url: 'https://github.com/',
|
||||
order: 1,
|
||||
tabs: [
|
||||
{
|
||||
name: 'TAB_MESSAGING',
|
||||
order: 0,
|
||||
isOpen: true,
|
||||
},
|
||||
{
|
||||
name: 'TAB_FOCALBOARD',
|
||||
order: 1,
|
||||
isOpen: true,
|
||||
},
|
||||
{
|
||||
name: 'TAB_PLAYBOOKS',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
],
|
||||
lastActiveTab: 0,
|
||||
}],
|
||||
}));
|
||||
|
||||
jest.mock('common/utils/url', () => {
|
||||
const actualUrl = jest.requireActual('common/utils/url');
|
||||
return {
|
||||
@@ -116,35 +68,35 @@ describe('main/authManager', () => {
|
||||
});
|
||||
|
||||
it('should popLoginModal when isTrustedURL', () => {
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://trustedurl.com/')}}});
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://trustedurl.com/')}}});
|
||||
authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://trustedurl.com/'}, null, jest.fn());
|
||||
expect(authManager.popLoginModal).toBeCalled();
|
||||
expect(authManager.popPermissionModal).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should popLoginModal when isCustomLoginURL', () => {
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://customloginurl.com/')}}});
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://customloginurl.com/')}}});
|
||||
authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://customloginurl.com/'}, null, jest.fn());
|
||||
expect(authManager.popLoginModal).toBeCalled();
|
||||
expect(authManager.popPermissionModal).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should popLoginModal when has permission', () => {
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://haspermissionurl.com/')}}});
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://haspermissionurl.com/')}}});
|
||||
authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://haspermissionurl.com/'}, null, jest.fn());
|
||||
expect(authManager.popLoginModal).toBeCalled();
|
||||
expect(authManager.popPermissionModal).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should popPermissionModal when anything else is true', () => {
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://someotherurl.com/')}}});
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://someotherurl.com/')}}});
|
||||
authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://someotherurl.com/'}, null, jest.fn());
|
||||
expect(authManager.popLoginModal).not.toBeCalled();
|
||||
expect(authManager.popPermissionModal).toBeCalled();
|
||||
});
|
||||
|
||||
it('should set login callback when logging in', () => {
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://someotherurl.com/')}}});
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://someotherurl.com/')}}});
|
||||
const callback = jest.fn();
|
||||
authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://someotherurl.com/'}, null, callback);
|
||||
expect(authManager.loginCallbackMap.get('http://someotherurl.com/')).toEqual(callback);
|
||||
|
@@ -40,7 +40,7 @@ export class AuthManager {
|
||||
if (!parsedURL) {
|
||||
return;
|
||||
}
|
||||
const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.tab.server.url;
|
||||
const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.view.server.url;
|
||||
if (!serverURL) {
|
||||
return;
|
||||
}
|
||||
|
@@ -15,26 +15,26 @@ const stepDescriptiveName = 'serverConnectivity';
|
||||
|
||||
const run = async (logger: ElectronLog): Promise<DiagnosticStepResponse> => {
|
||||
try {
|
||||
const teams = ServerManager.getAllServers();
|
||||
const servers = ServerManager.getAllServers();
|
||||
|
||||
await Promise.all(teams.map(async (team) => {
|
||||
logger.debug('Pinging server: ', team.url);
|
||||
await Promise.all(servers.map(async (server) => {
|
||||
logger.debug('Pinging server: ', server.url);
|
||||
|
||||
if (!team.name || !team.url) {
|
||||
throw new Error(`Invalid server configuration. Team Url: ${team.url}, team name: ${team.name}`);
|
||||
if (!server.name || !server.url) {
|
||||
throw new Error(`Invalid server configuration. Server Url: ${server.url}, server name: ${server.name}`);
|
||||
}
|
||||
|
||||
const serverOnline = await isOnline(logger, `${team.url}/api/v4/system/ping`);
|
||||
const serverOnline = await isOnline(logger, `${server.url}/api/v4/system/ping`);
|
||||
|
||||
if (!serverOnline) {
|
||||
throw new Error(`Server appears to be offline. Team url: ${team.url}`);
|
||||
throw new Error(`Server appears to be offline. Server url: ${server.url}`);
|
||||
}
|
||||
}));
|
||||
|
||||
return {
|
||||
message: `${stepName} finished successfully`,
|
||||
succeeded: true,
|
||||
payload: teams,
|
||||
payload: servers,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.warn(`Diagnostics ${stepName} Failure`, {error});
|
||||
|
@@ -554,7 +554,7 @@ export class DownloadsManager extends JsonFileManager<DownloadedItems> {
|
||||
log.debug('doneEventController', {state});
|
||||
|
||||
if (state === 'completed' && !this.open) {
|
||||
displayDownloadCompleted(path.basename(item.savePath), item.savePath, ViewManager.getViewByWebContentsId(webContents.id)?.tab.server.name ?? '');
|
||||
displayDownloadCompleted(path.basename(item.savePath), item.savePath, ViewManager.getViewByWebContentsId(webContents.id)?.view.server.name ?? '');
|
||||
}
|
||||
|
||||
const bookmark = this.bookmarks.get(this.getFileId(item));
|
||||
|
@@ -67,8 +67,8 @@ jest.mock('main/windows/mainWindow', () => ({
|
||||
sendToRenderer: jest.fn(),
|
||||
}));
|
||||
jest.mock('main/windows/settingsWindow', () => ({}));
|
||||
jest.mock('common/tabs/TabView', () => ({
|
||||
getTabDisplayName: (name) => name,
|
||||
jest.mock('common/views/View', () => ({
|
||||
getViewDisplayName: (name) => name,
|
||||
}));
|
||||
|
||||
describe('main/menus/app', () => {
|
||||
@@ -88,19 +88,19 @@ describe('main/menus/app', () => {
|
||||
url: 'https:/ /github.com/',
|
||||
},
|
||||
];
|
||||
const tabs = [
|
||||
const views = [
|
||||
{
|
||||
id: 'tab-1',
|
||||
id: 'view-1',
|
||||
name: 'TAB_MESSAGING',
|
||||
isOpen: true,
|
||||
},
|
||||
{
|
||||
id: 'tab-2',
|
||||
id: 'view-2',
|
||||
name: 'TAB_FOCALBOARD',
|
||||
isOpen: true,
|
||||
},
|
||||
{
|
||||
id: 'tab-3',
|
||||
id: 'view-3',
|
||||
name: 'TAB_PLAYBOOKS',
|
||||
isOpen: true,
|
||||
},
|
||||
@@ -109,7 +109,7 @@ describe('main/menus/app', () => {
|
||||
beforeEach(() => {
|
||||
ServerManager.getCurrentServer.mockReturnValue(servers[0]);
|
||||
ServerManager.getOrderedServers.mockReturnValue(servers);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue(tabs);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue(views);
|
||||
getDarwinDoNotDisturb.mockReturnValue(false);
|
||||
});
|
||||
|
||||
@@ -217,7 +217,7 @@ describe('main/menus/app', () => {
|
||||
expect(signInOption).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should not show `Sign in to Another Server` if no teams are configured', () => {
|
||||
it('should not show `Sign in to Another Server` if no servers are configured', () => {
|
||||
localizeMessage.mockImplementation((id) => {
|
||||
switch (id) {
|
||||
case 'main.menus.app.file':
|
||||
@@ -247,15 +247,15 @@ describe('main/menus/app', () => {
|
||||
name: `server-${key}`,
|
||||
url: `http://server-${key}.com`,
|
||||
}));
|
||||
const modifiedTabs = [
|
||||
const modifiedViews = [
|
||||
{
|
||||
id: 'tab-1',
|
||||
id: 'view-1',
|
||||
type: 'TAB_MESSAGING',
|
||||
isOpen: true,
|
||||
},
|
||||
];
|
||||
ServerManager.getOrderedServers.mockReturnValue(modifiedServers);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedTabs);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedViews);
|
||||
const menu = createTemplate(config);
|
||||
const windowMenu = menu.find((item) => item.label === '&Window');
|
||||
for (let i = 0; i < 9; i++) {
|
||||
@@ -268,32 +268,32 @@ describe('main/menus/app', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should show the first 9 tabs (using order) in the Window menu', () => {
|
||||
it('should show the first 9 views (using order) in the Window menu', () => {
|
||||
localizeMessage.mockImplementation((id) => {
|
||||
if (id === 'main.menus.app.window') {
|
||||
return '&Window';
|
||||
}
|
||||
if (id.startsWith('common.tabs')) {
|
||||
return id.replace('common.tabs.', '');
|
||||
if (id.startsWith('common.views')) {
|
||||
return id.replace('common.views.', '');
|
||||
}
|
||||
return id;
|
||||
});
|
||||
ServerManager.getCurrentServer.mockImplementation(() => ({id: servers[0].id}));
|
||||
|
||||
const modifiedTabs = [...Array(15).keys()].map((key) => ({
|
||||
id: `tab-${key}`,
|
||||
type: `tab-${key}`,
|
||||
const modifiedViews = [...Array(15).keys()].map((key) => ({
|
||||
id: `view-${key}`,
|
||||
type: `view-${key}`,
|
||||
isOpen: true,
|
||||
}));
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedTabs);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedViews);
|
||||
const menu = createTemplate(config);
|
||||
const windowMenu = menu.find((item) => item.label === '&Window');
|
||||
for (let i = 0; i < 9; i++) {
|
||||
const menuItem = windowMenu.submenu.find((item) => item.label === ` tab-${i}`);
|
||||
const menuItem = windowMenu.submenu.find((item) => item.label === ` view-${i}`);
|
||||
expect(menuItem).not.toBe(undefined);
|
||||
}
|
||||
for (let i = 9; i < 15; i++) {
|
||||
const menuItem = windowMenu.submenu.find((item) => item.label === ` tab-${i}`);
|
||||
const menuItem = windowMenu.submenu.find((item) => item.label === ` view-${i}`);
|
||||
expect(menuItem).toBe(undefined);
|
||||
}
|
||||
});
|
||||
|
@@ -6,9 +6,9 @@
|
||||
import {app, ipcMain, Menu, MenuItemConstructorOptions, MenuItem, session, shell, WebContents, clipboard} from 'electron';
|
||||
import log from 'electron-log';
|
||||
|
||||
import {OPEN_TEAMS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication';
|
||||
import {OPEN_SERVERS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication';
|
||||
import {t} from 'common/utils/util';
|
||||
import {getTabDisplayName, TabType} from 'common/tabs/TabView';
|
||||
import {getViewDisplayName, ViewType} from 'common/views/View';
|
||||
import {Config} from 'common/config';
|
||||
|
||||
import {localizeMessage} from 'main/i18nManager';
|
||||
@@ -18,7 +18,7 @@ import downloadsManager from 'main/downloadsManager';
|
||||
import Diagnostics from 'main/diagnostics';
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
import SettingsWindow from 'main/windows/settingsWindow';
|
||||
import {selectNextTab, selectPreviousTab} from 'main/app/tabs';
|
||||
import {selectNextView, selectPreviousView} from 'main/app/views';
|
||||
import {switchServer} from 'main/app/servers';
|
||||
|
||||
export function createTemplate(config: Config, updateManager: UpdateManager) {
|
||||
@@ -233,7 +233,7 @@ export function createTemplate(config: Config, updateManager: UpdateManager) {
|
||||
}],
|
||||
});
|
||||
|
||||
const teams = ServerManager.getOrderedServers();
|
||||
const servers = ServerManager.getOrderedServers();
|
||||
const windowMenu = {
|
||||
id: 'window',
|
||||
label: localizeMessage('main.menus.app.window', '&Window'),
|
||||
@@ -257,25 +257,25 @@ export function createTemplate(config: Config, updateManager: UpdateManager) {
|
||||
label: localizeMessage('main.menus.app.window.showServers', 'Show Servers'),
|
||||
accelerator: `${process.platform === 'darwin' ? 'Cmd+Ctrl' : 'Ctrl+Shift'}+S`,
|
||||
click() {
|
||||
ipcMain.emit(OPEN_TEAMS_DROPDOWN);
|
||||
ipcMain.emit(OPEN_SERVERS_DROPDOWN);
|
||||
},
|
||||
}] : []),
|
||||
...teams.slice(0, 9).map((team, i) => {
|
||||
...servers.slice(0, 9).map((server, i) => {
|
||||
const items = [];
|
||||
items.push({
|
||||
label: team.name,
|
||||
label: server.name,
|
||||
accelerator: `${process.platform === 'darwin' ? 'Cmd+Ctrl' : 'Ctrl+Shift'}+${i + 1}`,
|
||||
click() {
|
||||
switchServer(team.id);
|
||||
switchServer(server.id);
|
||||
},
|
||||
});
|
||||
if (ServerManager.getCurrentServer().id === team.id) {
|
||||
ServerManager.getOrderedTabsForServer(team.id).slice(0, 9).forEach((tab, i) => {
|
||||
if (ServerManager.getCurrentServer().id === server.id) {
|
||||
ServerManager.getOrderedTabsForServer(server.id).slice(0, 9).forEach((view, i) => {
|
||||
items.push({
|
||||
label: ` ${localizeMessage(`common.tabs.${tab.type}`, getTabDisplayName(tab.type as TabType))}`,
|
||||
label: ` ${localizeMessage(`common.views.${view.type}`, getViewDisplayName(view.type as ViewType))}`,
|
||||
accelerator: `CmdOrCtrl+${i + 1}`,
|
||||
click() {
|
||||
ViewManager.showById(tab.id);
|
||||
ViewManager.showById(view.id);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -285,16 +285,16 @@ export function createTemplate(config: Config, updateManager: UpdateManager) {
|
||||
label: localizeMessage('main.menus.app.window.selectNextTab', 'Select Next Tab'),
|
||||
accelerator: 'Ctrl+Tab',
|
||||
click() {
|
||||
selectNextTab();
|
||||
selectNextView();
|
||||
},
|
||||
enabled: (teams.length > 1),
|
||||
enabled: (servers.length > 1),
|
||||
}, {
|
||||
label: localizeMessage('main.menus.app.window.selectPreviousTab', 'Select Previous Tab'),
|
||||
accelerator: 'Ctrl+Shift+Tab',
|
||||
click() {
|
||||
selectPreviousTab();
|
||||
selectPreviousView();
|
||||
},
|
||||
enabled: (teams.length > 1),
|
||||
enabled: (servers.length > 1),
|
||||
}, ...(isMac ? [separatorItem, {
|
||||
role: 'front',
|
||||
label: localizeMessage('main.menus.app.window.bringAllToFront', 'Bring All to Front'),
|
||||
|
@@ -12,13 +12,13 @@ import SettingsWindow from 'main/windows/settingsWindow';
|
||||
import {switchServer} from 'main/app/servers';
|
||||
|
||||
export function createTemplate() {
|
||||
const teams = ServerManager.getOrderedServers();
|
||||
const servers = ServerManager.getOrderedServers();
|
||||
const template = [
|
||||
...teams.slice(0, 9).map((team) => {
|
||||
...servers.slice(0, 9).map((server) => {
|
||||
return {
|
||||
label: team.name.length > 50 ? `${team.name.slice(0, 50)}...` : team.name,
|
||||
label: server.name.length > 50 ? `${server.name.slice(0, 50)}...` : server.name,
|
||||
click: () => {
|
||||
switchServer(team.id);
|
||||
switchServer(server.id);
|
||||
},
|
||||
};
|
||||
}), {
|
||||
|
@@ -76,7 +76,7 @@ jest.mock('macos-notification-state', () => ({
|
||||
jest.mock('../views/viewManager', () => ({
|
||||
getViewByWebContentsId: () => ({
|
||||
id: 'server_id',
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
name: 'server_name',
|
||||
},
|
||||
@@ -231,7 +231,7 @@ describe('main/notifications', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should switch tab when clicking on notification', () => {
|
||||
it('should switch view when clicking on notification', () => {
|
||||
displayMention(
|
||||
'click_test',
|
||||
'mention_click_body',
|
||||
|
@@ -40,7 +40,7 @@ export function displayMention(title: string, body: string, channel: {id: string
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
const serverName = view.tab.server.name;
|
||||
const serverName = view.view.server.name;
|
||||
|
||||
const options = {
|
||||
title: `${serverName}: ${title}`,
|
||||
|
@@ -10,10 +10,10 @@ import {
|
||||
GET_LANGUAGE_INFORMATION,
|
||||
QUIT,
|
||||
OPEN_APP_MENU,
|
||||
CLOSE_TEAMS_DROPDOWN,
|
||||
OPEN_TEAMS_DROPDOWN,
|
||||
CLOSE_SERVERS_DROPDOWN,
|
||||
OPEN_SERVERS_DROPDOWN,
|
||||
SWITCH_TAB,
|
||||
CLOSE_TAB,
|
||||
CLOSE_VIEW,
|
||||
WINDOW_CLOSE,
|
||||
WINDOW_MINIMIZE,
|
||||
WINDOW_MAXIMIZE,
|
||||
@@ -59,8 +59,8 @@ import {
|
||||
DOWNLOADS_DROPDOWN_MENU_OPEN_FILE,
|
||||
UPDATE_DOWNLOADS_DROPDOWN_MENU,
|
||||
REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO,
|
||||
UPDATE_TEAMS_DROPDOWN,
|
||||
REQUEST_TEAMS_DROPDOWN_INFO,
|
||||
UPDATE_SERVERS_DROPDOWN,
|
||||
REQUEST_SERVERS_DROPDOWN_INFO,
|
||||
RECEIVE_DROPDOWN_MENU_SIZE,
|
||||
SWITCH_SERVER,
|
||||
SHOW_NEW_SERVER_MODAL,
|
||||
@@ -111,10 +111,10 @@ contextBridge.exposeInMainWorld('mas', {
|
||||
contextBridge.exposeInMainWorld('desktop', {
|
||||
quit: (reason, stack) => ipcRenderer.send(QUIT, reason, stack),
|
||||
openAppMenu: () => ipcRenderer.send(OPEN_APP_MENU),
|
||||
closeTeamsDropdown: () => ipcRenderer.send(CLOSE_TEAMS_DROPDOWN),
|
||||
openTeamsDropdown: () => ipcRenderer.send(OPEN_TEAMS_DROPDOWN),
|
||||
switchTab: (tabId) => ipcRenderer.send(SWITCH_TAB, tabId),
|
||||
closeTab: (tabId) => ipcRenderer.send(CLOSE_TAB, tabId),
|
||||
closeServersDropdown: () => ipcRenderer.send(CLOSE_SERVERS_DROPDOWN),
|
||||
openServersDropdown: () => ipcRenderer.send(OPEN_SERVERS_DROPDOWN),
|
||||
switchTab: (viewId) => ipcRenderer.send(SWITCH_TAB, viewId),
|
||||
closeView: (viewId) => ipcRenderer.send(CLOSE_VIEW, viewId),
|
||||
closeWindow: () => ipcRenderer.send(WINDOW_CLOSE),
|
||||
minimizeWindow: () => ipcRenderer.send(WINDOW_MINIMIZE),
|
||||
maximizeWindow: () => ipcRenderer.send(WINDOW_MAXIMIZE),
|
||||
@@ -130,7 +130,7 @@ contextBridge.exposeInMainWorld('desktop', {
|
||||
updateConfiguration: (saveQueueItems) => ipcRenderer.send(UPDATE_CONFIGURATION, saveQueueItems),
|
||||
|
||||
updateServerOrder: (serverOrder) => ipcRenderer.send(UPDATE_SERVER_ORDER, serverOrder),
|
||||
updateTabOrder: (serverId, tabOrder) => ipcRenderer.send(UPDATE_TAB_ORDER, serverId, tabOrder),
|
||||
updateTabOrder: (serverId, viewOrder) => ipcRenderer.send(UPDATE_TAB_ORDER, serverId, viewOrder),
|
||||
getLastActive: () => ipcRenderer.invoke(GET_LAST_ACTIVE),
|
||||
getOrderedServers: () => ipcRenderer.invoke(GET_ORDERED_SERVERS),
|
||||
getOrderedTabsForServer: (serverId) => ipcRenderer.invoke(GET_ORDERED_TABS_FOR_SERVER, serverId),
|
||||
@@ -153,7 +153,7 @@ contextBridge.exposeInMainWorld('desktop', {
|
||||
onLoadRetry: (listener) => ipcRenderer.on(LOAD_RETRY, (_, viewId, retry, err, loadUrl) => listener(viewId, retry, err, loadUrl)),
|
||||
onLoadSuccess: (listener) => ipcRenderer.on(LOAD_SUCCESS, (_, viewId) => listener(viewId)),
|
||||
onLoadFailed: (listener) => ipcRenderer.on(LOAD_FAILED, (_, viewId, err, loadUrl) => listener(viewId, err, loadUrl)),
|
||||
onSetActiveView: (listener) => ipcRenderer.on(SET_ACTIVE_VIEW, (_, serverId, tabId) => listener(serverId, tabId)),
|
||||
onSetActiveView: (listener) => ipcRenderer.on(SET_ACTIVE_VIEW, (_, serverId, viewId) => listener(serverId, viewId)),
|
||||
onMaximizeChange: (listener) => ipcRenderer.on(MAXIMIZE_CHANGE, (_, maximize) => listener(maximize)),
|
||||
onEnterFullScreen: (listener) => ipcRenderer.on('enter-full-screen', () => listener()),
|
||||
onLeaveFullScreen: (listener) => ipcRenderer.on('leave-full-screen', () => listener()),
|
||||
@@ -162,8 +162,8 @@ contextBridge.exposeInMainWorld('desktop', {
|
||||
onModalClose: (listener) => ipcRenderer.on(MODAL_CLOSE, () => listener()),
|
||||
onToggleBackButton: (listener) => ipcRenderer.on(TOGGLE_BACK_BUTTON, (_, showExtraBar) => listener(showExtraBar)),
|
||||
onUpdateMentions: (listener) => ipcRenderer.on(UPDATE_MENTIONS, (_event, view, mentions, unreads, isExpired) => listener(view, mentions, unreads, isExpired)),
|
||||
onCloseTeamsDropdown: (listener) => ipcRenderer.on(CLOSE_TEAMS_DROPDOWN, () => listener()),
|
||||
onOpenTeamsDropdown: (listener) => ipcRenderer.on(OPEN_TEAMS_DROPDOWN, () => listener()),
|
||||
onCloseServersDropdown: (listener) => ipcRenderer.on(CLOSE_SERVERS_DROPDOWN, () => listener()),
|
||||
onOpenServersDropdown: (listener) => ipcRenderer.on(OPEN_SERVERS_DROPDOWN, () => listener()),
|
||||
onCloseDownloadsDropdown: (listener) => ipcRenderer.on(CLOSE_DOWNLOADS_DROPDOWN, () => listener()),
|
||||
onOpenDownloadsDropdown: (listener) => ipcRenderer.on(OPEN_DOWNLOADS_DROPDOWN, () => listener()),
|
||||
onShowDownloadsDropdownButtonBadge: (listener) => ipcRenderer.on(SHOW_DOWNLOADS_DROPDOWN_BUTTON_BADGE, () => listener()),
|
||||
@@ -195,29 +195,29 @@ contextBridge.exposeInMainWorld('desktop', {
|
||||
},
|
||||
|
||||
serverDropdown: {
|
||||
requestInfo: () => ipcRenderer.send(REQUEST_TEAMS_DROPDOWN_INFO),
|
||||
requestInfo: () => ipcRenderer.send(REQUEST_SERVERS_DROPDOWN_INFO),
|
||||
sendSize: (width, height) => ipcRenderer.send(RECEIVE_DROPDOWN_MENU_SIZE, width, height),
|
||||
switchServer: (serverId) => ipcRenderer.send(SWITCH_SERVER, serverId),
|
||||
showNewServerModal: () => ipcRenderer.send(SHOW_NEW_SERVER_MODAL),
|
||||
showEditServerModal: (serverId) => ipcRenderer.send(SHOW_EDIT_SERVER_MODAL, serverId),
|
||||
showRemoveServerModal: (serverId) => ipcRenderer.send(SHOW_REMOVE_SERVER_MODAL, serverId),
|
||||
|
||||
onUpdateServerDropdown: (listener) => ipcRenderer.on(UPDATE_TEAMS_DROPDOWN, (_,
|
||||
teams,
|
||||
activeTeam,
|
||||
onUpdateServerDropdown: (listener) => ipcRenderer.on(UPDATE_SERVERS_DROPDOWN, (_,
|
||||
servers,
|
||||
activeServer,
|
||||
darkMode,
|
||||
enableServerManagement,
|
||||
hasGPOTeams,
|
||||
hasGPOServers,
|
||||
expired,
|
||||
mentions,
|
||||
unreads,
|
||||
windowBounds,
|
||||
) => listener(
|
||||
teams,
|
||||
activeTeam,
|
||||
servers,
|
||||
activeServer,
|
||||
darkMode,
|
||||
enableServerManagement,
|
||||
hasGPOTeams,
|
||||
hasGPOServers,
|
||||
expired,
|
||||
mentions,
|
||||
unreads,
|
||||
|
@@ -20,7 +20,7 @@ import {
|
||||
SET_VIEW_OPTIONS,
|
||||
REACT_APP_INITIALIZED,
|
||||
USER_ACTIVITY_UPDATE,
|
||||
CLOSE_TEAMS_DROPDOWN,
|
||||
CLOSE_SERVERS_DROPDOWN,
|
||||
BROWSER_HISTORY_BUTTON,
|
||||
BROWSER_HISTORY_PUSH,
|
||||
APP_LOGGED_IN,
|
||||
@@ -272,7 +272,7 @@ function isDownloadLink(el) {
|
||||
}
|
||||
|
||||
window.addEventListener('click', (e) => {
|
||||
ipcRenderer.send(CLOSE_TEAMS_DROPDOWN);
|
||||
ipcRenderer.send(CLOSE_SERVERS_DROPDOWN);
|
||||
const el = e.target;
|
||||
if (!isDownloadLink(el)) {
|
||||
ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN);
|
||||
|
@@ -6,13 +6,13 @@
|
||||
import AppState from 'common/appState';
|
||||
import {LOAD_FAILED, TOGGLE_BACK_BUTTON, UPDATE_TARGET_URL} from 'common/communication';
|
||||
import {MattermostServer} from 'common/servers/MattermostServer';
|
||||
import MessagingTabView from 'common/tabs/MessagingTabView';
|
||||
import MessagingView from 'common/views/MessagingView';
|
||||
|
||||
import MainWindow from '../windows/mainWindow';
|
||||
import ContextMenu from '../contextMenu';
|
||||
import Utils from '../utils';
|
||||
|
||||
import {MattermostView} from './MattermostView';
|
||||
import {MattermostBrowserView} from './MattermostBrowserView';
|
||||
|
||||
jest.mock('electron', () => ({
|
||||
app: {
|
||||
@@ -59,12 +59,12 @@ jest.mock('../utils', () => ({
|
||||
}));
|
||||
|
||||
const server = new MattermostServer({name: 'server_name', url: 'http://server-1.com'});
|
||||
const tabView = new MessagingTabView(server, true);
|
||||
const view = new MessagingView(server, true);
|
||||
|
||||
describe('main/views/MattermostView', () => {
|
||||
describe('main/views/MattermostBrowserView', () => {
|
||||
describe('load', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
beforeEach(() => {
|
||||
MainWindow.get.mockReturnValue(window);
|
||||
@@ -74,38 +74,38 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
it('should load provided URL when provided', async () => {
|
||||
const promise = Promise.resolve();
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.load('http://server-2.com');
|
||||
await promise;
|
||||
expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-2.com/', expect.any(Object));
|
||||
expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-2.com/', expect.any(Object));
|
||||
expect(mattermostView.loadSuccess).toBeCalledWith('http://server-2.com/');
|
||||
});
|
||||
|
||||
it('should load server URL when not provided', async () => {
|
||||
const promise = Promise.resolve();
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.load();
|
||||
await promise;
|
||||
expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.loadSuccess).toBeCalledWith('http://server-1.com/');
|
||||
});
|
||||
|
||||
it('should load server URL when bad url provided', async () => {
|
||||
const promise = Promise.resolve();
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.load('a-bad<url');
|
||||
await promise;
|
||||
expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.loadSuccess).toBeCalledWith('http://server-1.com/');
|
||||
});
|
||||
|
||||
it('should call retry when failing to load', async () => {
|
||||
const error = new Error('test');
|
||||
const promise = Promise.reject(error);
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.load('a-bad<url');
|
||||
await expect(promise).rejects.toThrow(error);
|
||||
expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.loadRetry).toBeCalledWith('http://server-1.com/', error);
|
||||
});
|
||||
|
||||
@@ -113,23 +113,23 @@ describe('main/views/MattermostView', () => {
|
||||
const error = new Error('test');
|
||||
error.code = 'ERR_CERT_ERROR';
|
||||
const promise = Promise.reject(error);
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.load('a-bad<url');
|
||||
await expect(promise).rejects.toThrow(error);
|
||||
expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object));
|
||||
expect(mattermostView.loadRetry).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('retry', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
const retryInBackgroundFn = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
MainWindow.get.mockReturnValue(window);
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => Promise.resolve());
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => Promise.resolve());
|
||||
mattermostView.loadSuccess = jest.fn();
|
||||
mattermostView.loadRetry = jest.fn();
|
||||
mattermostView.emit = jest.fn();
|
||||
@@ -143,16 +143,16 @@ describe('main/views/MattermostView', () => {
|
||||
});
|
||||
|
||||
it('should do nothing when webcontents are destroyed', () => {
|
||||
const webContents = mattermostView.view.webContents;
|
||||
mattermostView.view.webContents = null;
|
||||
const webContents = mattermostView.browserView.webContents;
|
||||
mattermostView.browserView.webContents = null;
|
||||
mattermostView.retry('http://server-1.com')();
|
||||
expect(mattermostView.loadSuccess).not.toBeCalled();
|
||||
mattermostView.view.webContents = webContents;
|
||||
mattermostView.browserView.webContents = webContents;
|
||||
});
|
||||
|
||||
it('should call loadSuccess on successful load', async () => {
|
||||
const promise = Promise.resolve();
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.retry('http://server-1.com')();
|
||||
await promise;
|
||||
expect(mattermostView.loadSuccess).toBeCalledWith('http://server-1.com');
|
||||
@@ -162,10 +162,10 @@ describe('main/views/MattermostView', () => {
|
||||
mattermostView.maxRetries = 10;
|
||||
const error = new Error('test');
|
||||
const promise = Promise.reject(error);
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.retry('http://server-1.com')();
|
||||
await expect(promise).rejects.toThrow(error);
|
||||
expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object));
|
||||
expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object));
|
||||
expect(mattermostView.loadRetry).toBeCalledWith('http://server-1.com', error);
|
||||
});
|
||||
|
||||
@@ -173,12 +173,12 @@ describe('main/views/MattermostView', () => {
|
||||
mattermostView.maxRetries = 0;
|
||||
const error = new Error('test');
|
||||
const promise = Promise.reject(error);
|
||||
mattermostView.view.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise);
|
||||
mattermostView.retry('http://server-1.com')();
|
||||
await expect(promise).rejects.toThrow(error);
|
||||
expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object));
|
||||
expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object));
|
||||
expect(mattermostView.loadRetry).not.toBeCalled();
|
||||
expect(MainWindow.sendToRenderer).toBeCalledWith(LOAD_FAILED, mattermostView.tab.id, expect.any(String), expect.any(String));
|
||||
expect(MainWindow.sendToRenderer).toBeCalledWith(LOAD_FAILED, mattermostView.view.id, expect.any(String), expect.any(String));
|
||||
expect(mattermostView.status).toBe(-1);
|
||||
jest.runAllTimers();
|
||||
expect(retryInBackgroundFn).toBeCalled();
|
||||
@@ -187,7 +187,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('goToOffset', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
mattermostView.reload = jest.fn();
|
||||
|
||||
afterEach(() => {
|
||||
@@ -196,18 +196,18 @@ describe('main/views/MattermostView', () => {
|
||||
});
|
||||
|
||||
it('should only go to offset if it can', () => {
|
||||
mattermostView.view.webContents.canGoToOffset.mockReturnValue(false);
|
||||
mattermostView.browserView.webContents.canGoToOffset.mockReturnValue(false);
|
||||
mattermostView.goToOffset(1);
|
||||
expect(mattermostView.view.webContents.goToOffset).not.toBeCalled();
|
||||
expect(mattermostView.browserView.webContents.goToOffset).not.toBeCalled();
|
||||
|
||||
mattermostView.view.webContents.canGoToOffset.mockReturnValue(true);
|
||||
mattermostView.browserView.webContents.canGoToOffset.mockReturnValue(true);
|
||||
mattermostView.goToOffset(1);
|
||||
expect(mattermostView.view.webContents.goToOffset).toBeCalled();
|
||||
expect(mattermostView.browserView.webContents.goToOffset).toBeCalled();
|
||||
});
|
||||
|
||||
it('should call reload if an error occurs', () => {
|
||||
mattermostView.view.webContents.canGoToOffset.mockReturnValue(true);
|
||||
mattermostView.view.webContents.goToOffset.mockImplementation(() => {
|
||||
mattermostView.browserView.webContents.canGoToOffset.mockReturnValue(true);
|
||||
mattermostView.browserView.webContents.goToOffset.mockImplementation(() => {
|
||||
throw new Error('hi');
|
||||
});
|
||||
mattermostView.goToOffset(1);
|
||||
@@ -217,8 +217,8 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('onLogin', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
mattermostView.view.webContents.getURL = jest.fn();
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
mattermostView.browserView.webContents.getURL = jest.fn();
|
||||
mattermostView.reload = jest.fn();
|
||||
|
||||
afterEach(() => {
|
||||
@@ -227,19 +227,19 @@ describe('main/views/MattermostView', () => {
|
||||
});
|
||||
|
||||
it('should reload view when URL is not on subpath of original server URL', () => {
|
||||
mattermostView.view.webContents.getURL.mockReturnValue('http://server-2.com/subpath');
|
||||
mattermostView.browserView.webContents.getURL.mockReturnValue('http://server-2.com/subpath');
|
||||
mattermostView.onLogin(true);
|
||||
expect(mattermostView.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not reload if URLs are matching', () => {
|
||||
mattermostView.view.webContents.getURL.mockReturnValue('http://server-1.com');
|
||||
mattermostView.browserView.webContents.getURL.mockReturnValue('http://server-1.com');
|
||||
mattermostView.onLogin(true);
|
||||
expect(mattermostView.reload).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not reload if URL is subpath of server URL', () => {
|
||||
mattermostView.view.webContents.getURL.mockReturnValue('http://server-1.com/subpath');
|
||||
mattermostView.browserView.webContents.getURL.mockReturnValue('http://server-1.com/subpath');
|
||||
mattermostView.onLogin(true);
|
||||
expect(mattermostView.reload).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -247,7 +247,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('loadSuccess', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
@@ -275,7 +275,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('show', () => {
|
||||
const window = {addBrowserView: jest.fn(), removeBrowserView: jest.fn(), on: jest.fn(), setTopBrowserView: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
@@ -293,7 +293,7 @@ describe('main/views/MattermostView', () => {
|
||||
it('should add browser view to window and set bounds when request is true and view not currently visible', () => {
|
||||
mattermostView.isVisible = false;
|
||||
mattermostView.show();
|
||||
expect(window.addBrowserView).toBeCalledWith(mattermostView.view);
|
||||
expect(window.addBrowserView).toBeCalledWith(mattermostView.browserView);
|
||||
expect(mattermostView.setBounds).toBeCalled();
|
||||
expect(mattermostView.isVisible).toBe(true);
|
||||
});
|
||||
@@ -314,7 +314,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('hide', () => {
|
||||
const window = {addBrowserView: jest.fn(), removeBrowserView: jest.fn(), on: jest.fn(), setTopBrowserView: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
beforeEach(() => {
|
||||
MainWindow.get.mockReturnValue(window);
|
||||
@@ -323,7 +323,7 @@ describe('main/views/MattermostView', () => {
|
||||
it('should remove browser view', () => {
|
||||
mattermostView.isVisible = true;
|
||||
mattermostView.hide();
|
||||
expect(window.removeBrowserView).toBeCalledWith(mattermostView.view);
|
||||
expect(window.removeBrowserView).toBeCalledWith(mattermostView.browserView);
|
||||
expect(mattermostView.isVisible).toBe(false);
|
||||
});
|
||||
|
||||
@@ -336,7 +336,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('updateHistoryButton', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
beforeEach(() => {
|
||||
MainWindow.get.mockReturnValue(window);
|
||||
@@ -345,7 +345,7 @@ describe('main/views/MattermostView', () => {
|
||||
it('should erase history and set isAtRoot when navigating to root URL', () => {
|
||||
mattermostView.atRoot = false;
|
||||
mattermostView.updateHistoryButton();
|
||||
expect(mattermostView.view.webContents.clearHistory).toHaveBeenCalled();
|
||||
expect(mattermostView.browserView.webContents.clearHistory).toHaveBeenCalled();
|
||||
expect(mattermostView.isAtRoot).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -362,22 +362,22 @@ describe('main/views/MattermostView', () => {
|
||||
});
|
||||
|
||||
it('should remove browser view from window', () => {
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
mattermostView.view.webContents.destroy = jest.fn();
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
mattermostView.browserView.webContents.destroy = jest.fn();
|
||||
mattermostView.destroy();
|
||||
expect(window.removeBrowserView).toBeCalledWith(mattermostView.view);
|
||||
expect(window.removeBrowserView).toBeCalledWith(mattermostView.browserView);
|
||||
});
|
||||
|
||||
it('should clear mentions', () => {
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
mattermostView.view.webContents.destroy = jest.fn();
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
mattermostView.browserView.webContents.destroy = jest.fn();
|
||||
mattermostView.destroy();
|
||||
expect(AppState.clear).toBeCalledWith(mattermostView.tab.id);
|
||||
expect(AppState.clear).toBeCalledWith(mattermostView.view.id);
|
||||
});
|
||||
|
||||
it('should clear outstanding timeouts', () => {
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
mattermostView.view.webContents.destroy = jest.fn();
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
mattermostView.browserView.webContents.destroy = jest.fn();
|
||||
const spy = jest.spyOn(global, 'clearTimeout');
|
||||
mattermostView.retryLoad = 999;
|
||||
mattermostView.removeLoading = 1000;
|
||||
@@ -388,7 +388,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('handleInputEvents', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
it('should open three dot menu on pressing Alt', () => {
|
||||
MainWindow.get.mockReturnValue(window);
|
||||
@@ -413,7 +413,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('handleDidNavigate', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
beforeEach(() => {
|
||||
MainWindow.get.mockReturnValue(window);
|
||||
@@ -435,7 +435,7 @@ describe('main/views/MattermostView', () => {
|
||||
|
||||
describe('handleUpdateTarget', () => {
|
||||
const window = {on: jest.fn()};
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
beforeEach(() => {
|
||||
MainWindow.get.mockReturnValue(window);
|
||||
@@ -466,16 +466,16 @@ describe('main/views/MattermostView', () => {
|
||||
});
|
||||
|
||||
describe('updateMentionsFromTitle', () => {
|
||||
const mattermostView = new MattermostView(tabView, {}, {});
|
||||
const mattermostView = new MattermostBrowserView(view, {}, {});
|
||||
|
||||
it('should parse mentions from title', () => {
|
||||
mattermostView.updateMentionsFromTitle('(7) Mattermost');
|
||||
expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.tab.id, 7);
|
||||
expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.view.id, 7);
|
||||
});
|
||||
|
||||
it('should parse unreads from title', () => {
|
||||
mattermostView.updateMentionsFromTitle('* Mattermost');
|
||||
expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.tab.id, 0);
|
||||
expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.view.id, 0);
|
||||
});
|
||||
});
|
||||
});
|
@@ -23,7 +23,7 @@ import {
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import {Logger} from 'common/log';
|
||||
import {isInternalURL, parseURL} from 'common/utils/url';
|
||||
import {TabView} from 'common/tabs/TabView';
|
||||
import {MattermostView} from 'common/views/View';
|
||||
|
||||
import MainWindow from 'main/windows/mainWindow';
|
||||
|
||||
@@ -42,12 +42,12 @@ enum Status {
|
||||
const MENTIONS_GROUP = 2;
|
||||
const titleParser = /(\((\d+)\) )?(\* )?/g;
|
||||
|
||||
export class MattermostView extends EventEmitter {
|
||||
tab: TabView;
|
||||
export class MattermostBrowserView extends EventEmitter {
|
||||
view: MattermostView;
|
||||
isVisible: boolean;
|
||||
|
||||
private log: Logger;
|
||||
private view: BrowserView;
|
||||
private browserView: BrowserView;
|
||||
private loggedIn: boolean;
|
||||
private atRoot: boolean;
|
||||
private options: BrowserViewConstructorOptions;
|
||||
@@ -58,9 +58,9 @@ export class MattermostView extends EventEmitter {
|
||||
private maxRetries: number;
|
||||
private altPressStatus: boolean;
|
||||
|
||||
constructor(tab: TabView, options: BrowserViewConstructorOptions) {
|
||||
constructor(view: MattermostView, options: BrowserViewConstructorOptions) {
|
||||
super();
|
||||
this.tab = tab;
|
||||
this.view = view;
|
||||
|
||||
const preload = getLocalPreload('preload.js');
|
||||
this.options = Object.assign({}, options);
|
||||
@@ -75,24 +75,24 @@ export class MattermostView extends EventEmitter {
|
||||
this.isVisible = false;
|
||||
this.loggedIn = false;
|
||||
this.atRoot = true;
|
||||
this.view = new BrowserView(this.options);
|
||||
this.browserView = new BrowserView(this.options);
|
||||
this.resetLoadingStatus();
|
||||
|
||||
this.log = ServerManager.getViewLog(this.id, 'MattermostView');
|
||||
this.log = ServerManager.getViewLog(this.id, 'MattermostBrowserView');
|
||||
this.log.verbose('View created');
|
||||
|
||||
this.view.webContents.on('did-finish-load', this.handleDidFinishLoad);
|
||||
this.view.webContents.on('page-title-updated', this.handleTitleUpdate);
|
||||
this.view.webContents.on('page-favicon-updated', this.handleFaviconUpdate);
|
||||
this.view.webContents.on('update-target-url', this.handleUpdateTarget);
|
||||
this.view.webContents.on('did-navigate', this.handleDidNavigate);
|
||||
this.browserView.webContents.on('did-finish-load', this.handleDidFinishLoad);
|
||||
this.browserView.webContents.on('page-title-updated', this.handleTitleUpdate);
|
||||
this.browserView.webContents.on('page-favicon-updated', this.handleFaviconUpdate);
|
||||
this.browserView.webContents.on('update-target-url', this.handleUpdateTarget);
|
||||
this.browserView.webContents.on('did-navigate', this.handleDidNavigate);
|
||||
if (process.platform !== 'darwin') {
|
||||
this.view.webContents.on('before-input-event', this.handleInputEvents);
|
||||
this.browserView.webContents.on('before-input-event', this.handleInputEvents);
|
||||
}
|
||||
|
||||
WebContentsEventManager.addWebContentsEventListeners(this.view.webContents);
|
||||
WebContentsEventManager.addWebContentsEventListeners(this.browserView.webContents);
|
||||
|
||||
this.contextMenu = new ContextMenu({}, this.view);
|
||||
this.contextMenu = new ContextMenu({}, this.browserView);
|
||||
this.maxRetries = MAX_SERVER_RETRIES;
|
||||
|
||||
this.altPressStatus = false;
|
||||
@@ -105,7 +105,7 @@ export class MattermostView extends EventEmitter {
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.tab.id;
|
||||
return this.view.id;
|
||||
}
|
||||
get isAtRoot() {
|
||||
return this.atRoot;
|
||||
@@ -114,10 +114,10 @@ export class MattermostView extends EventEmitter {
|
||||
return this.loggedIn;
|
||||
}
|
||||
get currentURL() {
|
||||
return parseURL(this.view.webContents.getURL());
|
||||
return parseURL(this.browserView.webContents.getURL());
|
||||
}
|
||||
get webContentsId() {
|
||||
return this.view.webContents.id;
|
||||
return this.browserView.webContents.id;
|
||||
}
|
||||
|
||||
onLogin = (loggedIn: boolean) => {
|
||||
@@ -127,19 +127,19 @@ export class MattermostView extends EventEmitter {
|
||||
|
||||
this.loggedIn = loggedIn;
|
||||
|
||||
// If we're logging in from a different tab, force a reload
|
||||
// If we're logging in from a different view, force a reload
|
||||
if (loggedIn &&
|
||||
this.currentURL?.toString() !== this.tab.url.toString() &&
|
||||
!this.currentURL?.toString().startsWith(this.tab.url.toString())
|
||||
this.currentURL?.toString() !== this.view.url.toString() &&
|
||||
!this.currentURL?.toString().startsWith(this.view.url.toString())
|
||||
) {
|
||||
this.reload();
|
||||
}
|
||||
}
|
||||
|
||||
goToOffset = (offset: number) => {
|
||||
if (this.view.webContents.canGoToOffset(offset)) {
|
||||
if (this.browserView.webContents.canGoToOffset(offset)) {
|
||||
try {
|
||||
this.view.webContents.goToOffset(offset);
|
||||
this.browserView.webContents.goToOffset(offset);
|
||||
this.updateHistoryButton();
|
||||
} catch (error) {
|
||||
this.log.error(error);
|
||||
@@ -149,17 +149,17 @@ export class MattermostView extends EventEmitter {
|
||||
}
|
||||
|
||||
updateHistoryButton = () => {
|
||||
if (this.currentURL?.toString() === this.tab.url.toString()) {
|
||||
this.view.webContents.clearHistory();
|
||||
if (this.currentURL?.toString() === this.view.url.toString()) {
|
||||
this.browserView.webContents.clearHistory();
|
||||
this.atRoot = true;
|
||||
} else {
|
||||
this.atRoot = false;
|
||||
}
|
||||
this.view.webContents.send(BROWSER_HISTORY_BUTTON, this.view.webContents.canGoBack(), this.view.webContents.canGoForward());
|
||||
this.browserView.webContents.send(BROWSER_HISTORY_BUTTON, this.browserView.webContents.canGoBack(), this.browserView.webContents.canGoForward());
|
||||
}
|
||||
|
||||
load = (someURL?: URL | string) => {
|
||||
if (!this.tab) {
|
||||
if (!this.browserView) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -170,13 +170,13 @@ export class MattermostView extends EventEmitter {
|
||||
loadURL = parsedURL.toString();
|
||||
} else {
|
||||
this.log.error('Cannot parse provided url, using current server url', someURL);
|
||||
loadURL = this.tab.url.toString();
|
||||
loadURL = this.view.url.toString();
|
||||
}
|
||||
} else {
|
||||
loadURL = this.tab.url.toString();
|
||||
loadURL = this.view.url.toString();
|
||||
}
|
||||
this.log.verbose(`Loading ${loadURL}`);
|
||||
const loading = this.view.webContents.loadURL(loadURL, {userAgent: composeUserAgent()});
|
||||
const loading = this.browserView.webContents.loadURL(loadURL, {userAgent: composeUserAgent()});
|
||||
loading.then(this.loadSuccess(loadURL)).catch((err) => {
|
||||
if (err.code && err.code.startsWith('ERR_CERT')) {
|
||||
MainWindow.sendToRenderer(LOAD_FAILED, this.id, err.toString(), loadURL.toString());
|
||||
@@ -205,9 +205,9 @@ export class MattermostView extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
this.isVisible = true;
|
||||
mainWindow.addBrowserView(this.view);
|
||||
mainWindow.setTopBrowserView(this.view);
|
||||
this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.tab.url || '', this.currentURL)));
|
||||
mainWindow.addBrowserView(this.browserView);
|
||||
mainWindow.setTopBrowserView(this.browserView);
|
||||
this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.view.url || '', this.currentURL)));
|
||||
if (this.status === Status.READY) {
|
||||
this.focus();
|
||||
}
|
||||
@@ -216,7 +216,7 @@ export class MattermostView extends EventEmitter {
|
||||
hide = () => {
|
||||
if (this.isVisible) {
|
||||
this.isVisible = false;
|
||||
MainWindow.get()?.removeBrowserView(this.view);
|
||||
MainWindow.get()?.removeBrowserView(this.browserView);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,27 +226,27 @@ export class MattermostView extends EventEmitter {
|
||||
}
|
||||
|
||||
getBounds = () => {
|
||||
return this.view.getBounds();
|
||||
return this.browserView.getBounds();
|
||||
}
|
||||
|
||||
openFind = () => {
|
||||
this.view.webContents.sendInputEvent({type: 'keyDown', keyCode: 'F', modifiers: [process.platform === 'darwin' ? 'cmd' : 'ctrl', 'shift']});
|
||||
this.browserView.webContents.sendInputEvent({type: 'keyDown', keyCode: 'F', modifiers: [process.platform === 'darwin' ? 'cmd' : 'ctrl', 'shift']});
|
||||
}
|
||||
|
||||
setBounds = (boundaries: Electron.Rectangle) => {
|
||||
this.view.setBounds(boundaries);
|
||||
this.browserView.setBounds(boundaries);
|
||||
}
|
||||
|
||||
destroy = () => {
|
||||
WebContentsEventManager.removeWebContentsListeners(this.webContentsId);
|
||||
AppState.clear(this.id);
|
||||
MainWindow.get()?.removeBrowserView(this.view);
|
||||
MainWindow.get()?.removeBrowserView(this.browserView);
|
||||
|
||||
// workaround to eliminate zombie processes
|
||||
// https://github.com/mattermost/desktop/pull/1519
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
this.view.webContents.destroy();
|
||||
this.browserView.webContents.destroy();
|
||||
|
||||
this.isVisible = false;
|
||||
if (this.retryLoad) {
|
||||
@@ -293,7 +293,7 @@ export class MattermostView extends EventEmitter {
|
||||
}
|
||||
|
||||
openDevTools = () => {
|
||||
this.view.webContents.openDevTools({mode: 'detach'});
|
||||
this.browserView.webContents.openDevTools({mode: 'detach'});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,16 +301,16 @@ export class MattermostView extends EventEmitter {
|
||||
*/
|
||||
|
||||
sendToRenderer = (channel: string, ...args: any[]) => {
|
||||
this.view.webContents.send(channel, ...args);
|
||||
this.browserView.webContents.send(channel, ...args);
|
||||
}
|
||||
|
||||
isDestroyed = () => {
|
||||
return this.view.webContents.isDestroyed();
|
||||
return this.browserView.webContents.isDestroyed();
|
||||
}
|
||||
|
||||
focus = () => {
|
||||
if (this.view.webContents) {
|
||||
this.view.webContents.focus();
|
||||
if (this.browserView.webContents) {
|
||||
this.browserView.webContents.focus();
|
||||
} else {
|
||||
this.log.warn('trying to focus the browserview, but it doesn\'t yet have webcontents.');
|
||||
}
|
||||
@@ -361,7 +361,7 @@ export class MattermostView extends EventEmitter {
|
||||
// if favicon is null, it will affect appState, but won't be memoized
|
||||
private findUnreadState = (favicon: string | null) => {
|
||||
try {
|
||||
this.view.webContents.send(IS_UNREAD, favicon, this.id);
|
||||
this.browserView.webContents.send(IS_UNREAD, favicon, this.id);
|
||||
} catch (err: any) {
|
||||
this.log.error('There was an error trying to request the unread state', err);
|
||||
}
|
||||
@@ -388,17 +388,17 @@ export class MattermostView extends EventEmitter {
|
||||
private retry = (loadURL: string) => {
|
||||
return () => {
|
||||
// window was closed while retrying
|
||||
if (!this.view || !this.view.webContents) {
|
||||
if (!this.browserView || !this.browserView.webContents) {
|
||||
return;
|
||||
}
|
||||
const loading = this.view.webContents.loadURL(loadURL, {userAgent: composeUserAgent()});
|
||||
const loading = this.browserView.webContents.loadURL(loadURL, {userAgent: composeUserAgent()});
|
||||
loading.then(this.loadSuccess(loadURL)).catch((err) => {
|
||||
if (this.maxRetries-- > 0) {
|
||||
this.loadRetry(loadURL, err);
|
||||
} else {
|
||||
MainWindow.sendToRenderer(LOAD_FAILED, this.id, err.toString(), loadURL.toString());
|
||||
this.emit(LOAD_FAILED, this.id, err.toString(), loadURL.toString());
|
||||
this.log.info(`Couldn't establish a connection with ${loadURL}, will continue to retry in the background`, err);
|
||||
this.log.info(`Couldn't esviewlish a connection with ${loadURL}, will continue to retry in the background`, err);
|
||||
this.status = Status.ERROR;
|
||||
this.retryLoad = setTimeout(this.retryInBackground(loadURL), RELOAD_INTERVAL);
|
||||
}
|
||||
@@ -409,10 +409,10 @@ export class MattermostView extends EventEmitter {
|
||||
private retryInBackground = (loadURL: string) => {
|
||||
return () => {
|
||||
// window was closed while retrying
|
||||
if (!this.view || !this.view.webContents) {
|
||||
if (!this.browserView || !this.browserView.webContents) {
|
||||
return;
|
||||
}
|
||||
const loading = this.view.webContents.loadURL(loadURL, {userAgent: composeUserAgent()});
|
||||
const loading = this.browserView.webContents.loadURL(loadURL, {userAgent: composeUserAgent()});
|
||||
loading.then(this.loadSuccess(loadURL)).catch(() => {
|
||||
this.retryLoad = setTimeout(this.retryInBackground(loadURL), RELOAD_INTERVAL);
|
||||
});
|
||||
@@ -431,7 +431,7 @@ export class MattermostView extends EventEmitter {
|
||||
MainWindow.sendToRenderer(LOAD_SUCCESS, this.id);
|
||||
this.maxRetries = MAX_SERVER_RETRIES;
|
||||
if (this.status === Status.LOADING) {
|
||||
this.updateMentionsFromTitle(this.view.webContents.getTitle());
|
||||
this.updateMentionsFromTitle(this.browserView.webContents.getTitle());
|
||||
this.findUnreadState(null);
|
||||
}
|
||||
this.status = Status.WAITING_MM;
|
||||
@@ -439,7 +439,7 @@ export class MattermostView extends EventEmitter {
|
||||
this.emit(LOAD_SUCCESS, this.id, loadURL);
|
||||
const mainWindow = MainWindow.get();
|
||||
if (mainWindow && this.currentURL) {
|
||||
this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.tab.url || '', this.currentURL)));
|
||||
this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.view.url || '', this.currentURL)));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -453,13 +453,13 @@ export class MattermostView extends EventEmitter {
|
||||
|
||||
// wait for screen to truly finish loading before sending the message down
|
||||
const timeout = setInterval(() => {
|
||||
if (!this.view.webContents) {
|
||||
if (!this.browserView.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.view.webContents.isLoading()) {
|
||||
if (!this.browserView.webContents.isLoading()) {
|
||||
try {
|
||||
this.view.webContents.send(SET_VIEW_OPTIONS, this.id, this.tab.shouldNotify);
|
||||
this.browserView.webContents.send(SET_VIEW_OPTIONS, this.id, this.view.shouldNotify);
|
||||
clearTimeout(timeout);
|
||||
} catch (e) {
|
||||
this.log.error('failed to send view options to view');
|
||||
@@ -480,7 +480,7 @@ export class MattermostView extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldHaveBackBar(this.tab.url || '', parsedURL)) {
|
||||
if (shouldHaveBackBar(this.view.url || '', parsedURL)) {
|
||||
this.setBounds(getWindowBoundaries(mainWindow, true));
|
||||
MainWindow.sendToRenderer(TOGGLE_BACK_BUTTON, true);
|
||||
this.log.debug('show back button');
|
||||
@@ -494,7 +494,7 @@ export class MattermostView extends EventEmitter {
|
||||
private handleUpdateTarget = (e: Event, url: string) => {
|
||||
this.log.silly('handleUpdateTarget', url);
|
||||
const parsedURL = parseURL(url);
|
||||
if (parsedURL && isInternalURL(parsedURL, this.tab.server.url)) {
|
||||
if (parsedURL && isInternalURL(parsedURL, this.view.server.url)) {
|
||||
this.emit(UPDATE_TARGET_URL);
|
||||
} else {
|
||||
this.emit(UPDATE_TARGET_URL, url);
|
||||
@@ -502,7 +502,7 @@ export class MattermostView extends EventEmitter {
|
||||
}
|
||||
|
||||
private handleServerWasModified = (serverIds: string) => {
|
||||
if (serverIds.includes(this.tab.server.id)) {
|
||||
if (serverIds.includes(this.view.server.id)) {
|
||||
this.reload();
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ import {TAB_BAR_HEIGHT, THREE_DOT_MENU_WIDTH, THREE_DOT_MENU_WIDTH_MAC, MENU_SHA
|
||||
|
||||
import MainWindow from 'main/windows/mainWindow';
|
||||
|
||||
import {TeamDropdownView} from './teamDropdownView';
|
||||
import {ServerDropdownView} from './serverDropdownView';
|
||||
|
||||
jest.mock('main/utils', () => ({
|
||||
getLocalPreload: (file) => file,
|
||||
@@ -38,36 +38,36 @@ jest.mock('common/servers/serverManager', () => ({
|
||||
getOrderedServers: jest.fn().mockReturnValue([]),
|
||||
}));
|
||||
|
||||
describe('main/views/teamDropdownView', () => {
|
||||
describe('main/views/serverDropdownView', () => {
|
||||
describe('getBounds', () => {
|
||||
beforeEach(() => {
|
||||
MainWindow.getBounds.mockReturnValue({width: 500, height: 400, x: 0, y: 0});
|
||||
});
|
||||
|
||||
const teamDropdownView = new TeamDropdownView();
|
||||
const serverDropdownView = new ServerDropdownView();
|
||||
if (process.platform === 'darwin') {
|
||||
it('should account for three dot menu, tab bar and shadow', () => {
|
||||
expect(teamDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH_MAC - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300});
|
||||
expect(serverDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH_MAC - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300});
|
||||
});
|
||||
} else {
|
||||
it('should account for three dot menu, tab bar and shadow', () => {
|
||||
expect(teamDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300});
|
||||
expect(serverDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('should change the view bounds based on open/closed state', () => {
|
||||
const teamDropdownView = new TeamDropdownView();
|
||||
teamDropdownView.view = {
|
||||
const serverDropdownView = new ServerDropdownView();
|
||||
serverDropdownView.view = {
|
||||
setBounds: jest.fn(),
|
||||
webContents: {
|
||||
focus: jest.fn(),
|
||||
},
|
||||
};
|
||||
teamDropdownView.bounds = {width: 400, height: 300};
|
||||
teamDropdownView.handleOpen();
|
||||
expect(teamDropdownView.view.setBounds).toBeCalledWith(teamDropdownView.bounds);
|
||||
teamDropdownView.handleClose();
|
||||
expect(teamDropdownView.view.setBounds).toBeCalledWith({width: 0, height: 0, x: expect.any(Number), y: expect.any(Number)});
|
||||
serverDropdownView.bounds = {width: 400, height: 300};
|
||||
serverDropdownView.handleOpen();
|
||||
expect(serverDropdownView.view.setBounds).toBeCalledWith(serverDropdownView.bounds);
|
||||
serverDropdownView.handleClose();
|
||||
expect(serverDropdownView.view.setBounds).toBeCalledWith({width: 0, height: 0, x: expect.any(Number), y: expect.any(Number)});
|
||||
});
|
||||
});
|
@@ -3,16 +3,16 @@
|
||||
|
||||
import {BrowserView, ipcMain, IpcMainEvent} from 'electron';
|
||||
|
||||
import {MattermostTeam} from 'types/config';
|
||||
import {UniqueServer} from 'types/config';
|
||||
|
||||
import AppState from 'common/appState';
|
||||
import {
|
||||
CLOSE_TEAMS_DROPDOWN,
|
||||
CLOSE_SERVERS_DROPDOWN,
|
||||
EMIT_CONFIGURATION,
|
||||
OPEN_TEAMS_DROPDOWN,
|
||||
UPDATE_TEAMS_DROPDOWN,
|
||||
OPEN_SERVERS_DROPDOWN,
|
||||
UPDATE_SERVERS_DROPDOWN,
|
||||
UPDATE_APPSTATE,
|
||||
REQUEST_TEAMS_DROPDOWN_INFO,
|
||||
REQUEST_SERVERS_DROPDOWN_INFO,
|
||||
RECEIVE_DROPDOWN_MENU_SIZE,
|
||||
SERVERS_UPDATE,
|
||||
MAIN_WINDOW_CREATED,
|
||||
@@ -27,12 +27,12 @@ import {getLocalPreload, getLocalURLString} from 'main/utils';
|
||||
|
||||
import MainWindow from '../windows/mainWindow';
|
||||
|
||||
const log = new Logger('TeamDropdownView');
|
||||
const log = new Logger('ServerDropdownView');
|
||||
|
||||
export class TeamDropdownView {
|
||||
export class ServerDropdownView {
|
||||
private view?: BrowserView;
|
||||
private teams: MattermostTeam[];
|
||||
private hasGPOTeams: boolean;
|
||||
private servers: UniqueServer[];
|
||||
private hasGPOServers: boolean;
|
||||
private isOpen: boolean;
|
||||
private bounds: Electron.Rectangle;
|
||||
|
||||
@@ -43,8 +43,8 @@ export class TeamDropdownView {
|
||||
private windowBounds?: Electron.Rectangle;
|
||||
|
||||
constructor() {
|
||||
this.teams = [];
|
||||
this.hasGPOTeams = false;
|
||||
this.servers = [];
|
||||
this.hasGPOServers = false;
|
||||
this.isOpen = false;
|
||||
this.bounds = this.getBounds(0, 0);
|
||||
|
||||
@@ -55,12 +55,12 @@ export class TeamDropdownView {
|
||||
MainWindow.on(MAIN_WINDOW_CREATED, this.init);
|
||||
MainWindow.on(MAIN_WINDOW_RESIZED, this.updateWindowBounds);
|
||||
|
||||
ipcMain.on(OPEN_TEAMS_DROPDOWN, this.handleOpen);
|
||||
ipcMain.on(CLOSE_TEAMS_DROPDOWN, this.handleClose);
|
||||
ipcMain.on(OPEN_SERVERS_DROPDOWN, this.handleOpen);
|
||||
ipcMain.on(CLOSE_SERVERS_DROPDOWN, this.handleClose);
|
||||
ipcMain.on(RECEIVE_DROPDOWN_MENU_SIZE, this.handleReceivedMenuSize);
|
||||
|
||||
ipcMain.on(EMIT_CONFIGURATION, this.updateDropdown);
|
||||
ipcMain.on(REQUEST_TEAMS_DROPDOWN_INFO, this.updateDropdown);
|
||||
ipcMain.on(REQUEST_SERVERS_DROPDOWN_INFO, this.updateDropdown);
|
||||
|
||||
AppState.on(UPDATE_APPSTATE, this.updateMentions);
|
||||
ServerManager.on(SERVERS_UPDATE, this.updateServers);
|
||||
@@ -84,7 +84,7 @@ export class TeamDropdownView {
|
||||
}});
|
||||
this.view.webContents.loadURL(getLocalURLString('dropdown.html'));
|
||||
|
||||
this.setOrderedTeams();
|
||||
this.setOrderedServers();
|
||||
this.windowBounds = MainWindow.getBounds();
|
||||
this.updateDropdown();
|
||||
MainWindow.get()?.addBrowserView(this.view);
|
||||
@@ -94,13 +94,13 @@ export class TeamDropdownView {
|
||||
log.silly('updateDropdown');
|
||||
|
||||
this.view?.webContents.send(
|
||||
UPDATE_TEAMS_DROPDOWN,
|
||||
this.teams,
|
||||
UPDATE_SERVERS_DROPDOWN,
|
||||
this.servers,
|
||||
Config.darkMode,
|
||||
this.windowBounds,
|
||||
ServerManager.hasServers() ? ServerManager.getCurrentServer().id : undefined,
|
||||
Config.enableServerManagement,
|
||||
this.hasGPOTeams,
|
||||
this.hasGPOServers,
|
||||
this.expired,
|
||||
this.mentions,
|
||||
this.unreads,
|
||||
@@ -108,7 +108,7 @@ export class TeamDropdownView {
|
||||
}
|
||||
|
||||
private updateServers = () => {
|
||||
this.setOrderedTeams();
|
||||
this.setOrderedServers();
|
||||
this.updateDropdown();
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ export class TeamDropdownView {
|
||||
this.view.setBounds(this.bounds);
|
||||
MainWindow.get()?.setTopBrowserView(this.view);
|
||||
this.view.webContents.focus();
|
||||
MainWindow.sendToRenderer(OPEN_TEAMS_DROPDOWN);
|
||||
MainWindow.sendToRenderer(OPEN_SERVERS_DROPDOWN);
|
||||
this.isOpen = true;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ export class TeamDropdownView {
|
||||
log.debug('handleClose');
|
||||
|
||||
this.view?.setBounds(this.getBounds(0, 0));
|
||||
MainWindow.sendToRenderer(CLOSE_TEAMS_DROPDOWN);
|
||||
MainWindow.sendToRenderer(CLOSE_SERVERS_DROPDOWN);
|
||||
this.isOpen = false;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ export class TeamDropdownView {
|
||||
private reduceNotifications = <T>(inputMap: Map<string, T>, items: Map<string, T>, modifier: (base?: T, value?: T) => T) => {
|
||||
inputMap.clear();
|
||||
return [...items.keys()].reduce((map, key) => {
|
||||
const view = ServerManager.getTab(key);
|
||||
const view = ServerManager.getView(key);
|
||||
if (!view) {
|
||||
return map;
|
||||
}
|
||||
@@ -183,11 +183,11 @@ export class TeamDropdownView {
|
||||
}, inputMap);
|
||||
}
|
||||
|
||||
private setOrderedTeams = () => {
|
||||
this.teams = ServerManager.getOrderedServers().map((team) => team.toMattermostTeam());
|
||||
this.hasGPOTeams = this.teams.some((srv) => srv.isPredefined);
|
||||
private setOrderedServers = () => {
|
||||
this.servers = ServerManager.getOrderedServers().map((server) => server.toUniqueServer());
|
||||
this.hasGPOServers = this.servers.some((srv) => srv.isPredefined);
|
||||
}
|
||||
}
|
||||
|
||||
const teamDropdownView = new TeamDropdownView();
|
||||
export default teamDropdownView;
|
||||
const serverDropdownView = new ServerDropdownView();
|
||||
export default serverDropdownView;
|
@@ -7,13 +7,13 @@
|
||||
import {dialog} from 'electron';
|
||||
|
||||
import {BROWSER_HISTORY_PUSH, LOAD_SUCCESS, SET_ACTIVE_VIEW} from 'common/communication';
|
||||
import {TAB_MESSAGING} from 'common/tabs/TabView';
|
||||
import {TAB_MESSAGING} from 'common/views/View';
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import urlUtils from 'common/utils/url';
|
||||
|
||||
import MainWindow from 'main/windows/mainWindow';
|
||||
|
||||
import {MattermostView} from './MattermostView';
|
||||
import {MattermostBrowserView} from './MattermostBrowserView';
|
||||
import {ViewManager} from './viewManager';
|
||||
import LoadingScreen from './loadingScreen';
|
||||
|
||||
@@ -30,12 +30,9 @@ jest.mock('electron', () => ({
|
||||
handle: jest.fn(),
|
||||
},
|
||||
}));
|
||||
jest.mock('common/config', () => ({
|
||||
teams: [],
|
||||
}));
|
||||
jest.mock('common/tabs/TabView', () => ({
|
||||
getTabViewName: jest.fn((a, b) => `${a}-${b}`),
|
||||
TAB_MESSAGING: 'tab',
|
||||
jest.mock('common/views/View', () => ({
|
||||
getViewName: jest.fn((a, b) => `${a}-${b}`),
|
||||
TAB_MESSAGING: 'view',
|
||||
}));
|
||||
|
||||
jest.mock('common/servers/MattermostServer', () => ({
|
||||
@@ -79,7 +76,7 @@ jest.mock('common/servers/serverManager', () => ({
|
||||
getLastActiveServer: jest.fn(),
|
||||
getLastActiveTabForServer: jest.fn(),
|
||||
updateLastActive: jest.fn(),
|
||||
lookupTabByURL: jest.fn(),
|
||||
lookupViewByURL: jest.fn(),
|
||||
getRemoteInfo: jest.fn(),
|
||||
on: jest.fn(),
|
||||
getServerLog: () => ({
|
||||
@@ -100,8 +97,8 @@ jest.mock('common/servers/serverManager', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('./MattermostView', () => ({
|
||||
MattermostView: jest.fn(),
|
||||
jest.mock('./MattermostBrowserView', () => ({
|
||||
MattermostBrowserView: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('./modalManager', () => ({
|
||||
@@ -121,12 +118,12 @@ describe('main/views/viewManager', () => {
|
||||
beforeEach(() => {
|
||||
viewManager.showById = jest.fn();
|
||||
MainWindow.get.mockReturnValue({});
|
||||
MattermostView.mockImplementation((tab) => ({
|
||||
MattermostBrowserView.mockImplementation((view) => ({
|
||||
on: jest.fn(),
|
||||
load: loadFn,
|
||||
once: onceFn,
|
||||
destroy: destroyFn,
|
||||
id: tab.id,
|
||||
id: view.id,
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -136,21 +133,21 @@ describe('main/views/viewManager', () => {
|
||||
viewManager.views = new Map();
|
||||
});
|
||||
|
||||
it('should add closed tabs to closedViews', () => {
|
||||
viewManager.loadView({id: 'server1'}, {id: 'tab1', isOpen: false});
|
||||
expect(viewManager.closedViews.has('tab1')).toBe(true);
|
||||
it('should add closed views to closedViews', () => {
|
||||
viewManager.loadView({id: 'server1'}, {id: 'view1', isOpen: false});
|
||||
expect(viewManager.closedViews.has('view1')).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove from remove from closedViews when the tab is open', () => {
|
||||
viewManager.closedViews.set('tab1', {});
|
||||
expect(viewManager.closedViews.has('tab1')).toBe(true);
|
||||
viewManager.loadView({id: 'server1'}, {id: 'tab1', isOpen: true});
|
||||
expect(viewManager.closedViews.has('tab1')).toBe(false);
|
||||
it('should remove from remove from closedViews when the view is open', () => {
|
||||
viewManager.closedViews.set('view1', {});
|
||||
expect(viewManager.closedViews.has('view1')).toBe(true);
|
||||
viewManager.loadView({id: 'server1'}, {id: 'view1', isOpen: true});
|
||||
expect(viewManager.closedViews.has('view1')).toBe(false);
|
||||
});
|
||||
|
||||
it('should add view to views map and add listeners', () => {
|
||||
viewManager.loadView({id: 'server1'}, {id: 'tab1', isOpen: true}, 'http://server-1.com/subpath');
|
||||
expect(viewManager.views.has('tab1')).toBe(true);
|
||||
viewManager.loadView({id: 'server1'}, {id: 'view1', isOpen: true}, 'http://server-1.com/subpath');
|
||||
expect(viewManager.views.has('view1')).toBe(true);
|
||||
expect(onceFn).toHaveBeenCalledWith(LOAD_SUCCESS, viewManager.activateView);
|
||||
expect(loadFn).toHaveBeenCalledWith('http://server-1.com/subpath');
|
||||
});
|
||||
@@ -173,14 +170,14 @@ describe('main/views/viewManager', () => {
|
||||
const onceFn = jest.fn();
|
||||
const loadFn = jest.fn();
|
||||
const destroyFn = jest.fn();
|
||||
MattermostView.mockImplementation((tab) => ({
|
||||
MattermostBrowserView.mockImplementation((view) => ({
|
||||
on: jest.fn(),
|
||||
load: loadFn,
|
||||
once: onceFn,
|
||||
destroy: destroyFn,
|
||||
id: tab.id,
|
||||
id: view.id,
|
||||
updateServerInfo: jest.fn(),
|
||||
tab,
|
||||
view,
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -193,45 +190,45 @@ describe('main/views/viewManager', () => {
|
||||
|
||||
it('should recycle existing views', () => {
|
||||
const makeSpy = jest.spyOn(viewManager, 'makeView');
|
||||
const view = new MattermostView({
|
||||
id: 'tab1',
|
||||
const view = new MattermostBrowserView({
|
||||
id: 'view1',
|
||||
server: {
|
||||
id: 'server1',
|
||||
},
|
||||
});
|
||||
viewManager.views.set('tab1', view);
|
||||
viewManager.views.set('view1', view);
|
||||
ServerManager.getAllServers.mockReturnValue([{
|
||||
id: 'server1',
|
||||
url: new URL('http://server1.com'),
|
||||
}]);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue([
|
||||
{
|
||||
id: 'tab1',
|
||||
id: 'view1',
|
||||
isOpen: true,
|
||||
},
|
||||
]);
|
||||
viewManager.handleReloadConfiguration();
|
||||
expect(viewManager.views.get('tab1')).toBe(view);
|
||||
expect(viewManager.views.get('view1')).toBe(view);
|
||||
expect(makeSpy).not.toHaveBeenCalled();
|
||||
makeSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should close tabs that arent open', () => {
|
||||
it('should close views that arent open', () => {
|
||||
ServerManager.getAllServers.mockReturnValue([{
|
||||
id: 'server1',
|
||||
url: new URL('http://server1.com'),
|
||||
}]);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue([
|
||||
{
|
||||
id: 'tab1',
|
||||
id: 'view1',
|
||||
isOpen: false,
|
||||
},
|
||||
]);
|
||||
viewManager.handleReloadConfiguration();
|
||||
expect(viewManager.closedViews.has('tab1')).toBe(true);
|
||||
expect(viewManager.closedViews.has('view1')).toBe(true);
|
||||
});
|
||||
|
||||
it('should create new views for new tabs', () => {
|
||||
it('should create new views for new views', () => {
|
||||
const makeSpy = jest.spyOn(viewManager, 'makeView');
|
||||
ServerManager.getAllServers.mockReturnValue([{
|
||||
id: 'server1',
|
||||
@@ -240,10 +237,10 @@ describe('main/views/viewManager', () => {
|
||||
}]);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue([
|
||||
{
|
||||
id: 'tab1',
|
||||
name: 'tab1',
|
||||
id: 'view1',
|
||||
name: 'view1',
|
||||
isOpen: true,
|
||||
url: new URL('http://server1.com/tab'),
|
||||
url: new URL('http://server1.com/view'),
|
||||
},
|
||||
]);
|
||||
viewManager.handleReloadConfiguration();
|
||||
@@ -254,10 +251,10 @@ describe('main/views/viewManager', () => {
|
||||
url: new URL('http://server1.com'),
|
||||
},
|
||||
{
|
||||
id: 'tab1',
|
||||
name: 'tab1',
|
||||
id: 'view1',
|
||||
name: 'view1',
|
||||
isOpen: true,
|
||||
url: new URL('http://server1.com/tab'),
|
||||
url: new URL('http://server1.com/view'),
|
||||
},
|
||||
);
|
||||
makeSpy.mockRestore();
|
||||
@@ -265,27 +262,27 @@ describe('main/views/viewManager', () => {
|
||||
|
||||
it('should set focus to current view on reload', () => {
|
||||
const view = {
|
||||
id: 'tab1',
|
||||
tab: {
|
||||
id: 'view1',
|
||||
view: {
|
||||
server: {
|
||||
id: 'server-1',
|
||||
},
|
||||
id: 'tab1',
|
||||
id: 'view1',
|
||||
url: new URL('http://server1.com'),
|
||||
},
|
||||
destroy: jest.fn(),
|
||||
updateServerInfo: jest.fn(),
|
||||
focus: jest.fn(),
|
||||
};
|
||||
viewManager.currentView = 'tab1';
|
||||
viewManager.views.set('tab1', view);
|
||||
viewManager.currentView = 'view1';
|
||||
viewManager.views.set('view1', view);
|
||||
ServerManager.getAllServers.mockReturnValue([{
|
||||
id: 'server1',
|
||||
url: new URL('http://server1.com'),
|
||||
}]);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue([
|
||||
{
|
||||
id: 'tab1',
|
||||
id: 'view1',
|
||||
isOpen: true,
|
||||
},
|
||||
]);
|
||||
@@ -295,23 +292,23 @@ describe('main/views/viewManager', () => {
|
||||
|
||||
it('should show initial if currentView has been removed', () => {
|
||||
const view = {
|
||||
id: 'tab1',
|
||||
tab: {
|
||||
id: 'tab1',
|
||||
id: 'view1',
|
||||
view: {
|
||||
id: 'view1',
|
||||
url: new URL('http://server1.com'),
|
||||
},
|
||||
destroy: jest.fn(),
|
||||
updateServerInfo: jest.fn(),
|
||||
};
|
||||
viewManager.currentView = 'tab1';
|
||||
viewManager.views.set('tab1', view);
|
||||
viewManager.currentView = 'view1';
|
||||
viewManager.views.set('view1', view);
|
||||
ServerManager.getAllServers.mockReturnValue([{
|
||||
id: 'server2',
|
||||
url: new URL('http://server2.com'),
|
||||
}]);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue([
|
||||
{
|
||||
id: 'tab1',
|
||||
id: 'view1',
|
||||
isOpen: false,
|
||||
},
|
||||
]);
|
||||
@@ -321,21 +318,21 @@ describe('main/views/viewManager', () => {
|
||||
|
||||
it('should remove unused views', () => {
|
||||
const view = {
|
||||
name: 'tab1',
|
||||
tab: {
|
||||
name: 'tab1',
|
||||
name: 'view1',
|
||||
view: {
|
||||
name: 'view1',
|
||||
url: new URL('http://server1.com'),
|
||||
},
|
||||
destroy: jest.fn(),
|
||||
};
|
||||
viewManager.views.set('tab1', view);
|
||||
viewManager.views.set('view1', view);
|
||||
ServerManager.getAllServers.mockReturnValue([{
|
||||
id: 'server2',
|
||||
url: new URL('http://server2.com'),
|
||||
}]);
|
||||
ServerManager.getOrderedTabsForServer.mockReturnValue([
|
||||
{
|
||||
id: 'tab1',
|
||||
id: 'view1',
|
||||
isOpen: false,
|
||||
},
|
||||
]);
|
||||
@@ -360,11 +357,11 @@ describe('main/views/viewManager', () => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should show last active tab and server', () => {
|
||||
it('should show last active view and server', () => {
|
||||
ServerManager.getLastActiveServer.mockReturnValue({id: 'server-1'});
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-1'});
|
||||
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-1'});
|
||||
viewManager.showInitial();
|
||||
expect(viewManager.showById).toHaveBeenCalledWith('tab-1');
|
||||
expect(viewManager.showById).toHaveBeenCalledWith('view-1');
|
||||
});
|
||||
|
||||
it('should open new server modal when no servers exist', () => {
|
||||
@@ -385,7 +382,7 @@ describe('main/views/viewManager', () => {
|
||||
order: 0,
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab-messaging',
|
||||
name: 'view-messaging',
|
||||
order: 0,
|
||||
isOpen: true,
|
||||
},
|
||||
@@ -403,9 +400,9 @@ describe('main/views/viewManager', () => {
|
||||
},
|
||||
];
|
||||
const view1 = {
|
||||
id: 'server-1_tab-messaging',
|
||||
id: 'server-1_view-messaging',
|
||||
isLoggedIn: true,
|
||||
tab: {
|
||||
view: {
|
||||
type: TAB_MESSAGING,
|
||||
server: {
|
||||
url: 'http://server-1.com',
|
||||
@@ -416,21 +413,21 @@ describe('main/views/viewManager', () => {
|
||||
const view2 = {
|
||||
...view1,
|
||||
id: 'server-1_other_type_1',
|
||||
tab: {
|
||||
...view1.tab,
|
||||
view: {
|
||||
...view1.view,
|
||||
type: 'other_type_1',
|
||||
},
|
||||
};
|
||||
const view3 = {
|
||||
...view1,
|
||||
id: 'server-1_other_type_2',
|
||||
tab: {
|
||||
...view1.tab,
|
||||
view: {
|
||||
...view1.view,
|
||||
type: 'other_type_2',
|
||||
},
|
||||
};
|
||||
const views = new Map([
|
||||
['server-1_tab-messaging', view1],
|
||||
['server-1_view-messaging', view1],
|
||||
['server-1_other_type_1', view2],
|
||||
]);
|
||||
const closedViews = new Map([
|
||||
@@ -438,7 +435,7 @@ describe('main/views/viewManager', () => {
|
||||
]);
|
||||
viewManager.getView = (viewId) => views.get(viewId);
|
||||
viewManager.isViewClosed = (viewId) => closedViews.has(viewId);
|
||||
viewManager.openClosedTab = jest.fn();
|
||||
viewManager.openClosedView = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
ServerManager.getAllServers.mockReturnValue(servers);
|
||||
@@ -451,24 +448,24 @@ describe('main/views/viewManager', () => {
|
||||
});
|
||||
|
||||
it('should open closed view if pushing to it', () => {
|
||||
viewManager.openClosedTab.mockImplementation((name) => {
|
||||
viewManager.openClosedView.mockImplementation((name) => {
|
||||
const view = closedViews.get(name);
|
||||
closedViews.delete(name);
|
||||
views.set(name, view);
|
||||
});
|
||||
ServerManager.lookupTabByURL.mockReturnValue({id: 'server-1_other_type_2'});
|
||||
viewManager.handleBrowserHistoryPush(null, 'server-1_tab-messaging', '/other_type_2/subpath');
|
||||
expect(viewManager.openClosedTab).toBeCalledWith('server-1_other_type_2', 'http://server-1.com/other_type_2/subpath');
|
||||
ServerManager.lookupViewByURL.mockReturnValue({id: 'server-1_other_type_2'});
|
||||
viewManager.handleBrowserHistoryPush(null, 'server-1_view-messaging', '/other_type_2/subpath');
|
||||
expect(viewManager.openClosedView).toBeCalledWith('server-1_other_type_2', 'http://server-1.com/other_type_2/subpath');
|
||||
});
|
||||
|
||||
it('should open redirect view if different from current view', () => {
|
||||
ServerManager.lookupTabByURL.mockReturnValue({id: 'server-1_other_type_1'});
|
||||
viewManager.handleBrowserHistoryPush(null, 'server-1_tab-messaging', '/other_type_1/subpath');
|
||||
ServerManager.lookupViewByURL.mockReturnValue({id: 'server-1_other_type_1'});
|
||||
viewManager.handleBrowserHistoryPush(null, 'server-1_view-messaging', '/other_type_1/subpath');
|
||||
expect(viewManager.showById).toBeCalledWith('server-1_other_type_1');
|
||||
});
|
||||
|
||||
it('should ignore redirects to "/" to Messages from other tabs', () => {
|
||||
ServerManager.lookupTabByURL.mockReturnValue({id: 'server-1_tab-messaging'});
|
||||
it('should ignore redirects to "/" to Messages from other views', () => {
|
||||
ServerManager.lookupViewByURL.mockReturnValue({id: 'server-1_view-messaging'});
|
||||
viewManager.handleBrowserHistoryPush(null, 'server-1_other_type_1', '/');
|
||||
expect(view1.sendToRenderer).not.toBeCalled();
|
||||
});
|
||||
@@ -487,11 +484,11 @@ describe('main/views/viewManager', () => {
|
||||
send: jest.fn(),
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
name: 'server-1',
|
||||
},
|
||||
type: 'tab-1',
|
||||
type: 'view-1',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -510,9 +507,9 @@ describe('main/views/viewManager', () => {
|
||||
...baseView,
|
||||
isVisible: true,
|
||||
};
|
||||
viewManager.views.set('server1-tab1', view);
|
||||
viewManager.views.set('server1-view1', view);
|
||||
|
||||
viewManager.showById('server1-tab1');
|
||||
viewManager.showById('server1-view1');
|
||||
expect(viewManager.currentView).toBeUndefined();
|
||||
expect(view.isReady).not.toBeCalled();
|
||||
expect(view.show).not.toBeCalled();
|
||||
@@ -584,7 +581,7 @@ describe('main/views/viewManager', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
viewManager.openClosedTab = jest.fn();
|
||||
viewManager.openClosedView = jest.fn();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -594,7 +591,7 @@ describe('main/views/viewManager', () => {
|
||||
});
|
||||
|
||||
it('should load URL into matching view', () => {
|
||||
ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
const view = {...baseView};
|
||||
viewManager.views.set('view1', view);
|
||||
viewManager.handleDeepLink('mattermost://server-1.com/deep/link?thing=yes');
|
||||
@@ -602,11 +599,11 @@ describe('main/views/viewManager', () => {
|
||||
});
|
||||
|
||||
it('should send the URL to the view if its already loaded on a 6.0 server', () => {
|
||||
ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
ServerManager.getRemoteInfo.mockReturnValue({serverVersion: '6.0.0'});
|
||||
const view = {
|
||||
...baseView,
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
url: new URL('http://server-1.com'),
|
||||
},
|
||||
@@ -619,7 +616,7 @@ describe('main/views/viewManager', () => {
|
||||
});
|
||||
|
||||
it('should throw error if view is missing', () => {
|
||||
ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
const view = {...baseView};
|
||||
viewManager.handleDeepLink('mattermost://server-1.com/deep/link?thing=yes');
|
||||
expect(view.load).not.toHaveBeenCalled();
|
||||
@@ -632,11 +629,11 @@ describe('main/views/viewManager', () => {
|
||||
expect(dialog.showErrorBox).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reopen closed tab if called upon', () => {
|
||||
ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
it('should reopen closed view if called upon', () => {
|
||||
ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')}));
|
||||
viewManager.closedViews.set('view1', {});
|
||||
viewManager.handleDeepLink('mattermost://server-1.com/deep/link?thing=yes');
|
||||
expect(viewManager.openClosedTab).toHaveBeenCalledWith('view1', 'http://server-1.com/deep/link?thing=yes');
|
||||
expect(viewManager.openClosedView).toHaveBeenCalledWith('view1', 'http://server-1.com/deep/link?thing=yes');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -11,7 +11,7 @@ import {
|
||||
LOAD_FAILED,
|
||||
LOADSCREEN_END,
|
||||
SET_ACTIVE_VIEW,
|
||||
OPEN_TAB,
|
||||
OPEN_VIEW,
|
||||
BROWSER_HISTORY_PUSH,
|
||||
UPDATE_URL_VIEW_WIDTH,
|
||||
SERVERS_UPDATE,
|
||||
@@ -33,7 +33,7 @@ import {Logger} from 'common/log';
|
||||
import Utils from 'common/utils/util';
|
||||
import {MattermostServer} from 'common/servers/MattermostServer';
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import {TabView, TAB_MESSAGING} from 'common/tabs/TabView';
|
||||
import {MattermostView, TAB_MESSAGING} from 'common/views/View';
|
||||
import {parseURL} from 'common/utils/url';
|
||||
|
||||
import {localizeMessage} from 'main/i18nManager';
|
||||
@@ -41,7 +41,7 @@ import MainWindow from 'main/windows/mainWindow';
|
||||
|
||||
import {getLocalURLString, getLocalPreload, getAdjustedWindowBoundaries, shouldHaveBackBar} from '../utils';
|
||||
|
||||
import {MattermostView} from './MattermostView';
|
||||
import {MattermostBrowserView} from './MattermostBrowserView';
|
||||
import modalManager from './modalManager';
|
||||
import LoadingScreen from './loadingScreen';
|
||||
|
||||
@@ -50,14 +50,14 @@ const URL_VIEW_DURATION = 10 * SECOND;
|
||||
const URL_VIEW_HEIGHT = 20;
|
||||
|
||||
export class ViewManager {
|
||||
private closedViews: Map<string, {srv: MattermostServer; tab: TabView}>;
|
||||
private views: Map<string, MattermostView>;
|
||||
private closedViews: Map<string, {srv: MattermostServer; view: MattermostView}>;
|
||||
private views: Map<string, MattermostBrowserView>;
|
||||
private currentView?: string;
|
||||
|
||||
private urlViewCancel?: () => void;
|
||||
|
||||
constructor() {
|
||||
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 views on the renderer need that.
|
||||
this.closedViews = new Map();
|
||||
|
||||
MainWindow.on(MAIN_WINDOW_CREATED, this.init);
|
||||
@@ -102,23 +102,23 @@ export class ViewManager {
|
||||
return this.closedViews.has(viewId);
|
||||
}
|
||||
|
||||
showById = (tabId: string) => {
|
||||
this.getViewLogger(tabId).debug('showById', tabId);
|
||||
showById = (viewId: string) => {
|
||||
this.getViewLogger(viewId).debug('showById', viewId);
|
||||
|
||||
const newView = this.views.get(tabId);
|
||||
const newView = this.views.get(viewId);
|
||||
if (newView) {
|
||||
if (newView.isVisible) {
|
||||
return;
|
||||
}
|
||||
let hidePrevious;
|
||||
if (this.currentView && this.currentView !== tabId) {
|
||||
if (this.currentView && this.currentView !== viewId) {
|
||||
const previous = this.getCurrentView();
|
||||
if (previous) {
|
||||
hidePrevious = () => previous.hide();
|
||||
}
|
||||
}
|
||||
|
||||
this.currentView = tabId;
|
||||
this.currentView = viewId;
|
||||
if (!newView.isErrored()) {
|
||||
newView.show();
|
||||
if (newView.needsLoadingScreen()) {
|
||||
@@ -126,10 +126,10 @@ export class ViewManager {
|
||||
}
|
||||
}
|
||||
hidePrevious?.();
|
||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.tab.server.id, newView.tab.id);
|
||||
ServerManager.updateLastActive(newView.tab.id);
|
||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.view.server.id, newView.view.id);
|
||||
ServerManager.updateLastActive(newView.view.id);
|
||||
} else {
|
||||
this.getViewLogger(tabId).warn(`Couldn't find a view with name: ${tabId}`);
|
||||
this.getViewLogger(viewId).warn(`Couldn't find a view with name: ${viewId}`);
|
||||
}
|
||||
modalManager.showModal();
|
||||
}
|
||||
@@ -175,28 +175,28 @@ export class ViewManager {
|
||||
handleDeepLink = (url: string | URL) => {
|
||||
if (url) {
|
||||
const parsedURL = parseURL(url)!;
|
||||
const tabView = ServerManager.lookupTabByURL(parsedURL, true);
|
||||
if (tabView) {
|
||||
const urlWithSchema = `${tabView.url.origin}${parsedURL.pathname}${parsedURL.search}`;
|
||||
if (this.closedViews.has(tabView.id)) {
|
||||
this.openClosedTab(tabView.id, urlWithSchema);
|
||||
const view = ServerManager.lookupViewByURL(parsedURL, true);
|
||||
if (view) {
|
||||
const urlWithSchema = `${view.url.origin}${parsedURL.pathname}${parsedURL.search}`;
|
||||
if (this.closedViews.has(view.id)) {
|
||||
this.openClosedView(view.id, urlWithSchema);
|
||||
} else {
|
||||
const view = this.views.get(tabView.id);
|
||||
if (!view) {
|
||||
log.error(`Couldn't find a view matching the id ${tabView.id}`);
|
||||
const browserView = this.views.get(view.id);
|
||||
if (!browserView) {
|
||||
log.error(`Couldn't find a view matching the id ${view.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.isReady() && ServerManager.getRemoteInfo(view.tab.server.id)?.serverVersion && Utils.isVersionGreaterThanOrEqualTo(ServerManager.getRemoteInfo(view.tab.server.id)?.serverVersion ?? '', '6.0.0')) {
|
||||
const pathName = `/${urlWithSchema.replace(view.tab.server.url.toString(), '')}`;
|
||||
view.sendToRenderer(BROWSER_HISTORY_PUSH, pathName);
|
||||
this.deeplinkSuccess(view.id);
|
||||
if (browserView.isReady() && ServerManager.getRemoteInfo(browserView.view.server.id)?.serverVersion && Utils.isVersionGreaterThanOrEqualTo(ServerManager.getRemoteInfo(browserView.view.server.id)?.serverVersion ?? '', '6.0.0')) {
|
||||
const pathName = `/${urlWithSchema.replace(browserView.view.server.url.toString(), '')}`;
|
||||
browserView.sendToRenderer(BROWSER_HISTORY_PUSH, pathName);
|
||||
this.deeplinkSuccess(browserView.id);
|
||||
} 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);
|
||||
browserView.resetLoadingStatus();
|
||||
browserView.load(urlWithSchema);
|
||||
browserView.once(LOAD_SUCCESS, this.deeplinkSuccess);
|
||||
browserView.once(LOAD_FAILED, this.deeplinkFailed);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -225,35 +225,35 @@ export class ViewManager {
|
||||
*/
|
||||
|
||||
private loadServer = (server: MattermostServer) => {
|
||||
const tabs = ServerManager.getOrderedTabsForServer(server.id);
|
||||
tabs.forEach((tab) => this.loadView(server, tab));
|
||||
const views = ServerManager.getOrderedTabsForServer(server.id);
|
||||
views.forEach((view) => this.loadView(server, view));
|
||||
}
|
||||
|
||||
private loadView = (srv: MattermostServer, tab: TabView, url?: string) => {
|
||||
if (!tab.isOpen) {
|
||||
this.closedViews.set(tab.id, {srv, tab});
|
||||
private loadView = (srv: MattermostServer, view: MattermostView, url?: string) => {
|
||||
if (!view.isOpen) {
|
||||
this.closedViews.set(view.id, {srv, view});
|
||||
return;
|
||||
}
|
||||
const view = this.makeView(srv, tab, url);
|
||||
this.addView(view);
|
||||
const browserView = this.makeView(srv, view, url);
|
||||
this.addView(browserView);
|
||||
}
|
||||
|
||||
private makeView = (srv: MattermostServer, tab: TabView, url?: string): MattermostView => {
|
||||
private makeView = (srv: MattermostServer, view: MattermostView, url?: string): MattermostBrowserView => {
|
||||
const mainWindow = MainWindow.get();
|
||||
if (!mainWindow) {
|
||||
throw new Error('Cannot create view, no main window present');
|
||||
}
|
||||
|
||||
const view = new MattermostView(tab, {webPreferences: {spellcheck: Config.useSpellChecker}});
|
||||
view.once(LOAD_SUCCESS, this.activateView);
|
||||
view.on(LOADSCREEN_END, this.finishLoading);
|
||||
view.on(LOAD_FAILED, this.failLoading);
|
||||
view.on(UPDATE_TARGET_URL, this.showURLView);
|
||||
view.load(url);
|
||||
return view;
|
||||
const browserView = new MattermostBrowserView(view, {webPreferences: {spellcheck: Config.useSpellChecker}});
|
||||
browserView.once(LOAD_SUCCESS, this.activateView);
|
||||
browserView.on(LOADSCREEN_END, this.finishLoading);
|
||||
browserView.on(LOAD_FAILED, this.failLoading);
|
||||
browserView.on(UPDATE_TARGET_URL, this.showURLView);
|
||||
browserView.load(url);
|
||||
return browserView;
|
||||
}
|
||||
|
||||
private addView = (view: MattermostView): void => {
|
||||
private addView = (view: MattermostBrowserView): void => {
|
||||
this.views.set(view.id, view);
|
||||
if (this.closedViews.has(view.id)) {
|
||||
this.closedViews.delete(view.id);
|
||||
@@ -265,8 +265,8 @@ export class ViewManager {
|
||||
|
||||
if (ServerManager.hasServers()) {
|
||||
const lastActiveServer = ServerManager.getCurrentServer();
|
||||
const lastActiveTab = ServerManager.getLastActiveTabForServer(lastActiveServer.id);
|
||||
this.showById(lastActiveTab.id);
|
||||
const lastActiveView = ServerManager.getLastActiveTabForServer(lastActiveServer.id);
|
||||
this.showById(lastActiveView.id);
|
||||
} else {
|
||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW);
|
||||
}
|
||||
@@ -382,33 +382,33 @@ export class ViewManager {
|
||||
*/
|
||||
|
||||
/** Called when a new configuration is received
|
||||
* Servers or tabs have been added or edited. We need to
|
||||
* close, open, or reload tabs, taking care to reuse tabs and
|
||||
* preserve focus on the currently selected tab. */
|
||||
* Servers or views have been added or edited. We need to
|
||||
* close, open, or reload views, taking care to reuse views and
|
||||
* preserve focus on the currently selected view. */
|
||||
private handleReloadConfiguration = () => {
|
||||
log.debug('handleReloadConfiguration');
|
||||
|
||||
const currentTabId: string | undefined = this.views.get(this.currentView as string)?.tab.id;
|
||||
const currentViewId: string | undefined = this.views.get(this.currentView as string)?.view.id;
|
||||
|
||||
const current: Map<string, MattermostView> = new Map();
|
||||
const current: Map<string, MattermostBrowserView> = new Map();
|
||||
for (const view of this.views.values()) {
|
||||
current.set(view.tab.id, view);
|
||||
current.set(view.view.id, view);
|
||||
}
|
||||
|
||||
const views: Map<string, MattermostView> = new Map();
|
||||
const closed: Map<string, {srv: MattermostServer; tab: TabView}> = new Map();
|
||||
const views: Map<string, MattermostBrowserView> = new Map();
|
||||
const closed: Map<string, {srv: MattermostServer; view: MattermostView}> = new Map();
|
||||
|
||||
const sortedTabs = ServerManager.getAllServers().flatMap((x) => ServerManager.getOrderedTabsForServer(x.id).
|
||||
map((t): [MattermostServer, TabView] => [x, t]));
|
||||
const sortedViews = ServerManager.getAllServers().flatMap((x) => ServerManager.getOrderedTabsForServer(x.id).
|
||||
map((t): [MattermostServer, MattermostView] => [x, t]));
|
||||
|
||||
for (const [srv, tab] of sortedTabs) {
|
||||
const recycle = current.get(tab.id);
|
||||
if (!tab.isOpen) {
|
||||
closed.set(tab.id, {srv, tab});
|
||||
for (const [srv, view] of sortedViews) {
|
||||
const recycle = current.get(view.id);
|
||||
if (!view.isOpen) {
|
||||
closed.set(view.id, {srv, view});
|
||||
} else if (recycle) {
|
||||
views.set(tab.id, recycle);
|
||||
views.set(view.id, recycle);
|
||||
} else {
|
||||
views.set(tab.id, this.makeView(srv, tab));
|
||||
views.set(view.id, this.makeView(srv, view));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,10 +428,10 @@ export class ViewManager {
|
||||
|
||||
// commit closed
|
||||
for (const x of closed.values()) {
|
||||
this.closedViews.set(x.tab.id, {srv: x.srv, tab: x.tab});
|
||||
this.closedViews.set(x.view.id, {srv: x.srv, view: x.view});
|
||||
}
|
||||
|
||||
if ((currentTabId && closed.has(currentTabId)) || (this.currentView && this.closedViews.has(this.currentView))) {
|
||||
if ((currentViewId && closed.has(currentViewId)) || (this.currentView && this.closedViews.has(this.currentView))) {
|
||||
if (ServerManager.hasServers()) {
|
||||
this.currentView = undefined;
|
||||
this.showInitial();
|
||||
@@ -440,13 +440,13 @@ export class ViewManager {
|
||||
}
|
||||
}
|
||||
|
||||
// show the focused tab (or initial)
|
||||
if (currentTabId && views.has(currentTabId)) {
|
||||
const view = views.get(currentTabId);
|
||||
// show the focused view (or initial)
|
||||
if (currentViewId && views.has(currentViewId)) {
|
||||
const view = views.get(currentViewId);
|
||||
if (view && view.id !== this.currentView) {
|
||||
this.currentView = view.id;
|
||||
this.showById(view.id);
|
||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, view.tab.server.id, view.tab.id);
|
||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, view.view.server.id, view.view.id);
|
||||
} else {
|
||||
this.focusCurrentView();
|
||||
}
|
||||
@@ -475,17 +475,17 @@ export class ViewManager {
|
||||
return;
|
||||
}
|
||||
let cleanedPathName = pathName;
|
||||
if (currentView.tab.server.url.pathname !== '/' && pathName.startsWith(currentView.tab.server.url.pathname)) {
|
||||
cleanedPathName = pathName.replace(currentView.tab.server.url.pathname, '');
|
||||
if (currentView.view.server.url.pathname !== '/' && pathName.startsWith(currentView.view.server.url.pathname)) {
|
||||
cleanedPathName = pathName.replace(currentView.view.server.url.pathname, '');
|
||||
}
|
||||
const redirectedviewId = ServerManager.lookupTabByURL(`${currentView.tab.server.url.toString().replace(/\/$/, '')}${cleanedPathName}`)?.id || viewId;
|
||||
const redirectedviewId = ServerManager.lookupViewByURL(`${currentView.view.server.url.toString().replace(/\/$/, '')}${cleanedPathName}`)?.id || viewId;
|
||||
if (this.isViewClosed(redirectedviewId)) {
|
||||
// If it's a closed view, just open it and stop
|
||||
this.openClosedTab(redirectedviewId, `${currentView.tab.server.url}${cleanedPathName}`);
|
||||
this.openClosedView(redirectedviewId, `${currentView.view.server.url}${cleanedPathName}`);
|
||||
return;
|
||||
}
|
||||
let redirectedView = this.getView(redirectedviewId) || currentView;
|
||||
if (redirectedView !== currentView && redirectedView?.tab.server.id === ServerManager.getCurrentServer().id && redirectedView?.isLoggedIn) {
|
||||
if (redirectedView !== currentView && redirectedView?.view.server.id === ServerManager.getCurrentServer().id && redirectedView?.isLoggedIn) {
|
||||
log.info('redirecting to a new view', redirectedView?.id || viewId);
|
||||
this.showById(redirectedView?.id || viewId);
|
||||
} else {
|
||||
@@ -493,7 +493,7 @@ export class ViewManager {
|
||||
}
|
||||
|
||||
// Special case check for Channels to not force a redirect to "/", causing a refresh
|
||||
if (!(redirectedView !== currentView && redirectedView?.tab.type === TAB_MESSAGING && cleanedPathName === '/')) {
|
||||
if (!(redirectedView !== currentView && redirectedView?.view.type === TAB_MESSAGING && cleanedPathName === '/')) {
|
||||
redirectedView?.sendToRenderer(BROWSER_HISTORY_PUSH, cleanedPathName);
|
||||
if (redirectedView) {
|
||||
this.handleBrowserHistoryButton(e, redirectedView.id);
|
||||
@@ -547,7 +547,7 @@ export class ViewManager {
|
||||
|
||||
const currentView = this.getCurrentView();
|
||||
if (currentView && currentView.currentURL) {
|
||||
const adjustedBounds = getAdjustedWindowBoundaries(newBounds.width, newBounds.height, shouldHaveBackBar(currentView.tab.url, currentView.currentURL));
|
||||
const adjustedBounds = getAdjustedWindowBoundaries(newBounds.width, newBounds.height, shouldHaveBackBar(currentView.view.url, currentView.currentURL));
|
||||
currentView.setBounds(adjustedBounds);
|
||||
}
|
||||
}
|
||||
@@ -556,21 +556,21 @@ export class ViewManager {
|
||||
* Helper functions
|
||||
*/
|
||||
|
||||
private openClosedTab = (id: string, url?: string) => {
|
||||
private openClosedView = (id: string, url?: string) => {
|
||||
if (!this.closedViews.has(id)) {
|
||||
return;
|
||||
}
|
||||
const {srv, tab} = this.closedViews.get(id)!;
|
||||
tab.isOpen = true;
|
||||
this.loadView(srv, tab, url);
|
||||
const {srv, view} = this.closedViews.get(id)!;
|
||||
view.isOpen = true;
|
||||
this.loadView(srv, view, url);
|
||||
this.showById(id);
|
||||
const view = this.views.get(id)!;
|
||||
view.isVisible = true;
|
||||
view.on(LOAD_SUCCESS, () => {
|
||||
view.isVisible = false;
|
||||
const browserView = this.views.get(id)!;
|
||||
browserView.isVisible = true;
|
||||
browserView.on(LOAD_SUCCESS, () => {
|
||||
browserView.isVisible = false;
|
||||
this.showById(id);
|
||||
});
|
||||
ipcMain.emit(OPEN_TAB, null, tab.id);
|
||||
ipcMain.emit(OPEN_VIEW, null, view.id);
|
||||
}
|
||||
|
||||
private getViewLogger = (viewId: string) => {
|
||||
@@ -585,8 +585,8 @@ export class ViewManager {
|
||||
return {
|
||||
id: view.id,
|
||||
webContentsId: view.webContentsId,
|
||||
serverName: view.tab.server.name,
|
||||
tabType: view.tab.type,
|
||||
serverName: view.view.server.name,
|
||||
viewType: view.view.type,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ export class WebContentsEventManager {
|
||||
return CallsWidgetWindow.getURL();
|
||||
}
|
||||
|
||||
return ViewManager.getViewByWebContentsId(webContentsId)?.tab.server.url;
|
||||
return ViewManager.getViewByWebContentsId(webContentsId)?.view.server.url;
|
||||
}
|
||||
|
||||
private generateWillNavigate = (webContentsId: number) => {
|
||||
@@ -274,7 +274,7 @@ export class WebContentsEventManager {
|
||||
return {action: 'deny'};
|
||||
}
|
||||
|
||||
const otherServerURL = ServerManager.lookupTabByURL(parsedURL);
|
||||
const otherServerURL = ServerManager.lookupViewByURL(parsedURL);
|
||||
if (otherServerURL && isTeamUrl(otherServerURL.server.url, parsedURL, true)) {
|
||||
ViewManager.handleDeepLink(parsedURL);
|
||||
return {action: 'deny'};
|
||||
|
@@ -247,7 +247,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
title: 'call test title #/&',
|
||||
};
|
||||
callsWidgetWindow.mainView = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
url: new URL('http://localhost:8065'),
|
||||
},
|
||||
@@ -262,7 +262,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
|
||||
it('getWidgetURL - under subpath', () => {
|
||||
callsWidgetWindow.mainView = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
url: new URL('http://localhost:8065/subpath'),
|
||||
},
|
||||
@@ -339,7 +339,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
beforeEach(() => {
|
||||
callsWidgetWindow.options = {callID: 'id'};
|
||||
callsWidgetWindow.mainView = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
url: new URL('http://localhost:8065'),
|
||||
},
|
||||
@@ -491,7 +491,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
callsWidgetWindow.close = jest.fn();
|
||||
callsWidgetWindow.getWidgetURL = jest.fn();
|
||||
const view = {
|
||||
name: 'server-1_tab-messaging',
|
||||
name: 'server-1_view-messaging',
|
||||
serverInfo: {
|
||||
server: {
|
||||
url: new URL('http://server-1.com'),
|
||||
@@ -526,12 +526,12 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
|
||||
it('should create calls widget window', async () => {
|
||||
expect(callsWidgetWindow.win).toBeUndefined();
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'});
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test'});
|
||||
expect(callsWidgetWindow.win).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create with correct initial configuration', async () => {
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'});
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test'});
|
||||
expect(BrowserWindow).toHaveBeenCalledWith(expect.objectContaining({
|
||||
width: MINIMUM_CALLS_WIDGET_WIDTH,
|
||||
height: MINIMUM_CALLS_WIDGET_HEIGHT,
|
||||
@@ -560,7 +560,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
const window = {webContents: {id: 2}};
|
||||
callsWidgetWindow.win = window;
|
||||
callsWidgetWindow.options = {callID: 'test'};
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'});
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test'});
|
||||
expect(callsWidgetWindow.win).toEqual(window);
|
||||
});
|
||||
|
||||
@@ -568,7 +568,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
const window = {webContents: {id: 2}};
|
||||
callsWidgetWindow.win = window;
|
||||
callsWidgetWindow.getCallID = jest.fn(() => 'test');
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test2'});
|
||||
await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test2'});
|
||||
expect(callsWidgetWindow.win).not.toEqual(window);
|
||||
});
|
||||
});
|
||||
@@ -580,18 +580,18 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
send: jest.fn(),
|
||||
},
|
||||
};
|
||||
const teams = [
|
||||
const servers = [
|
||||
{
|
||||
name: 'server-1',
|
||||
order: 1,
|
||||
tabs: [
|
||||
views: [
|
||||
{
|
||||
name: 'tab-1',
|
||||
name: 'view-1',
|
||||
order: 0,
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
name: 'tab-2',
|
||||
name: 'view-2',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
@@ -599,24 +599,24 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
}, {
|
||||
name: 'server-2',
|
||||
order: 0,
|
||||
tabs: [
|
||||
views: [
|
||||
{
|
||||
name: 'tab-1',
|
||||
name: 'view-1',
|
||||
order: 0,
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
name: 'tab-2',
|
||||
name: 'view-2',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
],
|
||||
lastActiveTab: 2,
|
||||
lastActiveView: 2,
|
||||
},
|
||||
];
|
||||
const map = teams.reduce((arr, item) => {
|
||||
item.tabs.forEach((tab) => {
|
||||
arr.push([`${item.name}_${tab.name}`, {
|
||||
const map = servers.reduce((arr, item) => {
|
||||
item.views.forEach((view) => {
|
||||
arr.push([`${item.name}_${view.name}`, {
|
||||
sendToRenderer: jest.fn(),
|
||||
}]);
|
||||
});
|
||||
@@ -649,9 +649,9 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null);
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null);
|
||||
|
||||
expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledWith('desktop-sources-result', [
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('desktop-sources-result', [
|
||||
{
|
||||
id: 'screen0',
|
||||
},
|
||||
@@ -663,11 +663,11 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
|
||||
it('should send error with no sources', async () => {
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([]);
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-2_tab-1', null);
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-2_view-1', null);
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(views.get('server-2_tab-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
expect(views.get('server-2_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||
@@ -684,16 +684,16 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
]);
|
||||
jest.spyOn(systemPreferences, 'getMediaAccessStatus').mockReturnValue('denied');
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null);
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null);
|
||||
|
||||
expect(systemPreferences.getMediaAccessStatus).toHaveBeenCalledWith('screen');
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledTimes(1);
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledTimes(1);
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -713,7 +713,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
]);
|
||||
jest.spyOn(systemPreferences, 'getMediaAccessStatus').mockReturnValue('denied');
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null);
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null);
|
||||
|
||||
expect(callsWidgetWindow.missingScreensharePermissions).toBe(true);
|
||||
expect(resetScreensharePermissionsMacOS).toHaveBeenCalledTimes(1);
|
||||
@@ -721,11 +721,11 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null);
|
||||
await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null);
|
||||
|
||||
expect(resetScreensharePermissionsMacOS).toHaveBeenCalledTimes(2);
|
||||
expect(openScreensharePermissionsSettingsMacOS).toHaveBeenCalledTimes(1);
|
||||
@@ -739,25 +739,25 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
describe('handleDesktopSourcesModalRequest', () => {
|
||||
const callsWidgetWindow = new CallsWidgetWindow();
|
||||
callsWidgetWindow.mainView = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
id: 'server-1',
|
||||
},
|
||||
},
|
||||
sendToRenderer: jest.fn(),
|
||||
};
|
||||
const teams = [
|
||||
const servers = [
|
||||
{
|
||||
name: 'server-1',
|
||||
order: 1,
|
||||
tabs: [
|
||||
views: [
|
||||
{
|
||||
name: 'tab-1',
|
||||
name: 'view-1',
|
||||
order: 0,
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
name: 'tab-2',
|
||||
name: 'view-2',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
@@ -765,24 +765,24 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
}, {
|
||||
name: 'server-2',
|
||||
order: 0,
|
||||
tabs: [
|
||||
views: [
|
||||
{
|
||||
name: 'tab-1',
|
||||
name: 'view-1',
|
||||
order: 0,
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
name: 'tab-2',
|
||||
name: 'view-2',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
],
|
||||
lastActiveTab: 2,
|
||||
lastActiveView: 2,
|
||||
},
|
||||
];
|
||||
const map = teams.reduce((arr, item) => {
|
||||
item.tabs.forEach((tab) => {
|
||||
arr.push([`${item.name}_${tab.name}`, {}]);
|
||||
const map = servers.reduce((arr, item) => {
|
||||
item.views.forEach((view) => {
|
||||
arr.push([`${item.name}_${view.name}`, {}]);
|
||||
});
|
||||
return arr;
|
||||
}, []);
|
||||
@@ -805,7 +805,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
describe('handleCallsWidgetChannelLinkClick', () => {
|
||||
const callsWidgetWindow = new CallsWidgetWindow();
|
||||
callsWidgetWindow.mainView = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
id: 'server-2',
|
||||
},
|
||||
@@ -813,18 +813,18 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
sendToRenderer: jest.fn(),
|
||||
};
|
||||
callsWidgetWindow.getChannelURL = jest.fn();
|
||||
const teams = [
|
||||
const servers = [
|
||||
{
|
||||
name: 'server-1',
|
||||
order: 1,
|
||||
tabs: [
|
||||
views: [
|
||||
{
|
||||
name: 'tab-1',
|
||||
name: 'view-1',
|
||||
order: 0,
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
name: 'tab-2',
|
||||
name: 'view-2',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
@@ -832,24 +832,24 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
}, {
|
||||
name: 'server-2',
|
||||
order: 0,
|
||||
tabs: [
|
||||
views: [
|
||||
{
|
||||
name: 'tab-1',
|
||||
name: 'view-1',
|
||||
order: 0,
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
name: 'tab-2',
|
||||
name: 'view-2',
|
||||
order: 2,
|
||||
isOpen: true,
|
||||
},
|
||||
],
|
||||
lastActiveTab: 2,
|
||||
lastActiveView: 2,
|
||||
},
|
||||
];
|
||||
const map = teams.reduce((arr, item) => {
|
||||
item.tabs.forEach((tab) => {
|
||||
arr.push([`${item.name}_${tab.name}`, {}]);
|
||||
const map = servers.reduce((arr, item) => {
|
||||
item.views.forEach((view) => {
|
||||
arr.push([`${item.name}_${view.name}`, {}]);
|
||||
});
|
||||
return arr;
|
||||
}, []);
|
||||
@@ -872,7 +872,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
describe('handleCallsError', () => {
|
||||
const callsWidgetWindow = new CallsWidgetWindow();
|
||||
callsWidgetWindow.mainView = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
id: 'server-2',
|
||||
},
|
||||
@@ -899,7 +899,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
||||
|
||||
describe('handleCallsLinkClick', () => {
|
||||
const view = {
|
||||
tab: {
|
||||
view: {
|
||||
server: {
|
||||
id: 'server-1',
|
||||
},
|
||||
|
@@ -14,7 +14,7 @@ import {
|
||||
CallsWidgetWindowConfig,
|
||||
} from 'types/calls';
|
||||
|
||||
import {MattermostView} from 'main/views/MattermostView';
|
||||
import {MattermostBrowserView} from 'main/views/MattermostBrowserView';
|
||||
|
||||
import {getLocalPreload, openScreensharePermissionsSettingsMacOS, resetScreensharePermissionsMacOS} from 'main/utils';
|
||||
|
||||
@@ -47,7 +47,7 @@ const log = new Logger('CallsWidgetWindow');
|
||||
|
||||
export class CallsWidgetWindow {
|
||||
private win?: BrowserWindow;
|
||||
private mainView?: MattermostView;
|
||||
private mainView?: MattermostBrowserView;
|
||||
private options?: CallsWidgetWindowConfig;
|
||||
private missingScreensharePermissions?: boolean;
|
||||
|
||||
@@ -82,7 +82,7 @@ export class CallsWidgetWindow {
|
||||
}
|
||||
|
||||
private get serverID() {
|
||||
return this.mainView?.tab.server.id;
|
||||
return this.mainView?.view.server.id;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +101,7 @@ export class CallsWidgetWindow {
|
||||
if (!this.mainView) {
|
||||
return undefined;
|
||||
}
|
||||
const u = parseURL(this.mainView.tab.server.url.toString()) as URL;
|
||||
const u = parseURL(this.mainView.view.server.url.toString()) as URL;
|
||||
|
||||
u.pathname = getFormattedPathName(u.pathname);
|
||||
u.pathname += `plugins/${CALLS_PLUGIN_ID}/standalone/widget.html`;
|
||||
@@ -119,7 +119,7 @@ export class CallsWidgetWindow {
|
||||
return u.toString();
|
||||
}
|
||||
|
||||
private init = (view: MattermostView, options: CallsWidgetWindowConfig) => {
|
||||
private init = (view: MattermostBrowserView, options: CallsWidgetWindowConfig) => {
|
||||
this.win = new BrowserWindow({
|
||||
width: MINIMUM_CALLS_WIDGET_WIDTH,
|
||||
height: MINIMUM_CALLS_WIDGET_HEIGHT,
|
||||
@@ -271,7 +271,7 @@ export class CallsWidgetWindow {
|
||||
if (!parsedURL) {
|
||||
return {action: 'deny' as const};
|
||||
}
|
||||
if (isCallsPopOutURL(this.mainView?.tab.server.url, parsedURL, this.options?.callID)) {
|
||||
if (isCallsPopOutURL(this.mainView?.view.server.url, parsedURL, this.options?.callID)) {
|
||||
return {
|
||||
action: 'allow' as const,
|
||||
overrideBrowserWindowOptions: {
|
||||
|
@@ -421,7 +421,7 @@ describe('main/windows/mainWindow', () => {
|
||||
expect(window.setFullScreen).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should select tabs using alt+cmd+arrow keys on Mac', () => {
|
||||
it('should select views using alt+cmd+arrow keys on Mac', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'darwin',
|
||||
|
Reference in New Issue
Block a user