Convert selection-state.js to typescript

Change-type: patch
This commit is contained in:
Alexis Svinartchouk 2020-01-09 18:47:41 +01:00 committed by Lorenzo Alberto Maria Ambrosi
parent fd127da342
commit d0d4ee843d
6 changed files with 180 additions and 583 deletions

View File

@ -71,7 +71,7 @@ const toggleDrive = (drive) => {
if (canChangeDriveSelectionState) {
analytics.logEvent('Toggle drive', {
drive,
previouslySelected: selectionState.isCurrentDrive(availableDrives.device),
previouslySelected: selectionState.isDriveSelected(availableDrives.device),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})

View File

@ -1,440 +0,0 @@
/*
* Copyright 2016 balena.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')
// eslint-disable-next-line node/no-missing-require
const { Actions, store } = require('./store')
// eslint-disable-next-line node/no-missing-require
const availableDrives = require('./available-drives')
/**
* @summary Select a drive by its device path
* @function
* @public
*
* @param {String} driveDevice - drive device
*
* @example
* selectionState.selectDrive('/dev/disk2');
*/
exports.selectDrive = (driveDevice) => {
store.dispatch({
type: Actions.SELECT_DRIVE,
data: driveDevice
})
}
/**
* @summary Toggle drive selection
* @function
* @public
*
* @param {String} driveDevice - drive device
*
* @example
* selectionState.toggleDrive('/dev/disk2');
*/
exports.toggleDrive = (driveDevice) => {
if (exports.isDriveSelected(driveDevice)) {
exports.deselectDrive(driveDevice)
} else {
exports.selectDrive(driveDevice)
}
}
/**
* @summary Deselect all other drives and keep the current drive's status
* @function
* @public
* @deprecated
*
* @description
* This is a temporary function during the transition to multi-writes,
* remove this and its uses when multi-selection should become user-facing.
*
* @param {String} driveDevice - drive device identifier
*
* @example
* console.log(selectionState.getSelectedDevices())
* > [ '/dev/disk1', '/dev/disk2', '/dev/disk3' ]
* selectionState.deselectOtherDrives('/dev/disk2')
* console.log(selectionState.getSelectedDevices())
* > [ '/dev/disk2' ]
*/
exports.deselectOtherDrives = (driveDevice) => {
if (exports.isDriveSelected(driveDevice)) {
const otherDevices = _.reject(exports.getSelectedDevices(), _.partial(_.isEqual, driveDevice))
_.each(otherDevices, exports.deselectDrive)
} else {
exports.deselectAllDrives()
}
}
/**
* @summary Select an image
* @function
* @public
*
* @param {Object} image - image
*
* @example
* selectionState.selectImage({
* path: 'foo.img',
* size: 1000000000,
* compressedSize: 1000000000,
* isSizeEstimated: false,
* });
*/
exports.selectImage = (image) => {
store.dispatch({
type: Actions.SELECT_IMAGE,
data: image
})
}
/**
* @summary Get all selected drives' devices
* @function
* @public
*
* @returns {String[]} selected drives' devices
*
* @example
* for (driveDevice of selectionState.getSelectedDevices()) {
* console.log(driveDevice)
* }
* > '/dev/disk1'
* > '/dev/disk2'
*/
exports.getSelectedDevices = () => {
return store.getState().getIn([ 'selection', 'devices' ]).toJS()
}
/**
* @summary Get all selected drive objects
* @function
* @public
*
* @returns {Object[]} selected drive objects
*
* @example
* for (drive of selectionState.getSelectedDrives()) {
* console.log(drive)
* }
* > '{ device: '/dev/disk1', size: 123456789, ... }'
* > '{ device: '/dev/disk2', size: 987654321, ... }'
*/
exports.getSelectedDrives = () => {
const drives = availableDrives.getDrives()
return _.map(exports.getSelectedDevices(), (device) => {
return _.find(drives, { device })
})
}
/**
* @summary Get the head of the list of selected drives
* @function
* @public
*
* @returns {Object} drive
*
* @example
* const drive = selectionState.getCurrentDrive();
* console.log(drive)
* > { device: '/dev/disk1', name: 'Flash drive', ... }
*/
exports.getCurrentDrive = () => {
const device = _.head(exports.getSelectedDevices())
return _.find(availableDrives.getDrives(), { device })
}
/**
* @summary Get the selected image
* @function
* @public
*
* @returns {Object} image
*
* @example
* const image = selectionState.getImage();
*/
exports.getImage = () => {
return _.get(store.getState().toJS(), [ 'selection', 'image' ])
}
/**
* @summary Get image path
* @function
* @public
*
* @returns {String} image path
*
* @example
* const imagePath = selectionState.getImagePath();
*/
exports.getImagePath = () => {
return _.get(store.getState().toJS(), [
'selection',
'image',
'path'
])
}
/**
* @summary Get image size
* @function
* @public
*
* @returns {Number} image size
*
* @example
* const imageSize = selectionState.getImageSize();
*/
exports.getImageSize = () => {
return _.get(store.getState().toJS(), [
'selection',
'image',
'size'
])
}
/**
* @summary Get image url
* @function
* @public
*
* @returns {String} image url
*
* @example
* const imageUrl = selectionState.getImageUrl();
*/
exports.getImageUrl = () => {
return _.get(store.getState().toJS(), [
'selection',
'image',
'url'
])
}
/**
* @summary Get image name
* @function
* @public
*
* @returns {String} image name
*
* @example
* const imageName = selectionState.getImageName();
*/
exports.getImageName = () => {
return _.get(store.getState().toJS(), [
'selection',
'image',
'name'
])
}
/**
* @summary Get image logo
* @function
* @public
*
* @returns {String} image logo
*
* @example
* const imageLogo = selectionState.getImageLogo();
*/
exports.getImageLogo = () => {
return _.get(store.getState().toJS(), [
'selection',
'image',
'logo'
])
}
/**
* @summary Get image support url
* @function
* @public
*
* @returns {String} image support url
*
* @example
* const imageSupportUrl = selectionState.getImageSupportUrl();
*/
exports.getImageSupportUrl = () => {
return _.get(store.getState().toJS(), [
'selection',
'image',
'supportUrl'
])
}
/**
* @summary Get image recommended drive size
* @function
* @public
*
* @returns {String} image recommended drive size
*
* @example
* const imageRecommendedDriveSize = selectionState.getImageRecommendedDriveSize();
*/
exports.getImageRecommendedDriveSize = () => {
return _.get(store.getState().toJS(), [
'selection',
'image',
'recommendedDriveSize'
])
}
/**
* @summary Check if there is a selected drive
* @function
* @public
*
* @returns {Boolean} whether there is a selected drive
*
* @example
* if (selectionState.hasDrive()) {
* console.log('There is a drive!');
* }
*/
exports.hasDrive = () => {
return Boolean(exports.getSelectedDevices().length)
}
/**
* @summary Check if there is a selected image
* @function
* @public
*
* @returns {Boolean} whether there is a selected image
*
* @example
* if (selectionState.hasImage()) {
* console.log('There is an image!');
* }
*/
exports.hasImage = () => {
return Boolean(exports.getImage())
}
/**
* @summary Remove drive from selection
* @function
* @public
*
* @param {String} driveDevice - drive device identifier
*
* @example
* selectionState.deselectDrive('/dev/sdc');
*
* @example
* selectionState.deselectDrive('\\\\.\\PHYSICALDRIVE3');
*/
exports.deselectDrive = (driveDevice) => {
store.dispatch({
type: Actions.DESELECT_DRIVE,
data: driveDevice
})
}
/**
* @summary Deselect image
* @function
* @public
*
* @example
* selectionState.deselectImage();
*/
exports.deselectImage = () => {
store.dispatch({
type: Actions.DESELECT_IMAGE
})
}
/**
* @summary Deselect all drives
* @function
* @public
*
* @example
* selectionState.deselectAllDrives()
*/
exports.deselectAllDrives = () => {
_.each(exports.getSelectedDevices(), exports.deselectDrive)
}
/**
* @summary Clear selections
* @function
* @public
*
* @example
* selectionState.clear();
*/
exports.clear = () => {
exports.deselectImage()
exports.deselectAllDrives()
}
/**
* @summary Check if a drive is the current drive
* @function
* @public
*
* @param {String} driveDevice - drive device
* @returns {Boolean} whether the drive is the current drive
*
* @example
* if (selectionState.isCurrentDrive('/dev/sdb')) {
* console.log('This is the current drive!');
* }
*/
exports.isCurrentDrive = (driveDevice) => {
if (!driveDevice) {
return false
}
return driveDevice === _.get(exports.getCurrentDrive(), [ 'device' ])
}
/**
* @summary Check whether a given device is selected.
* @function
* @public
*
* @param {String} driveDevice - drive device identifier
* @returns {Boolean}
*
* @example
* const isSelected = selectionState.isDriveSelected('/dev/sdb')
*
* if (isSelected) {
* selectionState.deselectDrive(driveDevice)
* }
*/
exports.isDriveSelected = (driveDevice) => {
if (!driveDevice) {
return false
}
const selectedDriveDevices = exports.getSelectedDevices()
return _.includes(selectedDriveDevices, driveDevice)
}

View File

@ -0,0 +1,161 @@
/*
* Copyright 2016 balena.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.
*/
import * as _ from 'lodash';
import * as availableDrives from './available-drives';
import { Actions, store } from './store';
/**
* @summary Select a drive by its device path
*/
export function selectDrive(driveDevice: string) {
store.dispatch({
type: Actions.SELECT_DRIVE,
data: driveDevice,
});
}
/**
* @summary Toggle drive selection
*/
export function toggleDrive(driveDevice: string) {
if (isDriveSelected(driveDevice)) {
deselectDrive(driveDevice);
} else {
selectDrive(driveDevice);
}
}
export function selectImage(image: any) {
store.dispatch({
type: Actions.SELECT_IMAGE,
data: image,
});
}
/**
* @summary Get all selected drives' devices
*/
export function getSelectedDevices(): string[] {
return store
.getState()
.getIn(['selection', 'devices'])
.toJS();
}
/**
* @summary Get all selected drive objects
*/
export function getSelectedDrives(): any[] {
const drives = availableDrives.getDrives();
return _.map(getSelectedDevices(), device => {
return _.find(drives, { device });
});
}
/**
* @summary Get the selected image
*/
export function getImage() {
return _.get(store.getState().toJS(), ['selection', 'image']);
}
export function getImagePath(): string {
return _.get(store.getState().toJS(), ['selection', 'image', 'path']);
}
export function getImageSize(): number {
return _.get(store.getState().toJS(), ['selection', 'image', 'size']);
}
export function getImageUrl(): string {
return _.get(store.getState().toJS(), ['selection', 'image', 'url']);
}
export function getImageName(): string {
return _.get(store.getState().toJS(), ['selection', 'image', 'name']);
}
export function getImageLogo(): string {
return _.get(store.getState().toJS(), ['selection', 'image', 'logo']);
}
export function getImageSupportUrl(): string {
return _.get(store.getState().toJS(), ['selection', 'image', 'supportUrl']);
}
export function getImageRecommendedDriveSize(): number {
return _.get(store.getState().toJS(), [
'selection',
'image',
'recommendedDriveSize',
]);
}
/**
* @summary Check if there is a selected drive
*/
export function hasDrive(): boolean {
return Boolean(getSelectedDevices().length);
}
/**
* @summary Check if there is a selected image
*/
export function hasImage(): boolean {
return Boolean(getImage());
}
/**
* @summary Remove drive from selection
*/
export function deselectDrive(driveDevice: string) {
store.dispatch({
type: Actions.DESELECT_DRIVE,
data: driveDevice,
});
}
export function deselectImage() {
store.dispatch({
type: Actions.DESELECT_IMAGE,
});
}
export function deselectAllDrives() {
_.each(getSelectedDevices(), deselectDrive);
}
/**
* @summary Clear selections
*/
export function clear() {
deselectImage();
deselectAllDrives();
}
/**
* @summary Check whether a given device is selected.
*/
export function isDriveSelected(driveDevice: string) {
if (!driveDevice) {
return false;
}
const selectedDriveDevices = getSelectedDevices();
return _.includes(selectedDriveDevices, driveDevice);
}

View File

@ -38,6 +38,7 @@ const analytics = require('../modules/analytics')
// eslint-disable-next-line node/no-missing-require
const { updateLock } = require('./update-lock')
const packageJSON = require('../../../../package.json')
// eslint-disable-next-line node/no-missing-require
const selectionState = require('../models/selection-state')
/**

View File

@ -20,6 +20,7 @@ const m = require('mochainon')
const path = require('path')
// eslint-disable-next-line node/no-missing-require
const availableDrives = require('../../../lib/gui/app/models/available-drives')
// eslint-disable-next-line node/no-missing-require
const selectionState = require('../../../lib/gui/app/models/selection-state')
// eslint-disable-next-line node/no-missing-require
const constraints = require('../../../lib/shared/drive-constraints')
@ -140,7 +141,7 @@ describe('Model: availableDrives', function () {
])
m.chai.expect(selectionState.hasDrive()).to.be.true
m.chai.expect(selectionState.getCurrentDrive().device).to.equal('/dev/sdb')
m.chai.expect(selectionState.getSelectedDevices()[0]).to.equal('/dev/sdb')
})
})
@ -211,16 +212,7 @@ describe('Model: availableDrives', function () {
}
])
m.chai.expect(selectionState.getCurrentDrive()).to.deep.equal({
device: '/dev/sdb',
name: 'Foo',
size: 2000000000,
mountpoints: [ {
path: '/mnt/foo'
} ],
isSystem: false,
isReadOnly: false
})
m.chai.expect(selectionState.getSelectedDevices()[0]).to.equal('/dev/sdb')
})
it('should not auto-select a single too small drive', function () {

View File

@ -21,6 +21,7 @@ const _ = require('lodash')
const path = require('path')
// eslint-disable-next-line node/no-missing-require
const availableDrives = require('../../../lib/gui/app/models/available-drives')
// eslint-disable-next-line node/no-missing-require
const selectionState = require('../../../lib/gui/app/models/selection-state')
describe('Model: selectionState', function () {
@ -29,11 +30,6 @@ describe('Model: selectionState', function () {
selectionState.clear()
})
it('getCurrentDrive() should return undefined', function () {
const drive = selectionState.getCurrentDrive()
m.chai.expect(drive).to.be.undefined
})
it('getImage() should return undefined', function () {
m.chai.expect(selectionState.getImage()).to.be.undefined
})
@ -105,12 +101,7 @@ describe('Model: selectionState', function () {
availableDrives.setDrives(this.drives)
selectionState.selectDrive('/dev/disk2')
availableDrives.setDrives(this.drives)
m.chai.expect(selectionState.getCurrentDrive()).to.deep.equal({
device: '/dev/disk2',
name: 'USB Drive',
size: 64e10,
isReadOnly: false
})
m.chai.expect(selectionState.getSelectedDevices()[0]).to.equal('/dev/disk2')
})
})
})
@ -139,18 +130,6 @@ describe('Model: selectionState', function () {
selectionState.clear()
})
describe('.getCurrentDrive()', function () {
it('should return the drive', function () {
const drive = selectionState.getCurrentDrive()
m.chai.expect(drive).to.deep.equal({
device: '/dev/disk2',
name: 'USB Drive',
size: 999999999,
isReadOnly: false
})
})
})
describe('.hasDrive()', function () {
it('should return true', function () {
const hasDrive = selectionState.hasDrive()
@ -175,10 +154,10 @@ describe('Model: selectionState', function () {
describe('.deselectDrive()', function () {
it('should clear drive', function () {
const firstDrive = selectionState.getCurrentDrive()
selectionState.deselectDrive(firstDrive.device)
const drive = selectionState.getCurrentDrive()
m.chai.expect(drive).to.be.undefined
const firstDevice = selectionState.getSelectedDevices()[0]
selectionState.deselectDrive(firstDevice)
const devices = selectionState.getSelectedDevices()
m.chai.expect(devices.length).to.equal(0)
})
})
@ -243,13 +222,6 @@ describe('Model: selectionState', function () {
m.chai.expect(selectionState.getSelectedDevices()).to.deep.equal([ this.drives[0].device ])
})
it('current drive should be affected by add order', function () {
m.chai.expect(selectionState.getCurrentDrive()).to.deep.equal(this.drives[0])
selectionState.toggleDrive(this.drives[0].device)
selectionState.toggleDrive(this.drives[0].device)
m.chai.expect(selectionState.getCurrentDrive()).to.deep.equal(this.drives[1])
})
it('should keep system drives selected', function () {
const systemDrive = {
device: '/dev/disk0',
@ -280,26 +252,12 @@ describe('Model: selectionState', function () {
})
})
describe('.deselectOtherDrives()', function () {
it('should deselect other drives', function () {
selectionState.deselectOtherDrives(this.drives[0].device)
m.chai.expect(selectionState.getSelectedDevices()).to.not.include.members([ this.drives[1].device ])
})
it('should not remove the specified drive', function () {
selectionState.deselectOtherDrives(this.drives[0].device)
m.chai.expect(selectionState.getSelectedDevices()).to.deep.equal([ this.drives[0].device ])
})
})
describe('.deselectDrive()', function () {
it('should clear drives', function () {
const firstDrive = selectionState.getCurrentDrive()
selectionState.deselectDrive(firstDrive.device)
const secondDrive = selectionState.getCurrentDrive()
selectionState.deselectDrive(secondDrive.device)
const drive = selectionState.getCurrentDrive()
m.chai.expect(drive).to.be.undefined
const devices = selectionState.getSelectedDevices()
selectionState.deselectDrive(devices[0])
selectionState.deselectDrive(devices[1])
m.chai.expect(selectionState.getSelectedDevices().length).to.equal(0)
})
})
@ -339,13 +297,7 @@ describe('Model: selectionState', function () {
])
selectionState.selectDrive('/dev/disk5')
const drive = selectionState.getCurrentDrive()
m.chai.expect(drive).to.deep.equal({
device: '/dev/disk5',
name: 'USB Drive',
size: 999999999,
isReadOnly: false
})
m.chai.expect(selectionState.getSelectedDevices()[0]).to.equal('/dev/disk5')
})
it('should throw if drive is read-only', function () {
@ -909,16 +861,6 @@ describe('Model: selectionState', function () {
selectionState.deselectImage()
})
it('getCurrentDrive() should return the selected drive object', function () {
const drive = selectionState.getCurrentDrive()
m.chai.expect(drive).to.deep.equal({
device: '/dev/disk1',
isReadOnly: false,
name: 'USB Drive',
size: 999999999
})
})
it('getImagePath() should return undefined', function () {
const imagePath = selectionState.getImagePath()
m.chai.expect(imagePath).to.be.undefined
@ -944,11 +886,6 @@ describe('Model: selectionState', function () {
selectionState.deselectAllDrives()
})
it('getCurrentDrive() should return undefined', function () {
const drive = selectionState.getCurrentDrive()
m.chai.expect(drive).to.be.undefined
})
it('getImagePath() should return the image path', function () {
const imagePath = selectionState.getImagePath()
m.chai.expect(imagePath).to.equal('foo.img')
@ -1018,59 +955,6 @@ describe('Model: selectionState', function () {
})
})
describe('.isCurrentDrive()', function () {
describe('given a selected drive', function () {
beforeEach(function () {
availableDrives.setDrives([
{
device: '/dev/sdb',
description: 'DataTraveler 2.0',
size: 999999999,
mountpoints: [ {
path: '/media/UNTITLED'
} ],
name: '/dev/sdb',
isSystem: false,
isReadOnly: false
}
])
selectionState.selectDrive('/dev/sdb')
})
afterEach(function () {
selectionState.clear()
availableDrives.setDrives([])
})
it('should return false if an undefined value is passed', function () {
m.chai.expect(selectionState.isCurrentDrive()).to.be.false
})
it('should return true given the exact same drive', function () {
m.chai.expect(selectionState.isCurrentDrive('/dev/sdb')).to.be.true
})
it('should return false if it is not the current drive', function () {
m.chai.expect(selectionState.isCurrentDrive('/dev/sdc')).to.be.false
})
})
describe('given no selected drive', function () {
beforeEach(function () {
selectionState.clear()
})
it('should return false if an undefined value is passed', function () {
m.chai.expect(selectionState.isCurrentDrive()).to.be.false
})
it('should return false for anything', function () {
m.chai.expect(selectionState.isCurrentDrive('/dev/sdb')).to.be.false
})
})
})
describe('.toggleDrive()', function () {
describe('given a selected drive', function () {
beforeEach(function () {
@ -1118,10 +1002,9 @@ describe('Model: selectionState', function () {
isReadOnly: false
}
m.chai.expect(selectionState.getCurrentDrive()).to.deep.equal(this.drive)
m.chai.expect(selectionState.getSelectedDevices()[0]).to.deep.equal(this.drive.device)
selectionState.toggleDrive(drive.device)
m.chai.expect(selectionState.getCurrentDrive()).to.deep.equal(this.drive)
m.chai.expect(selectionState.getCurrentDrive()).to.not.deep.equal(drive)
m.chai.expect(selectionState.getSelectedDevices()[0]).to.deep.equal(this.drive.device)
})
})
@ -1159,7 +1042,7 @@ describe('Model: selectionState', function () {
m.chai.expect(selectionState.hasDrive()).to.be.false
selectionState.toggleDrive(drive.device)
m.chai.expect(selectionState.getCurrentDrive()).to.deep.equal(drive)
m.chai.expect(selectionState.getSelectedDevices()[0]).to.equal('/dev/disk2')
})
})
})