Merge and migrate locally-trusted preload scripts to contextBridge API (#2553)

* Migrate intl_provider to contextBridge

* Migrate modalPreload to contextBridge

* Migrate loadingScreenPreload to contextBridge

* Migrate downloadDropdown preloads to contextBridge

* Migrate server dropdown preload to contextBridge

* Migrate urlView preload to contextBridge

* Merge all desktop API scripts into one

* Remove unused communication channel constants
This commit is contained in:
Devin Binnie 2023-02-15 13:42:53 -05:00 committed by GitHub
parent 1c0aeae118
commit 5cc2e98a1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 438 additions and 821 deletions

View file

@ -41,10 +41,8 @@ export const SHOW_REMOVE_SERVER_MODAL = 'show-remove-server-modal';
export const MAIN_WINDOW_SHOWN = 'main-window-shown';
export const RETRIEVE_MODAL_INFO = 'retrieve-modal-info';
export const MODAL_INFO = 'modal-info';
export const MODAL_CANCEL = 'modal-cancel';
export const MODAL_RESULT = 'modal-result';
export const MODAL_SEND_IPC_MESSAGE = 'modal-send-ipc-message';
export const MODAL_OPEN = 'modal-open';
export const MODAL_CLOSE = 'modal-close';
export const NOTIFY_MENTION = 'notify_mention';
@ -74,8 +72,6 @@ export const TOGGLE_BACK_BUTTON = 'toggle-back-button';
export const SHOW_SETTINGS_WINDOW = 'show-settings-window';
export const RECEIVED_LOADING_SCREEN_DATA = 'received-loading-screen-data';
export const GET_LOADING_SCREEN_DATA = 'get-loading-screen-data';
export const LOADING_SCREEN_ANIMATION_FINISHED = 'loading-screen-animation-finished';
export const TOGGLE_LOADING_SCREEN_VISIBILITY = 'toggle-loading-screen-visibility';
@ -91,7 +87,6 @@ export const UPDATE_TEAMS_DROPDOWN = 'update-teams-dropdown';
export const UPDATE_DROPDOWN_MENTIONS = 'update-dropdown-mentions';
export const REQUEST_TEAMS_DROPDOWN_INFO = 'request-teams-dropdown-info';
export const RECEIVE_DROPDOWN_MENU_SIZE = 'receive-dropdown-menu-size';
export const SEND_DROPDOWN_MENU_SIZE = 'send-dropdown-menu-size';
export const UPDATE_AVAILABLE = 'update-available';
export const UPDATE_DOWNLOADED = 'update-downloaded';
@ -116,7 +111,6 @@ export const GET_VIEW_WEBCONTENTS_ID = 'get-view-webcontents-id';
export const RESIZE_MODAL = 'resize-modal';
export const GET_MODAL_UNCLOSEABLE = 'get-modal-uncloseable';
export const MODAL_UNCLOSEABLE = 'modal-uncloseable';
export const UPDATE_PATHS = 'update-paths';
@ -128,7 +122,6 @@ export const PING_DOMAIN = 'ping-domain';
export const PING_DOMAIN_RESPONSE = 'ping-domain-response';
export const GET_LANGUAGE_INFORMATION = 'get-language-information';
export const RETRIEVED_LANGUAGE_INFORMATION = 'retrieved-language-information';
export const GET_AVAILABLE_LANGUAGES = 'get-available-languages';
export const VIEW_FINISHED_RESIZING = 'view-finished-resizing';
@ -152,12 +145,10 @@ export const SHOW_DOWNLOADS_DROPDOWN_BUTTON_BADGE = 'show-downloads-dropdown-but
export const HIDE_DOWNLOADS_DROPDOWN_BUTTON_BADGE = 'hide-downloads-dropdown-button-badge';
export const REQUEST_DOWNLOADS_DROPDOWN_INFO = 'request-downloads-dropdown-info';
export const UPDATE_DOWNLOADS_DROPDOWN = 'update-downloads-dropdown';
export const DOWNLOADS_DROPDOWN_SHOW_FILE_IN_FOLDER = 'downloads-dropdown-show-file-in-folder';
export const DOWNLOADS_DROPDOWN_OPEN_FILE = 'downloads-dropdown-open-file';
export const REQUEST_HAS_DOWNLOADS = 'request-has-downloads';
export const DOWNLOADS_DROPDOWN_FOCUSED = 'downloads-dropdown-focused';
export const RECEIVE_DOWNLOADS_DROPDOWN_SIZE = 'receive-downloads-dropdown-size';
export const SEND_DOWNLOADS_DROPDOWN_SIZE = 'send-downloads-dropdown-size';
export const GET_DOWNLOADED_IMAGE_THUMBNAIL_LOCATION = 'get-downloaded-image-thumbnail-location';
export const OPEN_DOWNLOADS_DROPDOWN_MENU = 'open-downloads-dropdown-menu';

View file

@ -151,13 +151,13 @@ export function handleNewServerModal() {
const html = getLocalURLString('newServer.html');
const modalPreload = getLocalPreload('modalPreload.js');
const preload = getLocalPreload('desktopAPI.js');
const mainWindow = WindowManager.getMainWindow();
if (!mainWindow) {
return;
}
const modalPromise = ModalManager.addModal<TeamWithIndex[], Team>('newServer', html, modalPreload, Config.teams.map((team, index) => ({...team, index})), mainWindow, Config.teams.length === 0);
const modalPromise = ModalManager.addModal<TeamWithIndex[], Team>('newServer', html, preload, Config.teams.map((team, index) => ({...team, index})), mainWindow, Config.teams.length === 0);
if (modalPromise) {
modalPromise.then((data) => {
const teams = Config.teams;
@ -183,7 +183,7 @@ export function handleEditServerModal(e: IpcMainEvent, name: string) {
const html = getLocalURLString('editServer.html');
const modalPreload = getLocalPreload('modalPreload.js');
const preload = getLocalPreload('desktopAPI.js');
const mainWindow = WindowManager.getMainWindow();
if (!mainWindow) {
@ -196,7 +196,7 @@ export function handleEditServerModal(e: IpcMainEvent, name: string) {
const modalPromise = ModalManager.addModal<{currentTeams: TeamWithIndex[]; team: TeamWithIndex}, Team>(
'editServer',
html,
modalPreload,
preload,
{
currentTeams: Config.teams.map((team, index) => ({...team, index})),
team: {...Config.teams[serverIndex], index: serverIndex},
@ -225,13 +225,13 @@ export function handleRemoveServerModal(e: IpcMainEvent, name: string) {
const html = getLocalURLString('removeServer.html');
const modalPreload = getLocalPreload('modalPreload.js');
const preload = getLocalPreload('desktopAPI.js');
const mainWindow = WindowManager.getMainWindow();
if (!mainWindow) {
return;
}
const modalPromise = ModalManager.addModal<string, boolean>('removeServer', html, modalPreload, name, mainWindow);
const modalPromise = ModalManager.addModal<string, boolean>('removeServer', html, preload, name, mainWindow);
if (modalPromise) {
modalPromise.then((remove) => {
if (remove) {
@ -265,13 +265,13 @@ export function handleWelcomeScreenModal() {
const html = getLocalURLString('welcomeScreen.html');
const modalPreload = getLocalPreload('modalPreload.js');
const preload = getLocalPreload('desktopAPI.js');
const mainWindow = WindowManager.getMainWindow();
if (!mainWindow) {
return;
}
const modalPromise = ModalManager.addModal<TeamWithIndex[], Team>('welcomeScreen', html, modalPreload, Config.teams.map((team, index) => ({...team, index})), mainWindow, Config.teams.length === 0);
const modalPromise = ModalManager.addModal<TeamWithIndex[], Team>('welcomeScreen', html, preload, Config.teams.map((team, index) => ({...team, index})), mainWindow, Config.teams.length === 0);
if (modalPromise) {
modalPromise.then((data) => {
const teams = Config.teams;

View file

@ -14,7 +14,7 @@ import TrustedOriginsStore from 'main/trustedOrigins';
import {getLocalURLString, getLocalPreload} from 'main/utils';
import WindowManager from 'main/windows/windowManager';
const modalPreload = getLocalPreload('modalPreload.js');
const preload = getLocalPreload('desktopAPI.js');
const loginModalHtml = getLocalURLString('loginModal.html');
const permissionModalHtml = getLocalURLString('permissionModal.html');
@ -56,7 +56,7 @@ export class AuthManager {
if (!mainWindow) {
return;
}
const modalPromise = modalManager.addModal<LoginModalData, LoginModalResult>(authInfo.isProxy ? `proxy-${authInfo.host}` : `login-${request.url}`, loginModalHtml, modalPreload, {request, authInfo}, mainWindow);
const modalPromise = modalManager.addModal<LoginModalData, LoginModalResult>(authInfo.isProxy ? `proxy-${authInfo.host}` : `login-${request.url}`, loginModalHtml, preload, {request, authInfo}, mainWindow);
if (modalPromise) {
modalPromise.then((data) => {
const {username, password} = data;
@ -75,7 +75,7 @@ export class AuthManager {
if (!mainWindow) {
return;
}
const modalPromise = modalManager.addModal(`permission-${request.url}`, permissionModalHtml, modalPreload, {url: request.url, permission}, mainWindow);
const modalPromise = modalManager.addModal(`permission-${request.url}`, permissionModalHtml, preload, {url: request.url, permission}, mainWindow);
if (modalPromise) {
modalPromise.then(() => {
this.handlePermissionGranted(request.url, permission);

View file

@ -10,7 +10,7 @@ import WindowManager from './windows/windowManager';
import modalManager from './views/modalManager';
import {getLocalURLString, getLocalPreload} from './utils';
const modalPreload = getLocalPreload('modalPreload.js');
const preload = getLocalPreload('desktopAPI.js');
const html = getLocalURLString('certificateModal.html');
type CertificateModalResult = {
@ -43,7 +43,7 @@ export class CertificateManager {
if (!mainWindow) {
return;
}
const modalPromise = modalManager.addModal<CertificateModalData, CertificateModalResult>(`certificate-${url}`, html, modalPreload, {url, list}, mainWindow);
const modalPromise = modalManager.addModal<CertificateModalData, CertificateModalResult>(`certificate-${url}`, html, preload, {url, list}, mainWindow);
if (modalPromise) {
modalPromise.then((data) => {
const {cert} = data;

View file

@ -8,7 +8,6 @@ import {ipcRenderer, contextBridge} from 'electron';
import {
GET_LANGUAGE_INFORMATION,
RETRIEVED_LANGUAGE_INFORMATION,
QUIT,
GET_VIEW_NAME,
GET_VIEW_WEBCONTENTS_ID,
@ -56,6 +55,36 @@ import {
UPDATE_DOWNLOADS_DROPDOWN,
APP_MENU_WILL_CLOSE,
FOCUS_THREE_DOT_MENU,
UPDATE_URL_VIEW_WIDTH,
DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE,
DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER,
DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD,
DOWNLOADS_DROPDOWN_MENU_OPEN_FILE,
UPDATE_DOWNLOADS_DROPDOWN_MENU,
REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO,
UPDATE_TEAMS_DROPDOWN,
REQUEST_TEAMS_DROPDOWN_INFO,
RECEIVE_DROPDOWN_MENU_SIZE,
SWITCH_SERVER,
SHOW_NEW_SERVER_MODAL,
SHOW_EDIT_SERVER_MODAL,
SHOW_REMOVE_SERVER_MODAL,
RECEIVE_DOWNLOADS_DROPDOWN_SIZE,
REQUEST_CLEAR_DOWNLOADS_DROPDOWN,
REQUEST_DOWNLOADS_DROPDOWN_INFO,
START_UPDATE_DOWNLOAD,
START_UPGRADE,
TOGGLE_DOWNLOADS_DROPDOWN_MENU,
GET_DOWNLOADED_IMAGE_THUMBNAIL_LOCATION,
DOWNLOADS_DROPDOWN_OPEN_FILE,
MODAL_CANCEL,
MODAL_RESULT,
RETRIEVE_MODAL_INFO,
GET_MODAL_UNCLOSEABLE,
PING_DOMAIN,
LOADING_SCREEN_ANIMATION_FINISHED,
TOGGLE_LOADING_SCREEN_VISIBILITY,
DOWNLOADS_DROPDOWN_FOCUSED,
} from 'common/communication';
console.log('Preload initialized');
@ -79,6 +108,10 @@ contextBridge.exposeInMainWorld('timers', {
setImmediate,
});
contextBridge.exposeInMainWorld('mas', {
getThumbnailLocation: (location) => ipcRenderer.invoke(GET_DOWNLOADED_IMAGE_THUMBNAIL_LOCATION, location),
});
contextBridge.exposeInMainWorld('desktop', {
quit: (reason, stack) => ipcRenderer.send(QUIT, reason, stack),
openAppMenu: () => ipcRenderer.send(OPEN_APP_MENU),
@ -110,6 +143,7 @@ contextBridge.exposeInMainWorld('desktop', {
getAvailableLanguages: () => ipcRenderer.invoke(GET_AVAILABLE_LANGUAGES),
getLocalConfiguration: (option) => ipcRenderer.invoke(GET_LOCAL_CONFIGURATION, option),
getDownloadLocation: (downloadLocation) => ipcRenderer.invoke(GET_DOWNLOAD_LOCATION, downloadLocation),
getLanguageInformation: () => ipcRenderer.invoke(GET_LANGUAGE_INFORMATION),
onSynchronizeConfig: (listener) => ipcRenderer.on('synchronize-config', () => listener()),
onReloadConfiguration: (listener) => ipcRenderer.on(RELOAD_CONFIGURATION, () => listener()),
@ -132,15 +166,86 @@ contextBridge.exposeInMainWorld('desktop', {
onOpenDownloadsDropdown: (listener) => ipcRenderer.on(OPEN_DOWNLOADS_DROPDOWN, () => listener()),
onShowDownloadsDropdownButtonBadge: (listener) => ipcRenderer.on(SHOW_DOWNLOADS_DROPDOWN_BUTTON_BADGE, () => listener()),
onHideDownloadsDropdownButtonBadge: (listener) => ipcRenderer.on(HIDE_DOWNLOADS_DROPDOWN_BUTTON_BADGE, () => listener()),
onUpdateDownloadsDropdown: (listener) => ipcRenderer.on(UPDATE_DOWNLOADS_DROPDOWN, (_, downloads) => listener(downloads)),
onUpdateDownloadsDropdown: (listener) => ipcRenderer.on(UPDATE_DOWNLOADS_DROPDOWN, (_, downloads, darkMode, windowBounds, item) => listener(downloads, darkMode, windowBounds, item)),
onAppMenuWillClose: (listener) => ipcRenderer.on(APP_MENU_WILL_CLOSE, () => listener()),
onFocusThreeDotMenu: (listener) => ipcRenderer.on(FOCUS_THREE_DOT_MENU, () => listener()),
updateURLViewWidth: (width) => ipcRenderer.send(UPDATE_URL_VIEW_WIDTH, width),
downloadsDropdown: {
toggleDownloadsDropdownMenu: (payload) => ipcRenderer.send(TOGGLE_DOWNLOADS_DROPDOWN_MENU, payload),
requestInfo: () => ipcRenderer.send(REQUEST_DOWNLOADS_DROPDOWN_INFO),
sendSize: (width, height) => ipcRenderer.send(RECEIVE_DOWNLOADS_DROPDOWN_SIZE, width, height),
requestClearDownloadsDropdown: () => ipcRenderer.send(REQUEST_CLEAR_DOWNLOADS_DROPDOWN),
openFile: (item) => ipcRenderer.send(DOWNLOADS_DROPDOWN_OPEN_FILE, item),
startUpdateDownload: () => ipcRenderer.send(START_UPDATE_DOWNLOAD),
startUpgrade: () => ipcRenderer.send(START_UPGRADE),
focus: () => ipcRenderer.send(DOWNLOADS_DROPDOWN_FOCUSED),
},
downloadsDropdownMenu: {
requestInfo: () => ipcRenderer.send(REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO),
showInFolder: (item) => ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER, item),
cancelDownload: (item) => ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD, item),
clearFile: (item) => ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE, item),
openFile: (item) => ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_OPEN_FILE, item),
onUpdateDownloadsDropdownMenu: (listener) => ipcRenderer.on(UPDATE_DOWNLOADS_DROPDOWN_MENU, (_, item, darkMode) => listener(item, darkMode)),
},
serverDropdown: {
requestInfo: () => ipcRenderer.send(REQUEST_TEAMS_DROPDOWN_INFO),
sendSize: (width, height) => ipcRenderer.send(RECEIVE_DROPDOWN_MENU_SIZE, width, height),
switchServer: (server) => ipcRenderer.send(SWITCH_SERVER, server),
showNewServerModal: () => ipcRenderer.send(SHOW_NEW_SERVER_MODAL),
showEditServerModal: (serverName) => ipcRenderer.send(SHOW_EDIT_SERVER_MODAL, serverName),
showRemoveServerModal: (serverName) => ipcRenderer.send(SHOW_REMOVE_SERVER_MODAL, serverName),
onUpdateServerDropdown: (listener) => ipcRenderer.on(UPDATE_TEAMS_DROPDOWN, (_,
teams,
activeTeam,
darkMode,
enableServerManagement,
hasGPOTeams,
expired,
mentions,
unreads,
windowBounds,
) => listener(
teams,
activeTeam,
darkMode,
enableServerManagement,
hasGPOTeams,
expired,
mentions,
unreads,
windowBounds,
)),
},
loadingScreen: {
loadingScreenAnimationFinished: () => ipcRenderer.send(LOADING_SCREEN_ANIMATION_FINISHED),
onToggleLoadingScreenVisibility: (listener) => ipcRenderer.on(TOGGLE_LOADING_SCREEN_VISIBILITY, (_, toggle) => listener(toggle)),
},
modals: {
cancelModal: (data) => ipcRenderer.send(MODAL_CANCEL, data),
finishModal: (data) => ipcRenderer.send(MODAL_RESULT, data),
getModalInfo: () => ipcRenderer.invoke(RETRIEVE_MODAL_INFO),
isModalUncloseable: () => ipcRenderer.invoke(GET_MODAL_UNCLOSEABLE),
confirmProtocol: (protocol, url) => ipcRenderer.send('confirm-protocol', protocol, url),
pingDomain: (url) => ipcRenderer.invoke(PING_DOMAIN, url),
},
});
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case GET_LANGUAGE_INFORMATION:
window.postMessage({type: RETRIEVED_LANGUAGE_INFORMATION, data: await ipcRenderer.invoke(GET_LANGUAGE_INFORMATION)});
break;
}
});
// TODO: This is for modals only, should probably move this out for them
const createKeyDownListener = () => {
ipcRenderer.invoke(GET_MODAL_UNCLOSEABLE).then((uncloseable) => {
window.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !uncloseable) {
ipcRenderer.send(MODAL_CANCEL);
}
});
});
};
createKeyDownListener();

View file

@ -1,90 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
import {ipcRenderer, contextBridge} from 'electron';
import {
CLOSE_DOWNLOADS_DROPDOWN,
CLOSE_DOWNLOADS_DROPDOWN_MENU,
DOWNLOADS_DROPDOWN_FOCUSED,
DOWNLOADS_DROPDOWN_SHOW_FILE_IN_FOLDER,
GET_LANGUAGE_INFORMATION,
RECEIVE_DOWNLOADS_DROPDOWN_SIZE,
REQUEST_CLEAR_DOWNLOADS_DROPDOWN,
REQUEST_DOWNLOADS_DROPDOWN_INFO,
RETRIEVED_LANGUAGE_INFORMATION,
SEND_DOWNLOADS_DROPDOWN_SIZE,
START_UPDATE_DOWNLOAD,
START_UPGRADE,
TOGGLE_DOWNLOADS_DROPDOWN_MENU,
UPDATE_DOWNLOADS_DROPDOWN,
GET_DOWNLOADED_IMAGE_THUMBNAIL_LOCATION,
DOWNLOADS_DROPDOWN_OPEN_FILE,
} from 'common/communication';
console.log('preloaded for the downloadsDropdown!');
contextBridge.exposeInMainWorld('process', {
platform: process.platform,
});
contextBridge.exposeInMainWorld('mas', {
getThumbnailLocation: (location) => ipcRenderer.invoke(GET_DOWNLOADED_IMAGE_THUMBNAIL_LOCATION, location),
});
window.addEventListener('click', () => {
ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN_MENU);
});
window.addEventListener('mousemove', () => {
ipcRenderer.send(DOWNLOADS_DROPDOWN_FOCUSED);
});
/**
* renderer => main
*/
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case CLOSE_DOWNLOADS_DROPDOWN:
ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN);
break;
case TOGGLE_DOWNLOADS_DROPDOWN_MENU:
ipcRenderer.send(TOGGLE_DOWNLOADS_DROPDOWN_MENU, event.data.payload);
break;
case REQUEST_DOWNLOADS_DROPDOWN_INFO:
ipcRenderer.send(REQUEST_DOWNLOADS_DROPDOWN_INFO);
break;
case SEND_DOWNLOADS_DROPDOWN_SIZE:
ipcRenderer.send(RECEIVE_DOWNLOADS_DROPDOWN_SIZE, event.data.data.width, event.data.data.height);
break;
case REQUEST_CLEAR_DOWNLOADS_DROPDOWN:
ipcRenderer.send(REQUEST_CLEAR_DOWNLOADS_DROPDOWN);
break;
case DOWNLOADS_DROPDOWN_OPEN_FILE:
ipcRenderer.send(DOWNLOADS_DROPDOWN_OPEN_FILE, event.data.payload.item);
break;
case DOWNLOADS_DROPDOWN_SHOW_FILE_IN_FOLDER:
ipcRenderer.send(DOWNLOADS_DROPDOWN_SHOW_FILE_IN_FOLDER, event.data.payload.item);
break;
case START_UPDATE_DOWNLOAD:
ipcRenderer.send(START_UPDATE_DOWNLOAD);
break;
case START_UPGRADE:
ipcRenderer.send(START_UPGRADE);
break;
case GET_LANGUAGE_INFORMATION:
window.postMessage({type: RETRIEVED_LANGUAGE_INFORMATION, data: await ipcRenderer.invoke(GET_LANGUAGE_INFORMATION)});
break;
default:
console.log('Got an unknown message. Unknown messages are ignored');
}
});
/**
* main => renderer
*/
ipcRenderer.on(UPDATE_DOWNLOADS_DROPDOWN, (event, downloads, darkMode, windowBounds, item) => {
window.postMessage({type: UPDATE_DOWNLOADS_DROPDOWN, data: {downloads, darkMode, windowBounds, item}}, window.location.href);
});

View file

@ -1,58 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
import {ipcRenderer, contextBridge} from 'electron';
import {
GET_LANGUAGE_INFORMATION,
DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE,
RETRIEVED_LANGUAGE_INFORMATION,
DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER,
DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD,
DOWNLOADS_DROPDOWN_MENU_OPEN_FILE,
UPDATE_DOWNLOADS_DROPDOWN_MENU,
REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO,
} from 'common/communication';
console.log('preloaded for the downloadsDropdownMenu!');
contextBridge.exposeInMainWorld('process', {
platform: process.platform,
});
/**
* renderer => main
*/
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO:
ipcRenderer.send(REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO);
break;
case DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER:
ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER, event.data.payload.item);
break;
case DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD:
ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD, event.data.payload.item);
break;
case DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE:
ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE, event.data.payload.item);
break;
case DOWNLOADS_DROPDOWN_MENU_OPEN_FILE:
ipcRenderer.send(DOWNLOADS_DROPDOWN_MENU_OPEN_FILE, event.data.payload.item);
break;
case GET_LANGUAGE_INFORMATION:
window.postMessage({type: RETRIEVED_LANGUAGE_INFORMATION, data: await ipcRenderer.invoke(GET_LANGUAGE_INFORMATION)});
break;
default:
console.log('Got an unknown message. Unknown messages are ignored');
}
});
/**
* main => renderer
*/
ipcRenderer.on(UPDATE_DOWNLOADS_DROPDOWN_MENU, (event, item, darkMode) => {
window.postMessage({type: UPDATE_DOWNLOADS_DROPDOWN_MENU, data: {item, darkMode}}, window.location.href);
});

View file

@ -1,66 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
import {ipcRenderer, contextBridge} from 'electron';
import {
UPDATE_TEAMS_DROPDOWN,
REQUEST_TEAMS_DROPDOWN_INFO,
RECEIVE_DROPDOWN_MENU_SIZE,
SEND_DROPDOWN_MENU_SIZE,
SWITCH_SERVER,
CLOSE_TEAMS_DROPDOWN,
SHOW_NEW_SERVER_MODAL,
SHOW_EDIT_SERVER_MODAL,
SHOW_REMOVE_SERVER_MODAL,
UPDATE_TEAMS,
GET_LANGUAGE_INFORMATION,
RETRIEVED_LANGUAGE_INFORMATION,
} from 'common/communication';
console.log('preloaded for the dropdown!');
contextBridge.exposeInMainWorld('process', {
platform: process.platform,
});
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case REQUEST_TEAMS_DROPDOWN_INFO:
ipcRenderer.send(REQUEST_TEAMS_DROPDOWN_INFO);
break;
case SEND_DROPDOWN_MENU_SIZE:
ipcRenderer.send(RECEIVE_DROPDOWN_MENU_SIZE, event.data.data.width, event.data.data.height);
break;
case SWITCH_SERVER:
ipcRenderer.send(SWITCH_SERVER, event.data.data);
break;
case SHOW_NEW_SERVER_MODAL:
ipcRenderer.send(SHOW_NEW_SERVER_MODAL);
break;
case SHOW_EDIT_SERVER_MODAL:
ipcRenderer.send(SHOW_EDIT_SERVER_MODAL, event.data.data.name);
break;
case SHOW_REMOVE_SERVER_MODAL:
ipcRenderer.send(SHOW_REMOVE_SERVER_MODAL, event.data.data.name);
break;
case CLOSE_TEAMS_DROPDOWN:
ipcRenderer.send(CLOSE_TEAMS_DROPDOWN);
break;
case UPDATE_TEAMS:
ipcRenderer.invoke(UPDATE_TEAMS, event.data.data);
break;
case GET_LANGUAGE_INFORMATION:
window.postMessage({type: RETRIEVED_LANGUAGE_INFORMATION, data: await ipcRenderer.invoke(GET_LANGUAGE_INFORMATION)});
break;
default:
console.log(`got a message: ${event}`);
console.log(event);
}
});
ipcRenderer.on(UPDATE_TEAMS_DROPDOWN, (event, teams, activeTeam, darkMode, enableServerManagement, hasGPOTeams, expired, mentions, unreads, windowBounds) => {
window.postMessage({type: UPDATE_TEAMS_DROPDOWN, data: {teams, activeTeam, darkMode, enableServerManagement, hasGPOTeams, expired, mentions, unreads, windowBounds}}, window.location.href);
});

View file

@ -1,45 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// Copyright (c) 2015-2016 Yuya Ochiai
'use strict';
import {ipcRenderer} from 'electron';
import {
RECEIVED_LOADING_SCREEN_DATA,
GET_LOADING_SCREEN_DATA,
LOADING_SCREEN_ANIMATION_FINISHED,
TOGGLE_LOADING_SCREEN_VISIBILITY,
CLOSE_TEAMS_DROPDOWN,
CLOSE_DOWNLOADS_DROPDOWN,
} from 'common/communication';
console.log('preloaded for the loading screen!');
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case GET_LOADING_SCREEN_DATA:
window.postMessage({type: RECEIVED_LOADING_SCREEN_DATA, data: await ipcRenderer.invoke(GET_LOADING_SCREEN_DATA)}, window.location.href);
break;
case LOADING_SCREEN_ANIMATION_FINISHED:
ipcRenderer.send(LOADING_SCREEN_ANIMATION_FINISHED);
break;
default:
console.log(`got a message: ${event}`);
console.log(event);
}
});
ipcRenderer.on(GET_LOADING_SCREEN_DATA, (_, result) => {
window.postMessage({type: RECEIVED_LOADING_SCREEN_DATA, data: result}, window.location.href);
});
ipcRenderer.on(TOGGLE_LOADING_SCREEN_VISIBILITY, (_, toggle) => {
window.postMessage({type: TOGGLE_LOADING_SCREEN_VISIBILITY, data: toggle}, window.location.href);
});
window.addEventListener('click', () => {
ipcRenderer.send(CLOSE_TEAMS_DROPDOWN);
ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN);
});

View file

@ -1,88 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// Copyright (c) 2015-2016 Yuya Ochiai
'use strict';
import {ipcRenderer} from 'electron';
import {
MODAL_CANCEL,
MODAL_RESULT,
MODAL_INFO,
RETRIEVE_MODAL_INFO,
MODAL_SEND_IPC_MESSAGE,
GET_DARK_MODE,
DARK_MODE_CHANGE,
GET_MODAL_UNCLOSEABLE,
MODAL_UNCLOSEABLE,
PING_DOMAIN,
PING_DOMAIN_RESPONSE,
GET_LANGUAGE_INFORMATION,
RETRIEVED_LANGUAGE_INFORMATION,
} from 'common/communication';
console.log('preloaded for the modal!');
let uncloseable = false;
const createKeyDownListener = () => {
window.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !uncloseable) {
ipcRenderer.send(MODAL_CANCEL);
}
});
};
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case MODAL_CANCEL: {
console.log('canceling modal');
ipcRenderer.send(MODAL_CANCEL, event.data.data);
break;
}
case MODAL_RESULT: {
console.log(`accepting modal with ${event.data.data}`);
ipcRenderer.send(MODAL_RESULT, event.data.data);
break;
}
case RETRIEVE_MODAL_INFO:
console.log('getting modal data');
window.postMessage({type: MODAL_INFO, data: await ipcRenderer.invoke(RETRIEVE_MODAL_INFO)}, window.location.href);
break;
case GET_MODAL_UNCLOSEABLE:
console.log('get modal uncloseable');
uncloseable = await ipcRenderer.invoke(GET_MODAL_UNCLOSEABLE);
createKeyDownListener();
window.postMessage({type: MODAL_UNCLOSEABLE, data: uncloseable}, window.location.href);
break;
case MODAL_SEND_IPC_MESSAGE:
console.log('sending custom ipc message');
ipcRenderer.send(event.data.data.type, ...event.data.data.args);
break;
case GET_DARK_MODE:
console.log('getting dark mode value');
window.postMessage({type: DARK_MODE_CHANGE, data: await ipcRenderer.invoke(GET_DARK_MODE)}, window.location.href);
break;
case PING_DOMAIN:
console.log('pinging domain: ' + event.data.data);
try {
const protocol = await ipcRenderer.invoke(PING_DOMAIN, event.data.data);
window.postMessage({type: PING_DOMAIN_RESPONSE, data: protocol}, window.location.href);
} catch (error) {
window.postMessage({type: PING_DOMAIN_RESPONSE, data: error}, window.location.href);
}
break;
case GET_LANGUAGE_INFORMATION:
window.postMessage({type: RETRIEVED_LANGUAGE_INFORMATION, data: await ipcRenderer.invoke(GET_LANGUAGE_INFORMATION)});
break;
default:
console.log(`got a message: ${event}`);
console.log(event);
}
});
createKeyDownListener();
ipcRenderer.on(DARK_MODE_CHANGE, (event, darkMode) => {
window.postMessage({type: DARK_MODE_CHANGE, data: darkMode}, window.location.href);
});

View file

@ -1,22 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// Copyright (c) 2015-2016 Yuya Ochiai
'use strict';
import {ipcRenderer} from 'electron';
import {UPDATE_URL_VIEW_WIDTH} from 'common/communication';
console.log('preloaded for the url view');
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case UPDATE_URL_VIEW_WIDTH:
ipcRenderer.send(UPDATE_URL_VIEW_WIDTH, event.data.data);
break;
default:
console.log(`got a message: ${event}`);
console.log(event);
}
});

View file

@ -51,7 +51,7 @@ export default class DownloadsDropdownMenuView {
this.windowBounds = this.window.getContentBounds();
this.bounds = this.getBounds(DOWNLOADS_DROPDOWN_MENU_FULL_WIDTH, DOWNLOADS_DROPDOWN_MENU_FULL_HEIGHT);
const preload = getLocalPreload('downloadsDropdownMenu.js');
const preload = getLocalPreload('desktopAPI.js');
this.view = new BrowserView({webPreferences: {
preload,

View file

@ -10,7 +10,6 @@ import {DownloadedItem, DownloadedItems} from 'types/downloads';
import {
CLOSE_DOWNLOADS_DROPDOWN,
DOWNLOADS_DROPDOWN_SHOW_FILE_IN_FOLDER,
EMIT_CONFIGURATION,
OPEN_DOWNLOADS_DROPDOWN,
RECEIVE_DOWNLOADS_DROPDOWN_SIZE,
@ -45,7 +44,7 @@ export default class DownloadsDropdownView {
this.windowBounds = this.window.getContentBounds();
this.bounds = this.getBounds(DOWNLOADS_DROPDOWN_FULL_WIDTH, DOWNLOADS_DROPDOWN_HEIGHT);
const preload = getLocalPreload('downloadsDropdown.js');
const preload = getLocalPreload('desktopAPI.js');
this.view = new BrowserView({webPreferences: {
preload,
@ -67,7 +66,6 @@ export default class DownloadsDropdownView {
ipcMain.on(REQUEST_CLEAR_DOWNLOADS_DROPDOWN, this.clearDownloads);
ipcMain.on(RECEIVE_DOWNLOADS_DROPDOWN_SIZE, this.handleReceivedDownloadsDropdownSize);
ipcMain.on(DOWNLOADS_DROPDOWN_OPEN_FILE, this.openFile);
ipcMain.on(DOWNLOADS_DROPDOWN_SHOW_FILE_IN_FOLDER, this.showFileInFolder);
ipcMain.on(UPDATE_DOWNLOADS_DROPDOWN, this.updateDownloads);
ipcMain.on(UPDATE_DOWNLOADS_DROPDOWN_MENU_ITEM, this.updateDownloadsDropdownMenuItem);
ipcMain.handle(GET_DOWNLOADED_IMAGE_THUMBNAIL_LOCATION, this.getDownloadImageThumbnailLocation);
@ -151,12 +149,6 @@ export default class DownloadsDropdownView {
downloadsManager.openFile(item);
}
showFileInFolder = (e: IpcMainEvent, item: DownloadedItem) => {
log.debug('DownloadsDropdownView.showFileInFolder', {item});
downloadsManager.showFileInFolder(item);
}
getBounds = (width: number, height: number) => {
// Must always use integers
return {

View file

@ -46,7 +46,7 @@ export default class TeamDropdownView {
this.windowBounds = this.window.getContentBounds();
const preload = getLocalPreload('dropdown.js');
const preload = getLocalPreload('desktopAPI.js');
this.view = new BrowserView({webPreferences: {
preload,
@ -105,14 +105,14 @@ export default class TeamDropdownView {
this.view.webContents.send(
UPDATE_TEAMS_DROPDOWN,
this.teams,
this.activeTeam,
this.darkMode,
this.windowBounds,
this.activeTeam,
this.enableServerManagement,
this.hasGPOTeams,
this.expired,
this.mentions,
this.unreads,
this.windowBounds,
);
}

View file

@ -13,7 +13,6 @@ import {
LOAD_SUCCESS,
LOAD_FAILED,
TOGGLE_LOADING_SCREEN_VISIBILITY,
GET_LOADING_SCREEN_DATA,
LOADSCREEN_END,
SET_ACTIVE_VIEW,
OPEN_TAB,
@ -21,6 +20,7 @@ import {
UPDATE_LAST_ACTIVE,
UPDATE_URL_VIEW_WIDTH,
MAIN_WINDOW_SHOWN,
DARK_MODE_CHANGE,
} from 'common/communication';
import Config from 'common/config';
import urlUtils, {equalUrlsIgnoringSubpath} from 'common/utils/url';
@ -362,7 +362,7 @@ export class ViewManager {
}
if (url && url !== '') {
const urlString = typeof url === 'string' ? url : url.toString();
const preload = getLocalPreload('urlView.js');
const preload = getLocalPreload('desktopAPI.js');
const urlView = new BrowserView({
webPreferences: {
preload,
@ -427,7 +427,7 @@ export class ViewManager {
}
createLoadingScreen = () => {
const preload = getLocalPreload('loadingScreenPreload.js');
const preload = getLocalPreload('desktopAPI.js');
this.loadingScreen = new BrowserView({webPreferences: {
preload,
@ -490,7 +490,7 @@ export class ViewManager {
updateLoadingScreenDarkMode = (darkMode: boolean) => {
if (this.loadingScreen) {
this.loadingScreen.webContents.send(GET_LOADING_SCREEN_DATA, {darkMode});
this.loadingScreen.webContents.send(DARK_MODE_CHANGE, darkMode);
}
}

View file

@ -46,7 +46,7 @@ function isFramelessWindow() {
function createMainWindow(options: {linuxAppIcon: string; fullscreen?: boolean}) {
// Create the browser window.
const preload = getLocalPreload('mainWindow.js');
const preload = getLocalPreload('desktopAPI.js');
let savedWindowState: any;
try {
savedWindowState = JSON.parse(fs.readFileSync(boundsInfoPath, 'utf-8'));

View file

@ -10,7 +10,7 @@ import ContextMenu from '../contextMenu';
import {getLocalPreload, getLocalURLString} from '../utils';
export function createSettingsWindow(mainWindow: BrowserWindow, withDevTools: boolean) {
const preload = getLocalPreload('mainWindow.js');
const preload = getLocalPreload('desktopAPI.js');
const spellcheck = (typeof Config.useSpellChecker === 'undefined' ? true : Config.useSpellChecker);
const settingsWindow = new BrowserWindow({
parent: mainWindow,

View file

@ -14,7 +14,6 @@ import {
import {
MAXIMIZE_CHANGE,
HISTORY,
GET_LOADING_SCREEN_DATA,
REACT_APP_INITIALIZED,
LOADING_SCREEN_ANIMATION_FINISHED,
FOCUS_THREE_DOT_MENU,
@ -79,7 +78,6 @@ export class WindowManager {
this.assetsDir = path.resolve(app.getAppPath(), 'assets');
ipcMain.on(HISTORY, this.handleHistory);
ipcMain.handle(GET_LOADING_SCREEN_DATA, this.handleLoadingScreenDataRequest);
ipcMain.handle(GET_DARK_MODE, this.handleGetDarkMode);
ipcMain.on(REACT_APP_INITIALIZED, this.handleReactAppInitialized);
ipcMain.on(LOADING_SCREEN_ANIMATION_FINISHED, this.handleLoadingScreenAnimationFinished);

View file

@ -14,7 +14,6 @@ import Input, {STATUS, SIZE} from 'renderer/components/Input';
import LoadingBackground from 'renderer/components/LoadingScreen/LoadingBackground';
import SaveButton from 'renderer/components/SaveButton/SaveButton';
import {PING_DOMAIN, PING_DOMAIN_RESPONSE} from 'common/communication';
import {MODAL_TRANSITION_TIMEOUT} from 'common/utils/constants';
import urlUtils from 'common/utils/url';
@ -77,33 +76,15 @@ function ConfigureServer({
if (urlUtils.startsWithProtocol(checkURL)) {
return Promise.resolve(checkURL);
}
return new Promise((resolve) => {
let eventCount = 0;
const handler = (event: {data: {type: string; data: string | Error}}) => {
let newURL = checkURL;
if (event.data.type === PING_DOMAIN_RESPONSE) {
if (event.data.data instanceof Error) {
console.error(`Could not ping url: ${checkURL}`);
} else {
newURL = `${event.data.data}://${checkURL}`;
setUrl(newURL);
}
window.removeEventListener('message', handler);
resolve(newURL);
} else if (eventCount >= 3) {
window.removeEventListener('message', handler);
resolve(newURL);
}
eventCount++;
};
window.addEventListener('message', handler);
window.postMessage({type: PING_DOMAIN, data: checkURL}, window.location.href);
return window.desktop.modals.pingDomain(checkURL).then((result: string | Error) => {
let newURL = checkURL;
if (result instanceof Error) {
console.error(`Could not ping url: ${checkURL}`);
} else {
newURL = `${result}://${checkURL}`;
setUrl(newURL);
}
return newURL;
});
};

View file

@ -7,8 +7,6 @@ import classNames from 'classnames';
import {useIntl} from 'react-intl';
import {DOWNLOADS_DROPDOWN_OPEN_FILE} from 'common/communication';
import FileSizeAndStatus from './FileSizeAndStatus';
import ProgressBar from './ProgressBar';
import ThreeDotButton from './ThreeDotButton';
@ -26,7 +24,7 @@ const DownloadsDropdownItemFile = ({item, activeItem}: OwnProps) => {
const onFileClick = (e: React.MouseEvent<HTMLDivElement>) => {
e.preventDefault();
window.postMessage({type: DOWNLOADS_DROPDOWN_OPEN_FILE, payload: {item}}, window.location.href);
window.desktop.downloadsDropdown.openFile(item);
};
const itemFilename = item.type === 'update' ?

View file

@ -6,8 +6,6 @@ import {DownloadedItem} from 'types/downloads';
import classNames from 'classnames';
import {TOGGLE_DOWNLOADS_DROPDOWN_MENU} from 'common/communication';
type OwnProps = {
activeItem?: DownloadedItem;
item: DownloadedItem;
@ -22,13 +20,10 @@ const ThreeDotButton = ({item, activeItem, visible}: OwnProps) => {
e.stopPropagation();
const coords = buttonElement.current?.getBoundingClientRect();
window.postMessage({
type: TOGGLE_DOWNLOADS_DROPDOWN_MENU,
payload: {
coordinates: coords?.toJSON(),
item,
},
}, window.location.href);
window.desktop.downloadsDropdown.toggleDownloadsDropdownMenu({
coordinates: coords?.toJSON(),
item,
});
};
return (

View file

@ -8,8 +8,6 @@ import {FormattedMessage} from 'react-intl';
import {Button} from 'react-bootstrap';
import {START_UPDATE_DOWNLOAD} from 'common/communication';
import Thumbnail from '../Thumbnail';
type OwnProps = {
@ -19,7 +17,7 @@ type OwnProps = {
const UpdateAvailable = ({item}: OwnProps) => {
const onButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e?.preventDefault?.();
window.postMessage({type: START_UPDATE_DOWNLOAD}, window.location.href);
window.desktop.downloadsDropdown.startUpdateDownload();
};
return (

View file

@ -10,8 +10,6 @@ import {Button} from 'react-bootstrap';
import classNames from 'classnames';
import {START_UPGRADE} from 'common/communication';
import Thumbnail from '../Thumbnail';
import FileSizeAndStatus from '../FileSizeAndStatus';
@ -24,7 +22,7 @@ const UpdateAvailable = ({item}: OwnProps) => {
const onButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e?.preventDefault?.();
window.postMessage({type: START_UPGRADE}, window.location.href);
window.desktop.downloadsDropdown.startUpgrade();
};
return (

View file

@ -9,7 +9,6 @@ import {FormattedMessage, injectIntl, IntlShape} from 'react-intl';
import {TeamWithIndex} from 'types/config';
import urlUtils from 'common/utils/url';
import {PING_DOMAIN, PING_DOMAIN_RESPONSE} from 'common/communication';
type Props = {
onClose?: () => void;
@ -157,20 +156,12 @@ class NewTeamModal extends React.PureComponent<Props, State> {
return Promise.resolve(undefined);
}
return new Promise((resolve) => {
const handler = (event: {data: {type: string; data: string | Error}}) => {
if (event.data.type === PING_DOMAIN_RESPONSE) {
if (event.data.data instanceof Error) {
console.error(`Could not ping url: ${teamUrl}`);
} else {
this.setState({teamUrl: `${event.data.data}://${this.state.teamUrl}`});
}
window.removeEventListener('message', handler);
resolve(undefined);
}
};
window.addEventListener('message', handler);
window.postMessage({type: PING_DOMAIN, data: teamUrl}, window.location.href);
return window.desktop.modals.pingDomain(teamUrl).then((result: string | Error) => {
if (result instanceof Error) {
console.error(`Could not ping url: ${teamUrl}`);
} else {
this.setState({teamUrl: `${result}://${this.state.teamUrl}`});
}
});
}

View file

@ -3,13 +3,11 @@
import React, {useEffect} from 'react';
import {UPDATE_URL_VIEW_WIDTH} from 'common/communication';
export default function UrlDescription(props: {url: string}) {
const urlRef = React.createRef<HTMLDivElement>();
useEffect(() => {
window.postMessage({type: UPDATE_URL_VIEW_WIDTH, data: urlRef.current?.scrollWidth}, window.location.href);
window.desktop.updateURLViewWidth(urlRef.current?.scrollWidth);
}, []);
if (props.url) {

View file

@ -6,15 +6,7 @@ import ReactDOM from 'react-dom';
import classNames from 'classnames';
import {FormattedMessage} from 'react-intl';
import {DownloadedItem} from 'types/downloads';
import {
CLOSE_DOWNLOADS_DROPDOWN,
REQUEST_CLEAR_DOWNLOADS_DROPDOWN,
REQUEST_DOWNLOADS_DROPDOWN_INFO,
SEND_DOWNLOADS_DROPDOWN_SIZE,
UPDATE_DOWNLOADS_DROPDOWN,
} from 'common/communication';
import {DownloadedItem, DownloadedItems} from 'types/downloads';
import IntlProvider from './intl_provider';
import DownloadsDropdownItem from './components/DownloadsDropdown/DownloadsDropdownItem';
@ -36,46 +28,51 @@ class DownloadsDropdown extends React.PureComponent<Record<string, never>, State
downloads: [],
};
window.addEventListener('message', this.handleMessageEvent);
window.desktop.onUpdateDownloadsDropdown(this.handleUpdate);
}
componentDidMount() {
window.postMessage({type: REQUEST_DOWNLOADS_DROPDOWN_INFO}, window.location.href);
window.addEventListener('click', () => {
window.desktop.closeDownloadsDropdownMenu();
});
window.addEventListener('mousemove', () => {
window.desktop.downloadsDropdown.focus();
});
window.desktop.downloadsDropdown.requestInfo();
}
componentDidUpdate() {
window.postMessage({type: SEND_DOWNLOADS_DROPDOWN_SIZE, data: {width: document.body.scrollWidth, height: document.body.scrollHeight}}, window.location.href);
window.desktop.downloadsDropdown.sendSize(document.body.scrollWidth, document.body.scrollHeight);
}
handleMessageEvent = (event: MessageEvent) => {
if (event.data.type === UPDATE_DOWNLOADS_DROPDOWN) {
const {downloads, darkMode, windowBounds, item} = event.data.data;
const newDownloads = Object.values<DownloadedItem>(downloads);
newDownloads.sort((a, b) => {
// Show App update first
if (a.type === 'update') {
return -1;
} else if (b.type === 'update') {
return 1;
}
return b?.addedAt - a?.addedAt;
});
this.setState({
downloads: newDownloads,
darkMode,
windowBounds,
item,
});
}
handleUpdate = (downloads: DownloadedItems, darkMode: boolean, windowBounds: Electron.Rectangle, item?: DownloadedItem) => {
const newDownloads = Object.values<DownloadedItem>(downloads);
newDownloads.sort((a, b) => {
// Show App update first
if (a.type === 'update') {
return -1;
} else if (b.type === 'update') {
return 1;
}
return b?.addedAt - a?.addedAt;
});
this.setState({
downloads: newDownloads,
darkMode,
windowBounds,
item,
});
}
closeMenu = () => {
window.postMessage({type: CLOSE_DOWNLOADS_DROPDOWN}, window.location.href);
window.desktop.closeDownloadsDropdown();
}
clearAll = () => {
if (!this.clearAllButtonDisabled()) {
window.postMessage({type: REQUEST_CLEAR_DOWNLOADS_DROPDOWN}, window.location.href);
window.desktop.downloadsDropdown.requestClearDownloadsDropdown();
}
}

View file

@ -8,15 +8,6 @@ import {FormattedMessage} from 'react-intl';
import {DownloadedItem} from 'types/downloads';
import {
DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD,
DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE,
DOWNLOADS_DROPDOWN_MENU_OPEN_FILE,
DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER,
REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO,
UPDATE_DOWNLOADS_DROPDOWN_MENU,
} from 'common/communication';
import IntlProvider from './intl_provider';
import './css/downloadsDropdownMenu.scss';
@ -25,20 +16,14 @@ const DownloadsDropdownMenu = () => {
const [item, setItem] = useState<DownloadedItem | null>(null);
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
const handleMessageEvent = (event: MessageEvent) => {
if (event.data.type === UPDATE_DOWNLOADS_DROPDOWN_MENU) {
const {item, darkMode} = event.data.data;
setItem(item);
setDarkMode(darkMode);
}
};
const handleUpdate = (item: DownloadedItem, darkMode: boolean) => {
setItem(item);
setDarkMode(darkMode);
};
window.addEventListener('message', handleMessageEvent);
window.postMessage({type: REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO}, window.location.href);
return () => {
window.removeEventListener('message', handleMessageEvent);
};
useEffect(() => {
window.desktop.downloadsDropdownMenu.requestInfo();
window.desktop.downloadsDropdownMenu.onUpdateDownloadsDropdownMenu(handleUpdate);
}, []);
const preventPropagation = (event: React.MouseEvent<HTMLDivElement>) => {
@ -76,31 +61,43 @@ const DownloadsDropdownMenu = () => {
};
const openFile = useCallback(() => {
if (!item) {
return;
}
if (item?.type === 'update') {
return;
}
window.postMessage({type: DOWNLOADS_DROPDOWN_MENU_OPEN_FILE, payload: {item}}, window.location.href);
window.desktop.downloadsDropdownMenu.openFile(item);
}, [item]);
const showInFolder = useCallback(() => {
if (!item) {
return;
}
if (item?.type === 'update') {
return;
}
window.postMessage({type: DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER, payload: {item}}, window.location.href);
window.desktop.downloadsDropdownMenu.showInFolder(item);
}, [item]);
const clearFile = useCallback(() => {
if (!item) {
return;
}
if (item?.type === 'update') {
return;
}
window.postMessage({type: DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE, payload: {item}}, window.location.href);
window.desktop.downloadsDropdownMenu.clearFile(item);
}, [item]);
const cancelDownload = useCallback(() => {
if (!item) {
return;
}
if (item?.state !== 'progressing') {
return;
}
window.postMessage({type: DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD, payload: {item}}, window.location.href);
window.desktop.downloadsDropdownMenu.cancelDownload(item);
}, [item]);
return (

View file

@ -9,16 +9,6 @@ import {DragDropContext, Draggable, DraggingStyle, Droppable, DropResult, NotDra
import {Team, TeamWithTabs, TeamWithTabsAndGpo} from 'types/config';
import {
CLOSE_TEAMS_DROPDOWN,
REQUEST_TEAMS_DROPDOWN_INFO,
SEND_DROPDOWN_MENU_SIZE,
SHOW_NEW_SERVER_MODAL,
SHOW_EDIT_SERVER_MODAL,
SHOW_REMOVE_SERVER_MODAL,
SWITCH_SERVER, UPDATE_TEAMS,
UPDATE_TEAMS_DROPDOWN,
} from 'common/communication';
import {getTabViewName} from 'common/tabs/TabView';
import {TAB_BAR_HEIGHT, THREE_DOT_MENU_WIDTH_MAC} from 'common/utils/constants';
@ -64,30 +54,38 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
this.buttonRefs = new Map();
this.addServerRef = React.createRef();
window.addEventListener('message', this.handleMessageEvent);
window.desktop.serverDropdown.onUpdateServerDropdown(this.handleUpdate);
}
handleMessageEvent = (event: MessageEvent) => {
if (event.data.type === UPDATE_TEAMS_DROPDOWN) {
const {teams, activeTeam, darkMode, enableServerManagement, hasGPOTeams, unreads, mentions, expired, windowBounds} = event.data.data;
this.setState({
teams,
orderedTeams: teams.concat().sort((a: TeamWithTabs, b: TeamWithTabs) => a.order - b.order),
activeTeam,
darkMode,
enableServerManagement,
hasGPOTeams,
unreads,
mentions,
expired,
windowBounds,
});
}
handleUpdate = (
teams: TeamWithTabsAndGpo[],
darkMode: boolean,
windowBounds: Electron.Rectangle,
activeTeam?: string,
enableServerManagement?: boolean,
hasGPOTeams?: boolean,
expired?: Map<string, boolean>,
mentions?: Map<string, number>,
unreads?: Map<string, boolean>,
) => {
this.setState({
teams,
orderedTeams: teams.concat().sort((a: TeamWithTabs, b: TeamWithTabs) => a.order - b.order),
activeTeam,
darkMode,
enableServerManagement,
hasGPOTeams,
unreads,
mentions,
expired,
windowBounds,
});
}
selectServer = (team: Team) => {
return () => {
window.postMessage({type: SWITCH_SERVER, data: team.name}, window.location.href);
window.desktop.serverDropdown.switchServer(team.name);
this.closeMenu();
};
}
@ -95,7 +93,7 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
closeMenu = () => {
if (!this.state.isAnyDragging) {
(document.activeElement as HTMLElement).blur();
window.postMessage({type: CLOSE_TEAMS_DROPDOWN}, window.location.href);
window.desktop.closeTeamsDropdown();
}
}
@ -104,7 +102,7 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
}
addServer = () => {
window.postMessage({type: SHOW_NEW_SERVER_MODAL}, window.location.href);
window.desktop.serverDropdown.showNewServerModal();
this.closeMenu();
}
@ -142,17 +140,17 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
teams[t.index].order = order;
});
this.setState({teams, orderedTeams: teams.concat().sort((a: Team, b: Team) => a.order - b.order), isAnyDragging: false});
window.postMessage({type: UPDATE_TEAMS, data: teams}, window.location.href);
window.desktop.updateTeams(teams);
}
componentDidMount() {
window.postMessage({type: REQUEST_TEAMS_DROPDOWN_INFO}, window.location.href);
window.desktop.serverDropdown.requestInfo();
window.addEventListener('click', this.closeMenu);
window.addEventListener('keydown', this.handleKeyboardShortcuts);
}
componentDidUpdate() {
window.postMessage({type: SEND_DROPDOWN_MENU_SIZE, data: {width: document.body.scrollWidth, height: document.body.scrollHeight}}, window.location.href);
window.desktop.serverDropdown.sendSize(document.body.scrollWidth, document.body.scrollHeight);
}
componentWillUnmount() {
@ -218,7 +216,7 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
}
return (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation();
window.postMessage({type: SHOW_EDIT_SERVER_MODAL, data: {name: teamName}}, window.location.href);
window.desktop.serverDropdown.showEditServerModal(teamName);
this.closeMenu();
};
}
@ -229,7 +227,7 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
}
return (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation();
window.postMessage({type: SHOW_REMOVE_SERVER_MODAL, data: {name: teamName}}, window.location.href);
window.desktop.serverDropdown.showRemoveServerModal(teamName);
this.closeMenu();
};
}

View file

@ -4,8 +4,6 @@
import React from 'react';
import {IntlProvider as BaseIntlProvider} from 'react-intl';
import {GET_LANGUAGE_INFORMATION, RETRIEVED_LANGUAGE_INFORMATION} from 'common/communication';
import {Language} from '../../i18n/i18n';
type State = {
@ -18,21 +16,13 @@ export default class IntlProvider extends React.PureComponent<any, State> {
this.state = {};
}
componentDidMount() {
window.addEventListener('message', this.handleMessageEvent);
window.postMessage({type: GET_LANGUAGE_INFORMATION});
async componentDidMount() {
await this.getLanguageInformation();
}
componentWillUnmount() {
window.removeEventListener('message', this.handleMessageEvent);
}
handleMessageEvent = (event: MessageEvent<{type: string; data: Language}>) => {
if (event.data.type === RETRIEVED_LANGUAGE_INFORMATION) {
this.setState({
language: event.data.data,
});
}
getLanguageInformation = async () => {
const language = await window.desktop.getLanguageInformation();
this.setState({language});
}
render() {

View file

@ -5,12 +5,12 @@ import React from 'react';
import ReactDOM from 'react-dom';
import {Certificate} from 'electron/renderer';
import {MODAL_CANCEL, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'renderer/css/modals.css';
import 'renderer/css/components/CertificateModal.css';
import {CertificateModalInfo} from 'types/modals';
import setupDarkMode from '../darkMode';
import SelectCertificateModal from './certificateModal';
@ -18,15 +18,15 @@ import SelectCertificateModal from './certificateModal';
setupDarkMode();
const handleCancel = () => {
window.postMessage({type: MODAL_CANCEL}, window.location.href);
window.desktop.modals.cancelModal();
};
const handleSelect = (cert: Certificate) => {
window.postMessage({type: MODAL_RESULT, data: {cert}}, window.location.href);
window.desktop.modals.finishModal({cert});
};
const getCertInfo = () => {
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
return window.desktop.modals.getModalInfo<CertificateModalInfo>();
};
const start = async () => {

View file

@ -6,11 +6,6 @@ import React, {Fragment} from 'react';
import {Modal, Button, Table, Row, Col} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
import {CertificateModalData} from 'types/certificate';
import {ModalMessage} from 'types/modals';
import {MODAL_INFO} from 'common/communication';
import IntlProvider from 'renderer/intl_provider';
import ShowCertificateModal from '../../components/showCertificateModal';
@ -18,7 +13,7 @@ import ShowCertificateModal from '../../components/showCertificateModal';
type Props = {
onSelect: (cert: Certificate) => void;
onCancel?: () => void;
getCertInfo: () => void;
getCertInfo: () => Promise<{url: string; list: Certificate[]}>;
}
type State = {
@ -34,27 +29,14 @@ export default class SelectCertificateModal extends React.PureComponent<Props, S
this.state = {};
}
componentDidMount() {
window.addEventListener('message', this.handleCertInfoMessage);
this.props.getCertInfo();
async componentDidMount() {
await this.getCertInfo();
}
componentWillUnmount() {
window.removeEventListener('message', this.handleCertInfoMessage);
}
handleCertInfoMessage = (event: {data: ModalMessage<CertificateModalData>}) => {
switch (event.data.type) {
case MODAL_INFO: {
const {url, list} = event.data.data;
this.setState({url, list});
break;
}
default:
break;
}
}
getCertInfo = async () => {
const {url, list} = await this.props.getCertInfo();
this.setState({url, list});
};
selectfn = (index: number) => {
return (() => {

View file

@ -1,19 +1,16 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {DARK_MODE_CHANGE, GET_DARK_MODE} from 'common/communication';
import darkStyles from 'renderer/css/lazy/modals-dark.lazy.css';
export default function addDarkModeListener() {
window.addEventListener('message', async (event) => {
if (event.data.type === DARK_MODE_CHANGE) {
if (event.data.data) {
darkStyles.use();
} else {
darkStyles.unuse();
}
const setDarkMode = (darkMode: boolean) => {
if (darkMode) {
darkStyles.use();
} else {
darkStyles.unuse();
}
});
window.postMessage({type: GET_DARK_MODE}, window.location.href);
};
window.desktop.onDarkModeChange(setDarkMode);
window.desktop.getDarkMode().then(setDarkMode);
}

View file

@ -8,9 +8,6 @@ import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import {TeamWithIndex} from 'types/config';
import {ModalMessage} from 'types/modals';
import {MODAL_CANCEL, MODAL_INFO, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication';
import IntlProvider from 'renderer/intl_provider';
@ -20,33 +17,28 @@ import setupDarkMode from '../darkMode';
setupDarkMode();
type ModalInfo = {
team: TeamWithIndex;
currentTeams: TeamWithIndex[];
};
const onClose = () => {
window.postMessage({type: MODAL_CANCEL}, window.location.href);
window.desktop.modals.cancelModal();
};
const onSave = (data: TeamWithIndex) => {
window.postMessage({type: MODAL_RESULT, data}, window.location.href);
window.desktop.modals.finishModal(data);
};
const EditServerModalWrapper: React.FC = () => {
const [server, setServer] = useState<TeamWithIndex>();
const [currentTeams, setCurrentTeams] = useState<TeamWithIndex[]>();
const handleEditServerMessage = (event: {data: ModalMessage<{currentTeams: TeamWithIndex[]; team: TeamWithIndex}>}) => {
switch (event.data.type) {
case MODAL_INFO: {
setServer(event.data.data.team);
setCurrentTeams(event.data.data.currentTeams);
break;
}
default:
break;
}
};
useEffect(() => {
window.addEventListener('message', handleEditServerMessage);
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
window.desktop.modals.getModalInfo<ModalInfo>().then(({team, currentTeams}) => {
setServer(team);
setCurrentTeams(currentTeams);
});
}, []);
return (

View file

@ -4,10 +4,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {ModalMessage} from 'types/modals';
import {RECEIVED_LOADING_SCREEN_DATA, GET_LOADING_SCREEN_DATA, LOADING_SCREEN_ANIMATION_FINISHED, TOGGLE_LOADING_SCREEN_VISIBILITY} from 'common/communication';
import LoadingScreen from '../../components/LoadingScreen';
import 'bootstrap/dist/css/bootstrap.min.css';
@ -31,32 +27,29 @@ class LoadingScreenRoot extends React.PureComponent<Props, State> {
};
}
componentDidMount() {
window.postMessage({type: GET_LOADING_SCREEN_DATA}, window.location.href);
async componentDidMount() {
window.desktop.onDarkModeChange(this.setDarkMode);
const darkMode = await window.desktop.getDarkMode();
this.setDarkMode(darkMode);
window.addEventListener('message', this.handleMessageEvent);
window.desktop.loadingScreen.onToggleLoadingScreenVisibility(this.onToggleLoadingScreenVisibility);
window.addEventListener('click', () => {
window.desktop.closeTeamsDropdown();
window.desktop.closeDownloadsDropdown();
});
}
componentWillUnmount() {
window.removeEventListener('message', this.handleMessageEvent);
setDarkMode = (darkMode: boolean) => {
this.setState({darkMode});
}
handleMessageEvent = (event: {data: ModalMessage<any>}) => {
if (event.data.type === RECEIVED_LOADING_SCREEN_DATA) {
this.setState({
darkMode: event.data.data.darkMode,
});
}
if (event.data.type === TOGGLE_LOADING_SCREEN_VISIBILITY) {
this.setState({
showLoadingScreen: event.data.data,
});
}
onToggleLoadingScreenVisibility = (showLoadingScreen: boolean) => {
this.setState({showLoadingScreen});
}
onFadeOutComplete = () => {
window.postMessage({type: LOADING_SCREEN_ANIMATION_FINISHED}, window.location.href);
window.desktop.loadingScreen.loadingScreenAnimationFinished();
}
render() {

View file

@ -5,7 +5,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import {AuthenticationResponseDetails} from 'electron/renderer';
import {MODAL_CANCEL, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication';
import {LoginModalInfo} from 'types/modals';
import IntlProvider from 'renderer/intl_provider';
@ -19,15 +19,15 @@ import LoginModal from './loginModal';
setupDarkMode();
const handleLoginCancel = (request: AuthenticationResponseDetails) => {
window.postMessage({type: MODAL_CANCEL, data: {request}}, window.location.href);
window.desktop.modals.cancelModal({request});
};
const handleLogin = (request: AuthenticationResponseDetails, username: string, password: string) => {
window.postMessage({type: MODAL_RESULT, data: {request, username, password}}, window.location.href);
window.desktop.modals.finishModal({request, username, password});
};
const getAuthInfo = () => {
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
return window.desktop.modals.getModalInfo<LoginModalInfo>();
};
const start = async () => {

View file

@ -6,17 +6,16 @@ import React from 'react';
import {Button, Col, FormLabel, Form, FormGroup, FormControl, Modal} from 'react-bootstrap';
import {FormattedMessage, injectIntl, IntlShape} from 'react-intl';
import {LoginModalData} from 'types/auth';
import {ModalMessage} from 'types/modals';
import {AuthenticationResponseDetails, AuthInfo} from 'electron/renderer';
import {LoginModalInfo} from 'types/modals';
import urlUtils from 'common/utils/url';
import {MODAL_INFO} from 'common/communication';
type Props = {
onCancel: (request: AuthenticationResponseDetails) => void;
onLogin: (request: AuthenticationResponseDetails, username: string, password: string) => void;
getAuthInfo: () => void;
getAuthInfo: () => Promise<LoginModalInfo>;
intl: IntlShape;
};
@ -36,26 +35,13 @@ class LoginModal extends React.PureComponent<Props, State> {
};
}
componentDidMount() {
window.addEventListener('message', this.handleAuthInfoMessage);
this.props.getAuthInfo();
async componentDidMount() {
await this.getAuthInfo();
}
componentWillUnmount() {
window.removeEventListener('message', this.handleAuthInfoMessage);
}
handleAuthInfoMessage = (event: {data: ModalMessage<LoginModalData>}) => {
switch (event.data.type) {
case MODAL_INFO: {
const {request, authInfo} = event.data.data;
this.setState({request, authInfo});
break;
}
default:
break;
}
getAuthInfo = async () => {
const {request, authInfo} = await this.props.getAuthInfo();
this.setState({request, authInfo});
}
handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {

View file

@ -8,9 +8,6 @@ import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import {TeamWithIndex} from 'types/config';
import {ModalMessage} from 'types/modals';
import {GET_MODAL_UNCLOSEABLE, MODAL_CANCEL, MODAL_INFO, MODAL_RESULT, MODAL_UNCLOSEABLE, RETRIEVE_MODAL_INFO} from 'common/communication';
import IntlProvider from 'renderer/intl_provider';
@ -21,39 +18,24 @@ import setupDarkMode from '../darkMode';
setupDarkMode();
const onClose = () => {
window.postMessage({type: MODAL_CANCEL}, window.location.href);
window.desktop.modals.cancelModal();
};
const onSave = (data: TeamWithIndex) => {
window.postMessage({type: MODAL_RESULT, data}, window.location.href);
window.desktop.modals.finishModal(data);
};
const NewServerModalWrapper: React.FC = () => {
const [unremoveable, setUnremovable] = useState<boolean>();
const [currentTeams, setCurrentTeams] = useState<TeamWithIndex[]>();
const handleNewServerMessage = (event: {data: ModalMessage<unknown>}) => {
switch (event.data.type) {
case MODAL_UNCLOSEABLE: {
setUnremovable(event.data.data as boolean);
break;
}
case MODAL_INFO:
setCurrentTeams(event.data.data as TeamWithIndex[]);
break;
default:
break;
}
};
useEffect(() => {
window.addEventListener('message', handleNewServerMessage);
window.postMessage({type: GET_MODAL_UNCLOSEABLE}, window.location.href);
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
return () => {
window.removeEventListener('message', handleNewServerMessage);
};
window.desktop.modals.isModalUncloseable().then((uncloseable) => {
setUnremovable(uncloseable);
});
window.desktop.modals.getModalInfo<TeamWithIndex[]>().then((teams) => {
setCurrentTeams(teams);
});
}, []);
return (

View file

@ -4,7 +4,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {MODAL_CANCEL, MODAL_RESULT, RETRIEVE_MODAL_INFO, MODAL_SEND_IPC_MESSAGE} from 'common/communication';
import {PermissionModalInfo} from 'types/modals';
import IntlProvider from 'renderer/intl_provider';
@ -18,19 +18,19 @@ import PermissionModal from './permissionModal';
setupDarkMode();
const handleDeny = () => {
window.postMessage({type: MODAL_CANCEL}, window.location.href);
window.desktop.modals.cancelModal();
};
const handleGrant = () => {
window.postMessage({type: MODAL_RESULT}, window.location.href);
window.desktop.modals.finishModal();
};
const getPermissionInfo = () => {
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
return window.desktop.modals.getModalInfo<PermissionModalInfo>();
};
const openExternalLink = (protocol: string, url: string) => {
window.postMessage({type: MODAL_SEND_IPC_MESSAGE, data: {type: 'confirm-protocol', args: [protocol, url]}}, window.location.href);
window.desktop.modals.confirmProtocol(protocol, url);
};
const start = async () => {

View file

@ -5,27 +5,21 @@ import React from 'react';
import {Modal, Button} from 'react-bootstrap';
import {FormattedMessage, injectIntl, IntlShape} from 'react-intl';
import {PermissionType} from 'types/trustedOrigin';
import {ModalMessage} from 'types/modals';
import {PermissionModalInfo} from 'types/modals';
import urlUtil from 'common/utils/url';
import {t} from 'common/utils/util';
import {MODAL_INFO} from 'common/communication';
import {PERMISSION_DESCRIPTION} from 'common/permissions';
type Props = {
handleDeny: React.MouseEventHandler<HTMLButtonElement>;
handleGrant: React.MouseEventHandler<HTMLButtonElement>;
getPermissionInfo: () => void;
getPermissionInfo: () => Promise<PermissionModalInfo>;
openExternalLink: (protocol: string, url: string) => void;
intl: IntlShape;
};
type State = {
url?: string;
permission?: PermissionType;
}
type State = Partial<PermissionModalInfo>;
class PermissionModal extends React.PureComponent<Props, State> {
constructor(props: Props) {
@ -33,26 +27,13 @@ class PermissionModal extends React.PureComponent<Props, State> {
this.state = {};
}
componentDidMount() {
window.addEventListener('message', this.handlePermissionInfoMessage);
this.props.getPermissionInfo();
getPermissionInfo = async () => {
const {url, permission} = await this.props.getPermissionInfo();
this.setState({url, permission});
}
componentWillUnmount() {
window.removeEventListener('message', this.handlePermissionInfoMessage);
}
handlePermissionInfoMessage = (event: {data: ModalMessage<{url: string; permission: PermissionType}>}) => {
switch (event.data.type) {
case MODAL_INFO: {
const {url, permission} = event.data.data;
this.setState({url, permission});
break;
}
default:
break;
}
async componentDidMount() {
await this.getPermissionInfo();
}
getModalTitle() {

View file

@ -7,10 +7,6 @@ import 'renderer/css/modals.css';
import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import {ModalMessage} from 'types/modals';
import {MODAL_CANCEL, MODAL_INFO, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication';
import IntlProvider from 'renderer/intl_provider';
import RemoveServerModal from '../../components/RemoveServerModal';
@ -20,30 +16,20 @@ import setupDarkMode from '../darkMode';
setupDarkMode();
const onClose = () => {
window.postMessage({type: MODAL_CANCEL}, window.location.href);
window.desktop.modals.cancelModal();
};
const onSave = (data: boolean) => {
window.postMessage({type: MODAL_RESULT, data}, window.location.href);
window.desktop.modals.finishModal(data);
};
const RemoveServerModalWrapper: React.FC = () => {
const [serverName, setServerName] = useState<string>('');
const handleRemoveServerMessage = (event: {data: ModalMessage<string>}) => {
switch (event.data.type) {
case MODAL_INFO: {
setServerName(event.data.data);
break;
}
default:
break;
}
};
useEffect(() => {
window.addEventListener('message', handleRemoveServerMessage);
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
window.desktop.modals.getModalInfo<{name: string}>().then(({name}) => {
setServerName(name);
});
}, []);
return (

View file

@ -5,16 +5,9 @@ import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import {TeamWithIndex} from 'types/config';
import {ModalMessage} from 'types/modals';
import {
MODAL_RESULT,
GET_MODAL_UNCLOSEABLE,
GET_DARK_MODE,
DARK_MODE_CHANGE,
MODAL_INFO,
} from 'common/communication';
import IntlProvider from 'renderer/intl_provider';
import WelcomeScreen from '../../components/WelcomeScreen';
import ConfigureServer from '../../components/ConfigureServer';
@ -23,7 +16,7 @@ import 'bootstrap/dist/css/bootstrap.min.css';
const MOBILE_SCREEN_WIDTH = 1200;
const onConnect = (data: TeamWithIndex) => {
window.postMessage({type: MODAL_RESULT, data}, window.location.href);
window.desktop.modals.finishModal(data);
};
const WelcomeScreenModalWrapper = () => {
@ -37,32 +30,26 @@ const WelcomeScreenModalWrapper = () => {
};
useEffect(() => {
window.postMessage({type: GET_MODAL_UNCLOSEABLE}, window.location.href);
window.postMessage({type: GET_DARK_MODE}, window.location.href);
window.desktop.getDarkMode().then((result) => {
setDarkMode(result);
});
window.desktop.onDarkModeChange((result) => {
setDarkMode(result);
});
window.desktop.modals.getModalInfo<TeamWithIndex[]>().then((result) => {
setCurrentTeams(result);
});
handleWindowResize();
window.addEventListener('resize', handleWindowResize);
window.addEventListener('message', handleMessageEvent);
return () => {
window.removeEventListener('message', handleMessageEvent);
window.removeEventListener('resize', handleWindowResize);
};
}, []);
const handleMessageEvent = (event: {data: ModalMessage<boolean | Electron.Rectangle | TeamWithIndex[]>}) => {
switch (event.data.type) {
case DARK_MODE_CHANGE:
setDarkMode(event.data.data as boolean);
break;
case MODAL_INFO:
setCurrentTeams(event.data.data as TeamWithIndex[]);
break;
default:
break;
}
};
const onGetStarted = () => {
setGetStarted(true);
};

View file

@ -1,7 +1,25 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export type ModalMessage<T> = {
type: string;
data: T;
import {
AuthInfo,
AuthenticationResponseDetails,
Certificate,
} from 'electron/common';
import {PermissionType} from './trustedOrigin';
export type CertificateModalInfo = {
url: string;
list: Certificate[];
}
export type LoginModalInfo = {
request: AuthenticationResponseDetails;
authInfo: AuthInfo;
}
export type PermissionModalInfo = {
url: string;
permission: PermissionType;
}

View file

@ -1,10 +1,12 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ipcRenderer} from 'electron/renderer';
import {ipcRenderer, Rectangle} from 'electron/renderer';
import {CombinedConfig, LocalConfiguration, Team} from './config';
import {DownloadedItems} from './downloads';
import {Language} from '../../i18n/i18n';
import {CombinedConfig, LocalConfiguration, Team, TeamWithTabsAndGpo} from './config';
import {DownloadedItem, DownloadedItems, DownloadsMenuOpenEventPayload} from './downloads';
import {SaveQueueItem} from './settings';
declare global {
@ -58,6 +60,7 @@ declare global {
getAvailableLanguages: () => Promise<string[]>;
getLocalConfiguration: (option?: keyof LocalConfiguration) => Promise<LocalConfiguration[keyof LocalConfiguration] | Partial<LocalConfiguration>>;
getDownloadLocation: (downloadLocation?: string) => Promise<string>;
getLanguageInformation: () => Promise<Language>;
onSynchronizeConfig: (listener: () => void) => void;
onReloadConfiguration: (listener: () => void) => void;
@ -80,9 +83,67 @@ declare global {
onOpenDownloadsDropdown: (listener: () => void) => void;
onShowDownloadsDropdownButtonBadge: (listener: () => void) => void;
onHideDownloadsDropdownButtonBadge: (listener: () => void) => void;
onUpdateDownloadsDropdown: (listener: (downloads: DownloadedItems) => void) => void;
onUpdateDownloadsDropdown: (listener: (downloads: DownloadedItems, darkMode: boolean, windowBounds: Rectangle, item: DownloadedItem) => void) => void;
onAppMenuWillClose: (listener: () => void) => void;
onFocusThreeDotMenu: (listener: () => void) => void;
updateURLViewWidth: (width?: number) => void;
modals: {
cancelModal: <T>(data?: T) => void;
finishModal: <T>(data?: T) => void;
getModalInfo: <T>() => Promise<T>;
isModalUncloseable: () => Promise<boolean>;
confirmProtocol: (protocol: string, url: string) => void;
pingDomain: (url: string) => Promise<string>;
};
loadingScreen: {
loadingScreenAnimationFinished: () => void;
onToggleLoadingScreenVisibility: (listener: (toggle: boolean) => void) => void;
};
downloadsDropdown: {
requestInfo: () => void;
sendSize: (width: number, height: number) => void;
openFile: (item: DownloadedItem) => void;
startUpdateDownload: () => void;
startUpgrade: () => void;
requestClearDownloadsDropdown: () => void;
toggleDownloadsDropdownMenu: (payload: DownloadsMenuOpenEventPayload) => void;
focus: () => void;
};
downloadsDropdownMenu: {
requestInfo: () => void;
showInFolder: (item: DownloadedItem) => void;
cancelDownload: (item: DownloadedItem) => void;
clearFile: (item: DownloadedItem) => void;
openFile: (item: DownloadedItem) => void;
onUpdateDownloadsDropdownMenu: (listener: (item: DownloadedItem, darkMode: boolean) => void) => void;
};
serverDropdown: {
requestInfo: () => void;
sendSize: (width: number, height: number) => void;
switchServer: (serverName: string) => void;
showNewServerModal: () => void;
showEditServerModal: (serverName: string) => void;
showRemoveServerModal: (serverName: string) => void;
onUpdateServerDropdown: (listener: (
teams: TeamWithTabsAndGpo[],
darkMode: boolean,
windowBounds: Rectangle,
activeTeam?: string,
enableServerManagement?: boolean,
hasGPOTeams?: boolean,
expired?: Map<string, boolean>,
mentions?: Map<string, number>,
unreads?: Map<string, boolean>,
) => void) => void;
};
};
}
}

View file

@ -15,14 +15,8 @@ const base = require('./webpack.config.base');
module.exports = merge(base, {
entry: {
index: './src/main/app/index.ts',
mainWindow: './src/main/preload/mainWindow.js',
dropdown: './src/main/preload/dropdown.js',
downloadsDropdown: './src/main/preload/downloadsDropdown.js',
downloadsDropdownMenu: './src/main/preload/downloadsDropdownMenu.js',
desktopAPI: './src/main/preload/desktopAPI.js',
preload: './src/main/preload/mattermost.js',
modalPreload: './src/main/preload/modalPreload.js',
loadingScreenPreload: './src/main/preload/loadingScreenPreload.js',
urlView: './src/main/preload/urlView.js',
callsWidget: './src/main/preload/callsWidget.js',
},
externals: {