mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-24 07:17:18 +00:00
feat(GUI): add uuid to flash events (#1344)
Change-Type: patch Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
parent
78ab59a55e
commit
9e7e5de63a
@ -206,7 +206,9 @@ app.run(($window, AnalyticsService, WarningModalService, ErrorService, OSDialogS
|
||||
description: messages.warning.exitWhileFlashing()
|
||||
}).then((confirmed) => {
|
||||
if (confirmed) {
|
||||
AnalyticsService.logEvent('Close confirmed while flashing');
|
||||
AnalyticsService.logEvent('Close confirmed while flashing', {
|
||||
uuid: flashState.getFlashUuid()
|
||||
});
|
||||
|
||||
// This circumvents the 'beforeunload' event unlike
|
||||
// electron.remote.app.quit() which does not.
|
||||
|
@ -220,3 +220,20 @@ exports.getLastFlashSourceChecksum = () => {
|
||||
exports.getLastFlashErrorCode = () => {
|
||||
return exports.getFlashResults().errorCode;
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Get current (or last) flash uuid
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @description
|
||||
* This function returns undefined if no flash has been started yet.
|
||||
*
|
||||
* @returns {String} the last flash uuid
|
||||
*
|
||||
* @example
|
||||
* const uuid = flashState.getFlashUuid();
|
||||
*/
|
||||
exports.getFlashUuid = () => {
|
||||
return Store.getState().toJS().flashUuid;
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ const Immutable = require('immutable');
|
||||
const _ = require('lodash');
|
||||
const redux = require('redux');
|
||||
const persistState = require('redux-localstorage');
|
||||
const uuidV4 = require('uuid/v4');
|
||||
const constraints = require('../../shared/drive-constraints');
|
||||
const errors = require('../../shared/errors');
|
||||
|
||||
@ -226,13 +227,16 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
|
||||
case ACTIONS.RESET_FLASH_STATE: {
|
||||
return state
|
||||
.set('isFlashing', false)
|
||||
.set('flashState', DEFAULT_STATE.get('flashState'))
|
||||
.set('flashResults', DEFAULT_STATE.get('flashResults'));
|
||||
.set('flashResults', DEFAULT_STATE.get('flashResults'))
|
||||
.delete('flashUuid');
|
||||
}
|
||||
|
||||
case ACTIONS.SET_FLASHING_FLAG: {
|
||||
return state
|
||||
.set('isFlashing', true)
|
||||
.set('flashUuid', uuidV4())
|
||||
.set('flashResults', DEFAULT_STATE.get('flashResults'));
|
||||
}
|
||||
|
||||
|
@ -21,16 +21,18 @@
|
||||
*/
|
||||
|
||||
const angular = require('angular');
|
||||
const _ = require('lodash');
|
||||
const childWriter = require('../../child-writer');
|
||||
const settings = require('../models/settings');
|
||||
const flashState = require('../models/flash-state');
|
||||
const windowProgress = require('../os/window-progress');
|
||||
|
||||
const MODULE_NAME = 'Etcher.Modules.ImageWriter';
|
||||
const imageWriter = angular.module(MODULE_NAME, [
|
||||
require('../models/selection-state')
|
||||
require('./analytics')
|
||||
]);
|
||||
|
||||
imageWriter.service('ImageWriterService', function($q, $rootScope) {
|
||||
imageWriter.service('ImageWriterService', function($q, $rootScope, AnalyticsService) {
|
||||
|
||||
/**
|
||||
* @summary Perform write operation
|
||||
@ -92,6 +94,16 @@ imageWriter.service('ImageWriterService', function($q, $rootScope) {
|
||||
|
||||
flashState.setFlashingFlag();
|
||||
|
||||
const analyticsData = {
|
||||
image,
|
||||
drive,
|
||||
uuid: flashState.getFlashUuid(),
|
||||
unmountOnSuccess: settings.get('unmountOnSuccess'),
|
||||
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
|
||||
};
|
||||
|
||||
AnalyticsService.logEvent('Flash', analyticsData);
|
||||
|
||||
return this.performWrite(image, drive, (state) => {
|
||||
|
||||
// Bring this value to the world of angular.
|
||||
@ -102,12 +114,34 @@ imageWriter.service('ImageWriterService', function($q, $rootScope) {
|
||||
flashState.setProgressState(state);
|
||||
});
|
||||
|
||||
}).then(flashState.unsetFlashingFlag).catch((error) => {
|
||||
}).then(flashState.unsetFlashingFlag).then(() => {
|
||||
if (flashState.wasLastFlashCancelled()) {
|
||||
AnalyticsService.logEvent('Elevation cancelled', analyticsData);
|
||||
} else {
|
||||
AnalyticsService.logEvent('Done', analyticsData);
|
||||
}
|
||||
}).catch((error) => {
|
||||
flashState.unsetFlashingFlag({
|
||||
errorCode: error.code
|
||||
});
|
||||
|
||||
if (error.code === 'EVALIDATION') {
|
||||
AnalyticsService.logEvent('Validation error', analyticsData);
|
||||
} else if (error.code === 'EUNPLUGGED') {
|
||||
AnalyticsService.logEvent('Drive unplugged', analyticsData);
|
||||
} else if (error.code === 'EIO') {
|
||||
AnalyticsService.logEvent('Input/output error', analyticsData);
|
||||
} else if (error.code === 'ENOSPC') {
|
||||
AnalyticsService.logEvent('Out of space', analyticsData);
|
||||
} else {
|
||||
AnalyticsService.logEvent('Flash error', _.merge({
|
||||
error
|
||||
}, analyticsData));
|
||||
}
|
||||
|
||||
return $q.reject(error);
|
||||
}).finally(() => {
|
||||
windowProgress.clear();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -19,13 +19,11 @@
|
||||
const messages = require('../../../../shared/messages');
|
||||
const settings = require('../../../models/settings');
|
||||
const flashState = require('../../../models/flash-state');
|
||||
const windowProgress = require('../../../os/window-progress');
|
||||
|
||||
module.exports = function(
|
||||
$state,
|
||||
DriveScannerService,
|
||||
ImageWriterService,
|
||||
AnalyticsService,
|
||||
FlashErrorModalService,
|
||||
ErrorService,
|
||||
OSNotificationService
|
||||
@ -60,69 +58,33 @@ module.exports = function(
|
||||
// otherwise Windows throws EPERM
|
||||
DriveScannerService.stop();
|
||||
|
||||
AnalyticsService.logEvent('Flash', {
|
||||
image,
|
||||
drive,
|
||||
unmountOnSuccess: settings.get('unmountOnSuccess'),
|
||||
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
|
||||
});
|
||||
|
||||
ImageWriterService.flash(image.path, drive).then(() => {
|
||||
if (flashState.wasLastFlashCancelled()) {
|
||||
AnalyticsService.logEvent('Elevation cancelled', {
|
||||
image,
|
||||
drive
|
||||
});
|
||||
return;
|
||||
if (!flashState.wasLastFlashCancelled()) {
|
||||
OSNotificationService.send('Success!', messages.info.flashComplete());
|
||||
$state.go('success');
|
||||
}
|
||||
|
||||
OSNotificationService.send('Success!', messages.info.flashComplete());
|
||||
AnalyticsService.logEvent('Done', {
|
||||
image,
|
||||
drive
|
||||
});
|
||||
$state.go('success');
|
||||
})
|
||||
.catch((error) => {
|
||||
OSNotificationService.send('Oops!', messages.error.flashFailure());
|
||||
|
||||
// TODO: All these error codes to messages translations
|
||||
// should go away if the writer emitted user friendly
|
||||
// messages on the first place.
|
||||
if (error.code === 'EVALIDATION') {
|
||||
FlashErrorModalService.show(messages.error.validation());
|
||||
AnalyticsService.logEvent('Validation error', {
|
||||
image,
|
||||
drive
|
||||
});
|
||||
} else if (error.code === 'EUNPLUGGED') {
|
||||
FlashErrorModalService.show(messages.error.driveUnplugged());
|
||||
AnalyticsService.logEvent('Drive unplugged', {
|
||||
image,
|
||||
drive
|
||||
});
|
||||
} else if (error.code === 'EIO') {
|
||||
FlashErrorModalService.show(messages.error.inputOutput());
|
||||
AnalyticsService.logEvent('Input/output error', {
|
||||
image,
|
||||
drive
|
||||
});
|
||||
} else if (error.code === 'ENOSPC') {
|
||||
FlashErrorModalService.show(messages.error.notEnoughSpaceInDrive());
|
||||
AnalyticsService.logEvent('Out of space', {
|
||||
image,
|
||||
drive
|
||||
});
|
||||
} else {
|
||||
FlashErrorModalService.show(messages.error.genericFlashError());
|
||||
ErrorService.reportException(error);
|
||||
AnalyticsService.logEvent('Flash error', {
|
||||
error,
|
||||
image,
|
||||
drive
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
.finally(() => {
|
||||
windowProgress.clear();
|
||||
DriveScannerService.start();
|
||||
});
|
||||
};
|
||||
|
5
npm-shrinkwrap.json
generated
5
npm-shrinkwrap.json
generated
@ -6942,6 +6942,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.0.1",
|
||||
"from": "uuid@latest",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz"
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.1",
|
||||
"from": "validate-npm-package-license@>=3.0.1 <4.0.0",
|
||||
|
@ -98,6 +98,7 @@
|
||||
"trackjs": "^2.1.16",
|
||||
"udif": "^0.9.0",
|
||||
"unbzip2-stream": "^1.0.11",
|
||||
"uuid": "^3.0.1",
|
||||
"yargs": "^4.6.0",
|
||||
"yauzl": "^2.6.0"
|
||||
},
|
||||
|
@ -5,6 +5,10 @@ const flashState = require('../../../lib/gui/models/flash-state');
|
||||
|
||||
describe('Browser: flashState', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
flashState.resetState();
|
||||
});
|
||||
|
||||
describe('flashState', function() {
|
||||
|
||||
describe('.resetState()', function() {
|
||||
@ -36,6 +40,18 @@ describe('Browser: flashState', function() {
|
||||
m.chai.expect(flashState.getFlashResults()).to.deep.equal({});
|
||||
});
|
||||
|
||||
it('should unset the flashing flag', function() {
|
||||
flashState.setFlashingFlag();
|
||||
flashState.resetState();
|
||||
m.chai.expect(flashState.isFlashing()).to.be.false;
|
||||
});
|
||||
|
||||
it('should unset the flash uuid', function() {
|
||||
flashState.setFlashingFlag();
|
||||
flashState.resetState();
|
||||
m.chai.expect(flashState.getFlashUuid()).to.be.undefined;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.isFlashing()', function() {
|
||||
@ -337,6 +353,19 @@ describe('Browser: flashState', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not reset the flash uuid', function() {
|
||||
flashState.setFlashingFlag();
|
||||
const uuidBeforeUnset = flashState.getFlashUuid();
|
||||
|
||||
flashState.unsetFlashingFlag({
|
||||
sourceChecksum: '1234',
|
||||
cancelled: false
|
||||
});
|
||||
|
||||
const uuidAfterUnset = flashState.getFlashUuid();
|
||||
m.chai.expect(uuidBeforeUnset).to.equal(uuidAfterUnset);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.setFlashingFlag()', function() {
|
||||
@ -441,6 +470,52 @@ describe('Browser: flashState', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('.getFlashUuid()', function() {
|
||||
|
||||
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
||||
|
||||
it('should be initially undefined', function() {
|
||||
m.chai.expect(flashState.getFlashUuid()).to.be.undefined;
|
||||
});
|
||||
|
||||
it('should be a valid uuid if the flashing flag is set', function() {
|
||||
flashState.setFlashingFlag();
|
||||
const uuid = flashState.getFlashUuid();
|
||||
m.chai.expect(UUID_REGEX.test(uuid)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return different uuids every time the flashing flag is set', function() {
|
||||
flashState.setFlashingFlag();
|
||||
const uuid1 = flashState.getFlashUuid();
|
||||
flashState.unsetFlashingFlag({
|
||||
sourceChecksum: '1234',
|
||||
cancelled: false
|
||||
});
|
||||
|
||||
flashState.setFlashingFlag();
|
||||
const uuid2 = flashState.getFlashUuid();
|
||||
flashState.unsetFlashingFlag({
|
||||
cancelled: true
|
||||
});
|
||||
|
||||
flashState.setFlashingFlag();
|
||||
const uuid3 = flashState.getFlashUuid();
|
||||
flashState.unsetFlashingFlag({
|
||||
sourceChecksum: '1234',
|
||||
cancelled: false
|
||||
});
|
||||
|
||||
m.chai.expect(UUID_REGEX.test(uuid1)).to.be.true;
|
||||
m.chai.expect(UUID_REGEX.test(uuid2)).to.be.true;
|
||||
m.chai.expect(UUID_REGEX.test(uuid3)).to.be.true;
|
||||
|
||||
m.chai.expect(uuid1).to.not.equal(uuid2);
|
||||
m.chai.expect(uuid2).to.not.equal(uuid3);
|
||||
m.chai.expect(uuid3).to.not.equal(uuid1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user