diff --git a/lib/gui/app/app.js b/lib/gui/app/app.js index e2eb71ce..a93a1b16 100644 --- a/lib/gui/app/app.js +++ b/lib/gui/app/app.js @@ -48,6 +48,7 @@ const analytics = require('./modules/analytics') const availableDrives = require('./models/available-drives') // eslint-disable-next-line node/no-missing-require const { scanner: driveScanner } = require('./modules/drive-scanner') +// eslint-disable-next-line node/no-missing-require const osDialog = require('./os/dialog') // eslint-disable-next-line node/no-missing-require const exceptionReporter = require('./modules/exception-reporter') diff --git a/lib/gui/app/os/dialog.js b/lib/gui/app/os/dialog.js deleted file mode 100644 index 6dc45c25..00000000 --- a/lib/gui/app/os/dialog.js +++ /dev/null @@ -1,149 +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') -const electron = require('electron') -const Bluebird = require('bluebird') -// eslint-disable-next-line node/no-missing-require -const errors = require('../../../shared/errors') -// eslint-disable-next-line node/no-missing-require -const supportedFormats = require('../../../shared/supported-formats') - -/** - * @summary Current renderer BrowserWindow instance - * @type {Object} - * @private - */ -const currentWindow = electron.remote.getCurrentWindow() - -/** - * @summary Open an image selection dialog - * @function - * @public - * - * @description - * Notice that by image, we mean *.img/*.iso/*.zip/etc files. - * - * @fulfil {Object} - selected image - * @returns {Promise}; - * - * @example - * osDialog.selectImage().then((image) => { - * console.log('The selected image is', image.path); - * }); - */ -exports.selectImage = () => { - return new Bluebird((resolve) => { - electron.remote.dialog.showOpenDialog(currentWindow, { - - // This variable is set when running in GNU/Linux from - // inside an AppImage, and represents the working directory - // from where the AppImage was run (which might not be the - // place where the AppImage is located). `OWD` stands for - // "Original Working Directory". - // - // See: https://github.com/probonopd/AppImageKit/commit/1569d6f8540aa6c2c618dbdb5d6fcbf0003952b7 - defaultPath: process.env.OWD, - properties: [ - 'openFile', - 'treatPackageAsDirectory' - ], - filters: [ - { - name: 'OS Images', - extensions: _.sortBy(supportedFormats.getAllExtensions()) - } - ] - }, (files) => { - // `_.first` is smart enough to not throw and return `undefined` - // if we pass it an `undefined` value (e.g: when the selection - // dialog was cancelled). - return resolve(_.first(files)) - }) - }) -} - -/** - * @summary Open a warning dialog - * @function - * @public - * - * @param {Object} options - options - * @param {String} options.title - dialog title - * @param {String} options.description - dialog description - * @param {String} [options.confirmationLabel="OK"] - confirmation label - * @param {String} [options.rejectionLabel="Cancel"] - rejection label - * @fulfil {Boolean} - whether the dialog was confirmed or not - * @returns {Promise}; - * - * @example - * osDialog.showWarning({ - * title: 'This is a warning', - * description: 'Are you sure you want to continue?', - * confirmationLabel: 'Yes, continue', - * rejectionLabel: 'Cancel' - * }).then((confirmed) => { - * if (confirmed) { - * console.log('The dialog was confirmed'); - * } - * }); - */ -exports.showWarning = (options) => { - _.defaults(options, { - confirmationLabel: 'OK', - rejectionLabel: 'Cancel' - }) - - const BUTTONS = [ - options.confirmationLabel, - options.rejectionLabel - ] - - const BUTTON_CONFIRMATION_INDEX = _.indexOf(BUTTONS, options.confirmationLabel) - const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, options.rejectionLabel) - - return new Bluebird((resolve) => { - electron.remote.dialog.showMessageBox(currentWindow, { - type: 'warning', - buttons: BUTTONS, - defaultId: BUTTON_REJECTION_INDEX, - cancelId: BUTTON_REJECTION_INDEX, - title: 'Attention', - message: options.title, - detail: options.description - }, (response) => { - return resolve(response === BUTTON_CONFIRMATION_INDEX) - }) - }) -} - -/** - * @summary Show error dialog for an Error instance - * @function - * @public - * - * @param {Error} error - error - * - * @example - * osDialog.showError(new Error('Foo Bar')); - */ -exports.showError = (error) => { - const title = errors.getTitle(error) - const message = errors.getDescription(error) - electron.remote.dialog.showErrorBox(title, message) -} diff --git a/lib/gui/app/os/dialog.ts b/lib/gui/app/os/dialog.ts new file mode 100644 index 00000000..ed931f73 --- /dev/null +++ b/lib/gui/app/os/dialog.ts @@ -0,0 +1,104 @@ +/* + * 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 * as _ from 'lodash'; + +import * as errors from '../../../shared/errors'; +import * as supportedFormats from '../../../shared/supported-formats'; + +/** + * @summary Open an image selection dialog + * + * @description + * Notice that by image, we mean *.img/*.iso/*.zip/etc files. + */ +export function selectImage() { + return new Promise(resolve => { + electron.remote.dialog.showOpenDialog( + electron.remote.getCurrentWindow(), + { + // This variable is set when running in GNU/Linux from + // inside an AppImage, and represents the working directory + // from where the AppImage was run (which might not be the + // place where the AppImage is located). `OWD` stands for + // "Original Working Directory". + // + // See: https://github.com/probonopd/AppImageKit/commit/1569d6f8540aa6c2c618dbdb5d6fcbf0003952b7 + defaultPath: process.env.OWD, + properties: ['openFile', 'treatPackageAsDirectory'], + filters: [ + { + name: 'OS Images', + extensions: _.sortBy(supportedFormats.getAllExtensions()), + }, + ], + }, + (files: string[]) => { + // `_.first` is smart enough to not throw and return `undefined` + // if we pass it an `undefined` value (e.g: when the selection + // dialog was cancelled). + resolve(_.first(files)); + }, + ); + }); +} + +/** + * @summary Open a warning dialog + */ +export async function showWarning(options: { + confirmationLabel: string; + rejectionLabel: string; + title: string; + description: string; +}): Promise { + _.defaults(options, { + confirmationLabel: 'OK', + rejectionLabel: 'Cancel', + }); + + const BUTTONS = [options.confirmationLabel, options.rejectionLabel]; + + const BUTTON_CONFIRMATION_INDEX = _.indexOf( + BUTTONS, + options.confirmationLabel, + ); + const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, options.rejectionLabel); + + const { response } = await electron.remote.dialog.showMessageBox( + electron.remote.getCurrentWindow(), + { + type: 'warning', + buttons: BUTTONS, + defaultId: BUTTON_REJECTION_INDEX, + cancelId: BUTTON_REJECTION_INDEX, + title: 'Attention', + message: options.title, + detail: options.description, + }, + ); + return response === BUTTON_CONFIRMATION_INDEX; +} + +/** + * @summary Show error dialog for an Error instance + */ +export function showError(error: Error) { + const title = errors.getTitle(error); + const message = errors.getDescription(error); + electron.remote.dialog.showErrorBox(title, message); +}