diff --git a/lib/gui/app/app.js b/lib/gui/app/app.js index d1b6a7a4..3fa6b64f 100644 --- a/lib/gui/app/app.js +++ b/lib/gui/app/app.js @@ -31,6 +31,7 @@ const store = require('./models/store') const packageJSON = require('../../../package.json') const flashState = require('./models/flash-state') const settings = require('./models/settings') +// eslint-disable-next-line node/no-missing-require const windowProgress = require('./os/window-progress') const analytics = require('./modules/analytics') const availableDrives = require('./models/available-drives') diff --git a/lib/gui/app/modules/image-writer.js b/lib/gui/app/modules/image-writer.js index cc7535e7..e23eff1d 100644 --- a/lib/gui/app/modules/image-writer.js +++ b/lib/gui/app/modules/image-writer.js @@ -27,6 +27,7 @@ const settings = require('../models/settings') const flashState = require('../models/flash-state') const errors = require('../../../shared/errors') const permissions = require('../../../shared/permissions') +// eslint-disable-next-line node/no-missing-require const windowProgress = require('../os/window-progress') const analytics = require('../modules/analytics') const updateLock = require('./update-lock') diff --git a/lib/gui/app/modules/progress-status.js b/lib/gui/app/modules/progress-status.js deleted file mode 100644 index 9aab2fec..00000000 --- a/lib/gui/app/modules/progress-status.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2017 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 settings = require('../models/settings') -const utils = require('../../../shared/utils') -const units = require('../../../shared/units') - -/** - * @summary Make the progress status subtitle string - * - * @param {Object} state - flashing metadata - * - * @returns {String} - * - * @example - * const status = progressStatus.fromFlashState({ - * flashing: 1, - * verifying: 0, - * successful: 0, - * failed: 0, - * percentage: 55, - * speed: 2049 - * }) - * - * console.log(status) - * // '55% Flashing' - */ -exports.fromFlashState = (state) => { - const isFlashing = Boolean(state.flashing) - const isValidating = !isFlashing && Boolean(state.verifying) - const shouldValidate = settings.get('validateWriteOnSuccess') - const shouldUnmount = settings.get('unmountOnSuccess') - - if (state.percentage === utils.PERCENTAGE_MINIMUM && !state.speed) { - if (isValidating) { - return 'Validating...' - } - - return 'Starting...' - } else if (state.percentage === utils.PERCENTAGE_MAXIMUM) { - if ((isValidating || !shouldValidate) && shouldUnmount) { - return 'Unmounting...' - } - - return 'Finishing...' - } else if (isFlashing) { - // eslint-disable-next-line no-eq-null - if (state.percentage != null) { - return `${state.percentage}% Flashing` - } - return `${units.bytesToClosestUnit(state.position)} flashed` - } else if (isValidating) { - return `${state.percentage}% Validating` - } else if (!isFlashing && !isValidating) { - return 'Failed' - } - - throw new Error(`Invalid state: ${JSON.stringify(state)}`) -} diff --git a/lib/gui/app/modules/progress-status.ts b/lib/gui/app/modules/progress-status.ts new file mode 100644 index 00000000..789bc815 --- /dev/null +++ b/lib/gui/app/modules/progress-status.ts @@ -0,0 +1,80 @@ +/* + * Copyright 2017 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 { bytesToClosestUnit } from '../../../shared/units'; +import * as settings from '../models/settings'; + +export interface FlashState { + flashing: number; + verifying: number; + successful: number; + failed: number; + percentage?: number; + speed: number; + position: number; +} + +/** + * @summary Make the progress status subtitle string + * + * @param {Object} state - flashing metadata + * + * @returns {String} + * + * @example + * const status = progressStatus.fromFlashState({ + * flashing: 1, + * verifying: 0, + * successful: 0, + * failed: 0, + * percentage: 55, + * speed: 2049 + * }) + * + * console.log(status) + * // '55% Flashing' + */ +export function fromFlashState(state: FlashState): string { + const isFlashing = Boolean(state.flashing); + const isValidating = !isFlashing && Boolean(state.verifying); + const shouldValidate = settings.get('validateWriteOnSuccess'); + const shouldUnmount = settings.get('unmountOnSuccess'); + + if (state.percentage === 0 && !state.speed) { + if (isValidating) { + return 'Validating...'; + } + + return 'Starting...'; + } else if (state.percentage === 100) { + if ((isValidating || !shouldValidate) && shouldUnmount) { + return 'Unmounting...'; + } + + return 'Finishing...'; + } else if (isFlashing) { + if (state.percentage != null) { + return `${state.percentage}% Flashing`; + } + return `${bytesToClosestUnit(state.position)} flashed`; + } else if (isValidating) { + return `${state.percentage}% Validating`; + } else if (!isFlashing && !isValidating) { + return 'Failed'; + } + + throw new Error(`Invalid state: ${JSON.stringify(state)}`); +} diff --git a/lib/gui/app/os/window-progress.js b/lib/gui/app/os/window-progress.js deleted file mode 100644 index 915cc9fe..00000000 --- a/lib/gui/app/os/window-progress.js +++ /dev/null @@ -1,114 +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 electron = require('electron') -const utils = require('../../../shared/utils') -const progressStatus = require('../modules/progress-status') - -/** - * @summary The title of the main window upon program launch - * @type {String} - * @private - * @constant - */ -const INITIAL_TITLE = document.title - -/** - * @summary Make the full window status title - * @private - * - * @param {Object} state - flash state object - * - * @returns {String} - * - * @example - * const title = getWindowTitle({ - * flashing: 1, - * validating: 0, - * successful: 0, - * failed: 0, - * percentage: 55, - * speed: 2049 - * }); - * - * console.log(title); - * // 'Etcher \u2013 55% Flashing' - */ -const getWindowTitle = (state) => { - if (state) { - const subtitle = progressStatus.fromFlashState(state) - const DASH_UNICODE_CHAR = '\u2013' - return `${INITIAL_TITLE} ${DASH_UNICODE_CHAR} ${subtitle}` - } - - return INITIAL_TITLE -} - -/** - * @summary A reference to the current renderer Electron window - * @type {Object} - * @protected - * - * @description - * We expose this property to `this` for testability purposes. - */ -exports.currentWindow = electron.remote.getCurrentWindow() - -/** - * @summary Set operating system window progress - * @function - * @public - * - * @description - * Show progress inline in operating system task bar - * - * @param {Number} state - flash state object - * - * @example - * windowProgress.set({ - * flashing: 1, - * validating: 0, - * successful: 0, - * failed: 0, - * percentage: 55, - * speed: 2049 - * }) - */ -exports.set = (state) => { - // eslint-disable-next-line no-eq-null - if (state.percentage != null) { - exports.currentWindow.setProgressBar(utils.percentageToFloat(state.percentage)) - } - exports.currentWindow.setTitle(getWindowTitle(state)) -} - -/** - * @summary Clear the window progress bar - * @function - * @public - * - * @example - * windowProgress.clear(); - */ -exports.clear = () => { - // Passing 0 or null/undefined doesn't work. - const ELECTRON_PROGRESS_BAR_RESET_VALUE = -1 - - exports.currentWindow.setProgressBar(ELECTRON_PROGRESS_BAR_RESET_VALUE) - exports.currentWindow.setTitle(getWindowTitle(null)) -} diff --git a/lib/gui/app/os/window-progress.ts b/lib/gui/app/os/window-progress.ts new file mode 100644 index 00000000..443fee7e --- /dev/null +++ b/lib/gui/app/os/window-progress.ts @@ -0,0 +1,65 @@ +/* + * 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 electron from 'electron'; + +import { percentageToFloat } from '../../../shared/utils'; +import { FlashState, fromFlashState } from '../modules/progress-status'; + +/** + * @summary The title of the main window upon program launch + */ +const INITIAL_TITLE = document.title; + +/** + * @summary Make the full window status title + */ +function getWindowTitle(state?: FlashState) { + if (state) { + return `${INITIAL_TITLE} – ${fromFlashState(state)}`; + } + return INITIAL_TITLE; +} + +/** + * @summary A reference to the current renderer Electron window + * + * @description + * We expose this property to `this` for testability purposes. + */ +export const currentWindow = electron.remote.getCurrentWindow(); + +/** + * @summary Set operating system window progress + * + * @description + * Show progress inline in operating system task bar + */ +export function set(state: FlashState) { + if (state.percentage != null) { + exports.currentWindow.setProgressBar(percentageToFloat(state.percentage)); + } + exports.currentWindow.setTitle(getWindowTitle(state)); +} + +/** + * @summary Clear the window progress bar + */ +export function clear() { + // Passing 0 or null/undefined doesn't work. + exports.currentWindow.setProgressBar(-1); + exports.currentWindow.setTitle(getWindowTitle(undefined)); +} diff --git a/lib/gui/app/pages/main/Flash.tsx b/lib/gui/app/pages/main/Flash.tsx index 31ca0710..ce605a95 100644 --- a/lib/gui/app/pages/main/Flash.tsx +++ b/lib/gui/app/pages/main/Flash.tsx @@ -145,7 +145,8 @@ const getProgressButtonLabel = () => { return 'Flash!'; } - return progressStatus.fromFlashState(flashState.getFlashState()); + // TODO: no any + return progressStatus.fromFlashState(flashState.getFlashState() as any); }; const formatSeconds = (totalSeconds: number) => { diff --git a/tests/gui/modules/progress-status.spec.js b/tests/gui/modules/progress-status.spec.js index 3eb38e69..42e3e95b 100644 --- a/tests/gui/modules/progress-status.spec.js +++ b/tests/gui/modules/progress-status.spec.js @@ -2,6 +2,7 @@ const m = require('mochainon') const settings = require('../../../lib/gui/app/models/settings') +// eslint-disable-next-line node/no-missing-require const progressStatus = require('../../../lib/gui/app/modules/progress-status') describe('Browser: progressStatus', function () { diff --git a/tests/gui/os/window-progress.spec.js b/tests/gui/os/window-progress.spec.js index 84321953..9893a6fc 100644 --- a/tests/gui/os/window-progress.spec.js +++ b/tests/gui/os/window-progress.spec.js @@ -17,6 +17,7 @@ 'use strict' const m = require('mochainon') +// eslint-disable-next-line node/no-missing-require const windowProgress = require('../../../lib/gui/app/os/window-progress') describe('Browser: WindowProgress', function () {