mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-17 16:26:31 +00:00
Convert the drive selection step to React
Change-type: patch Changelog-entry: Convert the drive selection step to React Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
This commit is contained in:
parent
1d15d582d9
commit
abfc6be84d
243
lib/gui/app/pages/main/DriveSelector.jsx
Normal file
243
lib/gui/app/pages/main/DriveSelector.jsx
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 resin.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const _ = require('lodash')
|
||||||
|
const prettyBytes = require('pretty-bytes')
|
||||||
|
const propTypes = require('prop-types')
|
||||||
|
const React = require('react')
|
||||||
|
const driveConstraints = require('../../../../shared/drive-constraints')
|
||||||
|
const utils = require('../../../../shared/utils')
|
||||||
|
const TargetSelector = require('../../components/drive-selector/target-selector')
|
||||||
|
const SvgIcon = require('../../components/svg-icon/svg-icon.jsx')
|
||||||
|
const selectionState = require('../../models/selection-state')
|
||||||
|
const settings = require('../../models/settings')
|
||||||
|
const store = require('../../models/store')
|
||||||
|
const analytics = require('../../modules/analytics')
|
||||||
|
const exceptionReporter = require('../../modules/exception-reporter')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get drive title based on device quantity
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {String} - drives title
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* console.log(getDrivesTitle())
|
||||||
|
* > 'Multiple Drives (4)'
|
||||||
|
*/
|
||||||
|
const getDrivesTitle = () => {
|
||||||
|
const drives = selectionState.getSelectedDrives()
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-magic-numbers
|
||||||
|
if (drives.length === 1) {
|
||||||
|
return _.head(drives).description || 'Untitled Device'
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-magic-numbers
|
||||||
|
if (drives.length === 0) {
|
||||||
|
return 'No targets found'
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${drives.length} Devices`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get drive subtitle
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {String} - drives subtitle
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* console.log(getDrivesSubtitle())
|
||||||
|
* > '32 GB'
|
||||||
|
*/
|
||||||
|
const getDrivesSubtitle = () => {
|
||||||
|
const drive = selectionState.getCurrentDrive()
|
||||||
|
|
||||||
|
if (drive) {
|
||||||
|
return prettyBytes(drive.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Please insert at least one target device'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get drive list label
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {String} - 'list' of drives separated by newlines
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* console.log(getDriveListLabel())
|
||||||
|
* > 'My Drive (/dev/disk1)\nMy Other Drive (/dev/disk2)'
|
||||||
|
*/
|
||||||
|
const getDriveListLabel = () => {
|
||||||
|
return _.join(_.map(selectionState.getSelectedDrives(), (drive) => {
|
||||||
|
return `${drive.description} (${drive.displayName})`
|
||||||
|
}), '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Open drive selector
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
* @param {Object} DriveSelectorService - drive selector service
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* openDriveSelector(DriveSelectorService);
|
||||||
|
*/
|
||||||
|
const openDriveSelector = (DriveSelectorService) => {
|
||||||
|
DriveSelectorService.open().then((drive) => {
|
||||||
|
if (!drive) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
selectionState.selectDrive(drive.device)
|
||||||
|
|
||||||
|
analytics.logEvent('Select drive', {
|
||||||
|
device: drive.device,
|
||||||
|
unsafeMode: settings.get('unsafeMode') && !settings.get('disableUnsafeMode'),
|
||||||
|
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
|
||||||
|
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
|
||||||
|
})
|
||||||
|
}).catch(exceptionReporter.report)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Reselect a drive
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
* @param {Object} DriveSelectorService - drive selector service
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* reselectDrive(DriveSelectorService);
|
||||||
|
*/
|
||||||
|
const reselectDrive = (DriveSelectorService) => {
|
||||||
|
openDriveSelector(DriveSelectorService)
|
||||||
|
analytics.logEvent('Reselect drive', {
|
||||||
|
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
|
||||||
|
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get memoized selected drives
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* getMemoizedSelectedDrives()
|
||||||
|
*/
|
||||||
|
const getMemoizedSelectedDrives = utils.memoize(selectionState.getSelectedDrives, _.isEqual)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Should the drive selection button be shown
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* shouldShowDrivesButton()
|
||||||
|
*/
|
||||||
|
const shouldShowDrivesButton = () => {
|
||||||
|
return !settings.get('disableExplicitDriveSelection')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDriveSelectionStateSlice = () => ({
|
||||||
|
showDrivesButton: shouldShowDrivesButton(),
|
||||||
|
driveListLabel: getDriveListLabel(),
|
||||||
|
targets: getMemoizedSelectedDrives()
|
||||||
|
})
|
||||||
|
|
||||||
|
const DriveSelector = ({
|
||||||
|
webviewShowing,
|
||||||
|
disabled,
|
||||||
|
nextStepDisabled,
|
||||||
|
hasDrive,
|
||||||
|
flashing,
|
||||||
|
DriveSelectorService
|
||||||
|
}) => {
|
||||||
|
// TODO: inject these from redux-connector
|
||||||
|
const [ {
|
||||||
|
showDrivesButton,
|
||||||
|
driveListLabel,
|
||||||
|
targets
|
||||||
|
}, setStateSlice ] = React.useState(getDriveSelectionStateSlice())
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
return store.observe(() => {
|
||||||
|
setStateSlice(getDriveSelectionStateSlice())
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const showStepConnectingLines = !webviewShowing || !flashing
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="box text-center relative">
|
||||||
|
|
||||||
|
{showStepConnectingLines && (
|
||||||
|
<React.Fragment>
|
||||||
|
<div
|
||||||
|
className="step-border-left"
|
||||||
|
disabled={disabled}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className="step-border-right"
|
||||||
|
disabled={nextStepDisabled}
|
||||||
|
></div>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="center-block">
|
||||||
|
<SvgIcon
|
||||||
|
paths={[ '../../assets/drive.svg' ]}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-vertical-large">
|
||||||
|
<TargetSelector
|
||||||
|
disabled={disabled}
|
||||||
|
show={!hasDrive && showDrivesButton}
|
||||||
|
tooltip={driveListLabel}
|
||||||
|
selection={selectionState}
|
||||||
|
openDriveSelector={() => openDriveSelector(DriveSelectorService)}
|
||||||
|
reselectDrive={() => reselectDrive(DriveSelectorService)}
|
||||||
|
flashing={flashing}
|
||||||
|
constraints={driveConstraints}
|
||||||
|
targets={targets}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
DriveSelector.propTypes = {
|
||||||
|
webviewShowing: propTypes.bool,
|
||||||
|
disabled: propTypes.bool,
|
||||||
|
nextStepDisabled: propTypes.bool,
|
||||||
|
hasDrive: propTypes.bool,
|
||||||
|
flashing: propTypes.bool
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DriveSelector
|
@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 resin.io
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const _ = require('lodash')
|
|
||||||
const angular = require('angular')
|
|
||||||
const prettyBytes = require('pretty-bytes')
|
|
||||||
const store = require('../../../models/store')
|
|
||||||
const settings = require('../../../models/settings')
|
|
||||||
const selectionState = require('../../../models/selection-state')
|
|
||||||
const analytics = require('../../../modules/analytics')
|
|
||||||
const exceptionReporter = require('../../../modules/exception-reporter')
|
|
||||||
const utils = require('../../../../../shared/utils')
|
|
||||||
|
|
||||||
module.exports = function (DriveSelectorService) {
|
|
||||||
/**
|
|
||||||
* @summary Get drive title based on device quantity
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @returns {String} - drives title
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* console.log(DriveSelectionController.getDrivesTitle())
|
|
||||||
* > 'Multiple Drives (4)'
|
|
||||||
*/
|
|
||||||
this.getDrivesTitle = () => {
|
|
||||||
const drives = selectionState.getSelectedDrives()
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-magic-numbers
|
|
||||||
if (drives.length === 1) {
|
|
||||||
return _.head(drives).description || 'Untitled Device'
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-magic-numbers
|
|
||||||
if (drives.length === 0) {
|
|
||||||
return 'No targets found'
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${drives.length} Devices`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get drive subtitle
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @returns {String} - drives subtitle
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* console.log(DriveSelectionController.getDrivesSubtitle())
|
|
||||||
* > '32 GB'
|
|
||||||
*/
|
|
||||||
this.getDrivesSubtitle = () => {
|
|
||||||
const drive = selectionState.getCurrentDrive()
|
|
||||||
|
|
||||||
if (drive) {
|
|
||||||
return prettyBytes(drive.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Please insert at least one target device'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get drive list label
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @returns {String} - 'list' of drives separated by newlines
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* console.log(DriveSelectionController.getDriveListLabel())
|
|
||||||
* > 'My Drive (/dev/disk1)\nMy Other Drive (/dev/disk2)'
|
|
||||||
*/
|
|
||||||
this.getDriveListLabel = () => {
|
|
||||||
return _.join(_.map(selectionState.getSelectedDrives(), (drive) => {
|
|
||||||
return `${drive.description} (${drive.displayName})`
|
|
||||||
}), '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Open drive selector
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* DriveSelectionController.openDriveSelector();
|
|
||||||
*/
|
|
||||||
this.openDriveSelector = () => {
|
|
||||||
DriveSelectorService.open().then((drive) => {
|
|
||||||
if (!drive) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
selectionState.selectDrive(drive.device)
|
|
||||||
|
|
||||||
analytics.logEvent('Select drive', {
|
|
||||||
device: drive.device,
|
|
||||||
unsafeMode: settings.get('unsafeMode') && !settings.get('disableUnsafeMode'),
|
|
||||||
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
|
|
||||||
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
|
|
||||||
})
|
|
||||||
}).catch(exceptionReporter.report)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Reselect a drive
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* DriveSelectionController.reselectDrive();
|
|
||||||
*/
|
|
||||||
this.reselectDrive = () => {
|
|
||||||
this.openDriveSelector()
|
|
||||||
analytics.logEvent('Reselect drive', {
|
|
||||||
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
|
|
||||||
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get memoized selected drives
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* DriveSelectionController.getMemoizedSelectedDrives()
|
|
||||||
*/
|
|
||||||
this.getMemoizedSelectedDrives = utils.memoize(selectionState.getSelectedDrives, angular.equals)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Should the drive selection button be shown
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @returns {Boolean}
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* DriveSelectionController.shouldShowDrivesButton()
|
|
||||||
*/
|
|
||||||
this.shouldShowDrivesButton = () => {
|
|
||||||
return !settings.get('disableExplicitDriveSelection')
|
|
||||||
}
|
|
||||||
}
|
|
@ -49,7 +49,16 @@ const MainPage = angular.module(MODULE_NAME, [
|
|||||||
])
|
])
|
||||||
|
|
||||||
MainPage.controller('MainController', require('./controllers/main'))
|
MainPage.controller('MainController', require('./controllers/main'))
|
||||||
MainPage.controller('DriveSelectionController', require('./controllers/drive-selection'))
|
MainPage.component('driveSelector', react2angular(require('./DriveSelector.jsx'),
|
||||||
|
[
|
||||||
|
'webviewShowing',
|
||||||
|
'disabled',
|
||||||
|
'nextStepDisabled',
|
||||||
|
'hasDrive',
|
||||||
|
'flashing'
|
||||||
|
],
|
||||||
|
[ 'DriveSelectorService' ]
|
||||||
|
))
|
||||||
MainPage.component('flash', react2angular(require('./Flash.jsx'),
|
MainPage.component('flash', react2angular(require('./Flash.jsx'),
|
||||||
[ 'shouldFlashStepBeDisabled', 'lastFlashErrorCode', 'progressMessage' ],
|
[ 'shouldFlashStepBeDisabled', 'lastFlashErrorCode', 'progressMessage' ],
|
||||||
[ '$timeout', '$state', 'WarningModalService', 'DriveSelectorService', 'FlashErrorModalService' ]))
|
[ '$timeout', '$state', 'WarningModalService', 'DriveSelectorService', 'FlashErrorModalService' ]))
|
||||||
|
@ -7,33 +7,14 @@
|
|||||||
</image-selector>
|
</image-selector>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs" ng-controller="DriveSelectionController as drive">
|
<div class="col-xs">
|
||||||
<div class="box text-center relative">
|
<drive-selector
|
||||||
|
webview-showing="main.isWebviewShowing"
|
||||||
<div class="step-border-left" ng-disabled="main.shouldDriveStepBeDisabled()" ng-hide="main.state.isFlashing() && main.isWebviewShowing"></div>
|
|
||||||
<div class="step-border-right" ng-disabled="main.shouldFlashStepBeDisabled()" ng-hide="main.state.isFlashing() && main.isWebviewShowing"></div>
|
|
||||||
|
|
||||||
<div class="center-block">
|
|
||||||
<svg-icon paths="[ '../../assets/drive.svg' ]"
|
|
||||||
disabled="main.shouldDriveStepBeDisabled()"></svg-icon>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="space-vertical-large">
|
|
||||||
<target-selector
|
|
||||||
disabled="main.shouldDriveStepBeDisabled()"
|
disabled="main.shouldDriveStepBeDisabled()"
|
||||||
show="!main.selection.hasDrive() && drive.shouldShowDrivesButton()"
|
next-step-disabled="main.shouldFlashStepBeDisabled()"
|
||||||
tooltip="drive.getDriveListLabel()"
|
has-drive="main.selection.hasDrive()"
|
||||||
selection="main.selection"
|
|
||||||
open-drive-selector="drive.openDriveSelector"
|
|
||||||
reselect-drive="drive.reselectDrive"
|
|
||||||
flashing="main.state.isFlashing()"
|
flashing="main.state.isFlashing()"
|
||||||
constraints="main.constraints"
|
></drive-selector>
|
||||||
targets="drive.getMemoizedSelectedDrives()"
|
|
||||||
>
|
|
||||||
</target-selector>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@ -164,89 +164,6 @@ describe('Browser: MainPage', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('DriveSelectionController', function () {
|
|
||||||
let $controller
|
|
||||||
let DriveSelectionController
|
|
||||||
|
|
||||||
const drivePaths = process.platform === 'win32'
|
|
||||||
? [ '\\\\.\\PhysicalDrive1', '\\\\.\\PhysicalDrive2', '\\\\.\\PhysicalDrive3' ]
|
|
||||||
: [ '/dev/disk1', '/dev/disk2', '/dev/disk3' ]
|
|
||||||
const drives = [
|
|
||||||
{
|
|
||||||
device: drivePaths[0],
|
|
||||||
description: 'My Drive',
|
|
||||||
size: 123456789,
|
|
||||||
displayName: drivePaths[0],
|
|
||||||
mountpoints: [ drivePaths[0] ],
|
|
||||||
isSystem: false,
|
|
||||||
isReadOnly: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
device: drivePaths[1],
|
|
||||||
description: 'My Other Drive',
|
|
||||||
size: 987654321,
|
|
||||||
displayName: drivePaths[1],
|
|
||||||
mountpoints: [ drivePaths[1] ],
|
|
||||||
isSystem: false,
|
|
||||||
isReadOnly: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
device: drivePaths[2],
|
|
||||||
size: 987654321,
|
|
||||||
displayName: drivePaths[2],
|
|
||||||
mountpoints: [],
|
|
||||||
isSystem: false,
|
|
||||||
isReadOnly: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
beforeEach(angular.mock.inject(function (_$controller_) {
|
|
||||||
$controller = _$controller_
|
|
||||||
DriveSelectionController = $controller('DriveSelectionController', {
|
|
||||||
$scope: {}
|
|
||||||
})
|
|
||||||
|
|
||||||
availableDrives.setDrives(drives)
|
|
||||||
}))
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
selectionState.clear()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('.getDrivesTitle()', function () {
|
|
||||||
it('should return the drive description when there is one drive', function () {
|
|
||||||
selectionState.selectDrive(drives[0].device)
|
|
||||||
m.chai.expect(DriveSelectionController.getDrivesTitle()).to.equal(drives[0].description)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return untitled when there is no description', function () {
|
|
||||||
selectionState.selectDrive(drives[2].device)
|
|
||||||
m.chai.expect(DriveSelectionController.getDrivesTitle()).to.equal('Untitled Device')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return a consolidated title with quantity when there are multiple drives', function () {
|
|
||||||
selectionState.selectDrive(drives[0].device)
|
|
||||||
selectionState.selectDrive(drives[1].device)
|
|
||||||
m.chai.expect(DriveSelectionController.getDrivesTitle()).to.equal('2 Devices')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('.getDriveListLabel()', function () {
|
|
||||||
it('should return the drive description and display name when there is one drive', function () {
|
|
||||||
const label = `${drives[0].description} (${drives[0].displayName})`
|
|
||||||
selectionState.selectDrive(drives[0].device)
|
|
||||||
m.chai.expect(DriveSelectionController.getDriveListLabel()).to.equal(label)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return drive descriptions and display names of all drives separated by newlines', function () {
|
|
||||||
const label = `${drives[0].description} (${drives[0].displayName})\n${drives[1].description} (${drives[1].displayName})`
|
|
||||||
selectionState.selectDrive(drives[0].device)
|
|
||||||
selectionState.selectDrive(drives[1].device)
|
|
||||||
m.chai.expect(DriveSelectionController.getDriveListLabel()).to.equal(label)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('page template', function () {
|
describe('page template', function () {
|
||||||
let $state
|
let $state
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user