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:
Benedict Aas 2018-04-17 15:52:02 +01:00 committed by GitHub
parent a044d2fe86
commit 32bc615e78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 118 additions and 28 deletions

View File

@ -126,16 +126,25 @@ exports.performWrite = (image, drives, onProgress) => {
console.log(message)
})
const flashResults = {
devices: {
succeeded: 0,
failed: 0
}
}
ipc.server.on('fail', (error) => {
console.log('Fail:', error)
})
const flashResults = {}
ipc.server.on('done', (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.emit(socket, 'write', {

View File

@ -16,10 +16,12 @@
'use strict'
const _ = require('lodash')
const settings = require('../../../models/settings')
const flashState = require('../../../../../shared/models/flash-state')
const selectionState = require('../../../../../shared/models/selection-state')
const analytics = require('../../../modules/analytics')
const messages = require('../../../../../shared/messages')
module.exports = function ($state) {
/**
@ -30,11 +32,13 @@ module.exports = function ($state) {
this.settings = settings
/**
* @summary Source checksum
* @type {String}
* @summary Flash state
* @type {Object}
* @public
*/
this.checksum = flashState.getLastFlashSourceChecksum()
this.flash = flashState
this.progressMessage = messages.progress
/**
* @summary Restart the flashing process
@ -55,4 +59,22 @@ module.exports = function ($state) {
analytics.logEvent('Restart', options)
$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')
}
}

View File

@ -124,3 +124,24 @@
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;
}
}

View File

@ -1,8 +1,17 @@
<div class="page-finish row around-xs">
<div class="col-xs">
<div class="box center">
<div class="col-xs-5">
<h3 class="title"><span class="tick tick--success space-right-tiny"></span> Flash Complete!</h3>
<div class="col-xs-5 inline-flex items-baseline">
<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 class="col-xs-4">

View File

@ -130,15 +130,15 @@ svg-icon > img[disabled] {
.target-status-line {
display: flex;
align-items: center;
font-size: 10px;
align-items: baseline;
font-size: 11px;
font-family: inherit;
> .target-status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 5px;
margin-right: 6px;
}
&.target-status-succeeded > .target-status-dot {
@ -151,11 +151,11 @@ svg-icon > img[disabled] {
> .target-status-quantity {
color: white;
font-weight: bold;
min-width: 32px;
}
> .target-status-message {
color: gray;
margin-left: 6px;
}
}

View File

@ -6595,24 +6595,24 @@ svg-icon > img[disabled] {
.target-status-line {
display: flex;
align-items: center;
font-size: 10px;
align-items: baseline;
font-size: 11px;
font-family: inherit; }
.target-status-line > .target-status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 5px; }
margin-right: 6px; }
.target-status-line.target-status-succeeded > .target-status-dot {
background-color: #5fb835; }
.target-status-line.target-status-failed > .target-status-dot {
background-color: #d9534f; }
.target-status-line > .target-status-quantity {
color: white;
font-weight: bold;
min-width: 32px; }
font-weight: bold; }
.target-status-line > .target-status-message {
color: gray; }
color: gray;
margin-left: 6px; }
.tooltip-inner {
white-space: pre-line; }
@ -6740,6 +6740,21 @@ svg-icon > img[disabled] {
border-top: none;
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-family: Roboto;
src: url("../../../node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff");

View File

@ -636,7 +636,13 @@ class ImageWriter extends EventEmitter {
this.emit('finish', {
bytesRead: this.bytesRead,
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
})
})
})
}

View File

@ -345,7 +345,8 @@ exports.toJSON = (error) => {
syscall: errorObject.syscall,
errno: errorObject.errno,
stdout: errorObject.stdout,
stderr: errorObject.stderr
stderr: errorObject.stderr,
device: errorObject.device
}
}

View File

@ -34,13 +34,13 @@ module.exports = {
succeeded: (quantity) => {
// eslint-disable-next-line no-magic-numbers
const plural = quantity > 1 ? 's' : ''
const plural = quantity === 1 ? '' : 's'
return `Succeeded device${plural}`
},
failed: (quantity) => {
// eslint-disable-next-line no-magic-numbers
const plural = quantity > 1 ? 's' : ''
const plural = quantity === 1 ? '' : 's'
return `Failed device${plural}`
}
},

View File

@ -35,7 +35,8 @@ angularValidate.validate(
// External
'hide-if-state',
'show-if-state',
'uib-tooltip'
'uib-tooltip',
'tooltip-placement'
],
angular: true,

View File

@ -651,7 +651,8 @@ describe('Shared: Errors', function () {
stdout: undefined,
syscall: undefined,
name: 'Error',
errno: undefined
errno: undefined,
device: undefined
})
})
@ -669,7 +670,8 @@ describe('Shared: Errors', function () {
stdout: undefined,
syscall: undefined,
name: 'Error',
errno: undefined
errno: undefined,
device: undefined
})
})
@ -687,7 +689,8 @@ describe('Shared: Errors', function () {
stdout: undefined,
syscall: undefined,
name: 'Error',
errno: undefined
errno: undefined,
device: undefined
})
})
@ -706,7 +709,8 @@ describe('Shared: Errors', function () {
stdout: undefined,
syscall: undefined,
name: 'Error',
errno: undefined
errno: undefined,
device: undefined
})
})
@ -724,7 +728,8 @@ describe('Shared: Errors', function () {
stdout: undefined,
syscall: undefined,
name: 'Error',
errno: undefined
errno: undefined,
device: undefined
})
})
@ -741,7 +746,8 @@ describe('Shared: Errors', function () {
stdout: undefined,
syscall: undefined,
name: 'Error',
errno: undefined
errno: undefined,
device: undefined
})
})
})