mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-25 07:47:18 +00:00
feat(GUI): display succeeded and failed devices on finish screen (#2206)
We display the quantity of succeeded and failed devices using status dots on the finish screen. Change-Type: patch Changelog-Entry: Display succeeded and failed device quantities on the finish screen.
This commit is contained in:
parent
a044d2fe86
commit
32bc615e78
@ -126,16 +126,25 @@ exports.performWrite = (image, drives, onProgress) => {
|
|||||||
console.log(message)
|
console.log(message)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const flashResults = {
|
||||||
|
devices: {
|
||||||
|
succeeded: 0,
|
||||||
|
failed: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
ipc.server.on('fail', (error) => {
|
ipc.server.on('fail', (error) => {
|
||||||
console.log('Fail:', error)
|
console.log('Fail:', error)
|
||||||
})
|
})
|
||||||
|
|
||||||
const flashResults = {}
|
|
||||||
ipc.server.on('done', (results) => {
|
ipc.server.on('done', (results) => {
|
||||||
_.merge(flashResults, results)
|
_.merge(flashResults, results)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipc.server.on('state', onProgress)
|
ipc.server.on('state', (progress) => {
|
||||||
|
flashResults.devices.succeeded = progress.succeeded
|
||||||
|
flashResults.devices.failed = progress.failed
|
||||||
|
onProgress(progress)
|
||||||
|
})
|
||||||
|
|
||||||
ipc.server.on('ready', (data, socket) => {
|
ipc.server.on('ready', (data, socket) => {
|
||||||
ipc.server.emit(socket, 'write', {
|
ipc.server.emit(socket, 'write', {
|
||||||
|
@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
const _ = require('lodash')
|
||||||
const settings = require('../../../models/settings')
|
const settings = require('../../../models/settings')
|
||||||
const flashState = require('../../../../../shared/models/flash-state')
|
const flashState = require('../../../../../shared/models/flash-state')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../../../shared/models/selection-state')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
|
const messages = require('../../../../../shared/messages')
|
||||||
|
|
||||||
module.exports = function ($state) {
|
module.exports = function ($state) {
|
||||||
/**
|
/**
|
||||||
@ -30,11 +32,13 @@ module.exports = function ($state) {
|
|||||||
this.settings = settings
|
this.settings = settings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Source checksum
|
* @summary Flash state
|
||||||
* @type {String}
|
* @type {Object}
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
this.checksum = flashState.getLastFlashSourceChecksum()
|
this.flash = flashState
|
||||||
|
|
||||||
|
this.progressMessage = messages.progress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Restart the flashing process
|
* @summary Restart the flashing process
|
||||||
@ -55,4 +59,22 @@ module.exports = function ($state) {
|
|||||||
analytics.logEvent('Restart', options)
|
analytics.logEvent('Restart', options)
|
||||||
$state.go('main')
|
$state.go('main')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Format the result errors with newlines
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {String} formatted errors
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const errors = FinishController.formattedErrors()
|
||||||
|
* console.log(errors)
|
||||||
|
*/
|
||||||
|
this.formattedErrors = () => {
|
||||||
|
const errors = _.map(_.get(flashState.getFlashResults(), [ 'results', 'errors' ]), (error) => {
|
||||||
|
return `${error.device}: ${error.message || error.code}`
|
||||||
|
})
|
||||||
|
return errors.join('\n')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,3 +124,24 @@
|
|||||||
height: 39px;
|
height: 39px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inline-flex {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-baseline {
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-finish .tick--success {
|
||||||
|
/* hack(Shou): for some reason the height is stretched */
|
||||||
|
height: 28.9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-wrap {
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
<div class="page-finish row around-xs">
|
<div class="page-finish row around-xs">
|
||||||
<div class="col-xs">
|
<div class="col-xs">
|
||||||
<div class="box center">
|
<div class="box center">
|
||||||
<div class="col-xs-5">
|
<div class="col-xs-5 inline-flex items-baseline">
|
||||||
<h3 class="title"><span class="tick tick--success space-right-tiny"></span> Flash Complete!</h3>
|
<span class="tick tick--success space-right-tiny"></span>
|
||||||
|
<div uib-tooltip="{{ finish.formattedErrors() }}" tooltip-placement="bottom" class="title-wrap">
|
||||||
|
<h3 class="title">Flash Complete!</h3>
|
||||||
|
<div class="target-status-line target-status-{{ type }}"
|
||||||
|
ng-repeat="(type, quantity) in finish.flash.getFlashResults().devices">
|
||||||
|
<span class="target-status-dot"></span>
|
||||||
|
<span class="target-status-quantity">{{ quantity }}</span>
|
||||||
|
<span class="target-status-message">{{ finish.progressMessage[type](quantity) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-4">
|
||||||
|
@ -130,15 +130,15 @@ svg-icon > img[disabled] {
|
|||||||
|
|
||||||
.target-status-line {
|
.target-status-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: baseline;
|
||||||
font-size: 10px;
|
font-size: 11px;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
|
||||||
> .target-status-dot {
|
> .target-status-dot {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-right: 5px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.target-status-succeeded > .target-status-dot {
|
&.target-status-succeeded > .target-status-dot {
|
||||||
@ -151,11 +151,11 @@ svg-icon > img[disabled] {
|
|||||||
> .target-status-quantity {
|
> .target-status-quantity {
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
min-width: 32px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .target-status-message {
|
> .target-status-message {
|
||||||
color: gray;
|
color: gray;
|
||||||
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6595,24 +6595,24 @@ svg-icon > img[disabled] {
|
|||||||
|
|
||||||
.target-status-line {
|
.target-status-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: baseline;
|
||||||
font-size: 10px;
|
font-size: 11px;
|
||||||
font-family: inherit; }
|
font-family: inherit; }
|
||||||
.target-status-line > .target-status-dot {
|
.target-status-line > .target-status-dot {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-right: 5px; }
|
margin-right: 6px; }
|
||||||
.target-status-line.target-status-succeeded > .target-status-dot {
|
.target-status-line.target-status-succeeded > .target-status-dot {
|
||||||
background-color: #5fb835; }
|
background-color: #5fb835; }
|
||||||
.target-status-line.target-status-failed > .target-status-dot {
|
.target-status-line.target-status-failed > .target-status-dot {
|
||||||
background-color: #d9534f; }
|
background-color: #d9534f; }
|
||||||
.target-status-line > .target-status-quantity {
|
.target-status-line > .target-status-quantity {
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: bold;
|
font-weight: bold; }
|
||||||
min-width: 32px; }
|
|
||||||
.target-status-line > .target-status-message {
|
.target-status-line > .target-status-message {
|
||||||
color: gray; }
|
color: gray;
|
||||||
|
margin-left: 6px; }
|
||||||
|
|
||||||
.tooltip-inner {
|
.tooltip-inner {
|
||||||
white-space: pre-line; }
|
white-space: pre-line; }
|
||||||
@ -6740,6 +6740,21 @@ svg-icon > img[disabled] {
|
|||||||
border-top: none;
|
border-top: none;
|
||||||
height: 39px; }
|
height: 39px; }
|
||||||
|
|
||||||
|
.inline-flex {
|
||||||
|
display: inline-flex; }
|
||||||
|
|
||||||
|
.items-baseline {
|
||||||
|
align-items: baseline; }
|
||||||
|
|
||||||
|
.page-finish .tick--success {
|
||||||
|
/* hack(Shou): for some reason the height is stretched */
|
||||||
|
height: 28.9px; }
|
||||||
|
|
||||||
|
.title-wrap {
|
||||||
|
margin-left: 5px; }
|
||||||
|
.title-wrap > .title {
|
||||||
|
margin-bottom: 3px; }
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
src: url("../../../node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff");
|
src: url("../../../node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff");
|
||||||
|
@ -636,7 +636,13 @@ class ImageWriter extends EventEmitter {
|
|||||||
this.emit('finish', {
|
this.emit('finish', {
|
||||||
bytesRead: this.bytesRead,
|
bytesRead: this.bytesRead,
|
||||||
bytesWritten: this.bytesWritten,
|
bytesWritten: this.bytesWritten,
|
||||||
checksum: this.checksum
|
checksum: this.checksum,
|
||||||
|
errors: Array.from(this.destinations).filter(([ device, dest ]) => {
|
||||||
|
return dest.error
|
||||||
|
}).map(([ device, dest ]) => {
|
||||||
|
dest.error.device = device
|
||||||
|
return dest.error
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,8 @@ exports.toJSON = (error) => {
|
|||||||
syscall: errorObject.syscall,
|
syscall: errorObject.syscall,
|
||||||
errno: errorObject.errno,
|
errno: errorObject.errno,
|
||||||
stdout: errorObject.stdout,
|
stdout: errorObject.stdout,
|
||||||
stderr: errorObject.stderr
|
stderr: errorObject.stderr,
|
||||||
|
device: errorObject.device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,13 +34,13 @@ module.exports = {
|
|||||||
|
|
||||||
succeeded: (quantity) => {
|
succeeded: (quantity) => {
|
||||||
// eslint-disable-next-line no-magic-numbers
|
// eslint-disable-next-line no-magic-numbers
|
||||||
const plural = quantity > 1 ? 's' : ''
|
const plural = quantity === 1 ? '' : 's'
|
||||||
return `Succeeded device${plural}`
|
return `Succeeded device${plural}`
|
||||||
},
|
},
|
||||||
|
|
||||||
failed: (quantity) => {
|
failed: (quantity) => {
|
||||||
// eslint-disable-next-line no-magic-numbers
|
// eslint-disable-next-line no-magic-numbers
|
||||||
const plural = quantity > 1 ? 's' : ''
|
const plural = quantity === 1 ? '' : 's'
|
||||||
return `Failed device${plural}`
|
return `Failed device${plural}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,8 @@ angularValidate.validate(
|
|||||||
// External
|
// External
|
||||||
'hide-if-state',
|
'hide-if-state',
|
||||||
'show-if-state',
|
'show-if-state',
|
||||||
'uib-tooltip'
|
'uib-tooltip',
|
||||||
|
'tooltip-placement'
|
||||||
|
|
||||||
],
|
],
|
||||||
angular: true,
|
angular: true,
|
||||||
|
@ -651,7 +651,8 @@ describe('Shared: Errors', function () {
|
|||||||
stdout: undefined,
|
stdout: undefined,
|
||||||
syscall: undefined,
|
syscall: undefined,
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
errno: undefined
|
errno: undefined,
|
||||||
|
device: undefined
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -669,7 +670,8 @@ describe('Shared: Errors', function () {
|
|||||||
stdout: undefined,
|
stdout: undefined,
|
||||||
syscall: undefined,
|
syscall: undefined,
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
errno: undefined
|
errno: undefined,
|
||||||
|
device: undefined
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -687,7 +689,8 @@ describe('Shared: Errors', function () {
|
|||||||
stdout: undefined,
|
stdout: undefined,
|
||||||
syscall: undefined,
|
syscall: undefined,
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
errno: undefined
|
errno: undefined,
|
||||||
|
device: undefined
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -706,7 +709,8 @@ describe('Shared: Errors', function () {
|
|||||||
stdout: undefined,
|
stdout: undefined,
|
||||||
syscall: undefined,
|
syscall: undefined,
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
errno: undefined
|
errno: undefined,
|
||||||
|
device: undefined
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -724,7 +728,8 @@ describe('Shared: Errors', function () {
|
|||||||
stdout: undefined,
|
stdout: undefined,
|
||||||
syscall: undefined,
|
syscall: undefined,
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
errno: undefined
|
errno: undefined,
|
||||||
|
device: undefined
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -741,7 +746,8 @@ describe('Shared: Errors', function () {
|
|||||||
stdout: undefined,
|
stdout: undefined,
|
||||||
syscall: undefined,
|
syscall: undefined,
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
errno: undefined
|
errno: undefined,
|
||||||
|
device: undefined
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user