feat(GUI): add button to cancel flash process (#2301)

We add a cancel button next to the flash progress bar that gracefully
aborts the flash process.

Closes: https://github.com/resin-io/etcher/issues/1791
Closes: https://github.com/resin-io/etcher/issues/2234
Closes: https://github.com/resin-io/etcher/issues/2245
Change-Type: patch
Changelog-Entry: Add a button to cancel the flash process.
This commit is contained in:
Benedict Aas 2018-05-03 10:58:15 +01:00 committed by GitHub
parent 71064cc760
commit 674019ea75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 80 additions and 3 deletions

View File

@ -30,6 +30,7 @@ const permissions = require('../../../shared/permissions')
const windowProgress = require('../os/window-progress')
const analytics = require('../modules/analytics')
const packageJSON = require('../../../../package.json')
const selectionState = require('../../../shared/models/selection-state')
/**
* @summary Number of threads per CPU to allocate to the UV_THREADPOOL
@ -175,6 +176,13 @@ exports.performWrite = (image, drives, onProgress) => {
_.merge(flashResults, event)
})
ipc.server.on('abort', () => {
terminateServer()
resolve({
cancelled: true
})
})
ipc.server.on('state', onProgress)
ipc.server.on('ready', (data, socket) => {
@ -321,3 +329,28 @@ exports.flash = (image, drives) => {
windowProgress.clear()
})
}
/**
* @summary Cancel write operation
* @function
* @public
*
* @example
* imageWriter.cancel()
*/
exports.cancel = () => {
analytics.logEvent('Cancel', {
image: selectionState.getImagePath(),
drives: selectionState.getSelectedDevices(),
uuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
})
try {
const [ socket ] = ipc.server.sockets
ipc.server.emit(socket, 'cancel')
} catch (error) {
analytics.logException(error)
}
}

View File

@ -209,4 +209,14 @@ module.exports = function (
return progressStatus.fromFlashState(flashState.getFlashState())
}
/**
* @summary Abort write process
* @function
* @public
*
* @example
* FlashController.cancelFlash()
*/
this.cancelFlash = imageWriter.cancel
}

View File

@ -41,6 +41,10 @@ svg-icon > img[disabled] {
min-width: $btn-min-width;
}
.page-main .button-abort-write {
margin-right: -35px;
}
%step-border {
height: 2px;
background-color: $palette-theme-dark-foreground;

View File

@ -106,6 +106,12 @@
<span ng-bind="flash.getProgressButtonLabel()"></span>
</progress-button>
<button class="button button-link button-abort-write"
ng-if="main.state.isFlashing()"
ng-click="flash.cancelFlash()">
<span class="glyphicon glyphicon-remove-sign"></span>
</button>
<p class="step-footer step-footer-split" ng-if="main.state.getFlashState().speed && main.state.getFlashState().percentage != 100">
<span ng-bind="main.state.getFlashState().speed.toFixed(2) + ' MB/s'"></span>
<span>ETA: {{ main.state.getFlashState().eta | secondsToDate | amDateFormat:'m[m]ss[s]' }}</span>

View File

@ -6523,6 +6523,9 @@ svg-icon > img[disabled] {
.page-main .button-brick {
min-width: 170px; }
.page-main .button-abort-write {
margin-right: -35px; }
.page-main .step-border-left, .page-main .step-border-right {
height: 2px;
background-color: #fff;

View File

@ -111,6 +111,8 @@ ipc.connectTo(IPC_SERVER_ID, () => {
terminate(EXIT_CODES.SUCCESS)
})
let writer = null
ipc.of[IPC_SERVER_ID].on('write', (options) => {
const destinations = [].concat(options.destinations)
@ -146,6 +148,17 @@ ipc.connectTo(IPC_SERVER_ID, () => {
terminate(exitCode)
}
/**
* @summary Abort handler
* @example
* writer.on('abort', onAbort)
*/
const onAbort = () => {
log('Abort')
ipc.of[IPC_SERVER_ID].emit('abort')
terminate(exitCode)
}
/**
* @summary Error handler
* @param {Error} error - error
@ -171,7 +184,7 @@ ipc.connectTo(IPC_SERVER_ID, () => {
})
}
const writer = new ImageWriter({
writer = new ImageWriter({
verify: options.validateWriteOnSuccess,
unmountOnSuccess: options.unmountOnSuccess,
checksumAlgorithms: options.checksumAlgorithms || []
@ -181,10 +194,17 @@ ipc.connectTo(IPC_SERVER_ID, () => {
writer.on('fail', onFail)
writer.on('progress', onProgress)
writer.on('finish', onFinish)
writer.on('abort', onAbort)
writer.write(options.imagePath, destinations)
})
ipc.of[IPC_SERVER_ID].on('cancel', () => {
if (writer) {
writer.abort()
}
})
ipc.of[IPC_SERVER_ID].on('connect', () => {
log(`Successfully connected to IPC server: ${IPC_SERVER_ID}, socket root ${ipc.config.socketRoot}`)
ipc.of[IPC_SERVER_ID].emit('ready', {})

View File

@ -4,3 +4,4 @@ rules:
no-param-reassign: off
no-underscore-dangle: off
lodash/prefer-lodash-method: off
lodash/prefer-get: off

View File

@ -568,8 +568,8 @@ class ImageWriter extends EventEmitter {
* imageWriter.abort()
*/
abort () {
if (this.source) {
this.source.destroy()
if (this.source && this.source.stream) {
this.source.stream.destroy()
}
this.emit('abort')
}