Merge pull request #91 from resin-io/feat/autoselect-single-drive

Autoselect the drive if only one drive is present
This commit is contained in:
Juan Cruz Viotti 2016-01-18 14:07:16 -04:00
commit 7e4d583f03
4 changed files with 128 additions and 14 deletions

View File

@ -20,6 +20,7 @@
*/
var angular = require('angular');
var _ = require('lodash');
var remote = window.require('remote');
var shell = remote.require('shell');
var dialog = remote.require('./src/dialog');
@ -52,7 +53,27 @@ app.controller('AppController', function($q, DriveScannerService, SelectionState
console.debug('Restarting');
this.selection.clear();
this.writer.setProgress(0);
this.scanner.start(2000);
this.scanner.start(2000).on('scan', function(drives) {
// Notice we only autoselect the drive if there is an image,
// which means that the first step was completed successfully,
// otherwise the drive is selected while the drive step is disabled
// which looks very weird.
if (drives.length === 1 && self.selection.hasImage()) {
var drive = _.first(drives);
// Do not autoselect the same drive over and over again
// and fill the logs unnecessary.
// `angular.equals` is used instead of `_.isEqual` to
// cope with `$$hashKey`.
if (!angular.equals(self.selection.getDrive(), drive)) {
console.debug('Autoselecting drive: ' + drive.device);
self.selectDrive(drive);
}
}
});
};
this.restart();
@ -111,6 +132,7 @@ app.controller('AppController', function($q, DriveScannerService, SelectionState
var angular = require('angular');
var _ = require('lodash');
var EventEmitter = require('events').EventEmitter;
var remote = window.require('remote');
if (window.mocha) {
@ -125,7 +147,7 @@ if (window.mocha) {
var driveScanner = angular.module('ResinEtcher.drive-scanner', []);
driveScanner.service('DriveScannerRefreshService', function($interval) {
driveScanner.service('DriveScannerRefreshService', function($interval, $timeout) {
'use strict';
var interval = null;
@ -144,8 +166,15 @@ driveScanner.service('DriveScannerRefreshService', function($interval) {
* }, 2000);
*/
this.every = function(fn, ms) {
fn();
interval = $interval(fn, ms);
// Call fn after in the next process tick
// to be able to capture the first run
// in unit tests.
$timeout(function() {
fn();
interval = $interval(fn, ms);
});
};
/**
@ -234,15 +263,32 @@ driveScanner.service('DriveScannerService', function($q, DriveScannerRefreshServ
* @function
* @public
*
* @description
* This function returns an event emitter instance
* that emits a `scan` event everything it scans
* the drives successfully.
*
* @param {Number} ms - interval milliseconds
* @returns {EventEmitter} event emitter instance
*
* @example
* DriveScannerService.start(2000);
* var emitter = DriveScannerService.start(2000);
*
* emitter.on('scan', function(drives) {
* console.log(drives);
* });
*/
this.start = function(ms) {
var emitter = new EventEmitter();
DriveScannerRefreshService.every(function() {
return self.scan().then(self.setDrives);
return self.scan().then(function(drives) {
emitter.emit('scan', drives);
self.setDrives(drives);
});
}, ms);
return emitter;
};
/**

View File

@ -19,6 +19,7 @@
*/
var angular = require('angular');
var _ = require('lodash');
var remote = window.require('remote');
var shell = remote.require('shell');
var dialog = remote.require('./src/dialog');
@ -51,7 +52,27 @@ app.controller('AppController', function($q, DriveScannerService, SelectionState
console.debug('Restarting');
this.selection.clear();
this.writer.setProgress(0);
this.scanner.start(2000);
this.scanner.start(2000).on('scan', function(drives) {
// Notice we only autoselect the drive if there is an image,
// which means that the first step was completed successfully,
// otherwise the drive is selected while the drive step is disabled
// which looks very weird.
if (drives.length === 1 && self.selection.hasImage()) {
var drive = _.first(drives);
// Do not autoselect the same drive over and over again
// and fill the logs unnecessary.
// `angular.equals` is used instead of `_.isEqual` to
// cope with `$$hashKey`.
if (!angular.equals(self.selection.getDrive(), drive)) {
console.debug('Autoselecting drive: ' + drive.device);
self.selectDrive(drive);
}
}
});
};
this.restart();

View File

@ -20,6 +20,7 @@
var angular = require('angular');
var _ = require('lodash');
var EventEmitter = require('events').EventEmitter;
var remote = window.require('remote');
if (window.mocha) {
@ -34,7 +35,7 @@ if (window.mocha) {
var driveScanner = angular.module('ResinEtcher.drive-scanner', []);
driveScanner.service('DriveScannerRefreshService', function($interval) {
driveScanner.service('DriveScannerRefreshService', function($interval, $timeout) {
'use strict';
var interval = null;
@ -53,8 +54,15 @@ driveScanner.service('DriveScannerRefreshService', function($interval) {
* }, 2000);
*/
this.every = function(fn, ms) {
fn();
interval = $interval(fn, ms);
// Call fn after in the next process tick
// to be able to capture the first run
// in unit tests.
$timeout(function() {
fn();
interval = $interval(fn, ms);
});
};
/**
@ -143,15 +151,32 @@ driveScanner.service('DriveScannerService', function($q, DriveScannerRefreshServ
* @function
* @public
*
* @description
* This function returns an event emitter instance
* that emits a `scan` event everything it scans
* the drives successfully.
*
* @param {Number} ms - interval milliseconds
* @returns {EventEmitter} event emitter instance
*
* @example
* DriveScannerService.start(2000);
* var emitter = DriveScannerService.start(2000);
*
* emitter.on('scan', function(drives) {
* console.log(drives);
* });
*/
this.start = function(ms) {
var emitter = new EventEmitter();
DriveScannerRefreshService.every(function() {
return self.scan().then(self.setDrives);
return self.scan().then(function(drives) {
emitter.emit('scan', drives);
self.setDrives(drives);
});
}, ms);
return emitter;
};
/**

View File

@ -12,9 +12,11 @@ describe('Browser: DriveScanner', function() {
var DriveScannerRefreshService;
var $interval;
var $timeout;
beforeEach(angular.mock.inject(function(_$interval_, _DriveScannerRefreshService_) {
beforeEach(angular.mock.inject(function(_$interval_, _$timeout_, _DriveScannerRefreshService_) {
$interval = _$interval_;
$timeout = _$timeout_;
DriveScannerRefreshService = _DriveScannerRefreshService_;
}));
@ -23,6 +25,7 @@ describe('Browser: DriveScanner', function() {
it('should call the function right away', function() {
var spy = m.sinon.spy();
DriveScannerRefreshService.every(spy, 1000);
$timeout.flush();
DriveScannerRefreshService.stop();
m.chai.expect(spy).to.have.been.calledOnce;
});
@ -30,6 +33,7 @@ describe('Browser: DriveScanner', function() {
it('should call the function in an interval', function() {
var spy = m.sinon.spy();
DriveScannerRefreshService.every(spy, 100);
$timeout.flush();
// 400ms = 100ms / 4 + 1 (the initial call)
$interval.flush(400);
@ -45,11 +49,13 @@ describe('Browser: DriveScanner', function() {
describe('DriveScannerService', function() {
var $interval;
var $timeout;
var $q;
var DriveScannerService;
beforeEach(angular.mock.inject(function(_$interval_, _$q_, _DriveScannerService_) {
beforeEach(angular.mock.inject(function(_$interval_, _$timeout_, _$q_, _DriveScannerService_) {
$interval = _$interval_;
$timeout = _$timeout_;
$q = _$q_;
DriveScannerService = _DriveScannerService_;
}));
@ -169,11 +175,27 @@ describe('Browser: DriveScanner', function() {
it('should set the drives to the scanned ones', function() {
DriveScannerService.start(200);
$timeout.flush();
$interval.flush(400);
m.chai.expect(DriveScannerService.drives).to.deep.equal(this.drives);
DriveScannerService.stop();
});
describe('.start()', function() {
it('should emit a `scan` event with the drives', function() {
var emitter = DriveScannerService.start(2000);
var scanSpy = m.sinon.spy();
emitter.on('scan', scanSpy);
$timeout.flush();
$interval.flush(1000);
m.chai.expect(scanSpy).to.have.been.calledOnce;
m.chai.expect(scanSpy).to.have.been.calledWith(this.drives);
DriveScannerService.stop();
});
});
});
});