fix(GUI): ensure settings are loaded before bootstrapping application (#1879)

We load localStorage settings into the Redux store in an asynchronous
way. This means that user settings might not be loaded by the time the
application starts, resulting in Mixpanel sending a few tracking events
before Etcher realises that the user opted out from anonoymous analytics
and error reporting.

In order to fix that, we remove `ng-app` and we manually bootstrap the
Angular.js application *after* the local settings are loaded.

Change-Type: patch
Changelog-Entry: Don't send initial Mixpanel events before "Anonymous Tracking" settings are loaded.
Fixes: https://github.com/resin-io/etcher/issues/1772
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
This commit is contained in:
Juan Cruz Viotti 2017-12-05 11:04:52 -04:00 committed by GitHub
parent 19b7ce0668
commit 618440e38f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 61 deletions

View File

@ -102,77 +102,75 @@ app.run(() => {
version: currentVersion version: currentVersion
}) })
settings.load().then(() => { const shouldCheckForUpdates = updateNotifier.shouldCheckForUpdates({
const shouldCheckForUpdates = updateNotifier.shouldCheckForUpdates({ currentVersion,
currentVersion, lastSleptUpdateNotifier: settings.get('lastSleptUpdateNotifier'),
lastSleptUpdateNotifier: settings.get('lastSleptUpdateNotifier'), lastSleptUpdateNotifierVersion: settings.get('lastSleptUpdateNotifierVersion')
lastSleptUpdateNotifierVersion: settings.get('lastSleptUpdateNotifierVersion') })
const isStableRelease = release.isStableRelease(currentVersion)
const updatesEnabled = settings.get('updatesEnabled')
if (!shouldCheckForUpdates || !updatesEnabled) {
analytics.logEvent('Not checking for updates', {
shouldCheckForUpdates,
updatesEnabled,
stable: isStableRelease
}) })
const isStableRelease = release.isStableRelease(currentVersion) return Bluebird.resolve()
const updatesEnabled = settings.get('updatesEnabled') }
if (!shouldCheckForUpdates || !updatesEnabled) { const updateSemverRange = packageJSON.updates.semverRange
analytics.logEvent('Not checking for updates', { const includeUnstableChannel = settings.get('includeUnstableUpdateChannel')
shouldCheckForUpdates,
updatesEnabled, analytics.logEvent('Checking for updates', {
stable: isStableRelease currentVersion,
stable: isStableRelease,
updateSemverRange,
includeUnstableChannel
})
return s3Packages.getLatestVersion(release.getReleaseType(currentVersion), {
range: updateSemverRange,
includeUnstableChannel
}).then((latestVersion) => {
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
analytics.logEvent('Update notification skipped', {
reason: 'Latest version'
}) })
return Bluebird.resolve() return Bluebird.resolve()
} }
const updateSemverRange = packageJSON.updates.semverRange // In case the internet connection is not good and checking the
const includeUnstableChannel = settings.get('includeUnstableUpdateChannel') // latest published version takes too long, only show notify
// the user about the new version if he didn't start the flash
// process (e.g: selected an image), otherwise such interruption
// might be annoying.
if (selectionState.hasImage()) {
analytics.logEvent('Update notification skipped', {
reason: 'Image selected'
})
return Bluebird.resolve()
}
analytics.logEvent('Checking for updates', { analytics.logEvent('Notifying update', {
currentVersion, latestVersion
stable: isStableRelease,
updateSemverRange,
includeUnstableChannel
}) })
return s3Packages.getLatestVersion(release.getReleaseType(currentVersion), { return updateNotifier.notify(latestVersion, {
range: updateSemverRange, allowSleepUpdateCheck: isStableRelease
includeUnstableChannel })
}).then((latestVersion) => {
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
analytics.logEvent('Update notification skipped', {
reason: 'Latest version'
})
return Bluebird.resolve()
}
// In case the internet connection is not good and checking the // If the error is an update user error, then we don't want
// latest published version takes too long, only show notify // to bother users each time they open the app.
// the user about the new version if he didn't start the flash // See: https://github.com/resin-io/etcher/issues/1525
// process (e.g: selected an image), otherwise such interruption }).catch((error) => {
// might be annoying. return errors.isUserError(error) && error.code === 'UPDATE_USER_ERROR'
if (selectionState.hasImage()) { }, (error) => {
analytics.logEvent('Update notification skipped', { analytics.logEvent('Update check user error', {
reason: 'Image selected' title: errors.getTitle(error),
}) description: errors.getDescription(error)
return Bluebird.resolve()
}
analytics.logEvent('Notifying update', {
latestVersion
})
return updateNotifier.notify(latestVersion, {
allowSleepUpdateCheck: isStableRelease
})
// If the error is an update user error, then we don't want
// to bother users each time they open the app.
// See: https://github.com/resin-io/etcher/issues/1525
}).catch((error) => {
return errors.isUserError(error) && error.code === 'UPDATE_USER_ERROR'
}, (error) => {
analytics.logEvent('Update check user error', {
title: errors.getTitle(error),
description: errors.getDescription(error)
})
}) })
}).catch(exceptionReporter.report) }).catch(exceptionReporter.report)
}) })
@ -347,3 +345,11 @@ app.controller('StateController', function ($rootScope, $scope) {
*/ */
this.currentName = null this.currentName = null
}) })
// Ensure user settings are loaded before
// we bootstrap the Angular.js application
angular.element(document).ready(() => {
settings.load().then(() => {
angular.bootstrap(document, [ 'Etcher' ])
}).catch(exceptionReporter.report)
})

View File

@ -8,7 +8,7 @@
<link rel="stylesheet" type="text/css" href="css/angular.css"> <link rel="stylesheet" type="text/css" href="css/angular.css">
<script src="./app.js"></script> <script src="./app.js"></script>
</head> </head>
<body ng-app="Etcher"> <body>
<header class="section-header" ng-controller="HeaderController as header"> <header class="section-header" ng-controller="HeaderController as header">
<button class="button button-link" <button class="button button-link"
ng-click="header.openHelpPage()" ng-click="header.openHelpPage()"