Merge pull request #2420 from resin-io/better-analytics

fix(GUI): Additional data on events
This commit is contained in:
Lorenzo Alberto Maria Ambrosi 2018-08-07 19:40:53 +02:00 committed by GitHub
commit ea834f6778
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 226 additions and 54 deletions

View File

@ -29,6 +29,7 @@ var angular = require('angular')
const electron = require('electron')
const Bluebird = require('bluebird')
const semver = require('semver')
const uuidV4 = require('uuid/v4')
const EXIT_CODES = require('../../shared/exit-codes')
const messages = require('../../shared/messages')
const s3Packages = require('../../shared/s3-packages')
@ -58,6 +59,21 @@ const updateLock = require('./modules/update-lock')
process.env.DRIVELIST_DEBUG = /drivelist|^\*$/i.test(process.env.DEBUG) ? '1' : ''
window.localStorage.debug = process.env.DEBUG
// Set application session UUID
store.dispatch({
type: store.Actions.SET_APPLICATION_SESSION_UUID,
data: uuidV4()
})
// Set first flashing workflow UUID
store.dispatch({
type: store.Actions.SET_FLASHING_WORKFLOW_UUID,
data: uuidV4()
})
const applicationSessionUuid = store.getState().toJS().applicationSessionUuid
const flashingWorkflowUuid = store.getState().toJS().flashingWorkflowUuid
const app = angular.module('Etcher', [
require('angular-ui-router'),
require('angular-ui-bootstrap'),
@ -103,7 +119,8 @@ app.run(() => {
analytics.logEvent('Application start', {
packageType: packageJSON.packageType,
version: currentVersion
version: currentVersion,
applicationSessionUuid
})
const shouldCheckForUpdates = updateNotifier.shouldCheckForUpdates({
@ -119,7 +136,8 @@ app.run(() => {
analytics.logEvent('Not checking for updates', {
shouldCheckForUpdates,
updatesEnabled,
stable: isStableRelease
stable: isStableRelease,
applicationSessionUuid
})
return Bluebird.resolve()
@ -132,7 +150,8 @@ app.run(() => {
currentVersion,
stable: isStableRelease,
updateSemverRange,
includeUnstableChannel
includeUnstableChannel,
applicationSessionUuid
})
return s3Packages.getLatestVersion(release.getReleaseType(currentVersion), {
@ -141,7 +160,8 @@ app.run(() => {
}).then((latestVersion) => {
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
analytics.logEvent('Update notification skipped', {
reason: 'Latest version'
reason: 'Latest version',
applicationSessionUuid
})
return Bluebird.resolve()
}
@ -153,13 +173,15 @@ app.run(() => {
// might be annoying.
if (selectionState.hasImage()) {
analytics.logEvent('Update notification skipped', {
reason: 'Image selected'
reason: 'Image selected',
applicationSessionUuid
})
return Bluebird.resolve()
}
analytics.logEvent('Notifying update', {
latestVersion
latestVersion,
applicationSessionUuid
})
return updateNotifier.notify(latestVersion, {
@ -174,7 +196,8 @@ app.run(() => {
}, (error) => {
analytics.logEvent('Update check user error', {
title: errors.getTitle(error),
description: errors.getDescription(error)
description: errors.getDescription(error),
applicationSessionUuid
})
}).catch(exceptionReporter.report)
})
@ -247,7 +270,8 @@ app.run(($window) => {
$window.addEventListener('beforeunload', (event) => {
if (!flashState.isFlashing() || popupExists) {
analytics.logEvent('Close application', {
isFlashing: flashState.isFlashing()
isFlashing: flashState.isFlashing(),
applicationSessionUuid
})
return
}
@ -258,7 +282,7 @@ app.run(($window) => {
// Don't open any more popups
popupExists = true
analytics.logEvent('Close attempt while flashing')
analytics.logEvent('Close attempt while flashing', { applicationSessionUuid, flashingWorkflowUuid })
osDialog.showWarning({
confirmationLabel: 'Yes, quit',
@ -268,7 +292,9 @@ app.run(($window) => {
}).then((confirmed) => {
if (confirmed) {
analytics.logEvent('Close confirmed while flashing', {
uuid: flashState.getFlashUuid()
flashInstanceUuid: flashState.getFlashUuid(),
applicationSessionUuid,
flashingWorkflowUuid
})
// This circumvents the 'beforeunload' event unlike
@ -276,7 +302,7 @@ app.run(($window) => {
electron.remote.process.exit(EXIT_CODES.SUCCESS)
}
analytics.logEvent('Close rejected while flashing')
analytics.logEvent('Close rejected while flashing', { applicationSessionUuid, flashingWorkflowUuid })
popupExists = false
}).catch(exceptionReporter.report)
})
@ -308,7 +334,8 @@ app.run(($rootScope) => {
analytics.logEvent('Navigate', {
to: toState.name,
from: fromState.name
from: fromState.name,
applicationSessionUuid
})
})
})

View File

@ -20,6 +20,7 @@ const angular = require('angular')
const _ = require('lodash')
const Bluebird = require('bluebird')
const constraints = require('../../../../../shared/drive-constraints')
const store = require('../../../models/store')
const analytics = require('../../../modules/analytics')
const availableDrives = require('../../../models/available-drives')
const selectionState = require('../../../models/selection-state')
@ -96,7 +97,9 @@ module.exports = function (
if (canChangeDriveSelectionState) {
analytics.logEvent('Toggle drive', {
drive,
previouslySelected: selectionState.isCurrentDrive(drive.device)
previouslySelected: selectionState.isCurrentDrive(drive.device),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
selectionState.toggleDrive(drive.device)
@ -125,7 +128,9 @@ module.exports = function (
this.installMissingDrivers = (drive) => {
if (drive.link) {
analytics.logEvent('Open driver link modal', {
url: drive.link
url: drive.link,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
return ConfirmModalService.show({
@ -187,7 +192,10 @@ module.exports = function (
if (canChangeDriveSelectionState) {
selectionState.selectDrive(drive.device)
analytics.logEvent('Drive selected (double click)')
analytics.logEvent('Drive selected (double click)', {
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
this.closeModal()
}

View File

@ -177,7 +177,11 @@ class FileSelector extends React.PureComponent {
})
osDialog.showError(invalidImageError)
analytics.logEvent('Invalid image', image)
analytics.logEvent('Invalid image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
return
}
@ -185,10 +189,18 @@ class FileSelector extends React.PureComponent {
let message = null
if (supportedFormats.looksLikeWindowsImage(image.path)) {
analytics.logEvent('Possibly Windows image', image)
analytics.logEvent('Possibly Windows image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
message = messages.warning.looksLikeWindowsImage()
} else if (!image.hasMBR) {
analytics.logEvent('Missing partition table', image)
analytics.logEvent('Missing partition table', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
message = messages.warning.missingPartitionTable()
}
@ -218,7 +230,11 @@ class FileSelector extends React.PureComponent {
image.logo = Boolean(image.logo)
image.bmap = Boolean(image.bmap)
analytics.logEvent('Select image', image)
analytics.logEvent('Select image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
}).catch(exceptionReporter.report)
}

View File

@ -18,6 +18,7 @@
const flashState = require('../../../models/flash-state')
const selectionState = require('../../../models/selection-state')
const store = require('../../../models/store')
const analytics = require('../../../modules/analytics')
module.exports = function (WarningModalService) {
@ -40,7 +41,10 @@ module.exports = function (WarningModalService) {
flashState.resetState()
if (confirmed) {
analytics.logEvent('Restart after failure')
analytics.logEvent('Restart after failure', {
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
} else {
selectionState.clear()
}

View File

@ -17,6 +17,7 @@
'use strict'
const _ = require('lodash')
const store = require('../../../models/store')
const analytics = require('../../../modules/analytics')
module.exports = function ($uibModal, $q) {
@ -45,7 +46,9 @@ module.exports = function ($uibModal, $q) {
})
analytics.logEvent('Open modal', {
name: options.name
name: options.name,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
const modal = $uibModal.open({
@ -62,7 +65,9 @@ module.exports = function ($uibModal, $q) {
modal.result.then((value) => {
analytics.logEvent('Modal accepted', {
name: options.name,
value
value,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
resolve(value)
@ -71,7 +76,9 @@ module.exports = function ($uibModal, $q) {
if (error === 'escape key press' || error === 'backdrop click') {
analytics.logEvent('Modal rejected', {
name: options.name,
method: error
method: error,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
return resolve()
@ -79,7 +86,9 @@ module.exports = function ($uibModal, $q) {
analytics.logEvent('Modal rejected', {
name: options.name,
value: error
value: error,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
return reject(error)

View File

@ -25,6 +25,7 @@ const react = require('react')
const propTypes = require('prop-types')
const { react2angular } = require('react2angular')
const analytics = require('../modules/analytics')
const store = require('../models/store')
const settings = require('../models/settings')
const packageJSON = require('../../../../package.json')
@ -198,7 +199,10 @@ class SafeWebview extends react.PureComponent {
if (event.resourceType === 'mainFrame') {
const HTTP_OK = 200
analytics.logEvent(event)
analytics.logEvent(event, {
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
this.setState({
shouldShow: event.httpResponseCode === HTTP_OK
@ -248,7 +252,10 @@ class SafeWebview extends react.PureComponent {
if (message.command === 'error') {
analytics.logException(message.data)
} else {
analytics.logEvent(message.data || message)
analytics.logEvent(message.data || message, {
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
}
}
}

View File

@ -19,6 +19,7 @@
const electron = require('electron')
const Bluebird = require('bluebird')
const _ = require('lodash')
const store = require('../models/store')
const settings = require('../models/settings')
const analytics = require('../modules/analytics')
const units = require('../../../shared/units')
@ -145,7 +146,9 @@ exports.notify = (version, options = {}) => {
sleepUpdateCheck: results.sleepUpdateCheck,
notifyVersion: version,
currentVersion: packageJSON.version,
agreed: results.agreed
agreed: results.agreed,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
if (results.agreed) {

View File

@ -80,6 +80,8 @@ const selectImageNoNilFields = [
* @private
*/
const DEFAULT_STATE = Immutable.fromJS({
applicationSessionUuid: '',
flashingWorkflowUuid: '',
availableDrives: [],
selection: {
devices: new Immutable.OrderedSet()
@ -111,7 +113,9 @@ const ACTIONS = _.fromPairs(_.map([
'SELECT_DRIVE',
'SELECT_IMAGE',
'DESELECT_DRIVE',
'DESELECT_IMAGE'
'DESELECT_IMAGE',
'SET_APPLICATION_SESSION_UUID',
'SET_FLASHING_WORKFLOW_UUID'
], (message) => {
return [ message, message ]
}))
@ -499,6 +503,14 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
return state.deleteIn([ 'selection', 'image' ])
}
case ACTIONS.SET_APPLICATION_SESSION_UUID: {
return state.set('applicationSessionUuid', action.data)
}
case ACTIONS.SET_FLASHING_WORKFLOW_UUID: {
return state.set('flashingWorkflowUuid', action.data)
}
default: {
return state
}

View File

@ -23,6 +23,7 @@ const os = require('os')
const ipc = require('node-ipc')
const isRunningInAsar = require('electron-is-running-in-asar')
const electron = require('electron')
const store = require('../models/store')
const settings = require('../models/settings')
const flashState = require('../models/flash-state')
const errors = require('../../../shared/errors')
@ -74,20 +75,26 @@ const getApplicationEntryPoint = () => {
* handleErrorLogging({ code: 'EUNPLUGGED' }, { image: 'resin.img' })
*/
const handleErrorLogging = (error, analyticsData) => {
const eventData = _.assign({
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid,
flashInstanceUuid: flashState.getFlashUuid()
}, analyticsData)
if (error.code === 'EVALIDATION') {
analytics.logEvent('Validation error', analyticsData)
analytics.logEvent('Validation error', eventData)
} else if (error.code === 'EUNPLUGGED') {
analytics.logEvent('Drive unplugged', analyticsData)
analytics.logEvent('Drive unplugged', eventData)
} else if (error.code === 'EIO') {
analytics.logEvent('Input/output error', analyticsData)
analytics.logEvent('Input/output error', eventData)
} else if (error.code === 'ENOSPC') {
analytics.logEvent('Out of space', analyticsData)
analytics.logEvent('Out of space', eventData)
} else if (error.code === 'ECHILDDIED') {
analytics.logEvent('Child died unexpectedly', analyticsData)
analytics.logEvent('Child died unexpectedly', eventData)
} else {
analytics.logEvent('Flash error', _.merge({
error: errors.toJSON(error)
}, analyticsData))
}, eventData))
}
}
@ -163,6 +170,7 @@ exports.performWrite = (image, drives, onProgress) => {
drives,
driveCount: drives.length,
uuid: flashState.getFlashUuid(),
flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
}
@ -306,8 +314,12 @@ exports.flash = (image, drives) => {
drives,
driveCount: drives.length,
uuid: flashState.getFlashUuid(),
status: 'started',
flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
validateWriteOnSuccess: settings.get('validateWriteOnSuccess'),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
}
analytics.logEvent('Flash', analyticsData)
@ -315,10 +327,17 @@ exports.flash = (image, drives) => {
return exports.performWrite(image, drives, (state) => {
flashState.setProgressState(state)
}).then(flashState.unsetFlashingFlag).then(() => {
const { results } = flashState.getFlashResults()
const event = _.assign({
errors: results.errors,
devices: results.devices,
status: 'finished'
},
analyticsData)
if (flashState.wasLastFlashCancelled()) {
analytics.logEvent('Elevation cancelled', analyticsData)
analytics.logEvent('Elevation cancelled', event)
} else {
analytics.logEvent('Done', analyticsData)
analytics.logEvent('Done', event)
}
}).catch((error) => {
flashState.unsetFlashingFlag({
@ -327,7 +346,14 @@ exports.flash = (image, drives) => {
// eslint-disable-next-line no-magic-numbers
if (drives.length > 1) {
analytics.logEvent('Write failed', analyticsData)
const { results } = flashState.getFlashResults()
const event = _.assign({
errors: results.errors,
devices: results.devices,
status: 'failed'
},
analyticsData)
analytics.logEvent('Write failed', event)
}
return Bluebird.reject(error)
@ -346,14 +372,25 @@ exports.flash = (image, drives) => {
*/
exports.cancel = () => {
const drives = selectionState.getSelectedDevices()
analytics.logEvent('Cancel', {
const { results } = flashState.getFlashResults()
const analyticsData = {
image: selectionState.getImagePath(),
drives,
driveCount: drives.length,
uuid: flashState.getFlashUuid(),
flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
})
validateWriteOnSuccess: settings.get('validateWriteOnSuccess'),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
}
const event = _.assign({
errors: results.errors,
devices: results.devices,
status: 'finished'
},
analyticsData)
analytics.logEvent('Cancel', event)
// Re-enable lock release on inactivity
updateLock.resume()

View File

@ -17,6 +17,7 @@
'use strict'
const electron = require('electron')
const store = require('../../../models/store')
const analytics = require('../../../modules/analytics')
const settings = require('../../../models/settings')
@ -38,7 +39,8 @@ module.exports = function () {
}
analytics.logEvent('Open external link', {
url
url,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid
})
if (url) {

View File

@ -17,6 +17,8 @@
'use strict'
const _ = require('lodash')
const uuidV4 = require('uuid/v4')
const store = require('../../../models/store')
const settings = require('../../../models/settings')
const flashState = require('../../../models/flash-state')
const selectionState = require('../../../models/selection-state')
@ -57,10 +59,20 @@ module.exports = function ($state) {
selectionState.deselectImage()
}
selectionState.deselectAllDrives()
analytics.logEvent('Restart', options)
analytics.logEvent('Restart', _.assign({
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
}, options))
// Re-enable lock release on inactivity
updateLock.resume()
// Reset the flashing workflow uuid
store.dispatch({
type: 'SET_FLASHING_WORKFLOW_UUID',
data: uuidV4()
})
$state.go('main')
}

View File

@ -19,6 +19,7 @@
const _ = require('lodash')
const angular = require('angular')
const prettyBytes = require('pretty-bytes')
const store = require('../../../models/store')
const settings = require('../../../models/settings')
const selectionState = require('../../../models/selection-state')
const analytics = require('../../../modules/analytics')
@ -109,7 +110,9 @@ module.exports = function (DriveSelectorService) {
analytics.logEvent('Select drive', {
device: drive.device,
unsafeMode: settings.get('unsafeMode') && !settings.get('disableUnsafeMode')
unsafeMode: settings.get('unsafeMode') && !settings.get('disableUnsafeMode'),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
}).catch(exceptionReporter.report)
}
@ -124,7 +127,10 @@ module.exports = function (DriveSelectorService) {
*/
this.reselectDrive = () => {
this.openDriveSelector()
analytics.logEvent('Reselect drive')
analytics.logEvent('Reselect drive', {
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
}
/**

View File

@ -19,6 +19,7 @@
const _ = require('lodash')
const Bluebird = require('bluebird')
const path = require('path')
const store = require('../../../models/store')
const messages = require('../../../../../shared/messages')
const errors = require('../../../../../shared/errors')
const imageStream = require('../../../../../sdk/image-stream')
@ -76,7 +77,10 @@ module.exports = function (
})
osDialog.showError(invalidImageError)
analytics.logEvent('Invalid image', image)
analytics.logEvent('Invalid image', _.merge({
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
}, image))
return
}
@ -84,10 +88,18 @@ module.exports = function (
let message = null
if (supportedFormats.looksLikeWindowsImage(image.path)) {
analytics.logEvent('Possibly Windows image', image)
analytics.logEvent('Possibly Windows image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
message = messages.warning.looksLikeWindowsImage()
} else if (!image.hasMBR) {
analytics.logEvent('Missing partition table', image)
analytics.logEvent('Missing partition table', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
message = messages.warning.missingPartitionTable()
}
@ -114,7 +126,11 @@ module.exports = function (
image.logo = Boolean(image.logo)
image.bmap = Boolean(image.bmap)
return analytics.logEvent('Select image', image)
return analytics.logEvent('Select image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
}).catch(exceptionReporter.report)
}
@ -155,7 +171,10 @@ module.exports = function (
* ImageSelectionController.openImageSelector();
*/
this.openImageSelector = () => {
analytics.logEvent('Open image selector')
analytics.logEvent('Open image selector', {
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
if (settings.get('experimentalFilePicker')) {
FileSelectorService.open()
@ -164,7 +183,10 @@ module.exports = function (
// Avoid analytics and selection state changes
// if no file was resolved from the dialog.
if (!imagePath) {
analytics.logEvent('Image selector closed')
analytics.logEvent('Image selector closed', {
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
return
}
@ -183,7 +205,9 @@ module.exports = function (
*/
this.reselectImage = () => {
analytics.logEvent('Reselect image', {
previousImage: selectionState.getImage()
previousImage: selectionState.getImage(),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
this.openImageSelector()

View File

@ -16,6 +16,7 @@
'use strict'
const store = require('../../../models/store')
const settings = require('../../../models/settings')
const flashState = require('../../../models/flash-state')
const analytics = require('../../../modules/analytics')
@ -82,7 +83,9 @@ module.exports = function (
*/
this.showSelectedImageDetails = () => {
analytics.logEvent('Show selected image tooltip', {
imagePath: selectionState.getImagePath()
imagePath: selectionState.getImagePath(),
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid
})
return TooltipModalService.show({

View File

@ -18,6 +18,7 @@
const os = require('os')
const _ = require('lodash')
const store = require('../../../models/store')
const settings = require('../../../models/settings')
const analytics = require('../../../modules/analytics')
const exceptionReporter = require('../../../modules/exception-reporter')
@ -87,7 +88,8 @@ module.exports = function (WarningModalService) {
analytics.logEvent('Toggle setting', {
setting,
value,
dangerous
dangerous,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid
})
if (!value || !dangerous) {