mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
fix: ELECTRON-1431: add logic to update pod version dynamically (#743)
* ELECTRON-1431: add logic to update pod version dynamically * ELECTRON-1431: refactor the code to keep version handler simple * ELECTRON-1431: add safety check for setting about panel on macOS * Merge branch 'master' into ELECTRON-1431 # Conflicts: # src/app/window-handler.ts
This commit is contained in:
parent
f8ea6a778f
commit
e1f7fa53d0
@ -42,6 +42,7 @@ jest.mock('../src/app/window-handler', () => {
|
||||
createScreenPickerWindow: jest.fn(),
|
||||
createScreenSharingIndicatorWindow: jest.fn(),
|
||||
isOnline: false,
|
||||
updateVersionInfo: jest.fn(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -49,6 +49,9 @@ ipcMain.on(apiName.symphonyApi, (event: Electron.Event, arg: IApiArgs) => {
|
||||
break;
|
||||
case apiCmds.registerProtocolHandler:
|
||||
protocolHandler.setPreloadWebContents(event.sender);
|
||||
// Since we register the prococol handler window upon login,
|
||||
// we make use of it and update the pod version info on SDA
|
||||
windowHandler.updateVersionInfo();
|
||||
break;
|
||||
case apiCmds.badgeDataUrl:
|
||||
if (typeof arg.dataUrl === 'string' && typeof arg.count === 'number') {
|
||||
|
@ -13,7 +13,6 @@ import './dialog-handler';
|
||||
import './main-api-handler';
|
||||
import { handlePerformanceSettings } from './perf-handler';
|
||||
import { protocolHandler } from './protocol-handler';
|
||||
import { IVersionInfo, versionHandler } from './version-handler';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
|
||||
logger.info(`App started with the args ${JSON.stringify(process.argv)}`);
|
||||
@ -53,28 +52,11 @@ setChromeFlags();
|
||||
// Electron sets the default protocol
|
||||
app.setAsDefaultProtocolClient('symphony');
|
||||
|
||||
const setAboutPanel = (clientVersion: string, buildNumber: string) => {
|
||||
const appName = app.getName();
|
||||
const copyright = `Copyright \xA9 ${new Date().getFullYear()} ${appName}`;
|
||||
app.setAboutPanelOptions({
|
||||
applicationName: appName,
|
||||
applicationVersion: clientVersion,
|
||||
version: buildNumber,
|
||||
copyright,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function that init the application
|
||||
*/
|
||||
const startApplication = async () => {
|
||||
await app.whenReady();
|
||||
versionHandler.getClientVersion()
|
||||
.then((versionInfo: IVersionInfo) => {
|
||||
if (isMac) {
|
||||
setAboutPanel(versionInfo.clientVersion, versionInfo.buildNumber);
|
||||
}
|
||||
});
|
||||
logger.info(`main: app is ready, performing initial checks`);
|
||||
createAppCacheFile();
|
||||
windowHandler.createApplication();
|
||||
|
@ -19,13 +19,14 @@ interface IVersionInfo {
|
||||
aresVersion: string;
|
||||
httpParserVersion: string;
|
||||
swiftSearchVersion: string;
|
||||
swiftSerchSupportedVersion: string;
|
||||
swiftSearchSupportedVersion: string;
|
||||
}
|
||||
|
||||
class VersionHandler {
|
||||
|
||||
private versionInfo: IVersionInfo;
|
||||
public versionInfo: IVersionInfo;
|
||||
private serverVersionInfo: any;
|
||||
private mainUrl;
|
||||
|
||||
constructor() {
|
||||
this.versionInfo = {
|
||||
@ -43,32 +44,42 @@ class VersionHandler {
|
||||
aresVersion: process.versions.ares,
|
||||
httpParserVersion: process.versions.http_parser,
|
||||
swiftSearchVersion: optionalDependencies['swift-search'],
|
||||
swiftSerchSupportedVersion: searchAPIVersion,
|
||||
swiftSearchSupportedVersion: searchAPIVersion,
|
||||
};
|
||||
this.mainUrl = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Symphony version from the pod
|
||||
*/
|
||||
public getClientVersion(): Promise<IVersionInfo> {
|
||||
public getClientVersion(fetchFromServer: boolean = false, mainUrl?: string): Promise<IVersionInfo> {
|
||||
return new Promise((resolve) => {
|
||||
if (this.serverVersionInfo) {
|
||||
|
||||
if (this.serverVersionInfo && !fetchFromServer) {
|
||||
this.versionInfo.clientVersion = this.serverVersionInfo['Implementation-Version'] || this.versionInfo.clientVersion;
|
||||
this.versionInfo.buildNumber = this.serverVersionInfo['Implementation-Build'] || this.versionInfo.buildNumber;
|
||||
resolve(this.versionInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainUrl) {
|
||||
this.mainUrl = mainUrl;
|
||||
}
|
||||
|
||||
const { url: podUrl }: IConfig = config.getGlobalConfigFields(['url']);
|
||||
|
||||
if (!podUrl) {
|
||||
if (!this.mainUrl || !nodeURL.parse(this.mainUrl)) {
|
||||
this.mainUrl = podUrl;
|
||||
}
|
||||
|
||||
if (!this.mainUrl) {
|
||||
logger.error(`version-handler: Unable to get pod url for getting version data from server! Setting defaults!`);
|
||||
resolve(this.versionInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
const hostname = nodeURL.parse(podUrl).hostname;
|
||||
const protocol = nodeURL.parse(podUrl).protocol;
|
||||
const hostname = nodeURL.parse(this.mainUrl).hostname;
|
||||
const protocol = nodeURL.parse(this.mainUrl).protocol;
|
||||
const versionApiPath = '/webcontroller/HealthCheck/version/advanced';
|
||||
|
||||
const url = `${protocol}//${hostname}${versionApiPath}`;
|
||||
@ -96,7 +107,7 @@ class VersionHandler {
|
||||
}
|
||||
});
|
||||
|
||||
res.on('error', (error) => {
|
||||
res.on('error', (error: Error) => {
|
||||
logger.error(`version-handler: Error getting version data from the server! ${error}`);
|
||||
resolve(this.versionInfo);
|
||||
return;
|
||||
@ -104,7 +115,7 @@ class VersionHandler {
|
||||
|
||||
});
|
||||
|
||||
request.on('error', (error) => {
|
||||
request.on('error', (error: Error) => {
|
||||
logger.error(`version-handler: Error getting version data from the server! ${error}`);
|
||||
resolve(this.versionInfo);
|
||||
return;
|
||||
|
@ -16,7 +16,7 @@ import { config, IConfig } from './config-handler';
|
||||
import { SpellChecker } from './spell-check-handler';
|
||||
import { checkIfBuildExpired } from './ttl-handler';
|
||||
import DesktopCapturerSource = Electron.DesktopCapturerSource;
|
||||
import { IVersionInfo, versionHandler } from './version-handler';
|
||||
import { versionHandler } from './version-handler';
|
||||
import { handlePermissionRequests, monitorWindowActions } from './window-actions';
|
||||
import {
|
||||
createComponentWindow,
|
||||
@ -88,9 +88,9 @@ export class WindowHandler {
|
||||
|
||||
constructor(opts?: Electron.BrowserViewConstructorOptions) {
|
||||
// Use these variables only on initial setup
|
||||
this.config = config.getConfigFields([ 'isCustomTitleBar', 'mainWinPos', 'minimizeOnClose', 'notificationSettings', 'alwaysOnTop' ]);
|
||||
this.globalConfig = config.getGlobalConfigFields([ 'url', 'contextIsolation', 'customFlags' ]);
|
||||
const { url, contextIsolation, customFlags }: IConfig = this.globalConfig;
|
||||
this.config = config.getConfigFields(['isCustomTitleBar', 'mainWinPos', 'minimizeOnClose', 'notificationSettings', 'alwaysOnTop']);
|
||||
this.globalConfig = config.getGlobalConfigFields(['url', 'contextIsolation', 'customFlags']);
|
||||
const {url, contextIsolation, customFlags}: IConfig = this.globalConfig;
|
||||
|
||||
this.windows = {};
|
||||
this.contextIsolation = contextIsolation || false;
|
||||
@ -114,12 +114,13 @@ export class WindowHandler {
|
||||
this.appMenu = null;
|
||||
|
||||
try {
|
||||
const extra = { podUrl: url, process: 'main' };
|
||||
const defaultOpts = { uploadToServer: false, companyName: 'Symphony', submitURL: '' };
|
||||
crashReporter.start({ ...defaultOpts, extra });
|
||||
const extra = {podUrl: url, process: 'main'};
|
||||
const defaultOpts = {uploadToServer: false, companyName: 'Symphony', submitURL: ''};
|
||||
crashReporter.start({...defaultOpts, extra});
|
||||
} catch (e) {
|
||||
throw new Error('failed to init crash report');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,6 +128,7 @@ export class WindowHandler {
|
||||
*/
|
||||
public createApplication() {
|
||||
|
||||
this.updateVersionInfo();
|
||||
this.spellchecker = new SpellChecker();
|
||||
logger.info(`window-handler: initialized spellchecker module with locale ${this.spellchecker.locale}`);
|
||||
|
||||
@ -135,7 +137,7 @@ export class WindowHandler {
|
||||
...this.windowOpts, ...getBounds(this.config.mainWinPos, DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
||||
}) as ICustomBrowserWindow;
|
||||
this.mainWindow.winName = apiName.mainWindowName;
|
||||
const { isFullScreen, isMaximized } = this.config.mainWinPos ? this.config.mainWinPos : { isFullScreen: false, isMaximized: false };
|
||||
const {isFullScreen, isMaximized} = this.config.mainWinPos ? this.config.mainWinPos : {isFullScreen: false, isMaximized: false};
|
||||
if (isMaximized) {
|
||||
this.mainWindow.maximize();
|
||||
logger.info(`window-handler: window is maximized!`);
|
||||
@ -183,7 +185,7 @@ export class WindowHandler {
|
||||
isMainWindow: true,
|
||||
});
|
||||
this.appMenu = new AppMenu();
|
||||
const { permissions } = config.getGlobalConfigFields([ 'permissions' ]);
|
||||
const {permissions} = config.getGlobalConfigFields(['permissions']);
|
||||
this.mainWindow.webContents.send('is-screen-share-enabled', permissions.media);
|
||||
});
|
||||
|
||||
@ -199,7 +201,7 @@ export class WindowHandler {
|
||||
if (href === 'data:text/html,chromewebdata' || href === 'chrome-error://chromewebdata/') {
|
||||
if (this.mainWindow && windowExists(this.mainWindow)) {
|
||||
this.mainWindow.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '..', '/renderer/styles/network-error.css'), 'utf8').toString());
|
||||
this.mainWindow.webContents.send('network-error', { error: this.loadFailError });
|
||||
this.mainWindow.webContents.send('network-error', {error: this.loadFailError});
|
||||
isSymphonyReachable(this.mainWindow);
|
||||
}
|
||||
}
|
||||
@ -219,7 +221,7 @@ export class WindowHandler {
|
||||
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' ],
|
||||
buttons: ['Reload', 'Close'],
|
||||
}, (index: number) => {
|
||||
if (!this.mainWindow || !windowExists(this.mainWindow)) {
|
||||
return;
|
||||
@ -239,7 +241,7 @@ export class WindowHandler {
|
||||
return this.destroyAllWindows();
|
||||
}
|
||||
|
||||
const { minimizeOnClose } = config.getConfigFields([ 'minimizeOnClose' ]);
|
||||
const {minimizeOnClose} = config.getConfigFields(['minimizeOnClose']);
|
||||
if (minimizeOnClose) {
|
||||
event.preventDefault();
|
||||
isMac ? this.mainWindow.hide() : this.mainWindow.minimize();
|
||||
@ -321,7 +323,7 @@ export class WindowHandler {
|
||||
break;
|
||||
case 'screen-sharing-indicator':
|
||||
if (winKey) {
|
||||
const browserWindow = this.windows[ winKey ];
|
||||
const browserWindow = this.windows[winKey];
|
||||
if (browserWindow && windowExists(browserWindow)) {
|
||||
browserWindow.close();
|
||||
}
|
||||
@ -373,7 +375,7 @@ export class WindowHandler {
|
||||
* @param window {Electron.BrowserWindow}
|
||||
*/
|
||||
public hasWindow(key: string, window: Electron.BrowserWindow): boolean {
|
||||
const browserWindow = this.windows[ key ];
|
||||
const browserWindow = this.windows[key];
|
||||
return browserWindow && window === browserWindow;
|
||||
}
|
||||
|
||||
@ -414,13 +416,16 @@ export class WindowHandler {
|
||||
this.aboutAppWindow = createComponentWindow('about-app', opts);
|
||||
this.aboutAppWindow.setVisibleOnAllWorkspaces(true);
|
||||
this.aboutAppWindow.webContents.once('did-finish-load', async () => {
|
||||
if (!this.aboutAppWindow || !windowExists(this.aboutAppWindow)) {
|
||||
return;
|
||||
}
|
||||
const ABOUT_SYMPHONY_NAMESPACE = 'AboutSymphony';
|
||||
const versionLocalised = i18n.t('Version', ABOUT_SYMPHONY_NAMESPACE)();
|
||||
const { clientVersion, buildNumber }: IVersionInfo = await versionHandler.getClientVersion();
|
||||
this.aboutAppWindow.webContents.send('about-app-data', { buildNumber, clientVersion, versionLocalised });
|
||||
const aboutInfo = {
|
||||
buildNumber: versionHandler.versionInfo.buildNumber,
|
||||
clientVersion: versionHandler.versionInfo.clientVersion,
|
||||
versionLocalised,
|
||||
};
|
||||
if (this.aboutAppWindow && windowExists(this.aboutAppWindow)) {
|
||||
this.aboutAppWindow.webContents.send('about-app-data', aboutInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -448,11 +453,9 @@ export class WindowHandler {
|
||||
|
||||
this.moreInfoWindow = createComponentWindow('more-info', opts);
|
||||
this.moreInfoWindow.webContents.once('did-finish-load', async () => {
|
||||
if (!this.moreInfoWindow || !windowExists(this.moreInfoWindow)) {
|
||||
return;
|
||||
if (this.moreInfoWindow && windowExists(this.moreInfoWindow)) {
|
||||
this.moreInfoWindow.webContents.send('more-info-data', versionHandler.versionInfo);
|
||||
}
|
||||
const versionInfo: IVersionInfo = await versionHandler.getClientVersion();
|
||||
this.moreInfoWindow.webContents.send('more-info-data', versionInfo);
|
||||
});
|
||||
}
|
||||
|
||||
@ -490,7 +493,7 @@ export class WindowHandler {
|
||||
if (!this.screenPickerWindow || !windowExists(this.screenPickerWindow)) {
|
||||
return;
|
||||
}
|
||||
this.screenPickerWindow.webContents.send('screen-picker-data', { sources, id });
|
||||
this.screenPickerWindow.webContents.send('screen-picker-data', {sources, id});
|
||||
this.addWindow(opts.winKey, this.screenPickerWindow);
|
||||
});
|
||||
ipcMain.once('screen-source-selected', (_event, source) => {
|
||||
@ -535,7 +538,7 @@ export class WindowHandler {
|
||||
if (!this.basicAuthWindow || !windowExists(this.basicAuthWindow)) {
|
||||
return;
|
||||
}
|
||||
this.basicAuthWindow.webContents.send('basic-auth-data', { hostname, isValidCredentials: isMultipleTries });
|
||||
this.basicAuthWindow.webContents.send('basic-auth-data', {hostname, isValidCredentials: isMultipleTries});
|
||||
});
|
||||
const closeBasicAuth = (shouldClearSettings = true) => {
|
||||
if (shouldClearSettings) {
|
||||
@ -548,7 +551,7 @@ export class WindowHandler {
|
||||
};
|
||||
|
||||
const login = (_event, arg) => {
|
||||
const { username, password } = arg;
|
||||
const {username, password} = arg;
|
||||
callback(username, password);
|
||||
closeBasicAuth(false);
|
||||
};
|
||||
@ -606,17 +609,17 @@ export class WindowHandler {
|
||||
if (app.isReady()) {
|
||||
screens = electron.screen.getAllDisplays();
|
||||
}
|
||||
const { position, display } = config.getConfigFields([ 'notificationSettings' ]).notificationSettings;
|
||||
this.notificationSettingsWindow.webContents.send('notification-settings-data', { screens, position, display });
|
||||
const {position, display} = config.getConfigFields(['notificationSettings']).notificationSettings;
|
||||
this.notificationSettingsWindow.webContents.send('notification-settings-data', {screens, position, display});
|
||||
}
|
||||
});
|
||||
|
||||
this.addWindow(opts.winKey, this.notificationSettingsWindow);
|
||||
|
||||
ipcMain.once('notification-settings-update', async (_event, args) => {
|
||||
const { display, position } = args;
|
||||
const {display, position} = args;
|
||||
try {
|
||||
await config.updateUserConfig({ notificationSettings: { display, position } });
|
||||
await config.updateUserConfig({notificationSettings: {display, position}});
|
||||
} catch (e) {
|
||||
logger.error(`NotificationSettings: Could not update user config file error`, e);
|
||||
}
|
||||
@ -650,7 +653,7 @@ export class WindowHandler {
|
||||
): void {
|
||||
const indicatorScreen =
|
||||
(displayId && electron.screen.getAllDisplays().filter((d) =>
|
||||
displayId.includes(d.id.toString()))[ 0 ]) || electron.screen.getPrimaryDisplay();
|
||||
displayId.includes(d.id.toString()))[0]) || electron.screen.getPrimaryDisplay();
|
||||
|
||||
const screenRect = indicatorScreen.workArea;
|
||||
// Set stream id as winKey to link stream to the window
|
||||
@ -669,7 +672,7 @@ export class WindowHandler {
|
||||
fullscreenable: false,
|
||||
}, {
|
||||
devTools: false,
|
||||
}), ...{ winKey: streamId },
|
||||
}), ...{winKey: streamId},
|
||||
};
|
||||
if (opts.width && opts.height) {
|
||||
opts = Object.assign({}, opts, {
|
||||
@ -683,7 +686,7 @@ export class WindowHandler {
|
||||
if (!this.screenSharingIndicatorWindow || !windowExists(this.screenSharingIndicatorWindow)) {
|
||||
return;
|
||||
}
|
||||
this.screenSharingIndicatorWindow.webContents.send('screen-sharing-indicator-data', { id, streamId });
|
||||
this.screenSharingIndicatorWindow.webContents.send('screen-sharing-indicator-data', {id, streamId});
|
||||
});
|
||||
const stopScreenSharing = (_event, indicatorId) => {
|
||||
if (id === indicatorId) {
|
||||
@ -701,6 +704,14 @@ export class WindowHandler {
|
||||
ipcMain.once('stop-screen-sharing', stopScreenSharing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update version info on the about app window and more info window
|
||||
*/
|
||||
public async updateVersionInfo() {
|
||||
await versionHandler.getClientVersion(true, this.url);
|
||||
this.setAboutPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an external url in the system's default browser
|
||||
*
|
||||
@ -720,7 +731,7 @@ export class WindowHandler {
|
||||
* @param browserWindow {Electron.BrowserWindow}
|
||||
*/
|
||||
public addWindow(key: string, browserWindow: Electron.BrowserWindow): void {
|
||||
this.windows[ key ] = browserWindow;
|
||||
this.windows[key] = browserWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -729,7 +740,25 @@ export class WindowHandler {
|
||||
* @param key {string}
|
||||
*/
|
||||
public removeWindow(key: string): void {
|
||||
delete this.windows[ key ];
|
||||
delete this.windows[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the about panel details for macOS
|
||||
*/
|
||||
private setAboutPanel() {
|
||||
if (!isMac) {
|
||||
return;
|
||||
}
|
||||
const appName = app.getName();
|
||||
const copyright = `Copyright \xA9 ${new Date().getFullYear()} ${appName}`;
|
||||
app.setAboutPanelOptions({
|
||||
applicationName: appName,
|
||||
applicationVersion: versionHandler.versionInfo.clientVersion,
|
||||
version: versionHandler.versionInfo.buildNumber,
|
||||
copyright,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -754,7 +783,7 @@ export class WindowHandler {
|
||||
*/
|
||||
private onRegisterDevtools(): void {
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
const { devToolsEnabled } = config.getGlobalConfigFields([ 'devToolsEnabled' ]);
|
||||
const {devToolsEnabled} = config.getGlobalConfigFields(['devToolsEnabled']);
|
||||
if (!focusedWindow || !windowExists(focusedWindow)) {
|
||||
return;
|
||||
}
|
||||
@ -766,7 +795,7 @@ export class WindowHandler {
|
||||
logger.info(`window-handler: dev tools disabled by admin, showing error dialog to user!`);
|
||||
electron.dialog.showMessageBox(focusedWindow, {
|
||||
type: 'warning',
|
||||
buttons: [ 'Ok' ],
|
||||
buttons: ['Ok'],
|
||||
title: i18n.t('Dev Tools disabled')(),
|
||||
message: i18n.t('Dev Tools has been disabled! Please contact your system administrator to enable it!')(),
|
||||
});
|
||||
@ -778,7 +807,7 @@ export class WindowHandler {
|
||||
private destroyAllWindows(): void {
|
||||
for (const key in this.windows) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.windows, key)) {
|
||||
const winKey = this.windows[ key ];
|
||||
const winKey = this.windows[key];
|
||||
this.removeWindow(winKey);
|
||||
}
|
||||
}
|
||||
@ -807,7 +836,7 @@ export class WindowHandler {
|
||||
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,
|
||||
};
|
||||
|
||||
@ -835,7 +864,7 @@ export class WindowHandler {
|
||||
winKey: getGuid(),
|
||||
};
|
||||
|
||||
return { ...defaultWindowOpts, ...windowOpts };
|
||||
return {...defaultWindowOpts, ...windowOpts};
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user