diff --git a/lib/browser/app.js b/lib/browser/app.js
index c627adfc..52ac4122 100644
--- a/lib/browser/app.js
+++ b/lib/browser/app.js
@@ -34,7 +34,7 @@ require('./browser/modules/path');
require('./browser/modules/notifier');
require('./browser/modules/analytics');
require('./browser/components/progress-button/progress-button');
-require('./browser/components/drive-selector');
+require('./browser/components/drive-selector/drive-selector');
require('./browser/pages/finish/finish');
require('./browser/pages/settings/settings');
require('./browser/utils/window-progress/window-progress');
diff --git a/lib/browser/components/drive-selector.js b/lib/browser/components/drive-selector.js
deleted file mode 100644
index 7d7be812..00000000
--- a/lib/browser/components/drive-selector.js
+++ /dev/null
@@ -1,184 +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';
-
-/**
- * @module Etcher.Components.DriveSelector
- */
-
-const _ = require('lodash');
-const angular = require('angular');
-require('angular-ui-bootstrap');
-require('../../browser/modules/drive-scanner');
-const DriveSelector = angular.module('Etcher.Components.DriveSelector', [
- 'ui.bootstrap',
- 'Etcher.drive-scanner'
-]);
-
-DriveSelector.service('DriveSelectorStateService', function() {
-
- /**
- * @summary Toggle select drive
- * @function
- * @public
- *
- * @param {Object} drive - drive
- *
- * @example
- * DriveSelectorController.toggleSelectDrive({ drive });
- */
- this.toggleSelectDrive = function(drive) {
- if (this.isSelectedDrive(drive)) {
- this.selectedDrive = null;
- } else {
- this.selectedDrive = drive;
- }
- };
-
- /**
- * @summary Check if a drive is the selected one
- * @function
- * @public
- *
- * @param {Object} drive - drive
- * @returns {Boolean} whether the drive is selected
- *
- * @example
- * if (DriveSelectorController.isSelectedDrive({ drive })) {
- * console.log('The drive is selected!');
- * }
- */
- this.isSelectedDrive = function(drive) {
- if (!_.has(drive, 'device')) {
- return false;
- }
-
- return drive.device === _.get(this.selectedDrive, 'device');
- };
-
- /**
- * @summary Get selected drive
- * @function
- * @public
- *
- * @returns {Object} selected drive
- *
- * @example
- * const drive = DriveSelectorStateService.getSelectedDrive();
- */
- this.getSelectedDrive = function() {
- if (_.isEmpty(this.selectedDrive)) {
- return;
- }
-
- return this.selectedDrive;
- };
-
-});
-
-DriveSelector.controller('DriveSelectorController', function($uibModalInstance, DriveSelectorStateService, DriveScannerService) {
-
- /**
- * @summary The drive selector state
- * @property
- * @type Object
- *
- * @description
- * The state has been splitted from the controller for
- * testability purposes.
- */
- this.state = DriveSelectorStateService;
-
- /**
- * @summary The drive scanner service
- * @property
- * @type Object
- *
- * @description
- * We expose the whole service instead of the `.drives`
- * property, which is the one we're interested in since
- * this allows the property to be automatically updated
- * when `DriveScannerService` detects a change in the drives.
- */
- this.scanner = DriveScannerService;
-
- /**
- * @summary Close the modal and resolve the selected drive
- * @function
- * @public
- *
- * @example
- * DriveSelectorController.closeModal();
- */
- this.closeModal = function() {
- const selectedDrive = DriveSelectorStateService.getSelectedDrive();
-
- // Sanity check to cover the case where a drive is selected,
- // the drive is then unplugged from the computer and the modal
- // is resolved with a non-existent drive.
- if (!selectedDrive || !_.includes(this.scanner.drives, selectedDrive)) {
- return $uibModalInstance.dismiss();
- }
-
- return $uibModalInstance.close(selectedDrive);
- };
-
-});
-
-DriveSelector.service('DriveSelectorService', function($uibModal) {
-
- /**
- * @summary Open the drive selector widget
- * @function
- * @public
- *
- * @fulfil {(Object|Undefined)} - selected drive
- * @returns {Promise}
- *
- * @example
- * DriveSelectorService.open().then(function(drive) {
- * console.log(drive);
- * });
- */
- this.open = function() {
- return $uibModal.open({
- animation: true,
- template: [
- '
',
-
- '',
- '
',
- '- ',
- '
',
- '
{{ drive.description }} - {{ drive.size }}
',
- '
{{ drive.device }}
',
- '
',
- '',
- ' ',
- '
',
- '
'
- ].join('\n'),
- controller: 'DriveSelectorController as modal',
- size: 'sm'
- }).result;
- };
-
-});
diff --git a/lib/browser/components/drive-selector/controllers/drive-selector.js b/lib/browser/components/drive-selector/controllers/drive-selector.js
new file mode 100644
index 00000000..3dfee3c7
--- /dev/null
+++ b/lib/browser/components/drive-selector/controllers/drive-selector.js
@@ -0,0 +1,68 @@
+/*
+ * 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');
+
+module.exports = function($uibModalInstance, DriveSelectorStateService, DriveScannerService) {
+
+ /**
+ * @summary The drive selector state
+ * @property
+ * @type Object
+ *
+ * @description
+ * The state has been splitted from the controller for
+ * testability purposes.
+ */
+ this.state = DriveSelectorStateService;
+
+ /**
+ * @summary The drive scanner service
+ * @property
+ * @type Object
+ *
+ * @description
+ * We expose the whole service instead of the `.drives`
+ * property, which is the one we're interested in since
+ * this allows the property to be automatically updated
+ * when `DriveScannerService` detects a change in the drives.
+ */
+ this.scanner = DriveScannerService;
+
+ /**
+ * @summary Close the modal and resolve the selected drive
+ * @function
+ * @public
+ *
+ * @example
+ * DriveSelectorController.closeModal();
+ */
+ this.closeModal = function() {
+ const selectedDrive = DriveSelectorStateService.getSelectedDrive();
+
+ // Sanity check to cover the case where a drive is selected,
+ // the drive is then unplugged from the computer and the modal
+ // is resolved with a non-existent drive.
+ if (!selectedDrive || !_.includes(this.scanner.drives, selectedDrive)) {
+ return $uibModalInstance.dismiss();
+ }
+
+ return $uibModalInstance.close(selectedDrive);
+ };
+
+};
diff --git a/lib/browser/components/drive-selector/drive-selector.js b/lib/browser/components/drive-selector/drive-selector.js
new file mode 100644
index 00000000..aa59ce5f
--- /dev/null
+++ b/lib/browser/components/drive-selector/drive-selector.js
@@ -0,0 +1,34 @@
+/*
+ * 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.Components.DriveSelector
+ */
+
+const angular = require('angular');
+require('angular-ui-bootstrap');
+require('../../../browser/modules/drive-scanner');
+
+const DriveSelector = angular.module('Etcher.Components.DriveSelector', [
+ 'ui.bootstrap',
+ 'Etcher.drive-scanner'
+]);
+
+DriveSelector.controller('DriveSelectorController', require('./controllers/drive-selector'));
+DriveSelector.service('DriveSelectorStateService', require('./services/drive-selector-state'));
+DriveSelector.service('DriveSelectorService', require('./services/drive-selector'));
diff --git a/lib/browser/components/drive-selector/services/drive-selector-state.js b/lib/browser/components/drive-selector/services/drive-selector-state.js
new file mode 100644
index 00000000..17ceba96
--- /dev/null
+++ b/lib/browser/components/drive-selector/services/drive-selector-state.js
@@ -0,0 +1,80 @@
+/*
+ * 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');
+
+module.exports = function() {
+
+ /**
+ * @summary Toggle select drive
+ * @function
+ * @public
+ *
+ * @param {Object} drive - drive
+ *
+ * @example
+ * DriveSelectorController.toggleSelectDrive({ drive });
+ */
+ this.toggleSelectDrive = function(drive) {
+ if (this.isSelectedDrive(drive)) {
+ this.selectedDrive = null;
+ } else {
+ this.selectedDrive = drive;
+ }
+ };
+
+ /**
+ * @summary Check if a drive is the selected one
+ * @function
+ * @public
+ *
+ * @param {Object} drive - drive
+ * @returns {Boolean} whether the drive is selected
+ *
+ * @example
+ * if (DriveSelectorController.isSelectedDrive({ drive })) {
+ * console.log('The drive is selected!');
+ * }
+ */
+ this.isSelectedDrive = function(drive) {
+ if (!_.has(drive, 'device')) {
+ return false;
+ }
+
+ return drive.device === _.get(this.selectedDrive, 'device');
+ };
+
+ /**
+ * @summary Get selected drive
+ * @function
+ * @public
+ *
+ * @returns {Object} selected drive
+ *
+ * @example
+ * const drive = DriveSelectorStateService.getSelectedDrive();
+ */
+ this.getSelectedDrive = function() {
+ if (_.isEmpty(this.selectedDrive)) {
+ return;
+ }
+
+ return this.selectedDrive;
+ };
+
+};
diff --git a/lib/browser/components/drive-selector/services/drive-selector.js b/lib/browser/components/drive-selector/services/drive-selector.js
new file mode 100644
index 00000000..3465b285
--- /dev/null
+++ b/lib/browser/components/drive-selector/services/drive-selector.js
@@ -0,0 +1,43 @@
+/*
+ * 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.exports = function($uibModal) {
+
+ /**
+ * @summary Open the drive selector widget
+ * @function
+ * @public
+ *
+ * @fulfil {(Object|Undefined)} - selected drive
+ * @returns {Promise}
+ *
+ * @example
+ * DriveSelectorService.open().then(function(drive) {
+ * console.log(drive);
+ * });
+ */
+ this.open = function() {
+ return $uibModal.open({
+ animation: true,
+ templateUrl: './browser/components/drive-selector/templates/drive-selector-modal.tpl.html',
+ controller: 'DriveSelectorController as modal',
+ size: 'sm'
+ }).result;
+ };
+
+};
diff --git a/lib/browser/components/drive-selector/templates/drive-selector-modal.tpl.html b/lib/browser/components/drive-selector/templates/drive-selector-modal.tpl.html
new file mode 100644
index 00000000..e966bfbb
--- /dev/null
+++ b/lib/browser/components/drive-selector/templates/drive-selector-modal.tpl.html
@@ -0,0 +1,17 @@
+
+
+
+
+ -
+
+
{{ drive.description }} - {{ drive.size }}
+
{{ drive.device }}
+
+
+
+
+
diff --git a/tests/browser/components/drive-selector.spec.js b/tests/browser/components/drive-selector.spec.js
index 0a0bb858..b2d5c04f 100644
--- a/tests/browser/components/drive-selector.spec.js
+++ b/tests/browser/components/drive-selector.spec.js
@@ -3,7 +3,7 @@
const m = require('mochainon');
const angular = require('angular');
require('angular-mocks');
-require('../../../lib/browser/components/drive-selector');
+require('../../../lib/browser/components/drive-selector/drive-selector');
describe('Browser: DriveSelector', function() {