diff --git a/spec/childWindowHandle.spec.ts b/spec/childWindowHandle.spec.ts index d1464cb9..04e49866 100644 --- a/spec/childWindowHandle.spec.ts +++ b/spec/childWindowHandle.spec.ts @@ -72,6 +72,10 @@ jest.mock('../src/common/logger', () => { }; }); +jest.mock('../src/app/auto-update-handler', () => { + return {}; +}); + describe('child window handle', () => { it('should set open window handler', () => { const spy = jest.spyOn(webContents, 'setWindowOpenHandler'); diff --git a/spec/config.spec.ts b/spec/config.spec.ts index b045a4be..1214aba4 100644 --- a/spec/config.spec.ts +++ b/spec/config.spec.ts @@ -4,6 +4,9 @@ import * as path from 'path'; import { IConfig, IGlobalConfig } from '../src/app/config-handler'; jest.mock('electron-log'); +jest.mock('../src/app/auto-update-handler', () => { + return {}; +}); describe('config', () => { const configFileName: string = 'Symphony.config'; @@ -75,9 +78,8 @@ describe('config', () => { configInstance.readUserConfig(); configInstance.readGlobalConfig(); - const configField: IGlobalConfig = configInstance.getGlobalConfigFields( - fieldMock, - ); + const configField: IGlobalConfig = + configInstance.getGlobalConfigFields(fieldMock); expect(configField.url).toBe('something'); }); diff --git a/src/app/analytics-handler.ts b/src/app/analytics-handler.ts index 326faf79..6038c748 100644 --- a/src/app/analytics-handler.ts +++ b/src/app/analytics-handler.ts @@ -6,7 +6,8 @@ export interface IAnalyticsData { | MenuActionTypes | ScreenSnippetActionTypes | ToastNotificationActionTypes - | SDAUserSessionActionTypes; + | SDAUserSessionActionTypes + | InstallActionTypes; action_result?: AnalyticsActions; extra_data?: object; } @@ -43,6 +44,13 @@ export interface ISessionData extends IAnalyticsData { }; } +export interface IInstallData extends IAnalyticsData { + extra_data?: { + installLocation: string; + installType: string; + }; +} + export enum MenuActionTypes { AUTO_LAUNCH_ON_START_UP = 'auto_launch_on_start_up', ALWAYS_ON_TOP = 'always_on_top', @@ -77,6 +85,24 @@ export enum SDAUserSessionActionTypes { ForceReload = 'Force_reload', } +export enum InstallActionTypes { + InstallStarted = 'Install_started', + InstallCompleted = 'Install_completed', + InstallFailed = 'Install_failed', +} + +export enum InstallTypes { + Auto = 'auto', + Manual = 'manual', +} + +export enum InstallLocationTypes { + PROG_FILES = 'PROG_FILES', + REMOTE = 'REMOTE', + LOCAL = 'LOCAL', + CUSTOM = 'CUSTOM', +} + export enum SDAEndReasonTypes { Reboot = 'Reboot', Closed = 'Closed', @@ -94,6 +120,7 @@ export enum AnalyticsElements { TOAST_NOTIFICATION = 'toast_notification', SDA_CRASH = 'sda_crash', SDA_SESSION = 'sda_session', + SDA_INSTALL = 'sda_install', } export enum SDACrashProcess { diff --git a/src/app/auto-update-handler.ts b/src/app/auto-update-handler.ts index 4c552189..89ea5496 100644 --- a/src/app/auto-update-handler.ts +++ b/src/app/auto-update-handler.ts @@ -2,10 +2,19 @@ import { GenericServerOptions } from 'builder-util-runtime'; import electronLog from 'electron-log'; import { MacUpdater, NsisUpdater } from 'electron-updater'; +import { app } from 'electron'; import { isMac, isWindowsOS } from '../common/env'; import { logger } from '../common/logger'; import { isUrl } from '../common/utils'; import { whitelistHandler } from '../common/whitelist-handler'; +import { + analytics, + AnalyticsElements, + IInstallData, + InstallActionTypes, + InstallLocationTypes, + InstallTypes, +} from './analytics-handler'; import { config } from './config-handler'; import { retrieveWindowsRegistry } from './registry-handler'; import { EChannelRegistry, RegistryStore } from './stores/registry-store'; @@ -97,6 +106,7 @@ export class AutoUpdate { if (!this.isUpdateAvailable) { return; } + this.sendAnalytics(InstallActionTypes.InstallStarted, InstallTypes.Auto); // Handle update and restart for macOS if (isMac) { windowHandler.setIsAutoUpdating(true); @@ -169,6 +179,24 @@ export class AutoUpdate { return updateUrl; }; + /** + * Sends install analytics + */ + public sendAnalytics = ( + action: InstallActionTypes, + installType: InstallTypes, + ) => { + const installLocation = this.getInstallLocation(); + const event: IInstallData = { + element: AnalyticsElements.SDA_INSTALL, + action_type: action, + extra_data: { + installLocation, + installType, + }, + }; + analytics.track(event); + }; private updateEventHandler = async (info, eventType: string) => { const mainWebContents = windowHandler.mainWebContents; if (mainWebContents && !mainWebContents.isDestroyed()) { @@ -253,6 +281,30 @@ export class AutoUpdate { } } }; + + /** + * Identifies and returns the installation location + */ + private getInstallLocation = () => { + const appPath = app.getPath('exe'); + if (isWindowsOS) { + if (appPath.includes('AppData\\Local\\Programs')) { + return InstallLocationTypes.LOCAL; + } + if (appPath.includes('Program Files')) { + return InstallLocationTypes.PROG_FILES; + } + return InstallLocationTypes.CUSTOM; + } + if (isMac) { + if (appPath.includes('/Applications')) { + return InstallLocationTypes.PROG_FILES; + } + return InstallLocationTypes.LOCAL; + } + + return InstallLocationTypes.PROG_FILES; + }; } const autoUpdate = new AutoUpdate(); diff --git a/src/app/config-handler.ts b/src/app/config-handler.ts index 1f8b6a60..5248b48b 100644 --- a/src/app/config-handler.ts +++ b/src/app/config-handler.ts @@ -8,9 +8,12 @@ import { isDevEnv, isElectronQA, isLinux, isMac } from '../common/env'; import { logger } from '../common/logger'; import { arrayEquals, filterOutSelectedValues, pick } from '../common/utils'; import { + InstallActionTypes, + InstallTypes, SDAEndReasonTypes, SDAUserSessionActionTypes, } from './analytics-handler'; +import { autoUpdate } from './auto-update-handler'; import { appStats } from './stats'; const writeFile = util.promisify(fs.writeFile); @@ -635,6 +638,10 @@ class Config { ); this.isFirstTime = true; this.bootCount = 0; + autoUpdate.sendAnalytics( + InstallActionTypes.InstallCompleted, + InstallTypes.Manual, + ); return; } @@ -646,6 +653,10 @@ class Config { await this.setUpFirstTimeLaunch(); // Skip welcome screen this.isFirstTime = false; + autoUpdate.sendAnalytics( + InstallActionTypes.InstallCompleted, + InstallTypes.Auto, + ); return; } @@ -659,6 +670,10 @@ class Config { ); this.isFirstTime = true; this.bootCount = 0; + autoUpdate.sendAnalytics( + InstallActionTypes.InstallCompleted, + InstallTypes.Manual, + ); return; } logger.info(