mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-24 07:17:18 +00:00
Implement Etcher.OS.Dialog module (#381)
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
parent
d373d32472
commit
ad758cf391
@ -22,8 +22,6 @@
|
||||
|
||||
var angular = require('angular');
|
||||
const _ = require('lodash');
|
||||
const electron = require('electron');
|
||||
const dialog = electron.remote.require('./gui/dialog');
|
||||
|
||||
const app = angular.module('Etcher', [
|
||||
require('angular-ui-router'),
|
||||
@ -51,6 +49,7 @@ const app = angular.module('Etcher', [
|
||||
require('./os/window-progress/window-progress'),
|
||||
require('./os/open-external/open-external'),
|
||||
require('./os/dropzone/dropzone'),
|
||||
require('./os/dialog/dialog'),
|
||||
|
||||
// Utils
|
||||
require('./utils/if-state/if-state'),
|
||||
@ -76,7 +75,6 @@ app.config(function($stateProvider, $urlRouterProvider) {
|
||||
});
|
||||
|
||||
app.controller('AppController', function(
|
||||
$q,
|
||||
$state,
|
||||
$scope,
|
||||
NotifierService,
|
||||
@ -87,7 +85,8 @@ app.controller('AppController', function(
|
||||
AnalyticsService,
|
||||
DriveSelectorService,
|
||||
OSWindowProgressService,
|
||||
OSNotificationService
|
||||
OSNotificationService,
|
||||
OSDialogService
|
||||
) {
|
||||
let self = this;
|
||||
this.selection = SelectionStateModel;
|
||||
@ -117,7 +116,7 @@ app.controller('AppController', function(
|
||||
OSWindowProgressService.set(state.progress);
|
||||
});
|
||||
|
||||
this.scanner.start(2000).on('error', dialog.showError).on('scan', function(drives) {
|
||||
this.scanner.start(2000).on('error', OSDialogService.showError).on('scan', function(drives) {
|
||||
|
||||
// Cover the case where you select a drive, but then eject it.
|
||||
if (self.selection.hasDrive() && !_.find(drives, self.selection.isCurrentDrive)) {
|
||||
@ -167,7 +166,7 @@ app.controller('AppController', function(
|
||||
};
|
||||
|
||||
this.openImageSelector = function() {
|
||||
return $q.when(dialog.selectImage()).then(function(image) {
|
||||
return OSDialogService.selectImage().then(function(image) {
|
||||
|
||||
// Avoid analytics and selection state changes
|
||||
// if no file was resolved from the dialog.
|
||||
@ -260,7 +259,7 @@ app.controller('AppController', function(
|
||||
}
|
||||
|
||||
self.writer.resetState();
|
||||
dialog.showError(error);
|
||||
OSDialogService.showError(error);
|
||||
})
|
||||
.finally(OSWindowProgressService.clear);
|
||||
};
|
||||
|
@ -1,88 +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 electron = require('electron');
|
||||
const Bluebird = require('bluebird');
|
||||
const zipImage = require('resin-zip-image');
|
||||
const packageJSON = require('../../package.json');
|
||||
|
||||
/**
|
||||
* @summary Open an image selection dialog
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @description
|
||||
* Notice that by image, we mean *.img/*.iso/*.zip files.
|
||||
*
|
||||
* If the user selects an invalid zip image, an error alert
|
||||
* is shown, and the promise resolves `undefined`.
|
||||
*
|
||||
* @fulfil {String} - selected image
|
||||
* @returns {Promise};
|
||||
*
|
||||
* @example
|
||||
* dialog.selectImage().then(function(image) {
|
||||
* console.log('The selected image is', image);
|
||||
* });
|
||||
*/
|
||||
exports.selectImage = function() {
|
||||
return new Bluebird(function(resolve) {
|
||||
electron.dialog.showOpenDialog({
|
||||
properties: [ 'openFile' ],
|
||||
filters: [
|
||||
{
|
||||
name: 'IMG/ISO/ZIP',
|
||||
extensions: [
|
||||
'zip',
|
||||
'img',
|
||||
'iso'
|
||||
]
|
||||
}
|
||||
]
|
||||
}, function(files) {
|
||||
return resolve(files || []);
|
||||
});
|
||||
}).get(0).then(function(file) {
|
||||
if (file && zipImage.isZip(file) && !zipImage.isValidZipImage(file)) {
|
||||
electron.dialog.showErrorBox(
|
||||
'Invalid zip image',
|
||||
`${packageJSON.displayName} can only open Zip archives that contain exactly one image file inside.`
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return file;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Show error dialog for an Error instance
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error
|
||||
*
|
||||
* @example
|
||||
* dialog.showError(new Error('Foo Bar'));
|
||||
*/
|
||||
exports.showError = function(error) {
|
||||
error = error || {};
|
||||
electron.dialog.showErrorBox(error.message || 'An error ocurred!', error.stack || '');
|
||||
throw error;
|
||||
};
|
31
lib/gui/os/dialog/dialog.js
Normal file
31
lib/gui/os/dialog/dialog.js
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* @module Etcher.OS.Dialog
|
||||
*
|
||||
* The purpose of this module is to provide an easy way
|
||||
* to interact with OS dialogs.
|
||||
*/
|
||||
|
||||
const angular = require('angular');
|
||||
const MODULE_NAME = 'Etcher.OS.Dialog';
|
||||
const OSDialog = angular.module(MODULE_NAME, []);
|
||||
OSDialog.service('OSDialogService', require('./services/dialog'));
|
||||
|
||||
module.exports = MODULE_NAME;
|
84
lib/gui/os/dialog/services/dialog.js
Normal file
84
lib/gui/os/dialog/services/dialog.js
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 electron = require('electron');
|
||||
const imageStream = require('etcher-image-stream');
|
||||
|
||||
module.exports = function($q) {
|
||||
|
||||
/**
|
||||
* @summary Open an image selection dialog
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @description
|
||||
* Notice that by image, we mean *.img/*.iso/*.zip/etc files.
|
||||
*
|
||||
* @fulfil {String} - selected image
|
||||
* @returns {Promise};
|
||||
*
|
||||
* @example
|
||||
* OSDialogService.selectImage().then(function(image) {
|
||||
* console.log('The selected image is', image);
|
||||
* });
|
||||
*/
|
||||
this.selectImage = function() {
|
||||
return $q(function(resolve) {
|
||||
electron.remote.dialog.showOpenDialog({
|
||||
properties: [
|
||||
'openFile'
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
name: 'OS Images',
|
||||
extensions: imageStream.supportedFileTypes
|
||||
}
|
||||
]
|
||||
}, function(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 Show error dialog for an Error instance
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error
|
||||
*
|
||||
* @example
|
||||
* OSDialogService.showError(new Error('Foo Bar'));
|
||||
*/
|
||||
this.showError = function(error) {
|
||||
error = error || {};
|
||||
electron.remote.dialog.showErrorBox(error.message || 'An error ocurred!', error.stack || '');
|
||||
|
||||
// Also throw it so it gets displayed in DevTools
|
||||
// and its reported by TrackJS.
|
||||
throw error;
|
||||
|
||||
};
|
||||
|
||||
};
|
@ -1,49 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const m = require('mochainon');
|
||||
const electron = require('electron');
|
||||
const dialog = require('../../lib/gui/dialog');
|
||||
|
||||
describe('Dialog:', function() {
|
||||
|
||||
describe('.selectImage()', function() {
|
||||
|
||||
describe('given the user does not select anything', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.showOpenDialogStub = m.sinon.stub(electron.dialog, 'showOpenDialog');
|
||||
this.showOpenDialogStub.yields(undefined);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
this.showOpenDialogStub.restore();
|
||||
});
|
||||
|
||||
it('should eventually be undefined', function() {
|
||||
const promise = dialog.selectImage();
|
||||
m.chai.expect(promise).to.eventually.be.undefined;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given the users performs a selection', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.showOpenDialogStub = m.sinon.stub(electron.dialog, 'showOpenDialog');
|
||||
this.showOpenDialogStub.yields([ 'foo/bar' ]);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
this.showOpenDialogStub.restore();
|
||||
});
|
||||
|
||||
it('should eventually equal the file', function() {
|
||||
const promise = dialog.selectImage();
|
||||
m.chai.expect(promise).to.eventually.equal('foo/bar');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user