From 0431a9f5add13cd16c19006775f1e907f3c3b2ce Mon Sep 17 00:00:00 2001 From: Kiran Niranjan Date: Wed, 30 Oct 2019 20:58:25 +0530 Subject: [PATCH] fix: Upgrade master to 6.x (#795) * Upgrade Electron version to 6.x * fix: SDA-1347 (Group multiple processes into a single task bar icon) (#778) * update mac build script * update mac packager * feat: ELECTRON-1462 (Combine more information into about app window) (#777) * ELECTRON-1462 - Merge more info window in to about app window * ELECTRON-1462 - Adjust window size * ELECTRON-1462 - Add line space * ELECTRON-1462 - Resize for windows * ELECTRON-1462 - Add translation for swift search * ELECTRON-1462 - Adjust width for Windows OS * ELECTRON-1462 - Add about app snapshots file * SDA-1347 - Group multiple processes into single task bar icon * Change dependency from gulp-tsc to gulp-typescript * 6.x Update activity detection api * 6.x Update aip file to remove unwanted spellchecker files * 6.x Update electron version to 6.1.2 * 6.x Update SDA version and change spellchecker base * 6.x Update electron-builder version to support 6.x * 6.x fix escape char for window build command * 6.x Optimize log path set and get methods * 6.x Change yml to json * 6.x Make Window local path as default user data path --- electron-builder.yml | 52 -------------------------- gulpfile.js | 12 +++--- installer/win/Symphony-x64.aip | 15 +------- installer/win/Symphony-x86.aip | 15 +------- package.json | 67 +++++++++++++++++++++++++++++----- spec/__mocks__/electron.ts | 8 +++- spec/dialogHandler.spec.ts | 22 ++++++----- src/app/activity-detection.ts | 8 +++- src/app/app-menu.ts | 16 ++++---- src/app/dialog-handler.ts | 43 ++++++++++------------ src/app/main-api-handler.ts | 2 +- src/app/reports-handler.ts | 2 +- src/app/window-handler.ts | 31 +++++++--------- src/app/window-utils.ts | 8 ++-- src/common/logger.ts | 12 +++++- tsconfig.json | 1 + 16 files changed, 153 insertions(+), 161 deletions(-) delete mode 100644 electron-builder.yml diff --git a/electron-builder.yml b/electron-builder.yml deleted file mode 100644 index 9669e2d8..00000000 --- a/electron-builder.yml +++ /dev/null @@ -1,52 +0,0 @@ -productName: "Symphony" -appId: "com.symphony.electron-desktop" - -# Package electron code into a asar archive. Set to false to debug issues. -asar: true - -# Unpack these files from asar to have them signed -asarUnpack: - - 'node_modules/@nornagon/cld/build/Release/cld.node' - - 'node_modules/@nornagon/spellchecker/build/Release/spellchecker.node' - - 'node_modules/keyboard-layout/build/Release/keyboard-layout-manager.node' - -# Don't package these files -files: - - '!coverage/*' - - '!installer/*' - - '!tests/*' - - '!node_modules/@nornagon/cld/deps/cld${/*}' - - '!node_modules/@nornagon/cld/build/deps${/*}' - - '!node_modules/@nornagon/spellchecker/vendor${/*}' - -# Extra files to package -extraFiles: - - 'config/Symphony.config' - - 'config/titleBarStyles.css' - - 'dictionaries/**' - - 'library/libsymphonysearch.dylib' - - 'library/indexvalidator.exec' - - 'library/cryptoLib.dylib' - - 'library/dictionary' - - 'library/lz4.exec' - -# Mac OS configuration -mac: - category: 'public.app-category.business' - icon: 'images/icon.icns' - -# Windows configuration -win: - icon: 'images/icon.ico' - target: - - 'squirrel' - -# Linux configuration -linux: - category: 'Network;InstantMessaging;Chat' - desktop: - StartupWMClass: 'Symphony' - target: - - 'deb' - - 'rpm' - icon: 'images/linux' diff --git a/gulpfile.js b/gulpfile.js index 43bc0929..39e09422 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,11 +2,11 @@ const fs = require('fs'); const gulp = require('gulp'); const less = require('gulp-less'); const sourcemaps = require('gulp-sourcemaps'); -const tsc = require('gulp-tsc'); +const tsc = require('gulp-typescript'); const del = require('del'); const path = require('path'); -// TODO: Add gulp watch tasks +const tsProject = tsc.createProject('./tsconfig.json'); gulp.task('clean', function() { return del('lib'); @@ -17,8 +17,9 @@ gulp.task('clean', function() { * and copy to the destination */ gulp.task('compile', function() { - return gulp.src(['src/**/*.ts', 'src/**/*.tsx']) - .pipe(tsc({ project: './tsconfig.json' })) + return tsProject.src() + .pipe(tsProject()) + .on('error', (err) => console.log(err)) .pipe(gulp.dest('lib/')) }); @@ -37,7 +38,8 @@ gulp.task('copy', function () { return gulp.src([ './src/renderer/assets/*', './src/renderer/*.html', - './src/locale/*' + './src/locale/*', + './package.json' ], { "base": "./src" }).pipe(gulp.dest('lib/src')) diff --git a/installer/win/Symphony-x64.aip b/installer/win/Symphony-x64.aip index 29437e11..5eee64df 100644 --- a/installer/win/Symphony-x64.aip +++ b/installer/win/Symphony-x64.aip @@ -71,16 +71,11 @@ - - - - - @@ -92,10 +87,8 @@ - - @@ -119,7 +112,6 @@ - @@ -133,18 +125,17 @@ - - + - + @@ -164,7 +155,6 @@ - @@ -227,7 +217,6 @@ - diff --git a/installer/win/Symphony-x86.aip b/installer/win/Symphony-x86.aip index 07af6b12..606e282b 100644 --- a/installer/win/Symphony-x86.aip +++ b/installer/win/Symphony-x86.aip @@ -70,16 +70,11 @@ - - - - - @@ -91,10 +86,8 @@ - - @@ -118,7 +111,6 @@ - @@ -132,18 +124,17 @@ - - + - + @@ -163,7 +154,6 @@ - @@ -226,7 +216,6 @@ - diff --git a/package.json b/package.json index f81e64cb..d57d34c6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "symphony", "productName": "Symphony", - "version": "5.0.0", + "version": "6.0.0", "clientVersion": "2.0.1", "buildNumber": "0", "searchAPIVersion": "1.55.3", @@ -16,15 +16,63 @@ "demo-win": "npm run prebuild && cross-env ELECTRON_DEV=true electron . --url=file:///src/demo/index.html", "demo-mac": "npm run prebuild && cross-env ELECTRON_DEV=true electron . --url=file://$(pwd)/src/demo/index.html", "lint": "tslint --project tsconfig.json", - "packed-linux": "npm run prebuild && npm run test && build --linux", + "packed-linux": "npm run prebuild && npm run test && ./node_modules/.bin/electron-builder build --linux", "packed-mac": "npm run unpacked-mac && packagesbuild -v installer/mac/symphony-mac-packager.pkgproj", "prebuild": "npm run compile && npm run rebuild && npm run browserify-preload", "rebuild": "electron-rebuild -f", "start": "npm run compile && npm run browserify-preload && cross-env ELECTRON_DEV=true electron .", "test": "npm run lint && cross-env ELECTRON_QA=true jest --config jest-config.json --runInBand --detectOpenHandles", - "unpacked-mac": "npm run prebuild && npm run test && build --mac --dir", - "unpacked-win": "npm run prebuild && npm run test && build --win --x64 --dir", - "unpacked-win-x86": "npm run prebuild && npm run test && build --win --ia32 --dir" + "unpacked-mac": "npm run prebuild && npm run test && ./node_modules/.bin/electron-builder build --mac --dir", + "unpacked-win": "npm run prebuild && npm run test && node_modules\\.bin\\electron-builder build --win --x64 --dir", + "unpacked-win-x86": "npm run prebuild && npm run test && node_modules\\.bin\\electron-builder build --win --ia32 --dir" + }, + "build": { + "appId": "com.symphony.electron-desktop", + "asar": true, + "asarUnpack": [ + "node_modules/@nornagon/cld/build/Release/cld.node", + "node_modules/@nornagon/spellchecker/build/Release/spellchecker.node", + "node_modules/keyboard-layout/build/Release/keyboard-layout-manager.node" + ], + "files": [ + "!coverage/*", + "!installer/*", + "!tests/*", + "!node_modules/@nornagon/cld/deps/cld${/*}", + "!node_modules/@nornagon/cld/build/deps${/*}", + "!node_modules/@nornagon/spellchecker/vendor${/*}" + ], + "extraFiles": [ + "config/Symphony.config", + "config/titleBarStyles.css", + "dictionaries/**", + "library/libsymphonysearch.dylib", + "library/indexvalidator.exec", + "library/cryptoLib.dylib", + "library/dictionary", + "library/lz4.exec" + ], + "mac": { + "category": "public.app-category.business", + "icon": "images/icon.icns" + }, + "win": { + "icon": "images/icon.ico", + "target": [ + "squirrel" + ] + }, + "linux": { + "category": "Network;InstantMessaging;Chat", + "desktop": { + "StartupWMClass": "Symphony" + }, + "target": [ + "deb", + "rpm" + ], + "icon": "images/linux" + } }, "repository": { "type": "git", @@ -49,8 +97,8 @@ "browserify": "16.2.3", "cross-env": "5.2.0", "del": "3.0.0", - "electron": "5.0.10", - "electron-builder": "20.38.4", + "electron": "6.1.2", + "electron-builder": "21.2.0", "electron-builder-squirrel-windows": "20.38.3", "electron-icon-maker": "0.0.4", "electron-rebuild": "1.8.2", @@ -60,10 +108,11 @@ "gulp": "4.0.0", "gulp-less": "4.0.1", "gulp-sourcemaps": "2.6.4", - "gulp-tsc": "1.3.2", + "gulp-typescript": "5.0.1", "jest": "23.6.0", "jest-html-reporter": "2.4.2", "less": "3.8.1", + "node-abi": "^2.12.0", "ts-jest": "23.10.5", "tslint": "5.11.0", "typescript": "3.1.1" @@ -76,7 +125,7 @@ "electron-dl": "1.14.0", "electron-fetch": "1.3.0", "electron-log": "3.0.7", - "electron-spellchecker": "git+https://github.com/symphonyoss/electron-spellchecker.git#v2.0.3", + "electron-spellchecker": "git+https://github.com/symphonyoss/electron-spellchecker.git#v2.3.0", "ffi-napi": "2.4.5", "filesize": "4.1.2", "react": "16.9.0", diff --git a/spec/__mocks__/electron.ts b/spec/__mocks__/electron.ts index 70725903..c28d0034 100644 --- a/spec/__mocks__/electron.ts +++ b/spec/__mocks__/electron.ts @@ -21,6 +21,7 @@ interface IApp { setPath(value: string, path: string): void; setLoginItemSettings(settings: { openAtLogin: boolean, path: string }): void; getLoginItemSettings(options?: { path: string, args: string[] }): ILoginItemSettings; + setAppLogsPath(): void; } interface ILoginItemSettings { openAtLogin: boolean; @@ -37,7 +38,7 @@ interface IIpcRenderer { once(eventName: any, cb: any): void; } interface IPowerMonitor { - querySystemIdleTime(): void; + getSystemIdleTime(): void; } const pathToConfigDir = (): string => { @@ -77,6 +78,9 @@ export const app: IApp = { getLoginItemSettings: (): ILoginItemSettings => { return { openAtLogin: true }; }, + setAppLogsPath: (): void => { + return; + }, }; // simple ipc mocks for render and main process ipc using @@ -98,7 +102,7 @@ export const ipcMain: IIpcMain = { }; export const powerMonitor: IPowerMonitor = { - querySystemIdleTime: jest.fn().mockImplementation((cb) => cb(mockIdleTime)), + getSystemIdleTime: jest.fn().mockReturnValue(mockIdleTime), }; export const ipcRenderer: IIpcRenderer = { diff --git a/spec/dialogHandler.spec.ts b/spec/dialogHandler.spec.ts index aede23f1..a325ea8d 100644 --- a/spec/dialogHandler.spec.ts +++ b/spec/dialogHandler.spec.ts @@ -44,18 +44,20 @@ describe('dialog handler', () => { const errorMocked = 'check for server certificate revocation'; const certificate = null; - it('should return false when buttonId is 1', () => { - dialog.showMessageBox = jest.fn(() => 1); - ipcRenderer.send('certificate-error', webContentsMocked, urlMocked, errorMocked, certificate, callbackMocked); - expect(callbackMocked).toBeCalledWith(false); + it('should return false when buttonId is 1', async (done) => { + dialog.showMessageBox = jest.fn(() => { + return { response: 1 }; + }); + await ipcRenderer.send('certificate-error', webContentsMocked, urlMocked, errorMocked, certificate, callbackMocked); + done(expect(callbackMocked).toBeCalledWith(false)); }); - it('should return true when buttonId is not 1', () => { + it('should return true when buttonId is not 1', async (done) => { dialog.showMessageBox = jest.fn(() => 2); - ipcRenderer.send('certificate-error', webContentsMocked, urlMocked, errorMocked, certificate, callbackMocked); - expect(callbackMocked).toBeCalledWith(true); - ipcRenderer.send('certificate-error', webContentsMocked, urlMocked, errorMocked, certificate, callbackMocked); + await ipcRenderer.send('certificate-error', webContentsMocked, urlMocked, errorMocked, certificate, callbackMocked); expect(callbackMocked).toBeCalledWith(true); + await ipcRenderer.send('certificate-error', webContentsMocked, urlMocked, errorMocked, certificate, callbackMocked); + done(expect(callbackMocked).toBeCalledWith(true)); }); }); }); @@ -78,7 +80,7 @@ describe('dialog handler', () => { message: `Error loading URL:\n${urlMocked}\n\n${errorDescMocked}\n\nError Code: ${errorCodeMocked}`, }; showLoadFailure(browserWindowMocked, urlMocked, errorDescMocked, errorCodeMocked, callbackMocked, showDialogMocked); - expect(spy).toBeCalledWith({ id: 123 }, expectedValue, expect.any(Function)); + expect(spy).toBeCalledWith({ id: 123 }, expectedValue); }); it('should call `showNetworkConnectivityError` correctly', () => { @@ -97,6 +99,6 @@ describe('dialog handler', () => { message: `Error loading URL:\n${urlMocked}\n\n${errorDescMocked}`, }; showNetworkConnectivityError(browserWindowMocked, urlMocked, callbackMocked); - expect(spy).toBeCalledWith({ id: 123 }, expectedValue, expect.any(Function)); + expect(spy).toBeCalledWith({ id: 123 }, expectedValue); }); }); diff --git a/src/app/activity-detection.ts b/src/app/activity-detection.ts index fbd3a70d..314d2447 100644 --- a/src/app/activity-detection.ts +++ b/src/app/activity-detection.ts @@ -38,7 +38,10 @@ class ActivityDetection { private startActivityMonitor(): void { if (app.isReady()) { logger.info(`activity-detection: Starting activity monitor`); - this.queryInterval = setInterval(() => (electron.powerMonitor as any).querySystemIdleTime(this.activity.bind(this)), this.idleThreshold); + this.queryInterval = setInterval(() => { + const idleTime = electron.powerMonitor.getSystemIdleTime(); + this.activity(idleTime); + }, this.idleThreshold); } } @@ -69,7 +72,8 @@ class ActivityDetection { // when user goes inactive this.timer = setInterval(() => { if (app.isReady()) { - (electron.powerMonitor as any).querySystemIdleTime(this.activity.bind(this)); + const activeTime = electron.powerMonitor.getSystemIdleTime(); + this.activity(activeTime); } }, 1000); } diff --git a/src/app/app-menu.ts b/src/app/app-menu.ts index 3a1a8320..c2e4609a 100644 --- a/src/app/app-menu.ts +++ b/src/app/app-menu.ts @@ -188,7 +188,7 @@ export class AppMenu { { label: i18n.t('Services')(), role: 'services' }, this.buildSeparator(), { label: i18n.t('Hide Symphony')(), role: 'hide' }, - { label: i18n.t('Hide Others')(), role: 'hideothers' }, + { label: i18n.t('Hide Others')(), role: 'hideOthers' }, { label: i18n.t('Show All')(), role: 'unhide' }, this.buildSeparator(), { label: i18n.t('Quit Symphony')(), role: 'quit' }, @@ -211,9 +211,9 @@ export class AppMenu { this.assignRoleOrLabel({ role: 'cut', label: i18n.t('Cut')() }), this.assignRoleOrLabel({ role: 'copy', label: i18n.t('Copy')() }), this.assignRoleOrLabel({ role: 'paste', label: i18n.t('Paste')() }), - this.assignRoleOrLabel({ role: 'pasteandmatchstyle', label: i18n.t('Paste and Match Style')() }), + this.assignRoleOrLabel({ role: 'pasteAndMatchStyle', label: i18n.t('Paste and Match Style')() }), this.assignRoleOrLabel({ role: 'delete', label: i18n.t('Delete')() }), - this.assignRoleOrLabel({ role: 'selectall', label: i18n.t('Select All')() }), + this.assignRoleOrLabel({ role: 'selectAll', label: i18n.t('Select All')() }), ], }; @@ -221,8 +221,8 @@ export class AppMenu { menu.submenu.push(this.buildSeparator(), { label: i18n.t('Speech')(), submenu: [ - { label: i18n.t('Start Speaking')(), role: 'startspeaking' }, - { label: i18n.t('Stop Speaking')(), role: 'stopspeaking' }, + { label: i18n.t('Start Speaking')(), role: 'startSpeaking' }, + { label: i18n.t('Stop Speaking')(), role: 'stopSpeaking' }, ], }); } @@ -242,9 +242,9 @@ export class AppMenu { label: i18n.t('Reload')(), }, this.buildSeparator(), - this.assignRoleOrLabel({ role: 'resetzoom', label: i18n.t('Actual Size')() }), - this.assignRoleOrLabel({ role: 'zoomin', label: i18n.t('Zoom In')() }), - this.assignRoleOrLabel({ role: 'zoomout', label: i18n.t('Zoom Out')() }), + this.assignRoleOrLabel({ role: 'resetZoom', label: i18n.t('Actual Size')() }), + this.assignRoleOrLabel({ role: 'zoomIn', label: i18n.t('Zoom In')() }), + this.assignRoleOrLabel({ role: 'zoomOut', label: i18n.t('Zoom Out')() }), this.buildSeparator(), this.assignRoleOrLabel({ role: 'togglefullscreen', label: i18n.t('Toggle Full Screen')() }), ], diff --git a/src/app/dialog-handler.ts b/src/app/dialog-handler.ts index 20f35345..3537c9bf 100644 --- a/src/app/dialog-handler.ts +++ b/src/app/dialog-handler.ts @@ -53,7 +53,7 @@ let ignoreAllCertErrors = false; * Note: the dialog is synchronous so further processing is blocked until * user provides a response. */ -electron.app.on('certificate-error', (event, webContents, url, error, _certificate, callback) => { +electron.app.on('certificate-error', async (event, webContents, url, error, _certificate, callback) => { // TODO: Add logic verify custom certificate if (ignoreAllCertErrors) { @@ -65,7 +65,7 @@ electron.app.on('certificate-error', (event, webContents, url, error, _certifica logger.warn(`Certificate error: ${error} for url: ${url}`); const browserWin = electron.BrowserWindow.fromWebContents(webContents); - const buttonId = electron.dialog.showMessageBox(browserWin, { + const { response } = await electron.dialog.showMessageBox(browserWin, { type: 'warning', buttons: [ i18n.t('Allow')(), @@ -81,11 +81,11 @@ electron.app.on('certificate-error', (event, webContents, url, error, _certifica event.preventDefault(); - if (buttonId === 2) { + if (response === 2) { ignoreAllCertErrors = true; } - callback(buttonId !== 1); + callback(response !== 1); }); /** @@ -98,7 +98,7 @@ electron.app.on('certificate-error', (event, webContents, url, error, _certifica * @param retryCallback {function} Callback when user clicks reload * @param showDialog {Boolean} Indicates if a dialog need to be show to a user */ -export const showLoadFailure = (browserWindow: Electron.BrowserWindow, url: string, errorDesc: string, errorCode: number, retryCallback: () => void, showDialog: boolean): void => { +export const showLoadFailure = async (browserWindow: Electron.BrowserWindow, url: string, errorDesc: string, errorCode: number, retryCallback: () => void, showDialog: boolean): Promise => { let message = url ? `${i18n.t('Error loading URL')()}:\n${url}` : i18n.t('Error loading window')(); if (errorDesc) { message += `\n\n${errorDesc}`; @@ -107,16 +107,8 @@ export const showLoadFailure = (browserWindow: Electron.BrowserWindow, url: stri message += `\n\nError Code: ${errorCode}`; } - // async handle of user input - const response = (buttonId: number): void => { - // retry if hitting button index 0 (i.e., reload) - if (buttonId === 0 && typeof retryCallback === 'function') { - retryCallback(); - } - }; - if (showDialog) { - electron.dialog.showMessageBox(browserWindow, { + const { response } = await electron.dialog.showMessageBox(browserWindow, { type: 'error', buttons: [ i18n.t('Reload')(), i18n.t('Ignore')() ], defaultId: 0, @@ -124,7 +116,13 @@ export const showLoadFailure = (browserWindow: Electron.BrowserWindow, url: stri noLink: true, title: i18n.t('Loading Error')(), message, - }, response); + }); + + // async handle of user input + // retry if hitting button index 0 (i.e., reload) + if (response === 0 && typeof retryCallback === 'function') { + retryCallback(); + } } logger.warn(`Load failure msg: ${errorDesc} errorCode: ${errorCode} for url: ${url}`); @@ -148,7 +146,7 @@ export const showNetworkConnectivityError = (browserWindow: Electron.BrowserWind * * @param isNativeStyle {boolean} */ -export const titleBarChangeDialog = (isNativeStyle: boolean) => { +export const titleBarChangeDialog = async (isNativeStyle: boolean) => { const focusedWindow = electron.BrowserWindow.getFocusedWindow(); if (!focusedWindow || !windowExists(focusedWindow)) { return; @@ -161,11 +159,10 @@ export const titleBarChangeDialog = (isNativeStyle: boolean) => { buttons: [ i18n.t('Relaunch')(), i18n.t('Cancel')() ], cancelId: 1, }; - electron.dialog.showMessageBox(focusedWindow, options, async (index) => { - if (index === 0) { - await config.updateUserConfig({ isCustomTitleBar: isNativeStyle }); - app.relaunch(); - app.exit(); - } - }); + const { response } = await electron.dialog.showMessageBox(focusedWindow, options); + if (response === 0) { + await config.updateUserConfig({ isCustomTitleBar: isNativeStyle }); + app.relaunch(); + app.exit(); + } }; diff --git a/src/app/main-api-handler.ts b/src/app/main-api-handler.ts index 47c36a98..fd274b1e 100644 --- a/src/app/main-api-handler.ts +++ b/src/app/main-api-handler.ts @@ -26,7 +26,7 @@ import { * Handle API related ipc messages from renderers. Only messages from windows * we have created are allowed. */ -ipcMain.on(apiName.symphonyApi, (event: Electron.Event, arg: IApiArgs) => { +ipcMain.on(apiName.symphonyApi, (event: Electron.IpcMainEvent, arg: IApiArgs) => { if (!isValidWindow(BrowserWindow.fromWebContents(event.sender))) { logger.error(`main-api-handler: invalid window try to perform action, ignoring action`, arg.cmd); return; diff --git a/src/app/reports-handler.ts b/src/app/reports-handler.ts index 56c756d9..9547deb0 100644 --- a/src/app/reports-handler.ts +++ b/src/app/reports-handler.ts @@ -67,7 +67,7 @@ export const exportLogs = (): void => { const FILE_EXTENSIONS = [ '.log' ]; const MAC_LOGS_PATH = '/Library/Logs/Symphony/'; const LINUX_LOGS_PATH = '/.config/Symphony/'; - const WINDOWS_LOGS_PATH = '\\AppData\\Roaming\\Symphony\\logs'; + const WINDOWS_LOGS_PATH = '\\AppData\\Local\\Symphony\\Symphony\\logs'; const logsPath = isMac ? MAC_LOGS_PATH : isLinux ? LINUX_LOGS_PATH : WINDOWS_LOGS_PATH; const source = app.getPath('home') + logsPath; diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts index 2e77236a..f71d7b8a 100644 --- a/src/app/window-handler.ts +++ b/src/app/window-handler.ts @@ -240,23 +240,22 @@ export class WindowHandler { } }); - this.mainWindow.webContents.on('crashed', (_event: Event, killed: boolean) => { + this.mainWindow.webContents.on('crashed', async (_event: Event, killed: boolean) => { if (killed) { logger.info(`window-handler: main window crashed (killed)!`); return; } logger.info(`window-handler: main window crashed!`); - electron.dialog.showMessageBox({ + const { response } = await electron.dialog.showMessageBox({ type: 'error', title: i18n.t('Renderer Process Crashed')(), message: i18n.t('Oops! Looks like we have had a crash. Please reload or close this window.')(), buttons: ['Reload', 'Close'], - }, (index: number) => { - if (!this.mainWindow || !windowExists(this.mainWindow)) { - return; - } - index === 0 ? this.mainWindow.reload() : this.mainWindow.close(); }); + if (!this.mainWindow || !windowExists(this.mainWindow)) { + return; + } + response === 0 ? this.mainWindow.reload() : this.mainWindow.close(); }); // Handle main window close @@ -551,7 +550,7 @@ export class WindowHandler { } this.basicAuthWindow.webContents.send('basic-auth-data', {hostname, isValidCredentials: isMultipleTries}); }); - const closeBasicAuth = (shouldClearSettings = true) => { + const closeBasicAuth = (_event, shouldClearSettings = true) => { if (shouldClearSettings) { clearSettings(); } @@ -564,7 +563,7 @@ export class WindowHandler { const login = (_event, arg) => { const {username, password} = arg; callback(username, password); - closeBasicAuth(false); + closeBasicAuth(null, false); }; this.basicAuthWindow.once('close', () => { @@ -822,7 +821,7 @@ export class WindowHandler { * Check if build is expired and show an error message * @param browserWindow Focused window instance */ - private checkExpiry(browserWindow: BrowserWindow) { + private async checkExpiry(browserWindow: BrowserWindow) { logger.info(`window handler: calling ttl handler to check for build expiry!`); const buildExpired = checkIfBuildExpired(); if (!buildExpired) { @@ -830,21 +829,19 @@ export class WindowHandler { return; } logger.info(`window handler: build expired, will inform the user and quit the app!`); - const response = (resp: number) => { - if (resp === 0) { - electron.app.exit(); - } - }; const options = { type: 'error', title: i18n.t('Build expired')(), message: i18n.t('Sorry, this is a test build and it has expired. Please contact your administrator to get a production build.')(), - buttons: [i18n.t('Quit')()], + buttons: [ i18n.t('Quit')() ], cancelId: 0, }; - electron.dialog.showMessageBox(browserWindow, options, response); + const { response } = await electron.dialog.showMessageBox(browserWindow, options); + if (response === 0) { + electron.app.exit(); + } } /** diff --git a/src/app/window-utils.ts b/src/app/window-utils.ts index 76f550d8..ccba463c 100644 --- a/src/app/window-utils.ts +++ b/src/app/window-utils.ts @@ -71,7 +71,7 @@ export const preventWindowNavigation = (browserWindow: BrowserWindow, isPopOutWi electron.dialog.showMessageBox(browserWindow, { type: 'warning', buttons: [ 'OK' ], - title: i18n.t('Not Allowed'), + title: i18n.t('Not Allowed')(), message: `${i18n.t(`Sorry, you are not allowed to access this website`)} (${winUrl}), ${i18n.t('please contact your administrator for more details')}`, }); } @@ -341,9 +341,9 @@ export const downloadManagerAction = (type, filePath): void => { } return; } - - const showResponse = electron.shell.showItemInFolder(filePath); - if (!showResponse) { + if (fs.existsSync(filePath)) { + electron.shell.showItemInFolder(filePath); + } else { electron.dialog.showMessageBox(focusedWindow, { message, title, diff --git a/src/common/logger.ts b/src/common/logger.ts index bdacb185..4b789b4e 100644 --- a/src/common/logger.ts +++ b/src/common/logger.ts @@ -4,7 +4,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as util from 'util'; -import { isElectronQA, isLinux } from './env'; +import { isElectronQA, isLinux, isWindowsOS } from './env'; import { getCommandLineArgs } from './utils'; export interface ILogMsg { @@ -22,6 +22,16 @@ interface IClientLogMsg { const MAX_LOG_QUEUE_LENGTH = 100; +// Force log path to local path in Windows rather than roaming +if (isWindowsOS && process.env.LOCALAPPDATA) { + app.setPath('appData', process.env.LOCALAPPDATA); + app.setPath('userData', path.join(app.getPath('appData'), app.getName())); +} + +// Electron wants this to be called initially before calling +// app.getPath('logs') +app.setAppLogsPath(); + class Logger { private readonly showInConsole: boolean = false; private readonly desiredLogLevel?: LogLevel; diff --git a/tsconfig.json b/tsconfig.json index 6981c740..f488abc7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "resolveJsonModule": true, "jsx": "react", "outDir": "lib", + "rootDir": ".", "lib": [ "es2016", "dom"