[MM-47706] Remove exposure of the ipcRenderer methods in the desktop app and only expose specific endpoints (#2387)

This commit is contained in:
Devin Binnie
2022-11-16 10:40:18 -04:00
committed by GitHub
parent 216674a673
commit 791c141aee
9 changed files with 261 additions and 133 deletions

View File

@@ -9,13 +9,63 @@ import {ipcRenderer, contextBridge} from 'electron';
import {
GET_LANGUAGE_INFORMATION,
RETRIEVED_LANGUAGE_INFORMATION,
QUIT,
GET_VIEW_NAME,
GET_VIEW_WEBCONTENTS_ID,
OPEN_APP_MENU,
CLOSE_TEAMS_DROPDOWN,
OPEN_TEAMS_DROPDOWN,
SWITCH_TAB,
CLOSE_TAB,
WINDOW_CLOSE,
WINDOW_MINIMIZE,
WINDOW_MAXIMIZE,
WINDOW_RESTORE,
DOUBLE_CLICK_ON_WINDOW,
FOCUS_BROWSERVIEW,
RELOAD_CURRENT_VIEW,
CLOSE_DOWNLOADS_DROPDOWN,
CLOSE_DOWNLOADS_DROPDOWN_MENU,
OPEN_DOWNLOADS_DROPDOWN,
HISTORY,
CHECK_FOR_UPDATES,
UPDATE_CONFIGURATION,
UPDATE_TEAMS,
GET_CONFIGURATION,
GET_DARK_MODE,
REQUEST_HAS_DOWNLOADS,
GET_FULL_SCREEN_STATUS,
GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
GET_AVAILABLE_LANGUAGES,
GET_LOCAL_CONFIGURATION,
GET_DOWNLOAD_LOCATION,
RELOAD_CONFIGURATION,
DARK_MODE_CHANGE,
LOAD_RETRY,
LOAD_SUCCESS,
LOAD_FAILED,
SET_ACTIVE_VIEW,
MAXIMIZE_CHANGE,
PLAY_SOUND,
MODAL_OPEN,
MODAL_CLOSE,
TOGGLE_BACK_BUTTON,
UPDATE_MENTIONS,
SHOW_DOWNLOADS_DROPDOWN_BUTTON_BADGE,
HIDE_DOWNLOADS_DROPDOWN_BUTTON_BADGE,
UPDATE_DOWNLOADS_DROPDOWN,
APP_MENU_WILL_CLOSE,
FOCUS_THREE_DOT_MENU,
} from 'common/communication';
contextBridge.exposeInMainWorld('ipcRenderer', {
send: ipcRenderer.send,
on: (channel, listener) => ipcRenderer.on(channel, (_, ...args) => listener(null, ...args)),
invoke: ipcRenderer.invoke,
});
console.log('Preload initialized');
if (process.env.NODE_ENV === 'test') {
contextBridge.exposeInMainWorld('testHelper', {
getViewName: () => ipcRenderer.invoke(GET_VIEW_NAME),
getWebContentsId: () => ipcRenderer.invoke(GET_VIEW_WEBCONTENTS_ID),
});
}
contextBridge.exposeInMainWorld('process', {
platform: process.platform,
@@ -29,6 +79,64 @@ contextBridge.exposeInMainWorld('timers', {
setImmediate,
});
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: (serverName, tabName) => ipcRenderer.send(SWITCH_TAB, serverName, tabName),
closeTab: (serverName, tabName) => ipcRenderer.send(CLOSE_TAB, serverName, tabName),
closeWindow: () => ipcRenderer.send(WINDOW_CLOSE),
minimizeWindow: () => ipcRenderer.send(WINDOW_MINIMIZE),
maximizeWindow: () => ipcRenderer.send(WINDOW_MAXIMIZE),
restoreWindow: () => ipcRenderer.send(WINDOW_RESTORE),
doubleClickOnWindow: (windowName) => ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW, windowName),
focusBrowserView: () => ipcRenderer.send(FOCUS_BROWSERVIEW),
reloadCurrentView: () => ipcRenderer.send(RELOAD_CURRENT_VIEW),
closeDownloadsDropdown: () => ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN),
closeDownloadsDropdownMenu: () => ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN_MENU),
openDownloadsDropdown: () => ipcRenderer.send(OPEN_DOWNLOADS_DROPDOWN),
goBack: () => ipcRenderer.send(HISTORY, -1),
checkForUpdates: () => ipcRenderer.send(CHECK_FOR_UPDATES),
updateConfiguration: (saveQueueItems) => ipcRenderer.send(UPDATE_CONFIGURATION, saveQueueItems),
updateTeams: (updatedTeams) => ipcRenderer.invoke(UPDATE_TEAMS, updatedTeams),
getConfiguration: (option) => ipcRenderer.invoke(GET_CONFIGURATION, option),
getVersion: () => ipcRenderer.invoke('get-app-version'),
getDarkMode: () => ipcRenderer.invoke(GET_DARK_MODE),
requestHasDownloads: () => ipcRenderer.invoke(REQUEST_HAS_DOWNLOADS),
getFullScreenStatus: () => ipcRenderer.invoke(GET_FULL_SCREEN_STATUS),
getAvailableSpellCheckerLanguages: () => ipcRenderer.invoke(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES),
getAvailableLanguages: () => ipcRenderer.invoke(GET_AVAILABLE_LANGUAGES),
getLocalConfiguration: (option) => ipcRenderer.invoke(GET_LOCAL_CONFIGURATION, option),
getDownloadLocation: (downloadLocation) => ipcRenderer.invoke(GET_DOWNLOAD_LOCATION, downloadLocation),
onSynchronizeConfig: (listener) => ipcRenderer.on('synchronize-config', () => listener()),
onReloadConfiguration: (listener) => ipcRenderer.on(RELOAD_CONFIGURATION, () => listener()),
onDarkModeChange: (listener) => ipcRenderer.on(DARK_MODE_CHANGE, (_, darkMode) => listener(darkMode)),
onLoadRetry: (listener) => ipcRenderer.on(LOAD_RETRY, (_, viewName, retry, err, loadUrl) => listener(viewName, retry, err, loadUrl)),
onLoadSuccess: (listener) => ipcRenderer.on(LOAD_SUCCESS, (_, viewName) => listener(viewName)),
onLoadFailed: (listener) => ipcRenderer.on(LOAD_FAILED, (_, viewName, err, loadUrl) => listener(viewName, err, loadUrl)),
onSetActiveView: (listener) => ipcRenderer.on(SET_ACTIVE_VIEW, (_, serverName, tabName) => listener(serverName, tabName)),
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()),
onPlaySound: (listener) => ipcRenderer.on(PLAY_SOUND, (_, soundName) => listener(soundName)),
onModalOpen: (listener) => ipcRenderer.on(MODAL_OPEN, () => listener()),
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()),
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()),
onHideDownloadsDropdownButtonBadge: (listener) => ipcRenderer.on(HIDE_DOWNLOADS_DROPDOWN_BUTTON_BADGE, () => listener()),
onUpdateDownloadsDropdown: (listener) => ipcRenderer.on(UPDATE_DOWNLOADS_DROPDOWN, (_, downloads) => listener(downloads)),
onAppMenuWillClose: (listener) => ipcRenderer.on(APP_MENU_WILL_CLOSE, () => listener()),
onFocusThreeDotMenu: (listener) => ipcRenderer.on(FOCUS_THREE_DOT_MENU, () => listener()),
});
window.addEventListener('message', async (event) => {
switch (event.data.type) {
case GET_LANGUAGE_INFORMATION:

View File

@@ -9,49 +9,12 @@ import React, {Fragment} from 'react';
import {Container, Row} from 'react-bootstrap';
import {DropResult} from 'react-beautiful-dnd';
import {injectIntl, IntlShape} from 'react-intl';
import {IpcRendererEvent} from 'electron/renderer';
import {TeamWithTabs} from 'types/config';
import {DownloadedItems} from 'types/downloads';
import {getTabViewName} from 'common/tabs/TabView';
import {
FOCUS_BROWSERVIEW,
MAXIMIZE_CHANGE,
DARK_MODE_CHANGE,
HISTORY,
LOAD_RETRY,
LOAD_SUCCESS,
LOAD_FAILED,
WINDOW_CLOSE,
WINDOW_MINIMIZE,
WINDOW_RESTORE,
WINDOW_MAXIMIZE,
DOUBLE_CLICK_ON_WINDOW,
PLAY_SOUND,
MODAL_OPEN,
MODAL_CLOSE,
SET_ACTIVE_VIEW,
UPDATE_MENTIONS,
TOGGLE_BACK_BUTTON,
FOCUS_THREE_DOT_MENU,
GET_FULL_SCREEN_STATUS,
CLOSE_TEAMS_DROPDOWN,
OPEN_TEAMS_DROPDOWN,
SWITCH_TAB,
CLOSE_TAB,
RELOAD_CURRENT_VIEW,
CLOSE_DOWNLOADS_DROPDOWN,
OPEN_DOWNLOADS_DROPDOWN,
SHOW_DOWNLOADS_DROPDOWN_BUTTON_BADGE,
HIDE_DOWNLOADS_DROPDOWN_BUTTON_BADGE,
UPDATE_DOWNLOADS_DROPDOWN,
REQUEST_HAS_DOWNLOADS,
CLOSE_DOWNLOADS_DROPDOWN_MENU,
APP_MENU_WILL_CLOSE,
} from 'common/communication';
import restoreButton from '../../assets/titlebar/chrome-restore.svg';
import maximizeButton from '../../assets/titlebar/chrome-maximize.svg';
import minimizeButton from '../../assets/titlebar/chrome-minimize.svg';
@@ -90,7 +53,7 @@ type State = {
activeServerName?: string;
activeTabName?: string;
sessionsExpired: Record<string, boolean>;
unreadCounts: Record<string, number>;
unreadCounts: Record<string, boolean>;
mentionCounts: Record<string, number>;
maximized: boolean;
tabViewStatus: Map<string, TabViewStatus>;
@@ -160,7 +123,7 @@ class MainPage extends React.PureComponent<Props, State> {
async requestDownloadsLength() {
try {
const hasDownloads = await window.ipcRenderer.invoke(REQUEST_HAS_DOWNLOADS);
const hasDownloads = await window.desktop.requestHasDownloads();
this.setState({
hasDownloads,
});
@@ -174,7 +137,7 @@ class MainPage extends React.PureComponent<Props, State> {
this.requestDownloadsLength();
// set page on retry
window.ipcRenderer.on(LOAD_RETRY, (_, viewName, retry, err, loadUrl) => {
window.desktop.onLoadRetry((viewName, retry, err, loadUrl) => {
console.log(`${viewName}: failed to load ${err}, but retrying`);
const statusValue = {
status: Status.RETRY,
@@ -187,11 +150,11 @@ class MainPage extends React.PureComponent<Props, State> {
this.updateTabStatus(viewName, statusValue);
});
window.ipcRenderer.on(LOAD_SUCCESS, (_, viewName) => {
window.desktop.onLoadSuccess((viewName) => {
this.updateTabStatus(viewName, {status: Status.DONE});
});
window.ipcRenderer.on(LOAD_FAILED, (_, viewName, err, loadUrl) => {
window.desktop.onLoadFailed((viewName, err, loadUrl) => {
console.log(`${viewName}: failed to load ${err}`);
const statusValue = {
status: Status.FAILED,
@@ -203,39 +166,39 @@ class MainPage extends React.PureComponent<Props, State> {
this.updateTabStatus(viewName, statusValue);
});
window.ipcRenderer.on(DARK_MODE_CHANGE, (_, darkMode) => {
window.desktop.onDarkModeChange((darkMode) => {
this.setState({darkMode});
});
// can't switch tabs sequentially for some reason...
window.ipcRenderer.on(SET_ACTIVE_VIEW, (event, serverName, tabName) => {
window.desktop.onSetActiveView((serverName, tabName) => {
this.setState({activeServerName: serverName, activeTabName: tabName});
});
window.ipcRenderer.on(MAXIMIZE_CHANGE, this.handleMaximizeState);
window.desktop.onMaximizeChange(this.handleMaximizeState);
window.ipcRenderer.on('enter-full-screen', () => this.handleFullScreenState(true));
window.ipcRenderer.on('leave-full-screen', () => this.handleFullScreenState(false));
window.desktop.onEnterFullScreen(() => this.handleFullScreenState(true));
window.desktop.onLeaveFullScreen(() => this.handleFullScreenState(false));
window.ipcRenderer.invoke(GET_FULL_SCREEN_STATUS).then((fullScreenStatus) => this.handleFullScreenState(fullScreenStatus));
window.desktop.getFullScreenStatus().then((fullScreenStatus) => this.handleFullScreenState(fullScreenStatus));
window.ipcRenderer.on(PLAY_SOUND, (_event, soundName) => {
window.desktop.onPlaySound((soundName) => {
playSound(soundName);
});
window.ipcRenderer.on(MODAL_OPEN, () => {
window.desktop.onModalOpen(() => {
this.setState({modalOpen: true});
});
window.ipcRenderer.on(MODAL_CLOSE, () => {
window.desktop.onModalClose(() => {
this.setState({modalOpen: false});
});
window.ipcRenderer.on(TOGGLE_BACK_BUTTON, (event, showExtraBar) => {
window.desktop.onToggleBackButton((showExtraBar) => {
this.setState({showExtraBar});
});
window.ipcRenderer.on(UPDATE_MENTIONS, (_event, view, mentions, unreads, isExpired) => {
window.desktop.onUpdateMentions((view, mentions, unreads, isExpired) => {
const {unreadCounts, mentionCounts, sessionsExpired} = this.state;
const newMentionCounts = {...mentionCounts};
@@ -250,40 +213,40 @@ class MainPage extends React.PureComponent<Props, State> {
this.setState({unreadCounts: newUnreads, mentionCounts: newMentionCounts, sessionsExpired: expired});
});
window.ipcRenderer.on(CLOSE_TEAMS_DROPDOWN, () => {
window.desktop.onCloseTeamsDropdown(() => {
this.setState({isMenuOpen: false});
});
window.ipcRenderer.on(OPEN_TEAMS_DROPDOWN, () => {
window.desktop.onOpenTeamsDropdown(() => {
this.setState({isMenuOpen: true});
});
window.ipcRenderer.on(CLOSE_DOWNLOADS_DROPDOWN, () => {
window.desktop.onCloseDownloadsDropdown(() => {
this.setState({isDownloadsDropdownOpen: false});
});
window.ipcRenderer.on(OPEN_DOWNLOADS_DROPDOWN, () => {
window.desktop.onOpenDownloadsDropdown(() => {
this.setState({isDownloadsDropdownOpen: true});
});
window.ipcRenderer.on(SHOW_DOWNLOADS_DROPDOWN_BUTTON_BADGE, () => {
window.desktop.onShowDownloadsDropdownButtonBadge(() => {
this.setState({showDownloadsBadge: true});
});
window.ipcRenderer.on(HIDE_DOWNLOADS_DROPDOWN_BUTTON_BADGE, () => {
window.desktop.onHideDownloadsDropdownButtonBadge(() => {
this.setState({showDownloadsBadge: false});
});
window.ipcRenderer.on(UPDATE_DOWNLOADS_DROPDOWN, (event, downloads: DownloadedItems) => {
window.desktop.onUpdateDownloadsDropdown((downloads: DownloadedItems) => {
this.setState({
hasDownloads: (Object.values(downloads)?.length || 0) > 0,
});
});
window.ipcRenderer.on(APP_MENU_WILL_CLOSE, this.unFocusThreeDotsButton);
window.desktop.onAppMenuWillClose(this.unFocusThreeDotsButton);
if (window.process.platform !== 'darwin') {
window.ipcRenderer.on(FOCUS_THREE_DOT_MENU, this.focusThreeDotsButton);
window.desktop.onFocusThreeDotMenu(this.focusThreeDotsButton);
}
window.addEventListener('click', this.handleCloseDropdowns);
@@ -294,11 +257,11 @@ class MainPage extends React.PureComponent<Props, State> {
}
handleCloseDropdowns = () => {
window.ipcRenderer.send(CLOSE_TEAMS_DROPDOWN);
window.desktop.closeTeamsDropdown();
this.closeDownloadsDropdown();
}
handleMaximizeState = (_: IpcRendererEvent, maximized: boolean) => {
handleMaximizeState = (maximized: boolean) => {
this.setState({maximized});
}
@@ -307,11 +270,17 @@ class MainPage extends React.PureComponent<Props, State> {
}
handleSelectTab = (name: string) => {
window.ipcRenderer.send(SWITCH_TAB, this.state.activeServerName, name);
if (!this.state.activeServerName) {
return;
}
window.desktop.switchTab(this.state.activeServerName, name);
}
handleCloseTab = (name: string) => {
window.ipcRenderer.send(CLOSE_TAB, this.state.activeServerName, name);
if (!this.state.activeServerName) {
return;
}
window.desktop.closeTab(this.state.activeServerName, name);
}
handleDragAndDrop = async (dropResult: DropResult) => {
@@ -338,21 +307,21 @@ class MainPage extends React.PureComponent<Props, State> {
handleClose = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation(); // since it is our button, the event goes into MainPage's onclick event, getting focus back.
window.ipcRenderer.send(WINDOW_CLOSE);
window.desktop.closeWindow();
}
handleMinimize = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
window.ipcRenderer.send(WINDOW_MINIMIZE);
window.desktop.minimizeWindow();
}
handleMaximize = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
window.ipcRenderer.send(WINDOW_MAXIMIZE);
window.desktop.maximizeWindow();
}
handleRestore = () => {
window.ipcRenderer.send(WINDOW_RESTORE);
window.desktop.restoreWindow();
}
openMenu = () => {
@@ -360,16 +329,16 @@ class MainPage extends React.PureComponent<Props, State> {
}
handleDoubleClick = () => {
window.ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW);
window.desktop.doubleClickOnWindow();
}
focusOnWebView = () => {
window.ipcRenderer.send(FOCUS_BROWSERVIEW);
window.desktop.focusBrowserView();
this.handleCloseDropdowns();
}
reloadCurrentView = () => {
window.ipcRenderer.send(RELOAD_CURRENT_VIEW);
window.desktop.reloadCurrentView();
}
showHideDownloadsBadge(value = false) {
@@ -377,12 +346,12 @@ class MainPage extends React.PureComponent<Props, State> {
}
closeDownloadsDropdown() {
window.ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN);
window.ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN_MENU);
window.desktop.closeDownloadsDropdown();
window.desktop.closeDownloadsDropdownMenu();
}
openDownloadsDropdown() {
window.ipcRenderer.send(OPEN_DOWNLOADS_DROPDOWN);
window.desktop.openDownloadsDropdown();
}
focusThreeDotsButton = () => {
@@ -497,12 +466,12 @@ class MainPage extends React.PureComponent<Props, State> {
}
return sum + this.state.mentionCounts[key];
}, 0);
const totalUnreadCount = Object.keys(this.state.unreadCounts).reduce((sum, key) => {
const hasAnyUnreads = Object.keys(this.state.unreadCounts).reduce((sum, key) => {
if (this.state.activeServerName && key.match(serverMatch)) {
return sum;
}
return sum + this.state.unreadCounts[key];
}, 0);
return sum || this.state.unreadCounts[key];
}, false);
const topRow = (
<Row
className={topBarClassName}
@@ -536,7 +505,7 @@ class MainPage extends React.PureComponent<Props, State> {
isDisabled={this.state.modalOpen}
activeServerName={this.state.activeServerName}
totalMentionCount={totalMentionCount}
hasUnreads={totalUnreadCount > 0}
hasUnreads={hasAnyUnreads}
isMenuOpen={this.state.isMenuOpen}
darkMode={this.state.darkMode}
/>
@@ -586,7 +555,7 @@ class MainPage extends React.PureComponent<Props, State> {
darkMode={this.state.darkMode}
show={this.state.showExtraBar}
goBack={() => {
window.ipcRenderer.send(HISTORY, -1);
window.desktop.goBack();
}}
/>
<Row>

View File

@@ -12,28 +12,16 @@ import {FormattedMessage, injectIntl, IntlShape} from 'react-intl';
import ReactSelect, {ActionMeta, MultiValue} from 'react-select';
import {CombinedConfig, LocalConfiguration} from 'types/config';
import {SaveQueueItem} from 'types/settings';
import {DeepPartial} from 'types/utils';
import {localeTranslations} from 'common/utils/constants';
import {
GET_LOCAL_CONFIGURATION,
UPDATE_CONFIGURATION,
DOUBLE_CLICK_ON_WINDOW,
GET_DOWNLOAD_LOCATION,
RELOAD_CONFIGURATION,
GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
CHECK_FOR_UPDATES,
GET_AVAILABLE_LANGUAGES,
} from 'common/communication';
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
const CONFIG_TYPE_UPDATES = 'updates';
const CONFIG_TYPE_APP_OPTIONS = 'appOptions';
type ConfigType = typeof CONFIG_TYPE_UPDATES | typeof CONFIG_TYPE_APP_OPTIONS;
type Props = {
intl: IntlShape;
}
@@ -54,12 +42,6 @@ type SavingStateItems = {
updates: SavingState;
}
type SaveQueueItem = {
configType: ConfigType;
key: keyof CombinedConfig;
data: CombinedConfig[keyof CombinedConfig];
}
class SettingsPage extends React.PureComponent<Props, State> {
trayIconThemeRef: React.RefObject<HTMLDivElement>;
downloadLocationRef: React.RefObject<HTMLInputElement>;
@@ -125,18 +107,18 @@ class SettingsPage extends React.PureComponent<Props, State> {
}
componentDidMount() {
window.ipcRenderer.on(RELOAD_CONFIGURATION, () => {
window.desktop.onReloadConfiguration(() => {
this.updateSaveState();
this.getConfig();
});
window.ipcRenderer.invoke(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES).then((languages: string[]) => {
window.desktop.getAvailableSpellCheckerLanguages().then((languages: string[]) => {
const availableSpellcheckerLanguages = languages.filter((language) => localeTranslations[language]).map((language) => ({label: localeTranslations[language], value: language}));
availableSpellcheckerLanguages.sort((a, b) => a.label.localeCompare(b.label));
this.setState({availableSpellcheckerLanguages});
});
window.ipcRenderer.invoke(GET_AVAILABLE_LANGUAGES).then((languages: string[]) => {
window.desktop.getAvailableLanguages().then((languages: string[]) => {
const availableLanguages = languages.filter((language) => localeTranslations[language]).map((language) => ({label: localeTranslations[language], value: language}));
availableLanguages.sort((a, b) => a.label.localeCompare(b.label));
this.setState({availableLanguages});
@@ -144,8 +126,8 @@ class SettingsPage extends React.PureComponent<Props, State> {
}
getConfig = () => {
window.ipcRenderer.invoke(GET_LOCAL_CONFIGURATION).then((config) => {
this.setState({ready: true, maximized: false, ...this.convertConfigDataToState(config, this.state) as Omit<State, 'ready'>});
window.desktop.getLocalConfiguration().then((config) => {
this.setState({ready: true, maximized: false, ...this.convertConfigDataToState(config as Partial<LocalConfiguration>, this.state) as Omit<State, 'ready'>});
});
}
@@ -159,7 +141,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
return newState;
}
saveSetting = (configType: ConfigType, {key, data}: {key: keyof CombinedConfig; data: CombinedConfig[keyof CombinedConfig]}) => {
saveSetting = (configType: 'updates' | 'appOptions', {key, data}: {key: keyof CombinedConfig; data: CombinedConfig[keyof CombinedConfig]}) => {
this.saveQueue.push({
configType,
key,
@@ -177,7 +159,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
this.savingIsDebounced = true;
setTimeout(() => {
this.savingIsDebounced = false;
window.ipcRenderer.send(UPDATE_CONFIGURATION, this.saveQueue.splice(0, this.saveQueue.length));
window.desktop.updateConfiguration(this.saveQueue.splice(0, this.saveQueue.length));
}, 500);
}
@@ -353,7 +335,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
}
checkForUpdates = () => {
window.ipcRenderer.send(CHECK_FOR_UPDATES);
window.desktop.checkForUpdates();
}
handleChangeSpellCheckerLocales = (value: MultiValue<{label: string; value: string}>, actionMeta: ActionMeta<{label: string; value: string}>) => {
@@ -402,7 +384,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
selectDownloadLocation = () => {
if (!this.state.userOpenedDownloadDialog) {
window.ipcRenderer.invoke(GET_DOWNLOAD_LOCATION, this.state.downloadLocation).then((result) => this.saveDownloadLocation(result));
window.desktop.getDownloadLocation(this.state.downloadLocation).then((result) => this.saveDownloadLocation(result));
this.setState({userOpenedDownloadDialog: true});
}
this.setState({userOpenedDownloadDialog: false});
@@ -434,7 +416,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
}
handleDoubleClick = () => {
window.ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW, 'settings');
window.desktop.doubleClickOnWindow('settings');
}
render() {

View File

@@ -21,7 +21,7 @@ type Props = {
onCloseTab: (name: string) => void;
tabs: Tab[];
sessionsExpired: Record<string, boolean>;
unreadCounts: Record<string, number>;
unreadCounts: Record<string, boolean>;
mentionCounts: Record<string, number>;
onDrop: (result: DropResult) => void;
tabsDisabled?: boolean;

View File

@@ -5,8 +5,6 @@ import classNames from 'classnames';
import React, {useEffect} from 'react';
import {FormattedMessage} from 'react-intl';
import {CLOSE_TEAMS_DROPDOWN, OPEN_TEAMS_DROPDOWN} from 'common/communication';
import '../css/components/TeamDropdownButton.scss';
type Props = {
@@ -31,7 +29,11 @@ const TeamDropdownButton: React.FC<Props> = (props: Props) => {
const handleToggleButton = (event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
event.stopPropagation();
window.ipcRenderer.send(isMenuOpen ? CLOSE_TEAMS_DROPDOWN : OPEN_TEAMS_DROPDOWN);
if (isMenuOpen) {
window.desktop.closeTeamsDropdown();
} else {
window.desktop.openTeamsDropdown();
}
};
let badgeDiv: React.ReactNode;

View File

@@ -10,8 +10,6 @@ import ReactDOM from 'react-dom';
import {CombinedConfig, Team} from 'types/config';
import {GET_CONFIGURATION, UPDATE_TEAMS, QUIT, RELOAD_CONFIGURATION, OPEN_APP_MENU} from 'common/communication';
import MainPage from './components/MainPage';
import IntlProvider from './intl_provider';
@@ -28,11 +26,11 @@ class Root extends React.PureComponent<Record<string, never>, State> {
async componentDidMount() {
await this.setInitialConfig();
window.ipcRenderer.on('synchronize-config', () => {
window.desktop.onSynchronizeConfig(() => {
this.reloadConfig();
});
window.ipcRenderer.on(RELOAD_CONFIGURATION, () => {
window.desktop.onReloadConfiguration(() => {
this.reloadConfig();
});
@@ -84,7 +82,7 @@ class Root extends React.PureComponent<Record<string, never>, State> {
};
teamConfigChange = async (updatedTeams: Team[]) => {
window.ipcRenderer.invoke(UPDATE_TEAMS, updatedTeams).then(() => {
window.desktop.updateTeams(updatedTeams).then(() => {
this.reloadConfig();
});
};
@@ -97,20 +95,20 @@ class Root extends React.PureComponent<Record<string, never>, State> {
requestConfig = async (exitOnError?: boolean) => {
// todo: should we block?
try {
const configRequest = await window.ipcRenderer.invoke(GET_CONFIGURATION);
const configRequest = await window.desktop.getConfiguration() as CombinedConfig;
return configRequest;
} catch (err: any) {
console.log(`there was an error with the config: ${err}`);
if (exitOnError) {
window.ipcRenderer.send(QUIT, `unable to load configuration: ${err}`, err.stack);
window.desktop.quit(`unable to load configuration: ${err}`, err.stack);
}
}
return null;
return undefined;
};
openMenu = () => {
if (window.process.platform !== 'darwin') {
window.ipcRenderer.send(OPEN_APP_MENU);
window.desktop.openAppMenu();
}
}
@@ -134,7 +132,7 @@ class Root extends React.PureComponent<Record<string, never>, State> {
);
}
}
window.ipcRenderer.invoke('get-app-version').then(({name, version}) => {
window.desktop.getVersion().then(({name, version}) => {
// eslint-disable-next-line no-undef
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore

View File

@@ -9,8 +9,6 @@ import 'renderer/css/settings.css';
import React from 'react';
import ReactDOM from 'react-dom';
import {DARK_MODE_CHANGE, GET_DARK_MODE} from 'common/communication';
import darkStyles from 'renderer/css/lazy/settings-dark.lazy.css';
import SettingsPage from './components/SettingsPage';
@@ -24,8 +22,8 @@ const setDarkMode = (darkMode: boolean) => {
}
};
window.ipcRenderer.on(DARK_MODE_CHANGE, (_, darkMode) => setDarkMode(darkMode));
window.ipcRenderer.invoke(GET_DARK_MODE).then(setDarkMode);
window.desktop.onDarkModeChange((darkMode) => setDarkMode(darkMode));
window.desktop.getDarkMode().then(setDarkMode);
const start = async () => {
ReactDOM.render(

10
src/types/settings.ts Normal file
View File

@@ -0,0 +1,10 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {CombinedConfig} from './config';
export type SaveQueueItem = {
configType: 'updates' | 'appOptions';
key: keyof CombinedConfig;
data: CombinedConfig[keyof CombinedConfig];
};

View File

@@ -3,6 +3,10 @@
import {ipcRenderer} from 'electron/renderer';
import {CombinedConfig, LocalConfiguration, Team} from './config';
import {DownloadedItems} from './downloads';
import {SaveQueueItem} from './settings';
declare global {
interface Window {
ipcRenderer: {
@@ -23,5 +27,62 @@ declare global {
mas: {
getThumbnailLocation: (location: string) => Promise<string>;
};
desktop: {
quit: (reason: string, stack: string) => void;
openAppMenu: () => void;
closeTeamsDropdown: () => void;
openTeamsDropdown: () => void;
switchTab: (serverName: string, tabName: string) => void;
closeTab: (serverName: string, tabName: string) => void;
closeWindow: () => void;
minimizeWindow: () => void;
maximizeWindow: () => void;
restoreWindow: () => void;
doubleClickOnWindow: (windowName?: string) => void;
focusBrowserView: () => void;
reloadCurrentView: () => void;
closeDownloadsDropdown: () => void;
closeDownloadsDropdownMenu: () => void;
openDownloadsDropdown: () => void;
goBack: () => void;
checkForUpdates: () => void;
updateConfiguration: (saveQueueItems: SaveQueueItem[]) => void;
updateTeams: (updatedTeams: Team[]) => Promise<void>;
getConfiguration: (option?: keyof CombinedConfig) => Promise<CombinedConfig[keyof CombinedConfig] | CombinedConfig>;
getVersion: () => Promise<{name: string; version: string}>;
getDarkMode: () => Promise<boolean>;
requestHasDownloads: () => Promise<boolean>;
getFullScreenStatus: () => Promise<boolean>;
getAvailableSpellCheckerLanguages: () => Promise<string[]>;
getAvailableLanguages: () => Promise<string[]>;
getLocalConfiguration: (option?: keyof LocalConfiguration) => Promise<LocalConfiguration[keyof LocalConfiguration] | Partial<LocalConfiguration>>;
getDownloadLocation: (downloadLocation?: string) => Promise<string>;
onSynchronizeConfig: (listener: () => void) => void;
onReloadConfiguration: (listener: () => void) => void;
onDarkModeChange: (listener: (darkMode: boolean) => void) => void;
onLoadRetry: (listener: (viewName: string, retry: Date, err: string, loadUrl: string) => void) => void;
onLoadSuccess: (listener: (viewName: string) => void) => void;
onLoadFailed: (listener: (viewName: string, err: string, loadUrl: string) => void) => void;
onSetActiveView: (listener: (serverName: string, tabName: string) => void) => void;
onMaximizeChange: (listener: (maximize: boolean) => void) => void;
onEnterFullScreen: (listener: () => void) => void;
onLeaveFullScreen: (listener: () => void) => void;
onPlaySound: (listener: (soundName: string) => void) => void;
onModalOpen: (listener: () => void) => void;
onModalClose: (listener: () => void) => void;
onToggleBackButton: (listener: (showExtraBar: boolean) => void) => void;
onUpdateMentions: (listener: (view: string, mentions: number, unreads: boolean, isExpired: boolean) => void) => void;
onCloseTeamsDropdown: (listener: () => void) => void;
onOpenTeamsDropdown: (listener: () => void) => void;
onCloseDownloadsDropdown: (listener: () => void) => void;
onOpenDownloadsDropdown: (listener: () => void) => void;
onShowDownloadsDropdownButtonBadge: (listener: () => void) => void;
onHideDownloadsDropdownButtonBadge: (listener: () => void) => void;
onUpdateDownloadsDropdown: (listener: (downloads: DownloadedItems) => void) => void;
onAppMenuWillClose: (listener: () => void) => void;
onFocusThreeDotMenu: (listener: () => void) => void;
};
}
}