xo: Handle floating promises.

Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This commit is contained in:
Anders Kaseorg
2020-04-25 14:44:06 -07:00
committed by Anders Kaseorg
parent 0225778050
commit bb88a7b7a8
16 changed files with 116 additions and 116 deletions

View File

@@ -34,36 +34,41 @@ export function appUpdater(updateFromMenu = false): void {
autoUpdater.allowPrerelease = isBetaUpdate || false;
const eventsListenerRemove = ['update-available', 'update-not-available'];
autoUpdater.on('update-available', (info: UpdateInfo) => {
autoUpdater.on('update-available', async (info: UpdateInfo) => {
if (updateFromMenu) {
dialog.showMessageBox({
message: `A new version ${info.version}, of Zulip Desktop is available`,
detail: 'The update will be downloaded in the background. You will be notified when it is ready to be installed.'
});
updateAvailable = true;
// This is to prevent removal of 'update-downloaded' and 'error' event listener.
eventsListenerRemove.forEach(event => {
autoUpdater.removeAllListeners(event);
});
await dialog.showMessageBox({
message: `A new version ${info.version}, of Zulip Desktop is available`,
detail: 'The update will be downloaded in the background. You will be notified when it is ready to be installed.'
});
}
});
autoUpdater.on('update-not-available', () => {
autoUpdater.on('update-not-available', async () => {
if (updateFromMenu) {
dialog.showMessageBox({
message: 'No updates available',
detail: `You are running the latest version of Zulip Desktop.\nVersion: ${app.getVersion()}`
});
// Remove all autoUpdator listeners so that next time autoUpdator is manually called these
// listeners don't trigger multiple times.
autoUpdater.removeAllListeners();
await dialog.showMessageBox({
message: 'No updates available',
detail: `You are running the latest version of Zulip Desktop.\nVersion: ${app.getVersion()}`
});
}
});
autoUpdater.on('error', async (error: Error) => {
if (updateFromMenu) {
// Remove all autoUpdator listeners so that next time autoUpdator is manually called these
// listeners don't trigger multiple times.
autoUpdater.removeAllListeners();
const messageText = (updateAvailable) ? ('Unable to download the updates') : ('Unable to check for updates');
const { response } = await dialog.showMessageBox({
type: 'error',
@@ -73,11 +78,8 @@ export function appUpdater(updateFromMenu = false): void {
Current Version: ${app.getVersion()}`
});
if (response === 0) {
LinkUtil.openBrowser(new URL('https://zulipchat.com/apps/'));
await LinkUtil.openBrowser(new URL('https://zulipchat.com/apps/'));
}
// Remove all autoUpdator listeners so that next time autoUpdator is manually called these
// listeners don't trigger multiple times.
autoUpdater.removeAllListeners();
}
});
@@ -100,5 +102,5 @@ export function appUpdater(updateFromMenu = false): void {
}
});
// Init for updates
autoUpdater.checkForUpdates();
(async () => autoUpdater.checkForUpdates())();
}

View File

@@ -91,7 +91,7 @@ function createMainWindow(): Electron.BrowserWindow {
win.webContents.send('focus');
});
win.loadURL(mainURL);
(async () => win.loadURL(mainURL))();
// Keep the app running in background on close event
win.on('close', event => {
@@ -182,7 +182,7 @@ app.on('ready', () => {
const isSystemProxy = ConfigUtil.getConfigItem('useSystemProxy');
if (isSystemProxy) {
ProxyUtil.resolveSystemProxy(mainWindow);
(async () => ProxyUtil.resolveSystemProxy(mainWindow))();
}
const page = mainWindow.webContents;
@@ -315,8 +315,8 @@ app.on('ready', () => {
}
});
ipcMain.on('toggleAutoLauncher', (_event: Electron.IpcMainEvent, AutoLaunchValue: boolean) => {
setAutoLaunch(AutoLaunchValue);
ipcMain.on('toggleAutoLauncher', async (_event: Electron.IpcMainEvent, AutoLaunchValue: boolean) => {
await setAutoLaunch(AutoLaunchValue);
});
ipcMain.on('downloadFile', (_event: Electron.IpcMainEvent, url: string, downloadPath: string) => {

View File

@@ -55,8 +55,8 @@ function getToolsSubmenu(): Electron.MenuItemConstructorOptions[] {
},
{
label: t.__('Release Notes'),
click() {
LinkUtil.openBrowser(new URL(`https://github.com/zulip/zulip-desktop/releases/tag/v${app.getVersion()}`));
async click() {
await LinkUtil.openBrowser(new URL(`https://github.com/zulip/zulip-desktop/releases/tag/v${app.getVersion()}`));
}
},
{
@@ -65,8 +65,8 @@ function getToolsSubmenu(): Electron.MenuItemConstructorOptions[] {
{
label: t.__('Factory Reset'),
accelerator: process.platform === 'darwin' ? 'Command+Shift+D' : 'Ctrl+Shift+D',
click() {
resetAppSettings();
async click() {
await resetAppSettings();
}
},
{

View File

@@ -4,7 +4,7 @@ import AutoLaunch from 'auto-launch';
import isDev from 'electron-is-dev';
import * as ConfigUtil from '../renderer/js/utils/config-util';
export const setAutoLaunch = (AutoLaunchValue: boolean): void => {
export const setAutoLaunch = async (AutoLaunchValue: boolean): Promise<void> => {
// Don't run this in development
if (isDev) {
return;
@@ -19,9 +19,9 @@ export const setAutoLaunch = (AutoLaunchValue: boolean): void => {
isHidden: false
});
if (autoLaunchOption) {
ZulipAutoLauncher.enable();
await ZulipAutoLauncher.enable();
} else {
ZulipAutoLauncher.disable();
await ZulipAutoLauncher.disable();
}
} else {
app.setLoginItemSettings({

View File

@@ -16,22 +16,22 @@ export default function handleExternalLink(this: WebView, event: Electron.NewWin
if (LinkUtil.isUploadsUrl(this.props.url, url)) {
ipcRenderer.send('downloadFile', url.href, downloadPath);
ipcRenderer.once('downloadFileCompleted', (_event: Event, filePath: string, fileName: string) => {
ipcRenderer.once('downloadFileCompleted', async (_event: Event, filePath: string, fileName: string) => {
const downloadNotification = new Notification('Download Complete', {
body: `Click to show ${fileName} in folder`,
silent: true // We'll play our own sound - ding.ogg
});
// Play sound to indicate download complete
if (!ConfigUtil.getConfigItem('silent')) {
dingSound.play();
}
downloadNotification.addEventListener('click', () => {
// Reveal file in download folder
shell.showItemInFolder(filePath);
});
ipcRenderer.removeAllListeners('downloadFileFailed');
// Play sound to indicate download complete
if (!ConfigUtil.getConfigItem('silent')) {
await dingSound.play();
}
});
ipcRenderer.once('downloadFileFailed', () => {
@@ -51,6 +51,6 @@ export default function handleExternalLink(this: WebView, event: Electron.NewWin
ipcRenderer.removeAllListeners('downloadFileCompleted');
});
} else {
LinkUtil.openBrowser(url);
(async () => LinkUtil.openBrowser(url))();
}
}

View File

@@ -188,7 +188,7 @@ export default class WebView extends BaseComponent {
this.focus();
this.props.onTitleChange();
// Injecting preload css in webview to override some css rules
this.$el.insertCSS(fs.readFileSync(path.join(__dirname, '/../../css/preload.css'), 'utf8'));
(async () => this.$el.insertCSS(fs.readFileSync(path.join(__dirname, '/../../css/preload.css'), 'utf8')))();
// get customCSS again from config util to avoid warning user again
this.customCSS = ConfigUtil.getConfigItem('customCSS');
@@ -202,7 +202,7 @@ export default class WebView extends BaseComponent {
return;
}
this.$el.insertCSS(fs.readFileSync(path.resolve(__dirname, this.customCSS), 'utf8'));
(async () => this.$el.insertCSS(fs.readFileSync(path.resolve(__dirname, this.customCSS), 'utf8')))();
}
}
@@ -298,6 +298,6 @@ export default class WebView extends BaseComponent {
async send(channel: string, ...parameters: any[]): Promise<void> {
await this.domReady;
this.$el.send(channel, ...parameters);
await this.$el.send(channel, ...parameters);
}
}

View File

@@ -142,9 +142,9 @@ class ServerManagerView {
this.initSidebar();
this.removeUAfromDisk();
if (EnterpriseUtil.configFile) {
this.initPresetOrgs();
await this.initPresetOrgs();
}
this.initTabs();
await this.initTabs();
this.initActions();
this.registerIpcs();
}
@@ -310,7 +310,7 @@ class ServerManagerView {
}
}
initTabs(): void {
async initTabs(): Promise<void> {
const servers = DomainUtil.getDomains();
if (servers.length > 0) {
for (const [i, server] of servers.entries()) {
@@ -322,22 +322,22 @@ class ServerManagerView {
lastActiveTab = 0;
}
// checkDomain() and webview.load() for lastActiveTab before the others
DomainUtil.updateSavedServer(servers[lastActiveTab].url, lastActiveTab);
await DomainUtil.updateSavedServer(servers[lastActiveTab].url, lastActiveTab);
this.activateTab(lastActiveTab);
for (const [i, server] of servers.entries()) {
await Promise.all(servers.map(async (server, i) => {
// after the lastActiveTab is activated, we load the others in the background
// without activating them, to prevent flashing of server icons
if (i === lastActiveTab) {
continue;
return;
}
DomainUtil.updateSavedServer(server.url, i);
await DomainUtil.updateSavedServer(server.url, i);
this.tabs[i].webview.load();
}
}));
// Remove focus from the settings icon at sidebar bottom
this.$settingsButton.classList.remove('active');
} else if (this.presetOrgs.length === 0) {
// not attempting to add organisations in the background
this.openSettings('AddServer');
await this.openSettings('AddServer');
} else {
this.showLoading(true);
}
@@ -411,11 +411,11 @@ class ServerManagerView {
this.$reloadButton.addEventListener('click', () => {
this.tabs[this.activeTabIndex].webview.reload();
});
this.$addServerButton.addEventListener('click', () => {
this.openSettings('AddServer');
this.$addServerButton.addEventListener('click', async () => {
await this.openSettings('AddServer');
});
this.$settingsButton.addEventListener('click', () => {
this.openSettings('General');
this.$settingsButton.addEventListener('click', async () => {
await this.openSettings('General');
});
this.$backButton.addEventListener('click', () => {
this.tabs[this.activeTabIndex].webview.back();
@@ -683,14 +683,14 @@ class ServerManagerView {
this.$webviewsContainer.innerHTML = '';
}
reloadView(): void {
async reloadView(): Promise<void> {
// Save and remember the index of last active tab so that we can use it later
const lastActiveTab = this.tabs[this.activeTabIndex].props.index;
ConfigUtil.setConfigItem('lastActiveTab', lastActiveTab);
// Destroy the current view and re-initiate it
this.destroyView();
this.initTabs();
await this.initTabs();
this.initServerActions();
}
@@ -839,15 +839,15 @@ class ServerManagerView {
this.openNetworkTroubleshooting(index);
});
ipcRenderer.on('open-settings', (event: Event, settingNav: string) => {
this.openSettings(settingNav);
ipcRenderer.on('open-settings', async (event: Event, settingNav: string) => {
await this.openSettings(settingNav);
});
ipcRenderer.on('open-about', this.openAbout.bind(this));
ipcRenderer.on('open-help', () => {
ipcRenderer.on('open-help', async () => {
// Open help page of current active server
LinkUtil.openBrowser(new URL('/help', this.getCurrentActiveServer()));
await LinkUtil.openBrowser(new URL('/help', this.getCurrentActiveServer()));
});
ipcRenderer.on('reload-viewer', this.reloadView.bind(this, this.tabs[this.activeTabIndex].props.index));
@@ -866,8 +866,8 @@ class ServerManagerView {
this.activateLastTab(index);
});
ipcRenderer.on('open-org-tab', () => {
this.openSettings('AddServer');
ipcRenderer.on('open-org-tab', async () => {
await this.openSettings('AddServer');
});
ipcRenderer.on('reload-proxy', async (event: Event, showAlert: boolean) => {
@@ -1014,8 +1014,8 @@ class ServerManagerView {
clipboard.writeText(this.getCurrentActiveServer());
});
ipcRenderer.on('new-server', () => {
this.openSettings('AddServer');
ipcRenderer.on('new-server', async () => {
await this.openSettings('AddServer');
});
// Redo and undo functionality since the default API doesn't work on macOS
@@ -1027,37 +1027,33 @@ class ServerManagerView {
return this.getActiveWebview().redo();
});
ipcRenderer.on('set-active', () => {
ipcRenderer.on('set-active', async () => {
const webviews: NodeListOf<Electron.WebviewTag> = document.querySelectorAll('webview');
webviews.forEach(webview => {
webview.send('set-active');
});
await Promise.all([...webviews].map(async webview => webview.send('set-active')));
});
ipcRenderer.on('set-idle', () => {
ipcRenderer.on('set-idle', async () => {
const webviews: NodeListOf<Electron.WebviewTag> = document.querySelectorAll('webview');
webviews.forEach(webview => {
webview.send('set-idle');
});
await Promise.all([...webviews].map(async webview => webview.send('set-idle')));
});
ipcRenderer.on('open-network-settings', () => {
this.openSettings('Network');
ipcRenderer.on('open-network-settings', async () => {
await this.openSettings('Network');
});
}
}
window.addEventListener('load', () => {
const serverManagerView = new ServerManagerView();
serverManagerView.init();
window.addEventListener('load', async () => {
// only start electron-connect (auto reload on change) when its ran
// from `npm run dev` or `gulp dev` and not from `npm start` when
// app is started `npm start` main process's proces.argv will have
// `--no-electron-connect`
const mainProcessArgv = remote.getGlobal('process').argv;
if (isDev && !mainProcessArgv.includes('--no-electron-connect')) {
if (isDev && !remote.getGlobal('process').argv.includes('--no-electron-connect')) {
require('electron-connect').client.create();
}
const serverManagerView = new ServerManagerView();
await serverManagerView.init();
});
export {};

View File

@@ -67,6 +67,6 @@ export function newNotification(
};
}
electron_bridge.once('zulip-loaded', () => {
loadBots();
electron_bridge.once('zulip-loaded', async () => {
await loadBots();
});

View File

@@ -49,7 +49,7 @@ export default class AddCertificate extends BaseComponent {
this.initListeners();
}
validateAndAdd(): void {
async validateAndAdd(): Promise<void> {
const certificate = this._certFile;
const serverUrl = this.serverUrl.value;
if (certificate !== '' && serverUrl !== '') {
@@ -60,11 +60,11 @@ export default class AddCertificate extends BaseComponent {
return;
}
CertificateUtil.setCertificate(server, fileName);
dialog.showMessageBox({
this.serverUrl.value = '';
await dialog.showMessageBox({
title: 'Success',
message: 'Certificate saved!'
});
this.serverUrl.value = '';
} else {
dialog.showErrorBox('Error', `Please, ${serverUrl === '' ?
'Enter an Organization URL' : 'Choose certificate file'}`);
@@ -80,18 +80,18 @@ export default class AddCertificate extends BaseComponent {
const { filePaths, canceled } = await dialog.showOpenDialog(showDialogOptions);
if (!canceled) {
this._certFile = filePaths[0] || '';
this.validateAndAdd();
await this.validateAndAdd();
}
}
initListeners(): void {
this.addCertificateButton.addEventListener('click', () => {
this.addHandler();
this.addCertificateButton.addEventListener('click', async () => {
await this.addHandler();
});
this.serverUrl.addEventListener('keypress', event => {
this.serverUrl.addEventListener('keypress', async event => {
if (event.key === 'Enter') {
this.addHandler();
await this.addHandler();
}
});
}

View File

@@ -40,19 +40,19 @@ export default class FindAccounts extends BaseComponent {
this.initListeners();
}
findAccounts(url: string): void {
async findAccounts(url: string): Promise<void> {
if (!url) {
return;
}
if (!url.startsWith('http')) {
url = 'https://' + url;
}
LinkUtil.openBrowser(new URL('/accounts/find', url));
await LinkUtil.openBrowser(new URL('/accounts/find', url));
}
initListeners(): void {
this.$findAccountsButton.addEventListener('click', () => {
this.findAccounts(this.$serverUrlField.value);
this.$findAccountsButton.addEventListener('click', async () => {
await this.findAccounts(this.$serverUrlField.value);
});
this.$serverUrlField.addEventListener('click', () => {
@@ -61,9 +61,9 @@ export default class FindAccounts extends BaseComponent {
}
});
this.$serverUrlField.addEventListener('keypress', event => {
this.$serverUrlField.addEventListener('keypress', async event => {
if (event.key === 'Enter') {
this.findAccounts(this.$serverUrlField.value);
await this.findAccounts(this.$serverUrlField.value);
}
});

View File

@@ -382,8 +382,8 @@ export default class GeneralSection extends BaseSection {
detail: clearAppDataMessage
});
if (response === 0) {
fs.remove(getAppPath);
setTimeout(() => ipcRenderer.send('forward-message', 'hard-reload'), 1000);
await fs.remove(getAppPath);
ipcRenderer.send('forward-message', 'hard-reload');
}
}
@@ -403,8 +403,8 @@ export default class GeneralSection extends BaseSection {
updateResetDataOption(): void {
const resetDataButton = document.querySelector('#resetdata-option .reset-data-button');
resetDataButton.addEventListener('click', () => {
this.clearAppDataDialog();
resetDataButton.addEventListener('click', async () => {
await this.clearAppDataDialog();
});
}
@@ -440,8 +440,8 @@ export default class GeneralSection extends BaseSection {
addCustomCSS(): void {
const customCSSButton = document.querySelector('#add-custom-css .custom-css-button');
customCSSButton.addEventListener('click', () => {
this.customCssDialog();
customCSSButton.addEventListener('click', async () => {
await this.customCssDialog();
});
}
@@ -476,8 +476,8 @@ export default class GeneralSection extends BaseSection {
downloadFolder(): void {
const downloadFolder = document.querySelector('#download-folder .download-folder-button');
downloadFolder.addEventListener('click', () => {
this.downloadFolderDialog();
downloadFolder.addEventListener('click', async () => {
await this.downloadFolderDialog();
});
}

View File

@@ -78,8 +78,8 @@ export default class NewServerForm extends BaseComponent {
openCreateNewOrgExternalLink(): void {
const link = 'https://zulipchat.com/new/';
const externalCreateNewOrgElement = document.querySelector('#open-create-org-link');
externalCreateNewOrgElement.addEventListener('click', () => {
LinkUtil.openBrowser(new URL(link));
externalCreateNewOrgElement.addEventListener('click', async () => {
await LinkUtil.openBrowser(new URL(link));
});
}
@@ -89,12 +89,12 @@ export default class NewServerForm extends BaseComponent {
}
initActions(): void {
this.$saveServerButton.addEventListener('click', () => {
this.submitFormHandler();
this.$saveServerButton.addEventListener('click', async () => {
await this.submitFormHandler();
});
this.$newServerUrl.addEventListener('keypress', event => {
this.$newServerUrl.addEventListener('keypress', async event => {
if (event.key === 'Enter') {
this.submitFormHandler();
await this.submitFormHandler();
}
});
// open create new org link in default browser

View File

@@ -332,8 +332,8 @@ export default class ShortcutsSection extends BaseSection {
openHotkeysExternalLink(): void {
const link = 'https://zulipchat.com/help/keyboard-shortcuts';
const externalCreateNewOrgElement = document.querySelector('#open-hotkeys-link');
externalCreateNewOrgElement.addEventListener('click', () => {
LinkUtil.openBrowser(new URL(link));
externalCreateNewOrgElement.addEventListener('click', async () => {
await LinkUtil.openBrowser(new URL(link));
});
}

View File

@@ -117,6 +117,6 @@ ipcRenderer.on('set-idle', () => {
electron_bridge.idle_on_system = true;
});
webFrame.executeJavaScript(
(async () => webFrame.executeJavaScript(
fs.readFileSync(require.resolve('./injected'), 'utf8')
);
))();

View File

@@ -32,11 +32,13 @@ export let db: JsonDB;
reloadDB();
// Migrate from old schema
if (db.getData('/').domain) {
addDomain({
alias: 'Zulip',
url: db.getData('/domain')
});
db.delete('/domain');
(async () => {
await addDomain({
alias: 'Zulip',
url: db.getData('/domain')
});
db.delete('/domain');
})();
}
export function getDomains(): ServerConf[] {

View File

@@ -8,9 +8,9 @@ export function isUploadsUrl(server: string, url: URL): boolean {
return url.origin === server && url.pathname.startsWith('/user_uploads/');
}
export function openBrowser(url: URL): void {
export async function openBrowser(url: URL): Promise<void> {
if (['http:', 'https:', 'mailto:'].includes(url.protocol)) {
shell.openExternal(url.href);
await shell.openExternal(url.href);
} else {
// For security, indirect links to non-whitelisted protocols
// through a real web browser via a local HTML file.