From 8b251a3cca164981cce208b0979e394d76cd82f4 Mon Sep 17 00:00:00 2001
From: Johan Kwarnmark
Date: Mon, 2 Mar 2020 14:36:53 +0100
Subject: [PATCH 1/7] sda-1717 made screenShareIndicatorFrameUtil and execCmd
public
---
src/app/window-handler.ts | 43 +++++++++++++++++++--------------------
1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts
index 32feebe9..c71b975d 100644
--- a/src/app/window-handler.ts
+++ b/src/app/window-handler.ts
@@ -75,6 +75,7 @@ export class WindowHandler {
public spellchecker: SpellChecker | undefined;
public isCustomTitleBar: boolean;
public isWebPageLoading: boolean = true;
+ public screenShareIndicatorFrameUtil: string;
private readonly contextIsolation: boolean;
private readonly backgroundThrottling: boolean;
@@ -92,7 +93,6 @@ export class WindowHandler {
private screenSharingFrameWindow: Electron.BrowserWindow | null = null;
private basicAuthWindow: Electron.BrowserWindow | null = null;
private notificationSettingsWindow: Electron.BrowserWindow | null = null;
- private screenShareIndicatorFrameUtil: string;
constructor(opts?: Electron.BrowserViewConstructorOptions) {
// Use these variables only on initial setup
@@ -918,6 +918,26 @@ export class WindowHandler {
delete this.windows[key];
}
+ /**
+ * Executes the given command via a child process
+ *
+ * @param util {string}
+ * @param utilArgs {ReadonlyArray}
+ */
+ public execCmd(util: string, utilArgs: ReadonlyArray): Promise {
+ logger.info(`window handler: execCmd: util: ${util} utilArgs: ${utilArgs}`);
+ return new Promise((resolve, reject) => {
+ return execFile(util, utilArgs, (error: ExecException | null) => {
+ logger.info(`window handler: execCmd: error: ${error}`);
+ if (error && error.killed) {
+ // processs was killed, just resolve with no data.
+ return reject(error);
+ }
+ resolve();
+ });
+ });
+ }
+
/**
* Sets the about panel details for macOS
*/
@@ -1046,27 +1066,6 @@ export class WindowHandler {
return {...defaultWindowOpts, ...windowOpts};
}
-
- /**
- * Executes the given command via a child process
- *
- * @param util {string}
- * @param utilArgs {ReadonlyArray}
- */
- private execCmd(util: string, utilArgs: ReadonlyArray): Promise {
- logger.info(`window handler: execCmd: util: ${util} utilArgs: ${utilArgs}`);
- return new Promise((resolve, reject) => {
- return execFile(util, utilArgs, (error: ExecException | null) => {
- logger.info(`window handler: execCmd: error: ${error}`);
- if (error && error.killed) {
- // processs was killed, just resolve with no data.
- return reject(error);
- }
- resolve();
- });
- });
- }
-
}
const windowHandler = new WindowHandler();
From 6a821548181a06117b99a70288acdfcba6a3add7 Mon Sep 17 00:00:00 2001
From: Johan Kwarnmark
Date: Mon, 2 Mar 2020 14:37:47 +0100
Subject: [PATCH 2/7] sda-1717 when application is reloading all childwindows
are closed, added kill of screen share frame
---
src/app/window-utils.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/app/window-utils.ts b/src/app/window-utils.ts
index 112bf167..5e95e97d 100644
--- a/src/app/window-utils.ts
+++ b/src/app/window-utils.ts
@@ -543,6 +543,9 @@ export const reloadWindow = (browserWindow: ICustomBrowserWindow) => {
if (windowName === apiName.mainWindowName) {
logger.info(`window-utils: reloading the main window`);
browserWindow.reload();
+
+ windowHandler.execCmd(windowHandler.screenShareIndicatorFrameUtil, []);
+
return;
}
// Send an event to SFE that restarts the pop-out window
From 890268f9d8f0915833b5cb9f5f3121e5bb7bab14 Mon Sep 17 00:00:00 2001
From: Johan Kwarnmark
<55975938+johankwarnmarksymphony@users.noreply.github.com>
Date: Mon, 2 Mar 2020 14:46:49 +0100
Subject: [PATCH 3/7] Update src/app/window-handler.ts
Co-Authored-By: mattias-symphony <57355424+mattias-symphony@users.noreply.github.com>
---
src/app/window-handler.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts
index c71b975d..7a9166f1 100644
--- a/src/app/window-handler.ts
+++ b/src/app/window-handler.ts
@@ -928,7 +928,9 @@ export class WindowHandler {
logger.info(`window handler: execCmd: util: ${util} utilArgs: ${utilArgs}`);
return new Promise((resolve, reject) => {
return execFile(util, utilArgs, (error: ExecException | null) => {
- logger.info(`window handler: execCmd: error: ${error}`);
+ if (error) {
+ logger.info(`window handler: execCmd: error: ${error}`);
+ }
if (error && error.killed) {
// processs was killed, just resolve with no data.
return reject(error);
From 45cfbbdd6b522d002dd8a16bc4e9286031670fe3 Mon Sep 17 00:00:00 2001
From: Kiran Niranjan
Date: Tue, 3 Mar 2020 11:15:27 +0530
Subject: [PATCH 4/7] feat: SDA-1748 (Add support for Cloud Config) (#878)
* SDA-1748 - Initial Cloud config
* SDA-1748 - Read menu items enabled values from filtered cloud config
* SDA-1748 - Fix unit tests
* SDA-1748 - Fix issues with custom title bar and devtools
* SDA-1748 - Fix unit tests
---
config/Symphony.config | 13 +--
spec/appMenu.spec.ts | 34 +++++--
spec/chromeFlags.spec.ts | 6 +-
spec/config.spec.ts | 4 +-
spec/mainApiHandler.spec.ts | 7 +-
src/app/app-menu.ts | 101 ++++++++++++-------
src/app/auto-launch-controller.ts | 2 +-
src/app/child-window-handler.ts | 2 +-
src/app/chrome-flags.ts | 4 +-
src/app/config-handler.ts | 162 ++++++++++++++++++++++++++----
src/app/config-utils.ts | 40 ++++++++
src/app/dialog-handler.ts | 7 +-
src/app/main-api-handler.ts | 15 ++-
src/app/memory-monitor.ts | 15 ++-
src/app/perf-handler.ts | 4 +-
src/app/screen-snippet-handler.ts | 4 +-
src/app/version-handler.ts | 4 +-
src/app/window-actions.ts | 10 +-
src/app/window-handler.ts | 36 +++----
src/app/window-utils.ts | 38 ++++++-
src/common/api-interface.ts | 2 +
src/common/utils.ts | 19 ++++
src/common/whitelist-handler.ts | 2 +-
src/renderer/app-bridge.ts | 3 +
src/renderer/preload-main.ts | 10 +-
src/renderer/ssf-api.ts | 16 +++
26 files changed, 437 insertions(+), 123 deletions(-)
create mode 100644 src/app/config-utils.ts
diff --git a/config/Symphony.config b/config/Symphony.config
index 7cf68cb1..109a35ca 100644
--- a/config/Symphony.config
+++ b/config/Symphony.config
@@ -1,12 +1,13 @@
{
"url":"https://foundation-dev.symphony.com",
- "minimizeOnClose" : true,
- "launchOnStartup" : true,
- "alwaysOnTop" : false,
- "bringToFront": false,
+ "minimizeOnClose" : "ENABLED",
+ "launchOnStartup" : "ENABLED",
+ "alwaysOnTop" : "DISABLED",
+ "bringToFront": "DISABLED",
"whitelistUrl": "*",
- "isCustomTitleBar": true,
- "memoryRefresh": true,
+ "isCustomTitleBar": "ENABLED",
+ "memoryRefresh": "ENABLED",
+ "memoryThreshold": "800",
"devToolsEnabled": true,
"contextIsolation": true,
"ctWhitelist": [],
diff --git a/spec/appMenu.spec.ts b/spec/appMenu.spec.ts
index d7ac6d1d..7be8354b 100644
--- a/spec/appMenu.spec.ts
+++ b/spec/appMenu.spec.ts
@@ -39,14 +39,20 @@ jest.mock('../src/app/auto-launch-controller', () => {
jest.mock('../src/app/config-handler', () => {
return {
+ CloudConfigDataTypes: {
+ NOT_SET: 'NOT_SET',
+ ENABLED: 'ENABLED',
+ DISABLED: 'DISABLED',
+ },
config: {
getConfigFields: jest.fn(() => {
return {
- minimizeOnClose: true,
- launchOnStartup: true,
- alwaysOnTop: true,
- isAlwaysOnTop: true,
- bringToFront: true,
+ minimizeOnClose: 'ENABLED',
+ launchOnStartup: 'ENABLED',
+ alwaysOnTop: 'ENABLED',
+ isAlwaysOnTop: 'ENABLED',
+ bringToFront: 'ENABLED',
+ devToolsEnabled: true,
};
}),
getGlobalConfigFields: jest.fn(() => {
@@ -54,6 +60,16 @@ jest.mock('../src/app/config-handler', () => {
devToolsEnabled: true,
};
}),
+ getFilteredCloudConfigFields: jest.fn(() => {
+ return {
+ devToolsEnabled: true,
+ };
+ }),
+ getCloudConfigFields: jest.fn(() => {
+ return {
+ devToolsEnabled: true,
+ };
+ }),
updateUserConfig: jest.fn(),
},
};
@@ -202,7 +218,7 @@ describe('app menu', () => {
it('should disable `AutoLaunch` when click is triggered', async () => {
const spyFn = 'disableAutoLaunch';
const spyConfig = jest.spyOn(config, updateUserFnLabel);
- const expectedValue = { launchOnStartup: false };
+ const expectedValue = { launchOnStartup: 'NOT_SET' };
const spy = jest.spyOn(autoLaunchInstance, spyFn);
const customItem = {
checked: false,
@@ -215,7 +231,7 @@ describe('app menu', () => {
it('should enable `AutoLaunch` when click is triggered', async () => {
const spyFn = 'enableAutoLaunch';
const spyConfig = jest.spyOn(config, updateUserFnLabel);
- const expectedValue = { launchOnStartup: true };
+ const expectedValue = { launchOnStartup: 'ENABLED' };
const spy = jest.spyOn(autoLaunchInstance, spyFn);
await autoLaunchMenuItem.click(item);
expect(spy).toBeCalled();
@@ -231,7 +247,7 @@ describe('app menu', () => {
it('should update `minimizeOnClose` value when click is triggered', async () => {
const spyConfig = jest.spyOn(config, updateUserFnLabel);
- const expectedValue = { minimizeOnClose: true };
+ const expectedValue = { minimizeOnClose: 'ENABLED' };
const menuItem = findMenuItemBuildWindowMenu('Minimize on Close');
await menuItem.click(item);
expect(spyConfig).lastCalledWith(expectedValue);
@@ -240,7 +256,7 @@ describe('app menu', () => {
describe('`bringToFront`', () => {
it('should update `bringToFront` value when click is triggered', async () => {
const spyConfig = jest.spyOn(config, updateUserFnLabel);
- const expectedValue = { bringToFront: true };
+ const expectedValue = { bringToFront: 'ENABLED' };
const menuItem = findMenuItemBuildWindowMenu('Bring to Front on Notifications');
await menuItem.click(item);
expect(spyConfig).lastCalledWith(expectedValue);
diff --git a/spec/chromeFlags.spec.ts b/spec/chromeFlags.spec.ts
index da2ec1ca..9474be1a 100644
--- a/spec/chromeFlags.spec.ts
+++ b/spec/chromeFlags.spec.ts
@@ -6,7 +6,7 @@ import { app } from './__mocks__/electron';
jest.mock('../src/common/utils', () => {
return {
config: {
- getGlobalConfigFields: jest.fn(() => {
+ getCloudConfigField: jest.fn(() => {
return {
customFlags: {
authServerWhitelist: 'url',
@@ -35,7 +35,7 @@ describe('chrome flags', () => {
(isMac as any) = true;
(isWindowsOS as any) = false;
(isLinux as any) = false;
- config.getGlobalConfigFields = jest.fn(() => {
+ config.getConfigFields = jest.fn(() => {
return {
customFlags: {
authServerWhitelist: 'url',
@@ -59,7 +59,7 @@ describe('chrome flags', () => {
});
it('should call `setChromeFlags` correctly when `disableGpu` is false', () => {
- config.getGlobalConfigFields = jest.fn(() => {
+ config.getConfigFields = jest.fn(() => {
return {
customFlags: {
authServerWhitelist: 'url',
diff --git a/spec/config.spec.ts b/spec/config.spec.ts
index 0b378ca4..c79d3c57 100644
--- a/spec/config.spec.ts
+++ b/spec/config.spec.ts
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
-import { IConfig } from '../src/app/config-handler';
+import { IConfig, IGlobalConfig } from '../src/app/config-handler';
jest.mock('electron-log');
@@ -75,7 +75,7 @@ describe('config', () => {
configInstance.readUserConfig();
configInstance.readGlobalConfig();
- const configField: IConfig = configInstance.getConfigFields(fieldMock);
+ const configField: IGlobalConfig = configInstance.getGlobalConfigFields(fieldMock);
expect(configField.url).toBe('something');
});
diff --git a/spec/mainApiHandler.spec.ts b/spec/mainApiHandler.spec.ts
index f21bc968..c119a651 100644
--- a/spec/mainApiHandler.spec.ts
+++ b/spec/mainApiHandler.spec.ts
@@ -71,10 +71,15 @@ jest.mock('../src/common/logger', () => {
jest.mock('../src/app/config-handler', () => {
return {
+ CloudConfigDataTypes: {
+ NOT_SET: 'NOT_SET',
+ ENABLED: 'ENABLED',
+ DISABLED: 'DISABLED',
+ },
config: {
getConfigFields: jest.fn(() => {
return {
- bringToFront: true,
+ bringToFront: 'ENABLED',
};
}),
},
diff --git a/src/app/app-menu.ts b/src/app/app-menu.ts
index 90272d5d..ed2e3468 100644
--- a/src/app/app-menu.ts
+++ b/src/app/app-menu.ts
@@ -10,7 +10,7 @@ import {
MenuActionTypes,
} from './analytics-handler';
import { autoLaunchInstance as autoLaunch } from './auto-launch-controller';
-import { config, IConfig } from './config-handler';
+import { CloudConfigDataTypes, config, IConfig } from './config-handler';
import { titleBarChangeDialog } from './dialog-handler';
import { exportCrashDumps, exportLogs } from './reports-handler';
import { updateAlwaysOnTop } from './window-actions';
@@ -25,11 +25,6 @@ export const menuSections = {
help: 'help', // tslint:disable-line
};
-enum TitleBarStyles {
- CUSTOM,
- NATIVE,
-}
-
const windowsAccelerator = Object.assign({
close: 'Ctrl+W',
copy: 'Ctrl+C',
@@ -52,12 +47,16 @@ let {
alwaysOnTop: isAlwaysOnTop,
bringToFront,
memoryRefresh,
+ isCustomTitleBar,
+ devToolsEnabled,
} = config.getConfigFields([
'minimizeOnClose',
'launchOnStartup',
'alwaysOnTop',
'bringToFront',
'memoryRefresh',
+ 'isCustomTitleBar',
+ 'devToolsEnabled',
]) as IConfig;
let initialAnalyticsSent = false;
@@ -66,29 +65,28 @@ const menuItemsArray = Object.keys(menuSections)
.filter((value) => isMac ?
true : value !== menuSections.about);
-const { devToolsEnabled } = config.getGlobalConfigFields([ 'devToolsEnabled' ]);
-
export class AppMenu {
private menu: Electron.Menu | undefined;
private menuList: Electron.MenuItemConstructorOptions[];
private locale: LocaleType;
- private titleBarStyle: TitleBarStyles;
+ private cloudConfig: IConfig | {};
+
+ private readonly menuItemConfigFields: string[];
constructor() {
this.menuList = [];
this.locale = i18n.getLocale();
- this.titleBarStyle = config.getConfigFields([ 'isCustomTitleBar' ]).isCustomTitleBar
- ? TitleBarStyles.CUSTOM
- : TitleBarStyles.NATIVE;
+ this.menuItemConfigFields = [ 'minimizeOnClose', 'launchOnStartup', 'alwaysOnTop', 'bringToFront', 'memoryRefresh', 'isCustomTitleBar', 'devToolsEnabled' ];
+ this.cloudConfig = config.getFilteredCloudConfigFields(this.menuItemConfigFields);
this.buildMenu();
// send initial analytic
if (!initialAnalyticsSent) {
- this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.MINIMIZE_ON_CLOSE, minimizeOnClose);
- this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.AUTO_LAUNCH_ON_START_UP, launchOnStartup);
- this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.ALWAYS_ON_TOP, isAlwaysOnTop);
- this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.FLASH_NOTIFICATION_IN_TASK_BAR, bringToFront);
- this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.REFRESH_APP_IN_IDLE, memoryRefresh);
- this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.HAMBURGER_MENU, (isMac || isLinux) ? false : this.titleBarStyle === TitleBarStyles.CUSTOM);
+ this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.MINIMIZE_ON_CLOSE, minimizeOnClose === CloudConfigDataTypes.ENABLED);
+ this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.AUTO_LAUNCH_ON_START_UP, launchOnStartup === CloudConfigDataTypes.ENABLED);
+ this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.ALWAYS_ON_TOP, isAlwaysOnTop === CloudConfigDataTypes.ENABLED);
+ this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.FLASH_NOTIFICATION_IN_TASK_BAR, bringToFront === CloudConfigDataTypes.ENABLED);
+ this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.REFRESH_APP_IN_IDLE, memoryRefresh === CloudConfigDataTypes.ENABLED);
+ this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.HAMBURGER_MENU, (isMac || isLinux) ? false : isCustomTitleBar === CloudConfigDataTypes.ENABLED);
}
initialAnalyticsSent = true;
}
@@ -97,6 +95,9 @@ export class AppMenu {
* Builds the menu items for all the menu
*/
public buildMenu(): void {
+ // updates the global variables
+ this.updateGlobals();
+
this.menuList = menuItemsArray.reduce((map: Electron.MenuItemConstructorOptions, key: string) => {
map[ key ] = this.buildMenuKey(key);
return map;
@@ -133,6 +134,23 @@ export class AppMenu {
}
}
+ /**
+ * Updates the global variables
+ */
+ public updateGlobals(): void {
+ const configData = config.getConfigFields(this.menuItemConfigFields) as IConfig;
+ minimizeOnClose = configData.minimizeOnClose;
+ launchOnStartup = configData.launchOnStartup;
+ isAlwaysOnTop = configData.alwaysOnTop;
+ bringToFront = configData.bringToFront;
+ memoryRefresh = configData.memoryRefresh;
+ isCustomTitleBar = configData.isCustomTitleBar;
+ devToolsEnabled = configData.devToolsEnabled;
+
+ // fetch updated cloud config
+ this.cloudConfig = config.getFilteredCloudConfigFields(this.menuItemConfigFields);
+ }
+
/**
* Displays popup application at the x,y coordinates
*
@@ -257,51 +275,63 @@ export class AppMenu {
private buildWindowMenu(): Electron.MenuItemConstructorOptions {
logger.info(`app-menu: building window menu`);
+ const {
+ alwaysOnTop: isAlwaysOnTopCC,
+ minimizeOnClose: minimizeOnCloseCC,
+ launchOnStartup: launchOnStartupCC,
+ bringToFront: bringToFrontCC,
+ memoryRefresh: memoryRefreshCC,
+ isCustomTitleBar: isCustomTitleBarCC,
+ } = this.cloudConfig as IConfig;
+
const submenu: MenuItemConstructorOptions[] = [
this.assignRoleOrLabel({ role: 'minimize', label: i18n.t('Minimize')() }),
this.assignRoleOrLabel({ role: 'close', label: i18n.t('Close')() }),
this.buildSeparator(),
{
- checked: launchOnStartup,
+ checked: launchOnStartup === CloudConfigDataTypes.ENABLED,
click: async (item) => {
if (item.checked) {
autoLaunch.enableAutoLaunch();
} else {
autoLaunch.disableAutoLaunch();
}
- launchOnStartup = item.checked;
+ launchOnStartup = item.checked ? CloudConfigDataTypes.ENABLED : CloudConfigDataTypes.NOT_SET;
await config.updateUserConfig({ launchOnStartup });
this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.AUTO_LAUNCH_ON_START_UP, item.checked);
},
label: i18n.t('Auto Launch On Startup')(),
type: 'checkbox',
visible: !isLinux,
+ enabled: !launchOnStartupCC || launchOnStartupCC === CloudConfigDataTypes.NOT_SET,
},
{
- checked: isAlwaysOnTop,
+ checked: isAlwaysOnTop === CloudConfigDataTypes.ENABLED,
click: async (item) => {
- isAlwaysOnTop = item.checked;
+ isAlwaysOnTop = item.checked ? CloudConfigDataTypes.ENABLED : CloudConfigDataTypes.NOT_SET;
await updateAlwaysOnTop(item.checked, true);
this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.ALWAYS_ON_TOP, item.checked);
},
label: i18n.t('Always on Top')(),
type: 'checkbox',
visible: !isLinux,
+ enabled: !isAlwaysOnTopCC || isAlwaysOnTopCC === CloudConfigDataTypes.NOT_SET,
},
{
- checked: minimizeOnClose,
+ checked: minimizeOnClose === CloudConfigDataTypes.ENABLED,
click: async (item) => {
- minimizeOnClose = item.checked;
+ minimizeOnClose = item.checked ? CloudConfigDataTypes.ENABLED : CloudConfigDataTypes.NOT_SET;
await config.updateUserConfig({ minimizeOnClose });
this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.MINIMIZE_ON_CLOSE, item.checked);
},
label: i18n.t('Minimize on Close')(),
type: 'checkbox',
+ enabled: !minimizeOnCloseCC || minimizeOnCloseCC === CloudConfigDataTypes.NOT_SET,
},
{
- checked: bringToFront,
+ checked: bringToFront === CloudConfigDataTypes.ENABLED,
click: async (item) => {
- bringToFront = item.checked;
+ bringToFront = item.checked ? CloudConfigDataTypes.ENABLED : CloudConfigDataTypes.NOT_SET;
await config.updateUserConfig({ bringToFront });
this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.FLASH_NOTIFICATION_IN_TASK_BAR, item.checked);
},
@@ -309,30 +339,30 @@ export class AppMenu {
? i18n.t('Flash Notification in Taskbar')()
: i18n.t('Bring to Front on Notifications')(),
type: 'checkbox',
+ enabled: !bringToFrontCC || bringToFrontCC === CloudConfigDataTypes.NOT_SET,
},
this.buildSeparator(),
{
- label: this.titleBarStyle === TitleBarStyles.NATIVE
+ label: (isCustomTitleBar === CloudConfigDataTypes.DISABLED || isCustomTitleBar === CloudConfigDataTypes.NOT_SET)
? i18n.t('Enable Hamburger menu')()
: i18n.t('Disable Hamburger menu')(),
visible: isWindowsOS,
click: () => {
- const isNativeStyle = this.titleBarStyle === TitleBarStyles.NATIVE;
-
- this.titleBarStyle = isNativeStyle ? TitleBarStyles.NATIVE : TitleBarStyles.CUSTOM;
- titleBarChangeDialog(isNativeStyle);
- this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.HAMBURGER_MENU, this.titleBarStyle === TitleBarStyles.CUSTOM);
+ titleBarChangeDialog(isCustomTitleBar === CloudConfigDataTypes.DISABLED ? CloudConfigDataTypes.ENABLED : CloudConfigDataTypes.DISABLED);
+ this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.HAMBURGER_MENU, isCustomTitleBar === CloudConfigDataTypes.ENABLED);
},
+ enabled: !isCustomTitleBarCC || isCustomTitleBarCC === CloudConfigDataTypes.NOT_SET,
},
{
- checked: memoryRefresh,
+ checked: memoryRefresh === CloudConfigDataTypes.ENABLED,
click: async (item) => {
- memoryRefresh = item.checked;
+ memoryRefresh = item.checked ? CloudConfigDataTypes.ENABLED : CloudConfigDataTypes.NOT_SET;
await config.updateUserConfig({ memoryRefresh });
this.sendAnalytics(AnalyticsElements.MENU, MenuActionTypes.REFRESH_APP_IN_IDLE, item.checked);
},
label: i18n.t('Refresh app when idle')(),
type: 'checkbox',
+ enabled: !memoryRefreshCC || memoryRefreshCC === CloudConfigDataTypes.NOT_SET,
},
{
click: (_item, focusedWindow) => {
@@ -387,6 +417,7 @@ export class AppMenu {
if (isLinux) {
showCrashesLabel = i18n.t('Show crash dump in File Manager')();
}
+ const { devToolsEnabled: isDevToolsEnabledCC } = this.cloudConfig as IConfig;
return {
label: i18n.t('Help')(),
@@ -409,7 +440,7 @@ export class AppMenu {
}, {
label: i18n.t('Toggle Developer Tools')(),
accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
- visible: devToolsEnabled,
+ visible: isDevToolsEnabledCC,
click(_item, focusedWindow) {
if (!focusedWindow || !windowExists(focusedWindow)) {
return;
diff --git a/src/app/auto-launch-controller.ts b/src/app/auto-launch-controller.ts
index 5b087fec..abc6870d 100644
--- a/src/app/auto-launch-controller.ts
+++ b/src/app/auto-launch-controller.ts
@@ -4,7 +4,7 @@ import { isMac } from '../common/env';
import { logger } from '../common/logger';
import { config, IConfig } from './config-handler';
-const { autoLaunchPath }: IConfig = config.getGlobalConfigFields([ 'autoLaunchPath' ]);
+const { autoLaunchPath }: IConfig = config.getConfigFields([ 'autoLaunchPath' ]);
const props = isMac ? {
mac: {
diff --git a/src/app/child-window-handler.ts b/src/app/child-window-handler.ts
index 93562f38..2221bb06 100644
--- a/src/app/child-window-handler.ts
+++ b/src/app/child-window-handler.ts
@@ -215,7 +215,7 @@ export const handleChildWindow = (webContents: WebContents): void => {
}
// Updates media permissions for preload context
- const { permissions } = config.getGlobalConfigFields([ 'permissions' ]);
+ const { permissions } = config.getConfigFields([ 'permissions' ]);
browserWin.webContents.send('is-screen-share-enabled', permissions.media);
}
});
diff --git a/src/app/chrome-flags.ts b/src/app/chrome-flags.ts
index 969f52f1..123680ac 100644
--- a/src/app/chrome-flags.ts
+++ b/src/app/chrome-flags.ts
@@ -15,7 +15,7 @@ const specialArgs = [ '--url', '--multiInstance', '--userDataPath=', 'symphony:/
*/
export const setChromeFlags = () => {
logger.info(`chrome-flags: Checking if we need to set chrome flags!`);
- const { customFlags } = config.getGlobalConfigFields([ 'customFlags' ]) as IConfig;
+ const { customFlags } = config.getConfigFields([ 'customFlags' ]) as IConfig;
const configFlags: object = {
'auth-negotiate-delegate-whitelist': customFlags.authServerWhitelist,
@@ -72,7 +72,7 @@ export const setChromeFlags = () => {
*/
export const setSessionProperties = () => {
logger.info(`chrome-flags: Settings session properties`);
- const { customFlags } = config.getGlobalConfigFields([ 'customFlags' ]) as IConfig;
+ const { customFlags } = config.getConfigFields([ 'customFlags' ]) as IConfig;
if (session.defaultSession && customFlags && customFlags.authServerWhitelist && customFlags.authServerWhitelist !== '') {
session.defaultSession.allowNTLMCredentialsForDomains(customFlags.authServerWhitelist);
diff --git a/src/app/config-handler.ts b/src/app/config-handler.ts
index b6b52148..887c0117 100644
--- a/src/app/config-handler.ts
+++ b/src/app/config-handler.ts
@@ -6,33 +6,81 @@ import * as util from 'util';
import { buildNumber } from '../../package.json';
import { isDevEnv, isElectronQA, isLinux, isMac } from '../common/env';
import { logger } from '../common/logger';
-import { pick } from '../common/utils';
+import { filterOutSelectedValues, pick } from '../common/utils';
+import { getDefaultUserConfig } from './config-utils';
const writeFile = util.promisify(fs.writeFile);
-export interface IConfig {
+export enum CloudConfigDataTypes {
+ NOT_SET = 'NOT_SET',
+ ENABLED = 'ENABLED',
+ DISABLED = 'DISABLED',
+}
+
+export interface IGlobalConfig {
url: string;
- minimizeOnClose: boolean;
- launchOnStartup: boolean;
- alwaysOnTop: boolean;
- bringToFront: boolean;
- whitelistUrl: string;
- isCustomTitleBar: boolean;
- memoryRefresh: boolean;
- devToolsEnabled: boolean;
contextIsolation: boolean;
+}
+
+export interface IConfig {
+ minimizeOnClose: CloudConfigDataTypes;
+ launchOnStartup: CloudConfigDataTypes;
+ alwaysOnTop: CloudConfigDataTypes;
+ bringToFront: CloudConfigDataTypes;
+ whitelistUrl: string;
+ isCustomTitleBar: CloudConfigDataTypes;
+ memoryRefresh: CloudConfigDataTypes;
+ memoryThreshold: string;
+ devToolsEnabled: boolean;
ctWhitelist: string[];
podWhitelist: string[];
- configVersion: string;
- buildNumber: string;
autoLaunchPath: string;
- notificationSettings: INotificationSetting;
permissions: IPermission;
customFlags: ICustomFlag;
+ buildNumber?: string;
+ configVersion?: string;
+ notificationSettings: INotificationSetting;
mainWinPos?: ICustomRectangle;
locale?: string;
}
+export interface ICloudConfig {
+ configVersion?: string;
+ podLevelEntitlements: IPodLevelEntitlements;
+ acpFeatureLevelEntitlements: IACPFeatureLevelEntitlements;
+ pmpEntitlements: IPMPEntitlements;
+}
+
+export interface IPodLevelEntitlements {
+ minimizeOnClose: CloudConfigDataTypes;
+ isCustomTitleBar: CloudConfigDataTypes;
+ alwaysOnTop: CloudConfigDataTypes;
+ memoryRefresh: CloudConfigDataTypes;
+ bringToFront: CloudConfigDataTypes;
+ disableThrottling: CloudConfigDataTypes;
+ launchOnStartup: CloudConfigDataTypes;
+ memoryThreshold: string;
+ ctWhitelist: string;
+ podWhitelist: string;
+ authNegotiateDelegateWhitelist: string;
+ whitelistUrl: string;
+ authServerWhitelist: string;
+ autoLaunchPath: string;
+}
+
+export interface IACPFeatureLevelEntitlements {
+ devToolsEnabled: boolean;
+ permissions: IPermission;
+}
+
+export interface IPMPEntitlements {
+ minimizeOnClose: CloudConfigDataTypes;
+ bringToFront: CloudConfigDataTypes;
+ memoryRefresh: CloudConfigDataTypes;
+ refreshAppThreshold: CloudConfigDataTypes;
+ disableThrottling: CloudConfigDataTypes;
+}
+
export interface IPermission {
media: boolean;
geolocation: boolean;
@@ -63,15 +111,19 @@ export interface ICustomRectangle extends Partial {
class Config {
private userConfig: IConfig | {};
private globalConfig: IConfig | {};
+ private cloudConfig: ICloudConfig | {};
+ private filteredCloudConfig: ICloudConfig | {};
private isFirstTime: boolean = true;
private readonly configFileName: string;
private readonly userConfigPath: string;
private readonly appPath: string;
private readonly globalConfigPath: string;
+ private readonly cloudConfigPath: string;
constructor() {
this.configFileName = 'Symphony.config';
this.userConfigPath = path.join(app.getPath('userData'), this.configFileName);
+ this.cloudConfigPath = path.join(app.getPath('userData'), 'cloudConfig.config');
this.appPath = isDevEnv ? app.getAppPath() : path.dirname(app.getPath('exe'));
this.globalConfigPath = isDevEnv
? path.join(this.appPath, path.join('config', this.configFileName))
@@ -83,8 +135,11 @@ class Config {
this.globalConfig = {};
this.userConfig = {};
+ this.cloudConfig = {};
+ this.filteredCloudConfig = {};
this.readUserConfig();
this.readGlobalConfig();
+ this.readCloudConfig();
this.checkFirstTimeLaunch();
}
@@ -96,8 +151,8 @@ class Config {
* @param fields
*/
public getConfigFields(fields: string[]): IConfig {
- logger.info(`config-handler: Trying to get config values for the fields`, fields);
- return { ...this.getGlobalConfigFields(fields), ...this.getUserConfigFields(fields) } as IConfig;
+ logger.info(`config-handler: Trying to get cloud config values for the fields`, fields);
+ return { ...this.getGlobalConfigFields(fields), ...this.getUserConfigFields(fields), ...this.getFilteredCloudConfigFields(fields) } as IConfig;
}
/**
@@ -115,9 +170,28 @@ class Config {
*
* @param fields {Array}
*/
- public getGlobalConfigFields(fields: string[]): IConfig {
+ public getGlobalConfigFields(fields: string[]): IGlobalConfig {
logger.info(`config-handler: Trying to get global config values for the fields`, fields);
- return pick(this.globalConfig, fields) as IConfig;
+ return pick(this.globalConfig, fields) as IGlobalConfig;
+ }
+
+ /**
+ * Returns filtered & prioritised fields from cloud config file
+ *
+ * @param fields {Array}
+ */
+ public getFilteredCloudConfigFields(fields: string[]): IConfig | {} {
+ return pick(this.filteredCloudConfig, fields) as IConfig;
+ }
+
+ /**
+ * Returns the actual cloud config with priority
+ * @param fields
+ */
+ public getCloudConfigFields(fields: string[]): IConfig {
+ const { acpFeatureLevelEntitlements, podLevelEntitlements, pmpEntitlements } = this.cloudConfig as ICloudConfig;
+ const cloudConfig = { ...acpFeatureLevelEntitlements, ...podLevelEntitlements, ...pmpEntitlements };
+ return pick(cloudConfig, fields) as IConfig;
}
/**
@@ -137,6 +211,25 @@ class Config {
}
}
+ /**
+ * updates new data to the cloud config
+ *
+ * @param data {IConfig}
+ */
+ public async updateCloudConfig(data: Partial): Promise {
+ logger.info(`config-handler: Updating the cloud config data from SFE: `, data);
+ this.cloudConfig = { ...this.cloudConfig, ...data };
+ // recalculate cloud config when we have data from SFE
+ this.filterCloudConfig();
+ logger.info(`config-handler: prioritized and filtered cloud config: `, this.filteredCloudConfig);
+ try {
+ await writeFile(this.cloudConfigPath, JSON.stringify(this.cloudConfig), { encoding: 'utf8' });
+ logger.info(`config-handler: writting cloud config values to file`);
+ } catch (error) {
+ logger.error(`config-handler: failed to update cloud config file with ${data}`, error);
+ }
+ }
+
/**
* Return true if the app is launched for the first time
* otherwise false
@@ -157,7 +250,6 @@ class Config {
minimizeOnClose,
launchOnStartup,
alwaysOnTop,
- url,
memoryRefresh,
bringToFront,
isCustomTitleBar,
@@ -169,6 +261,21 @@ class Config {
}
}
+ /**
+ * filters out the cloud config
+ */
+ private filterCloudConfig(): void {
+ const { acpFeatureLevelEntitlements, podLevelEntitlements, pmpEntitlements } = this.cloudConfig as ICloudConfig;
+
+ // Filter out some values
+ const filteredACP = filterOutSelectedValues(acpFeatureLevelEntitlements, [ true, 'NOT_SET' ]);
+ const filteredPod = filterOutSelectedValues(podLevelEntitlements, [ true, 'NOT_SET' ]);
+ const filteredPMP = filterOutSelectedValues(pmpEntitlements, [ true, 'NOT_SET' ]);
+
+ // priority is PMP > ACP > SDA
+ this.filteredCloudConfig = { ...filteredACP, ...filteredPod, ...filteredPMP };
+ }
+
/**
* Parses the config data string
*
@@ -201,7 +308,7 @@ class Config {
// Need to wait until app ready event to access user data
await app.whenReady();
logger.info(`config-handler: user config doesn't exist! will create new one and update config`);
- await this.updateUserConfig({ configVersion: app.getVersion().toString(), buildNumber } as IConfig);
+ await this.updateUserConfig({ configVersion: app.getVersion().toString(), buildNumber, ...getDefaultUserConfig() } as IConfig);
}
this.userConfig = this.parseConfigData(fs.readFileSync(this.userConfigPath, 'utf8'));
logger.info(`config-handler: User configuration: `, this.userConfig);
@@ -215,6 +322,23 @@ class Config {
logger.info(`config-handler: Global configuration: `, this.globalConfig);
}
+ /**
+ * Reads and stores the cloud config file
+ *
+ * If cloud config doesn't exits?
+ * this creates a new one with { }
+ */
+ private async readCloudConfig() {
+ if (!fs.existsSync(this.cloudConfigPath)) {
+ await app.whenReady();
+ await this.updateCloudConfig({ configVersion: app.getVersion().toString() });
+ }
+ this.cloudConfig = this.parseConfigData(fs.readFileSync(this.cloudConfigPath, 'utf8'));
+ // recalculate cloud config when we the application starts
+ this.filterCloudConfig();
+ logger.info(`config-handler: Cloud configuration: `, this.userConfig);
+ }
+
/**
* Verifies if the application is launched for the first time
*/
diff --git a/src/app/config-utils.ts b/src/app/config-utils.ts
new file mode 100644
index 00000000..ab63996f
--- /dev/null
+++ b/src/app/config-utils.ts
@@ -0,0 +1,40 @@
+/**
+ * Returns the default user config data
+ */
+import { CloudConfigDataTypes, IConfig } from './config-handler';
+
+export const getDefaultUserConfig = (): IConfig => {
+ return {
+ minimizeOnClose: CloudConfigDataTypes.ENABLED,
+ launchOnStartup: CloudConfigDataTypes.ENABLED,
+ alwaysOnTop: CloudConfigDataTypes.DISABLED,
+ bringToFront: CloudConfigDataTypes.DISABLED,
+ whitelistUrl: '*',
+ isCustomTitleBar: CloudConfigDataTypes.ENABLED,
+ memoryRefresh: CloudConfigDataTypes.ENABLED,
+ memoryThreshold: '800',
+ devToolsEnabled: true,
+ ctWhitelist: [],
+ podWhitelist: [],
+ notificationSettings: {
+ position: 'upper-right',
+ display: '',
+ },
+ customFlags: {
+ authServerWhitelist: '',
+ authNegotiateDelegateWhitelist: '',
+ disableGpu: false,
+ disableThrottling: false,
+ },
+ permissions: {
+ media: true,
+ geolocation: true,
+ notifications: true,
+ midiSysex: true,
+ pointerLock: true,
+ fullscreen: true,
+ openExternal: true,
+ },
+ autoLaunchPath: '',
+ };
+};
diff --git a/src/app/dialog-handler.ts b/src/app/dialog-handler.ts
index dfc00db2..c6bf16b3 100644
--- a/src/app/dialog-handler.ts
+++ b/src/app/dialog-handler.ts
@@ -3,7 +3,7 @@ import { app } from 'electron';
import { i18n } from '../common/i18n';
import { logger } from '../common/logger';
-import { config } from './config-handler';
+import { CloudConfigDataTypes, config } from './config-handler';
import { ICustomBrowserWindow, windowHandler } from './window-handler';
import { windowExists } from './window-utils';
@@ -146,7 +146,7 @@ export const showNetworkConnectivityError = (browserWindow: Electron.BrowserWind
*
* @param isNativeStyle {boolean}
*/
-export const titleBarChangeDialog = async (isNativeStyle: boolean) => {
+export const titleBarChangeDialog = async (isNativeStyle: CloudConfigDataTypes) => {
const focusedWindow = electron.BrowserWindow.getFocusedWindow();
if (!focusedWindow || !windowExists(focusedWindow)) {
return;
@@ -161,7 +161,8 @@ export const titleBarChangeDialog = async (isNativeStyle: boolean) => {
};
const { response } = await electron.dialog.showMessageBox(focusedWindow, options);
if (response === 0) {
- await config.updateUserConfig({ isCustomTitleBar: isNativeStyle });
+ logger.error(`test`, isNativeStyle);
+ 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 58ec1818..2e841628 100644
--- a/src/app/main-api-handler.ts
+++ b/src/app/main-api-handler.ts
@@ -5,7 +5,7 @@ import { LocaleType } from '../common/i18n';
import { logger } from '../common/logger';
import { activityDetection } from './activity-detection';
import { analytics } from './analytics-handler';
-import { config } from './config-handler';
+import { CloudConfigDataTypes, config, ICloudConfig } from './config-handler';
import { memoryMonitor } from './memory-monitor';
import { protocolHandler } from './protocol-handler';
import { finalizeLogExports, registerLogRetriever } from './reports-handler';
@@ -19,6 +19,7 @@ import {
setDataUrl,
showBadgeCount,
showPopupMenu,
+ updateFeaturesForCloudConfig,
updateLocale,
windowExists,
} from './window-utils';
@@ -27,7 +28,7 @@ import {
* Handle API related ipc messages from renderers. Only messages from windows
* we have created are allowed.
*/
-ipcMain.on(apiName.symphonyApi, (event: Electron.IpcMainEvent, arg: IApiArgs) => {
+ipcMain.on(apiName.symphonyApi, async (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;
@@ -99,7 +100,7 @@ ipcMain.on(apiName.symphonyApi, (event: Electron.IpcMainEvent, arg: IApiArgs) =>
// validates the user bring to front config and activates the wrapper
if (typeof arg.reason === 'string' && arg.reason === 'notification') {
const { bringToFront } = config.getConfigFields([ 'bringToFront' ]);
- if (bringToFront) {
+ if (bringToFront === CloudConfigDataTypes.ENABLED) {
activate(arg.windowName, false);
}
}
@@ -168,6 +169,14 @@ ipcMain.on(apiName.symphonyApi, (event: Electron.IpcMainEvent, arg: IApiArgs) =>
case apiCmds.registerAnalyticsHandler:
analytics.registerPreloadWindow(event.sender);
break;
+ case apiCmds.setCloudConfig:
+ const { podLevelEntitlements, acpFeatureLevelEntitlements, pmpEntitlements, ...rest } = arg.cloudConfig as ICloudConfig;
+ logger.info('main-api-handler: ignored other values from SFE', rest);
+ await config.updateCloudConfig({ podLevelEntitlements, acpFeatureLevelEntitlements, pmpEntitlements });
+ await updateFeaturesForCloudConfig();
+ if (windowHandler.appMenu) {
+ windowHandler.appMenu.buildMenu();
+ }
default:
}
diff --git a/src/app/memory-monitor.ts b/src/app/memory-monitor.ts
index f6c72a82..b579abf0 100644
--- a/src/app/memory-monitor.ts
+++ b/src/app/memory-monitor.ts
@@ -2,7 +2,7 @@ import * as electron from 'electron';
import { isMac } from '../common/env';
import { logger } from '../common/logger';
-import { config } from './config-handler';
+import { CloudConfigDataTypes, config } from './config-handler';
import { windowHandler } from './window-handler';
import { windowExists } from './window-utils';
@@ -11,9 +11,9 @@ class MemoryMonitor {
private isInMeeting: boolean;
private canReload: boolean;
private lastReloadTime?: number;
+ private memoryThreshold: number;
private readonly maxIdleTime: number;
- private readonly memoryThreshold: number;
private readonly memoryRefreshThreshold: number;
constructor() {
@@ -46,13 +46,22 @@ class MemoryMonitor {
logger.info(`memory-monitor: setting meeting status to ${isInMeeting}`);
}
+ /**
+ * Sets the memory threshold
+ *
+ * @param memoryThreshold
+ */
+ public setMemoryThreshold(memoryThreshold: number): void {
+ this.memoryThreshold = memoryThreshold * 1024;
+ }
+
/**
* Validates the predefined conditions and refreshes the client
*/
private validateMemory(): void {
logger.info(`memory-monitor: validating memory refresh conditions`);
const { memoryRefresh } = config.getConfigFields([ 'memoryRefresh' ]);
- if (!memoryRefresh) {
+ if (memoryRefresh !== CloudConfigDataTypes.ENABLED) {
logger.info(`memory-monitor: memory reload is disabled in the config, not going to refresh!`);
return;
}
diff --git a/src/app/perf-handler.ts b/src/app/perf-handler.ts
index 8c02fbfc..784ff7a6 100644
--- a/src/app/perf-handler.ts
+++ b/src/app/perf-handler.ts
@@ -3,9 +3,9 @@ import { logger } from '../common/logger';
import { config, IConfig } from './config-handler';
export const handlePerformanceSettings = () => {
- const { customFlags } = config.getGlobalConfigFields([ 'customFlags' ]) as IConfig;
+ const { customFlags } = config.getCloudConfigFields([ 'customFlags' ]) as IConfig;
- if (customFlags.disableThrottling) {
+ if (customFlags && customFlags.disableThrottling) {
logger.info(`perf-handler: Disabling power throttling!`);
powerSaveBlocker.start('prevent-display-sleep');
return;
diff --git a/src/app/screen-snippet-handler.ts b/src/app/screen-snippet-handler.ts
index 68aa96e6..af18728e 100644
--- a/src/app/screen-snippet-handler.ts
+++ b/src/app/screen-snippet-handler.ts
@@ -47,7 +47,7 @@ class ScreenSnippet {
if (mainWindow && windowExists(mainWindow) && isWindowsOS) {
this.shouldUpdateAlwaysOnTop = mainWindow.isAlwaysOnTop();
if (this.shouldUpdateAlwaysOnTop) {
- await updateAlwaysOnTop(false, false);
+ await updateAlwaysOnTop(false, false, false);
}
}
logger.info(`screen-snippet-handler: Starting screen capture!`);
@@ -179,7 +179,7 @@ class ScreenSnippet {
*/
private async verifyAndUpdateAlwaysOnTop(): Promise {
if (this.shouldUpdateAlwaysOnTop) {
- await updateAlwaysOnTop(true, false);
+ await updateAlwaysOnTop(true, false, false);
this.shouldUpdateAlwaysOnTop = false;
}
}
diff --git a/src/app/version-handler.ts b/src/app/version-handler.ts
index 98366c70..e3466bf4 100644
--- a/src/app/version-handler.ts
+++ b/src/app/version-handler.ts
@@ -2,7 +2,7 @@ import { net } from 'electron';
import * as nodeURL from 'url';
import { buildNumber, clientVersion, optionalDependencies, searchAPIVersion, sfeVersion, version } from '../../package.json';
import { logger } from '../common/logger';
-import { config, IConfig } from './config-handler';
+import { config, IGlobalConfig } from './config-handler';
interface IVersionInfo {
clientVersion: string;
@@ -69,7 +69,7 @@ class VersionHandler {
this.mainUrl = mainUrl;
}
- const { url: podUrl }: IConfig = config.getGlobalConfigFields(['url']);
+ const { url: podUrl }: IGlobalConfig = config.getGlobalConfigFields(['url']);
if (!this.mainUrl || !nodeURL.parse(this.mainUrl)) {
this.mainUrl = podUrl;
diff --git a/src/app/window-actions.ts b/src/app/window-actions.ts
index 5e9b7abf..6a0c906f 100644
--- a/src/app/window-actions.ts
+++ b/src/app/window-actions.ts
@@ -6,7 +6,7 @@ import { i18n } from '../common/i18n';
import { logger } from '../common/logger';
import { throttle } from '../common/utils';
import { notification } from '../renderer/notification';
-import { config } from './config-handler';
+import { CloudConfigDataTypes, config } from './config-handler';
import { ICustomBrowserWindow, windowHandler } from './window-handler';
import { showPopupMenu, windowExists } from './window-utils';
@@ -146,14 +146,18 @@ export const activate = (windowName: string, shouldFocus: boolean = true): void
*
* @param shouldSetAlwaysOnTop {boolean} - Whether to enable always on top or not
* @param shouldActivateMainWindow {boolean} - Whether to active main window
+ * @param shouldUpdateUserConfig {boolean} - whether to update config file
*/
export const updateAlwaysOnTop = async (
shouldSetAlwaysOnTop: boolean,
shouldActivateMainWindow: boolean = true,
+ shouldUpdateUserConfig: boolean = true,
): Promise => {
logger.info(`window-actions: Should we set always on top? ${shouldSetAlwaysOnTop}!`);
const browserWins: ICustomBrowserWindow[] = BrowserWindow.getAllWindows() as ICustomBrowserWindow[];
- await config.updateUserConfig({ alwaysOnTop: shouldSetAlwaysOnTop });
+ if (shouldUpdateUserConfig) {
+ await config.updateUserConfig({ alwaysOnTop: shouldSetAlwaysOnTop ? CloudConfigDataTypes.ENABLED : CloudConfigDataTypes.NOT_SET });
+ }
if (browserWins.length > 0) {
browserWins
.filter((browser) => typeof browser.notificationData !== 'object')
@@ -310,7 +314,7 @@ export const handlePermissionRequests = (webContents: Electron.webContents): voi
}
const { session } = webContents;
- const { permissions } = config.getGlobalConfigFields([ 'permissions' ]);
+ const { permissions } = config.getConfigFields([ 'permissions' ]);
if (!permissions) {
logger.error('permissions configuration is invalid, so, everything will be true by default!');
return;
diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts
index 32feebe9..8fed101a 100644
--- a/src/app/window-handler.ts
+++ b/src/app/window-handler.ts
@@ -1,10 +1,10 @@
+import { ChildProcess, ExecException, execFile } from 'child_process';
import * as electron from 'electron';
-import { app, BrowserWindow, BrowserWindowConstructorOptions, crashReporter, globalShortcut, ipcMain } from 'electron';
+import { app, BrowserWindow, BrowserWindowConstructorOptions, crashReporter, DesktopCapturerSource, globalShortcut, ipcMain } from 'electron';
import * as fs from 'fs';
import * as path from 'path';
import { format, parse } from 'url';
-import { ChildProcess, ExecException, execFile } from 'child_process';
import { apiName, WindowTypes } from '../common/api-interface';
import { isDevEnv, isMac, isWindowsOS } from '../common/env';
import { i18n, LocaleType } from '../common/i18n';
@@ -13,10 +13,9 @@ import { getCommandLineArgs, getGuid } from '../common/utils';
import { notification } from '../renderer/notification';
import { AppMenu } from './app-menu';
import { handleChildWindow } from './child-window-handler';
-import { config, IConfig } from './config-handler';
+import { CloudConfigDataTypes, config, IConfig, IGlobalConfig } from './config-handler';
import { SpellChecker } from './spell-check-handler';
import { checkIfBuildExpired } from './ttl-handler';
-import DesktopCapturerSource = Electron.DesktopCapturerSource;
import { versionHandler } from './version-handler';
import { handlePermissionRequests, monitorWindowActions } from './window-actions';
import {
@@ -47,8 +46,6 @@ export interface ICustomBrowserWindow extends Electron.BrowserWindow {
const DEFAULT_WIDTH: number = 900;
const DEFAULT_HEIGHT: number = 900;
-const {devToolsEnabled} = config.getGlobalConfigFields(['devToolsEnabled']);
-
export class WindowHandler {
/**
@@ -79,7 +76,7 @@ export class WindowHandler {
private readonly contextIsolation: boolean;
private readonly backgroundThrottling: boolean;
private readonly windowOpts: ICustomBrowserWindowConstructorOpts;
- private readonly globalConfig: IConfig;
+ private readonly globalConfig: IGlobalConfig;
private readonly config: IConfig;
// Window reference
private readonly windows: object;
@@ -96,18 +93,20 @@ export class WindowHandler {
constructor(opts?: Electron.BrowserViewConstructorOptions) {
// Use these variables only on initial setup
- this.config = config.getConfigFields([ 'isCustomTitleBar', 'mainWinPos', 'minimizeOnClose', 'notificationSettings', 'alwaysOnTop', 'locale' ]);
- this.globalConfig = config.getGlobalConfigFields(['url', 'contextIsolation', 'customFlags']);
- const {url, contextIsolation, customFlags}: IConfig = this.globalConfig;
+ this.config = config.getConfigFields([ 'isCustomTitleBar', 'mainWinPos', 'minimizeOnClose', 'notificationSettings', 'alwaysOnTop', 'locale', 'customFlags' ]);
+ logger.info(`window-handler: main windows initialized with following config data`, this.config);
+ this.globalConfig = config.getGlobalConfigFields([ 'url', 'contextIsolation' ]);
+ const { url, contextIsolation }: IGlobalConfig = this.globalConfig;
+ const { customFlags } = this.config;
this.windows = {};
this.contextIsolation = contextIsolation || false;
this.backgroundThrottling = !customFlags.disableThrottling;
this.contextIsolation = contextIsolation || false;
- this.isCustomTitleBar = isWindowsOS && this.config.isCustomTitleBar;
+ this.isCustomTitleBar = isWindowsOS && this.config.isCustomTitleBar === CloudConfigDataTypes.ENABLED;
this.windowOpts = {
...this.getWindowOpts({
- alwaysOnTop: this.config.alwaysOnTop || false,
+ alwaysOnTop: this.config.alwaysOnTop === CloudConfigDataTypes.ENABLED || false,
frame: !this.isCustomTitleBar,
minHeight: 300,
minWidth: 300,
@@ -185,7 +184,7 @@ export class WindowHandler {
// Event needed to hide native menu bar on Windows 10 as we use custom menu bar
this.mainWindow.webContents.once('did-start-loading', () => {
logger.info(`window-handler: main window web contents started loading!`);
- if ((this.config.isCustomTitleBar && isWindowsOS) && this.mainWindow && windowExists(this.mainWindow)) {
+ if ((this.config.isCustomTitleBar === CloudConfigDataTypes.ENABLED && isWindowsOS) && this.mainWindow && windowExists(this.mainWindow)) {
this.mainWindow.setMenuBarVisibility(false);
}
// monitors network connection and
@@ -202,7 +201,7 @@ export class WindowHandler {
if (urlFromCmd) {
const commandLineUrl = urlFromCmd.substr(6);
logger.info(`window-handler: trying to set url ${commandLineUrl} from command line.`);
- const { podWhitelist } = config.getGlobalConfigFields([ 'podWhitelist' ]);
+ const { podWhitelist } = config.getConfigFields([ 'podWhitelist' ]);
logger.info(`window-handler: checking pod whitelist.`);
if (podWhitelist.length > 0) {
logger.info(`window-handler: pod whitelist is not empty ${podWhitelist}`);
@@ -245,7 +244,7 @@ export class WindowHandler {
isMainWindow: true,
});
this.appMenu = new AppMenu();
- const { permissions } = config.getGlobalConfigFields(['permissions']);
+ const { permissions } = config.getConfigFields([ 'permissions' ]);
this.mainWindow.webContents.send('is-screen-share-enabled', permissions.media);
});
@@ -304,8 +303,8 @@ export class WindowHandler {
return this.destroyAllWindows();
}
- const {minimizeOnClose} = config.getConfigFields(['minimizeOnClose']);
- if (minimizeOnClose) {
+ const { minimizeOnClose } = config.getConfigFields([ 'minimizeOnClose' ]);
+ if (minimizeOnClose === CloudConfigDataTypes.ENABLED) {
event.preventDefault();
this.mainWindow.minimize();
return;
@@ -716,7 +715,7 @@ export class WindowHandler {
if (app.isReady()) {
screens = electron.screen.getAllDisplays();
}
- const {position, display} = config.getConfigFields(['notificationSettings']).notificationSettings;
+ const { position, display } = config.getConfigFields([ 'notificationSettings' ]).notificationSettings;
this.notificationSettingsWindow.webContents.send('notification-settings-data', {screens, position, display});
}
});
@@ -964,6 +963,7 @@ export class WindowHandler {
if (!focusedWindow || !windowExists(focusedWindow)) {
return;
}
+ const { devToolsEnabled } = config.getConfigFields([ 'devToolsEnabled' ]);
if (devToolsEnabled) {
focusedWindow.webContents.toggleDevTools();
return;
diff --git a/src/app/window-utils.ts b/src/app/window-utils.ts
index 112bf167..a1d482f7 100644
--- a/src/app/window-utils.ts
+++ b/src/app/window-utils.ts
@@ -12,8 +12,11 @@ import { i18n, LocaleType } from '../common/i18n';
import { logger } from '../common/logger';
import { getGuid } from '../common/utils';
import { whitelistHandler } from '../common/whitelist-handler';
-import { config, ICustomRectangle } from './config-handler';
+import { autoLaunchInstance } from './auto-launch-controller';
+import { CloudConfigDataTypes, config, IConfig, ICustomRectangle } from './config-handler';
+import { memoryMonitor } from './memory-monitor';
import { screenSnippet } from './screen-snippet-handler';
+import { updateAlwaysOnTop } from './window-actions';
import { ICustomBrowserWindow, windowHandler } from './window-handler';
interface IStyles {
@@ -28,7 +31,8 @@ enum styleNames {
}
const checkValidWindow = true;
-const { url: configUrl, ctWhitelist } = config.getGlobalConfigFields([ 'url', 'ctWhitelist' ]);
+const { url: configUrl } = config.getGlobalConfigFields([ 'url' ]);
+const { ctWhitelist } = config.getConfigFields([ 'ctWhitelist' ]);
// Network status check variables
const networkStatusCheckInterval = 10 * 1000;
@@ -581,6 +585,36 @@ export const getWindowByName = (windowName: string): BrowserWindow | undefined =
});
};
+export const updateFeaturesForCloudConfig = async (): Promise => {
+ const {
+ alwaysOnTop: isAlwaysOnTop,
+ launchOnStartup,
+ memoryRefresh,
+ memoryThreshold,
+ } = config.getConfigFields([
+ 'launchOnStartup',
+ 'alwaysOnTop',
+ 'memoryRefresh',
+ 'memoryThreshold',
+ ]) as IConfig;
+
+ const mainWindow = windowHandler.getMainWindow();
+
+ // Update Always on top feature
+ await updateAlwaysOnTop(isAlwaysOnTop === CloudConfigDataTypes.ENABLED, false, false);
+
+ // Update launch on start up
+ launchOnStartup === CloudConfigDataTypes.ENABLED ? autoLaunchInstance.enableAutoLaunch() : autoLaunchInstance.disableAutoLaunch();
+
+ if (mainWindow && windowExists(mainWindow)) {
+ if (memoryRefresh) {
+ logger.info(`window-utils: updating the memory threshold`, memoryThreshold);
+ memoryMonitor.setMemoryThreshold(parseInt(memoryThreshold, 10));
+ mainWindow.webContents.send('initialize-memory-refresh');
+ }
+ }
+};
+
/**
* Monitors network requests and displays red banner on failure
*/
diff --git a/src/common/api-interface.ts b/src/common/api-interface.ts
index 1f7669c8..ebd4d68d 100644
--- a/src/common/api-interface.ts
+++ b/src/common/api-interface.ts
@@ -35,6 +35,7 @@ export enum apiCmds {
swiftSearch = 'swift-search',
getConfigUrl = 'get-config-url',
registerRestartFloater = 'register-restart-floater',
+ setCloudConfig = 'set-cloud-config',
}
export enum apiName {
@@ -67,6 +68,7 @@ export interface IApiArgs {
type: string;
logName: string;
logs: ILogs;
+ cloudConfig: object;
}
export type WindowTypes = 'screen-picker' | 'screen-sharing-indicator' | 'notification-settings';
diff --git a/src/common/utils.ts b/src/common/utils.ts
index 105a373d..c11334c2 100644
--- a/src/common/utils.ts
+++ b/src/common/utils.ts
@@ -153,6 +153,25 @@ export const pick = (object: object, fields: string[]) => {
return obj;
};
+/**
+ * Filters out truthy values
+ *
+ * @param data {Object} { test: true, test1: false, test2: 'NOT_SET' }
+ * @param values {Array} [ true, "NOT_SET" ]
+ * @return {Object} { test1: false }
+ */
+export const filterOutSelectedValues = (data: object, values): object => {
+ if (!data) {
+ return {};
+ }
+ return Object.keys(data).reduce((obj, key) => {
+ if (values.indexOf(data[key]) <= -1) {
+ obj[key] = data[key];
+ }
+ return obj;
+ }, {});
+};
+
/**
* Limits your function to be called at most every milliseconds
*
diff --git a/src/common/whitelist-handler.ts b/src/common/whitelist-handler.ts
index fbd1dbc1..2087b66d 100644
--- a/src/common/whitelist-handler.ts
+++ b/src/common/whitelist-handler.ts
@@ -18,7 +18,7 @@ export class WhitelistHandler {
* @returns {boolean}
*/
public isWhitelisted(url: string): boolean {
- const { whitelistUrl } = config.getGlobalConfigFields([ 'whitelistUrl' ]);
+ const { whitelistUrl } = config.getConfigFields([ 'whitelistUrl' ]);
return this.checkWhitelist(url, whitelistUrl);
}
diff --git a/src/renderer/app-bridge.ts b/src/renderer/app-bridge.ts
index f0badfe9..6b7c3342 100644
--- a/src/renderer/app-bridge.ts
+++ b/src/renderer/app-bridge.ts
@@ -166,6 +166,9 @@ export class AppBridge {
case apiCmds.registerRestartFloater:
ssf.registerRestartFloater(this.callbackHandlers.restartFloater);
break;
+ case apiCmds.setCloudConfig:
+ ssf.setCloudConfig(data as object);
+ break;
case apiCmds.swiftSearch:
if (ssInstance) {
ssInstance.handleMessageEvents(data);
diff --git a/src/renderer/preload-main.ts b/src/renderer/preload-main.ts
index b0187322..7c443871 100644
--- a/src/renderer/preload-main.ts
+++ b/src/renderer/preload-main.ts
@@ -77,7 +77,7 @@ const monitorMemory = (time) => {
};
// When the window is completely loaded
-ipcRenderer.on('page-load', (_event, { locale, resources, enableCustomTitleBar, isMainWindow }) => {
+ipcRenderer.on('page-load', (_event, { locale, resources, enableCustomTitleBar }) => {
i18n.setResource(locale, resources);
@@ -113,10 +113,6 @@ ipcRenderer.on('page-load', (_event, { locale, resources, enableCustomTitleBar,
// initialize red banner
banner.initBanner();
banner.showBanner(false, 'error');
-
- if (isMainWindow) {
- monitorMemory(getRandomTime(minMemoryFetchInterval, maxMemoryFetchInterval));
- }
});
// When the window fails to load
@@ -140,3 +136,7 @@ ipcRenderer.on('show-banner', (_event, { show, bannerType, url }) => {
}
banner.showBanner(show, bannerType, url);
});
+
+ipcRenderer.on('initialize-memory-refresh', () => {
+ monitorMemory(getRandomTime(minMemoryFetchInterval, maxMemoryFetchInterval));
+});
diff --git a/src/renderer/ssf-api.ts b/src/renderer/ssf-api.ts
index 6b82c436..ad38cb1d 100644
--- a/src/renderer/ssf-api.ts
+++ b/src/renderer/ssf-api.ts
@@ -93,6 +93,13 @@ const throttledSetIsInMeetingStatus = throttle((isInMeeting) => {
});
}, 1000);
+const throttledSetCloudConfig = throttle((data) => {
+ ipcRenderer.send(apiName.symphonyApi, {
+ cmd: apiCmds.setCloudConfig,
+ cloudConfig: data,
+ });
+}, 1000);
+
let cryptoLib: ICryptoLib | null;
try {
cryptoLib = remote.require('../app/crypto-handler.js').cryptoLibrary;
@@ -470,6 +477,15 @@ export class SSFApi {
local.restartFloater = callback;
}
+ /**
+ * Allows JS to set the PMP & ACP cloud config
+ *
+ * @param data {ICloudConfig}
+ */
+ public setCloudConfig(data: {}): void {
+ throttledSetCloudConfig(data);
+ }
+
}
/**
From 3b94161e59888cb90ca9cf85911866c6d343695d Mon Sep 17 00:00:00 2001
From: Kiran Niranjan
Date: Tue, 3 Mar 2020 11:53:32 +0530
Subject: [PATCH 5/7] feat: SDA-1814 (Redesign about Symphony window) (#880)
* SDA-1814 - Redesign about symphony window
* SDA-1814 - text align right
* SDA-1748 - Update design changes
* SDA-1748 - Update window height
---
spec/__snapshots__/aboutApp.spec.ts.snap | 104 +----------------------
src/app/window-handler.ts | 4 +-
src/renderer/components/about-app.tsx | 30 +------
src/renderer/styles/about-app.less | 34 ++------
4 files changed, 11 insertions(+), 161 deletions(-)
diff --git a/spec/__snapshots__/aboutApp.spec.ts.snap b/spec/__snapshots__/aboutApp.spec.ts.snap
index 5e3ad69e..010ce1c7 100644
--- a/spec/__snapshots__/aboutApp.spec.ts.snap
+++ b/spec/__snapshots__/aboutApp.spec.ts.snap
@@ -32,14 +32,10 @@ exports[`about app should render correctly 1`] = `
-
-
- Symphony
-
@@ -50,13 +46,6 @@ exports[`about app should render correctly 1`] = `
N/A (N/A)
- -
-
- SFE:
-
-
- N/A
-
-
SDA:
@@ -64,99 +53,9 @@ exports[`about app should render correctly 1`] = `
N/A (N/A)
-
-
-
-
- Electron
-
-
-
- Electron:
-
-
- N/A
-
- -
-
- Chrome:
-
-
- N/A
-
- -
-
- V8:
-
-
- N/A
-
- -
-
- Node:
-
-
- N/A
-
-
-
-
-
- Others
-
-
- -
-
- openssl:
-
-
- N/A
-
- -
-
- zlib:
-
-
- N/A
-
- -
-
- uv:
-
-
- N/A
-
- -
-
- ares:
-
-
- N/A
-
- -
-
- http_parser:
-
-
- N/A
-
- -
-
- Swift Search
- :
-
-
- N/A
-
- -
-
- Swift Search API
- :
+ SFE:
N/A
@@ -164,7 +63,6 @@ exports[`about app should render correctly 1`] = `
-
-
- Symphony
- SBE: {podVersion}
- - SFE: {sfeVersion}
- SDA: {sdaVersionBuild}
-
-
-
- Electron
-
- - Electron: {electronVersion}
- - Chrome: {chromeVersion}
- - V8: {v8Version}
- - Node: {nodeVersion}
-
-
-
- {i18n.t('Others', ABOUT_SYMPHONY_NAMESPACE)()}
-
- - openssl: {openSslVersion}
- - zlib: {zlibVersion}
- - uv: {uvVersion}
- - ares: {aresVersion}
- - http_parser: {httpParserVersion}
- - {i18n.t('Swift Search', ABOUT_SYMPHONY_NAMESPACE)()}: {swiftSearchVersion}
- - {i18n.t('Swift Search API', ABOUT_SYMPHONY_NAMESPACE)()}: {swiftSearchSupportedVersion}
+ - SFE: {sfeVersion}
-