refactor(GUI): remove analytics angular dependency (#1387)

We rename `AnalyticsService` to `analytics` and remove its dependency on
Angular.
This commit is contained in:
Benedict Aas 2017-05-11 01:27:54 +01:00 committed by Juan Cruz Viotti
parent 66547c5abd
commit 69a982bf8d
23 changed files with 133 additions and 156 deletions

View File

@ -38,6 +38,7 @@ const packageJSON = require('../../package.json');
const flashState = require('./models/flash-state');
const settings = require('./models/settings');
const windowProgress = require('./os/window-progress');
const analytics = require('./modules/analytics');
const Store = require('./models/store');
@ -47,7 +48,6 @@ const app = angular.module('Etcher', [
require('angular-if-state'),
// Etcher modules
require('./modules/analytics'),
require('./modules/error'),
require('./modules/drive-scanner'),
@ -88,8 +88,8 @@ app.run(() => {
].join('\n'));
});
app.run((AnalyticsService, ErrorService, UpdateNotifierService, SelectionStateModel) => {
AnalyticsService.logEvent('Application start');
app.run((ErrorService, UpdateNotifierService, SelectionStateModel) => {
analytics.logEvent('Application start');
const currentVersion = packageJSON.version;
const currentReleaseType = release.getReleaseType(currentVersion);
@ -102,7 +102,7 @@ app.run((AnalyticsService, ErrorService, UpdateNotifierService, SelectionStateMo
process.env.ETCHER_DISABLE_UPDATES,
currentReleaseType === release.RELEASE_TYPE.UNKNOWN
])) {
AnalyticsService.logEvent('Not checking for updates', {
analytics.logEvent('Not checking for updates', {
shouldCheckForUpdates,
disableUpdatesEnvironmentVariable: process.env.ETCHER_DISABLE_UPDATES,
releaseType: currentReleaseType
@ -113,7 +113,7 @@ app.run((AnalyticsService, ErrorService, UpdateNotifierService, SelectionStateMo
const updateSemverRange = packageJSON.updates.semverRange;
const includeUnstableChannel = settings.get('includeUnstableUpdateChannel');
AnalyticsService.logEvent('Checking for updates', {
analytics.logEvent('Checking for updates', {
currentVersion,
releaseType: currentReleaseType,
updateSemverRange,
@ -125,7 +125,7 @@ app.run((AnalyticsService, ErrorService, UpdateNotifierService, SelectionStateMo
includeUnstableChannel
}).then((latestVersion) => {
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
AnalyticsService.logEvent('Update notification skipped', {
analytics.logEvent('Update notification skipped', {
reason: 'Latest version'
});
return Bluebird.resolve();
@ -137,13 +137,13 @@ app.run((AnalyticsService, ErrorService, UpdateNotifierService, SelectionStateMo
// process (e.g: selected an image), otherwise such interruption
// might be annoying.
if (SelectionStateModel.hasImage()) {
AnalyticsService.logEvent('Update notification skipped', {
analytics.logEvent('Update notification skipped', {
reason: 'Image selected'
});
return Bluebird.resolve();
}
AnalyticsService.logEvent('Notifying update', {
analytics.logEvent('Notifying update', {
latestVersion
});
@ -153,7 +153,7 @@ app.run((AnalyticsService, ErrorService, UpdateNotifierService, SelectionStateMo
}).catch(ErrorService.reportException);
});
app.run((AnalyticsService) => {
app.run(() => {
Store.subscribe(() => {
const currentFlashState = flashState.getFlashState();
@ -168,7 +168,7 @@ app.run((AnalyticsService) => {
return;
}
AnalyticsService.logDebug([
analytics.logDebug([
`Progress (${currentFlashState.type}):`,
`${currentFlashState.percentage}% at ${currentFlashState.speed} MB/s`,
`(eta ${currentFlashState.eta}s)`
@ -204,12 +204,12 @@ app.run(($timeout, DriveScannerService, DrivesModel, ErrorService) => {
DriveScannerService.start();
});
app.run(($window, AnalyticsService, WarningModalService, ErrorService, OSDialogService) => {
app.run(($window, WarningModalService, ErrorService, OSDialogService) => {
let popupExists = false;
$window.addEventListener('beforeunload', (event) => {
if (!flashState.isFlashing() || popupExists) {
AnalyticsService.logEvent('Close application', {
analytics.logEvent('Close application', {
isFlashing: flashState.isFlashing()
});
return;
@ -221,7 +221,7 @@ app.run(($window, AnalyticsService, WarningModalService, ErrorService, OSDialogS
// Don't open any more popups
popupExists = true;
AnalyticsService.logEvent('Close attempt while flashing');
analytics.logEvent('Close attempt while flashing');
OSDialogService.showWarning({
confirmationLabel: 'Yes, quit',
@ -230,7 +230,7 @@ app.run(($window, AnalyticsService, WarningModalService, ErrorService, OSDialogS
description: messages.warning.exitWhileFlashing()
}).then((confirmed) => {
if (confirmed) {
AnalyticsService.logEvent('Close confirmed while flashing', {
analytics.logEvent('Close confirmed while flashing', {
uuid: flashState.getFlashUuid()
});
@ -240,13 +240,13 @@ app.run(($window, AnalyticsService, WarningModalService, ErrorService, OSDialogS
}
AnalyticsService.logEvent('Close rejected while flashing');
analytics.logEvent('Close rejected while flashing');
popupExists = false;
}).catch(ErrorService.reportException);
});
});
app.run(($rootScope, AnalyticsService) => {
app.run(($rootScope) => {
$rootScope.$on('$stateChangeSuccess', (event, toState, toParams, fromState) => {
// Ignore first navigation
@ -254,7 +254,7 @@ app.run(($rootScope, AnalyticsService) => {
return;
}
AnalyticsService.logEvent('Navigate', {
analytics.logEvent('Navigate', {
to: toState.name,
from: fromState.name
});

View File

@ -20,14 +20,14 @@ const angular = require('angular');
const _ = require('lodash');
const messages = require('../../../../shared/messages');
const constraints = require('../../../../shared/drive-constraints');
const analytics = require('../../../modules/analytics');
module.exports = function(
$q,
$uibModalInstance,
DrivesModel,
SelectionStateModel,
WarningModalService,
AnalyticsService
WarningModalService
) {
/**
@ -109,7 +109,7 @@ module.exports = function(
*/
this.toggleDrive = (drive) => {
AnalyticsService.logEvent('Toggle drive', {
analytics.logEvent('Toggle drive', {
drive,
previouslySelected: SelectionStateModel.isCurrentDrive(drive.device)
});
@ -164,7 +164,7 @@ module.exports = function(
if (canChangeDriveSelectionState) {
SelectionStateModel.setDrive(drive.device);
AnalyticsService.logEvent('Drive selected (double click)');
analytics.logEvent('Drive selected (double click)');
this.closeModal();
}

View File

@ -27,8 +27,7 @@ const DriveSelector = angular.module(MODULE_NAME, [
require('../warning-modal/warning-modal'),
require('../../models/drives'),
require('../../models/selection-state'),
require('../../utils/byte-size/byte-size'),
require('../../modules/analytics')
require('../../utils/byte-size/byte-size')
]);
DriveSelector.controller('DriveSelectorController', require('./controllers/drive-selector'));

View File

@ -24,8 +24,7 @@ const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.FlashErrorModal';
const FlashErrorModal = angular.module(MODULE_NAME, [
require('../warning-modal/warning-modal'),
require('../../models/selection-state'),
require('../../modules/analytics')
require('../../models/selection-state')
]);
FlashErrorModal.service('FlashErrorModalService', require('./services/flash-error-modal'));

View File

@ -17,8 +17,9 @@
'use strict';
const flashState = require('../../../models/flash-state');
const analytics = require('../../../modules/analytics');
module.exports = function(WarningModalService, SelectionStateModel, AnalyticsService) {
module.exports = function(WarningModalService, SelectionStateModel) {
/**
* @summary Open the flash error modal
@ -39,7 +40,7 @@ module.exports = function(WarningModalService, SelectionStateModel, AnalyticsSer
flashState.resetState();
if (confirmed) {
AnalyticsService.logEvent('Restart after failure');
analytics.logEvent('Restart after failure');
} else {
SelectionStateModel.clear();
}

View File

@ -23,8 +23,7 @@
const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.Modal';
const Modal = angular.module(MODULE_NAME, [
require('angular-ui-bootstrap'),
require('../../modules/analytics')
require('angular-ui-bootstrap')
]);
Modal.service('ModalService', require('./services/modal'));

View File

@ -17,8 +17,9 @@
'use strict';
const _ = require('lodash');
const analytics = require('../../../modules/analytics');
module.exports = function($uibModal, $q, AnalyticsService) {
module.exports = function($uibModal, $q) {
/**
* @summary Open a modal
@ -44,7 +45,7 @@ module.exports = function($uibModal, $q, AnalyticsService) {
size: 'sm'
});
AnalyticsService.logEvent('Open modal', {
analytics.logEvent('Open modal', {
template: options.template
});
@ -60,7 +61,7 @@ module.exports = function($uibModal, $q, AnalyticsService) {
close: modal.close,
result: $q((resolve, reject) => {
modal.result.then((value) => {
AnalyticsService.logEvent('Modal accepted', {
analytics.logEvent('Modal accepted', {
value
});
@ -69,14 +70,14 @@ module.exports = function($uibModal, $q, AnalyticsService) {
// Bootstrap doesn't 'resolve' these but cancels the dialog
if (error === 'escape key press' || error === 'backdrop click') {
AnalyticsService.logEvent('Modal rejected', {
analytics.logEvent('Modal rejected', {
method: error
});
return resolve();
}
AnalyticsService.logEvent('Modal rejected', {
analytics.logEvent('Modal rejected', {
value: error
});

View File

@ -17,8 +17,9 @@
'use strict';
const settings = require('../../../models/settings');
const analytics = require('../../../modules/analytics');
module.exports = function($uibModalInstance, AnalyticsService, UPDATE_NOTIFIER_SLEEP_DAYS, options) {
module.exports = function($uibModalInstance, UPDATE_NOTIFIER_SLEEP_DAYS, options) {
// We update this value in this controller since its the only place
// where we can be sure the modal was really presented to the user.
@ -58,7 +59,7 @@ module.exports = function($uibModalInstance, AnalyticsService, UPDATE_NOTIFIER_S
* UpdateNotifierController.closeModal();
*/
this.closeModal = () => {
AnalyticsService.logEvent('Close update modal', {
analytics.logEvent('Close update modal', {
sleepUpdateCheck: this.sleepUpdateCheck,
notifyVersion: options.version
});

View File

@ -24,8 +24,7 @@ const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.UpdateNotifier';
const UpdateNotifier = angular.module(MODULE_NAME, [
require('../modal/modal'),
require('../../os/open-external/open-external'),
require('../../modules/analytics')
require('../../os/open-external/open-external')
]);
/**

View File

@ -16,84 +16,68 @@
'use strict';
/**
* @module Etcher.Modules.Analytics
*/
const angular = require('angular');
const _ = require('lodash');
const resinCorvus = require('resin-corvus/browser');
const packageJSON = require('../../../package.json');
const settings = require('../models/settings');
const MODULE_NAME = 'Etcher.Modules.Analytics';
const analytics = angular.module(MODULE_NAME, []);
analytics.run(() => {
resinCorvus.install({
services: {
sentry: _.get(packageJSON, [ 'analytics', 'sentry', 'token' ]),
mixpanel: _.get(packageJSON, [ 'analytics', 'mixpanel', 'token' ])
},
options: {
release: packageJSON.version,
shouldReport: () => {
return settings.get('errorReporting');
}
resinCorvus.install({
services: {
sentry: _.get(packageJSON, [ 'analytics', 'sentry', 'token' ]),
mixpanel: _.get(packageJSON, [ 'analytics', 'mixpanel', 'token' ])
},
options: {
release: packageJSON.version,
shouldReport: () => {
return settings.get('errorReporting');
}
});
}
});
analytics.service('AnalyticsService', function() {
/**
* @summary Log a debug message
* @function
* @public
*
* @description
* This function sends the debug message to error reporting services.
*
* @param {String} message - message
*
* @example
* analytics.log('Hello World');
*/
exports.logDebug = resinCorvus.logDebug;
/**
* @summary Log a debug message
* @function
* @public
*
* @description
* This function sends the debug message to error reporting services.
*
* @param {String} message - message
*
* @example
* AnalyticsService.log('Hello World');
*/
this.logDebug = resinCorvus.logDebug;
/**
* @summary Log an event
* @function
* @public
*
* @description
* This function sends the debug message to product analytics services.
*
* @param {String} message - message
* @param {Object} [data] - event data
*
* @example
* analytics.logEvent('Select image', {
* image: '/dev/disk2'
* });
*/
exports.logEvent = resinCorvus.logEvent;
/**
* @summary Log an event
* @function
* @public
*
* @description
* This function sends the debug message to product analytics services.
*
* @param {String} message - message
* @param {Object} [data] - event data
*
* @example
* AnalyticsService.logEvent('Select image', {
* image: '/dev/disk2'
* });
*/
this.logEvent = resinCorvus.logEvent;
/**
* @summary Log an exception
* @function
* @public
*
* @description
* This function logs an exception to error reporting services.
*
* @param {Error} exception - exception
*
* @example
* AnalyticsService.logException(new Error('Something happened'));
*/
this.logException = resinCorvus.logException;
});
module.exports = MODULE_NAME;
/**
* @summary Log an exception
* @function
* @public
*
* @description
* This function logs an exception to error reporting services.
*
* @param {Error} exception - exception
*
* @example
* analytics.logException(new Error('Something happened'));
*/
exports.logException = resinCorvus.logException;

View File

@ -22,14 +22,14 @@
const angular = require('angular');
const _ = require('lodash');
const analytics = require('../modules/analytics');
const MODULE_NAME = 'Etcher.Modules.Error';
const error = angular.module(MODULE_NAME, [
require('../modules/analytics'),
require('../os/dialog/dialog')
]);
error.service('ErrorService', function(AnalyticsService, OSDialogService) {
error.service('ErrorService', function(OSDialogService) {
/**
* @summary Report an exception
@ -47,7 +47,7 @@ error.service('ErrorService', function(AnalyticsService, OSDialogService) {
}
OSDialogService.showError(exception);
AnalyticsService.logException(exception);
analytics.logException(exception);
};
});

View File

@ -26,13 +26,12 @@ const childWriter = require('../../child-writer');
const settings = require('../models/settings');
const flashState = require('../models/flash-state');
const windowProgress = require('../os/window-progress');
const analytics = require('../modules/analytics');
const MODULE_NAME = 'Etcher.Modules.ImageWriter';
const imageWriter = angular.module(MODULE_NAME, [
require('./analytics')
]);
const imageWriter = angular.module(MODULE_NAME, []);
imageWriter.service('ImageWriterService', function($q, $rootScope, AnalyticsService) {
imageWriter.service('ImageWriterService', function($q, $rootScope) {
/**
* @summary Perform write operation
@ -102,7 +101,7 @@ imageWriter.service('ImageWriterService', function($q, $rootScope, AnalyticsServ
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
};
AnalyticsService.logEvent('Flash', analyticsData);
analytics.logEvent('Flash', analyticsData);
return this.performWrite(image, drive, (state) => {
@ -116,9 +115,9 @@ imageWriter.service('ImageWriterService', function($q, $rootScope, AnalyticsServ
}).then(flashState.unsetFlashingFlag).then(() => {
if (flashState.wasLastFlashCancelled()) {
AnalyticsService.logEvent('Elevation cancelled', analyticsData);
analytics.logEvent('Elevation cancelled', analyticsData);
} else {
AnalyticsService.logEvent('Done', analyticsData);
analytics.logEvent('Done', analyticsData);
}
}).catch((error) => {
flashState.unsetFlashingFlag({
@ -126,15 +125,15 @@ imageWriter.service('ImageWriterService', function($q, $rootScope, AnalyticsServ
});
if (error.code === 'EVALIDATION') {
AnalyticsService.logEvent('Validation error', analyticsData);
analytics.logEvent('Validation error', analyticsData);
} else if (error.code === 'EUNPLUGGED') {
AnalyticsService.logEvent('Drive unplugged', analyticsData);
analytics.logEvent('Drive unplugged', analyticsData);
} else if (error.code === 'EIO') {
AnalyticsService.logEvent('Input/output error', analyticsData);
analytics.logEvent('Input/output error', analyticsData);
} else if (error.code === 'ENOSPC') {
AnalyticsService.logEvent('Out of space', analyticsData);
analytics.logEvent('Out of space', analyticsData);
} else {
AnalyticsService.logEvent('Flash error', _.merge({
analytics.logEvent('Flash error', _.merge({
error
}, analyticsData));
}

View File

@ -24,9 +24,7 @@ const angular = require('angular');
const url = require('url');
const MODULE_NAME = 'Etcher.OS.OpenExternal';
const OSOpenExternal = angular.module(MODULE_NAME, [
require('../../modules/analytics')
]);
const OSOpenExternal = angular.module(MODULE_NAME, []);
OSOpenExternal.service('OSOpenExternalService', require('./services/open-external'));
OSOpenExternal.directive('osOpenExternal', require('./directives/open-external'));

View File

@ -17,8 +17,9 @@
'use strict';
const electron = require('electron');
const analytics = require('../../../modules/analytics');
module.exports = function(AnalyticsService) {
module.exports = function() {
/**
* @summary Open an external resource
@ -31,7 +32,7 @@ module.exports = function(AnalyticsService) {
* OSOpenExternalService.open('https://www.google.com');
*/
this.open = (url) => {
AnalyticsService.logEvent('Open external link', {
analytics.logEvent('Open external link', {
url
});

View File

@ -18,8 +18,9 @@
const settings = require('../../../models/settings');
const flashState = require('../../../models/flash-state');
const analytics = require('../../../modules/analytics');
module.exports = function($state, SelectionStateModel, AnalyticsService) {
module.exports = function($state, SelectionStateModel) {
/**
* @summary Settings model
@ -48,7 +49,7 @@ module.exports = function($state, SelectionStateModel, AnalyticsService) {
*/
this.restart = (options) => {
SelectionStateModel.clear(options);
AnalyticsService.logEvent('Restart', options);
analytics.logEvent('Restart', options);
$state.go('main');
};

View File

@ -30,7 +30,6 @@ const angular = require('angular');
const MODULE_NAME = 'Etcher.Pages.Finish';
const FinishPage = angular.module(MODULE_NAME, [
require('angular-ui-router'),
require('../../modules/analytics'),
require('../../models/selection-state')
]);

View File

@ -17,8 +17,9 @@
'use strict';
const settings = require('../../../models/settings');
const analytics = require('../../../modules/analytics');
module.exports = function(SelectionStateModel, AnalyticsService, ErrorService, DriveSelectorService) {
module.exports = function(SelectionStateModel, ErrorService, DriveSelectorService) {
/**
* @summary Open drive selector
@ -36,7 +37,7 @@ module.exports = function(SelectionStateModel, AnalyticsService, ErrorService, D
SelectionStateModel.setDrive(drive.device);
AnalyticsService.logEvent('Select drive', {
analytics.logEvent('Select drive', {
device: drive.device,
unsafeMode: settings.get('unsafeMode')
});
@ -53,7 +54,7 @@ module.exports = function(SelectionStateModel, AnalyticsService, ErrorService, D
*/
this.reselectDrive = () => {
this.openDriveSelector();
AnalyticsService.logEvent('Reselect drive');
analytics.logEvent('Reselect drive');
};
};

View File

@ -23,10 +23,10 @@ const messages = require('../../../../shared/messages');
const errors = require('../../../../shared/errors');
const imageStream = require('../../../../image-stream');
const supportedFormats = require('../../../../shared/supported-formats');
const analytics = require('../../../modules/analytics');
module.exports = function(
SelectionStateModel,
AnalyticsService,
ErrorService,
OSDialogService,
WarningModalService
@ -76,7 +76,7 @@ module.exports = function(
});
OSDialogService.showError(invalidImageError);
AnalyticsService.logEvent('Invalid image', image);
analytics.logEvent('Invalid image', image);
return;
}
@ -85,7 +85,7 @@ module.exports = function(
return false;
}
AnalyticsService.logEvent('Possibly Windows image', image);
analytics.logEvent('Possibly Windows image', image);
// TODO: `Continue` should be on a red background (dangerous action) instead of `Change`.
// We want `X` to act as `Continue`, that's why `Continue` is the `rejectionLabel`
@ -107,7 +107,7 @@ module.exports = function(
image.logo = Boolean(image.logo);
image.bmap = Boolean(image.bmap);
return AnalyticsService.logEvent('Select image', image);
return analytics.logEvent('Select image', image);
}).catch(ErrorService.reportException);
};
@ -136,14 +136,14 @@ module.exports = function(
* ImageSelectionController.openImageSelector();
*/
this.openImageSelector = () => {
AnalyticsService.logEvent('Open image selector');
analytics.logEvent('Open image selector');
OSDialogService.selectImage().then((imagePath) => {
// Avoid analytics and selection state changes
// if no file was resolved from the dialog.
if (!imagePath) {
AnalyticsService.logEvent('Image selector closed');
analytics.logEvent('Image selector closed');
return;
}
@ -160,7 +160,7 @@ module.exports = function(
* ImageSelectionController.reselectImage();
*/
this.reselectImage = () => {
AnalyticsService.logEvent('Reselect image', {
analytics.logEvent('Reselect image', {
previousImage: SelectionStateModel.getImage()
});

View File

@ -18,14 +18,14 @@
const settings = require('../../../models/settings');
const flashState = require('../../../models/flash-state');
const analytics = require('../../../modules/analytics');
module.exports = function(
SelectionStateModel,
DrivesModel,
TooltipModalService,
ErrorService,
OSOpenExternalService,
AnalyticsService
OSOpenExternalService
) {
// Expose several modules to the template for convenience
@ -78,7 +78,7 @@ module.exports = function(
* MainController.showSelectedImageDetails()
*/
this.showSelectedImageDetails = () => {
AnalyticsService.logEvent('Show selected image tooltip', {
analytics.logEvent('Show selected image tooltip', {
imagePath: SelectionStateModel.getImagePath()
});

View File

@ -45,7 +45,6 @@ const MainPage = angular.module(MODULE_NAME, [
require('../../modules/drive-scanner'),
require('../../modules/image-writer'),
require('../../modules/analytics'),
require('../../modules/error'),
require('../../models/selection-state'),
require('../../models/drives'),

View File

@ -19,8 +19,9 @@
const os = require('os');
const _ = require('lodash');
const settings = require('../../../models/settings');
const analytics = require('../../../modules/analytics');
module.exports = function(WarningModalService, ErrorService, AnalyticsService) {
module.exports = function(WarningModalService, ErrorService) {
/**
* @summary Client platform
@ -81,7 +82,7 @@ module.exports = function(WarningModalService, ErrorService, AnalyticsService) {
const value = this.currentData[setting];
const dangerous = !_.isUndefined(options);
AnalyticsService.logEvent('Toggle setting', {
analytics.logEvent('Toggle setting', {
setting,
value,
dangerous

View File

@ -25,8 +25,7 @@ const MODULE_NAME = 'Etcher.Pages.Settings';
const SettingsPage = angular.module(MODULE_NAME, [
require('angular-ui-router'),
require('../../components/warning-modal/warning-modal'),
require('../../modules/error'),
require('../../modules/analytics')
require('../../modules/error')
]);
SettingsPage.controller('SettingsController', require('./controllers/settings'));

View File

@ -20,7 +20,6 @@ describe('Browser: DriveSelector', function() {
let DrivesModel;
let SelectionStateModel;
let WarningModalService;
let AnalyticsService;
let controller;
@ -29,8 +28,7 @@ describe('Browser: DriveSelector', function() {
_$rootScope_,
_$q_,
_DrivesModel_, _SelectionStateModel_,
_WarningModalService_,
_AnalyticsService_
_WarningModalService_
) {
$controller = _$controller_;
$rootScope = _$rootScope_;
@ -39,7 +37,6 @@ describe('Browser: DriveSelector', function() {
DrivesModel = _DrivesModel_;
SelectionStateModel = _SelectionStateModel_;
WarningModalService = _WarningModalService_;
AnalyticsService = _AnalyticsService_;
}));
beforeEach(() => {
@ -49,8 +46,7 @@ describe('Browser: DriveSelector', function() {
$uibModalInstance,
DrivesModel,
SelectionStateModel,
WarningModalService,
AnalyticsService
WarningModalService
});
});