From 401cdb6f52acc2fdfe7f5a5f7b4509c4a9408f59 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Wed, 14 Sep 2016 18:06:00 -0700 Subject: [PATCH] feat(GUI): image-defined recommended drive size (#703) Recently, we've added support for a `recommendedDriveSize` property in the `manifest.json` of extended image archives, which the image can use to warn the user that his drive, even if it is large enough to hold the image, might not be large enough to deliver a good usage experience later on. When this property is found, the GUI reacts in the following ways: - Drives that are large enough to hold the image but don't meet the recommended drive size are tagged with a warning label in the drive selector component. - Attempting to select a "labeled" drive opens a warning modal asking for user confirmation. - Drives that don't meet the recommended drive size declared in the image won't get auto-selected. - If there is a drive already selected, and the user picks an image whose recommended drive size is greater than the drive size, the currently selected drive gets auto-deselected. Code-wise, the following significant changes have been introduced: - Implement `SelectionStateModel.getImageRecommendedDriveSize()`. - Implement `SelectionStateModel.isDriveSizeRecommended()`. - Extract `WarningModal` out of the settings page (the dangerous setting modal). Change-Type: minor Changelog-Entry: Allow images to declare a recommended minimum drive size. See: https://github.com/resin-io-modules/etcher-image-stream/pull/36 Fixes: https://github.com/resin-io/etcher/issues/698 Signed-off-by: Juan Cruz Viotti --- .../controllers/drive-selector.js | 41 ++++++++- .../drive-selector/drive-selector.js | 1 + .../templates/drive-selector-modal.tpl.html | 7 +- .../controllers/warning-modal.js} | 8 +- .../warning-modal/services/warning-modal.js | 46 ++++++++++ .../warning-modal/styles/_warning-modal.scss | 19 ++++ .../templates/warning-modal.tpl.html} | 2 +- .../components/warning-modal/warning-modal.js | 32 +++++++ lib/gui/models/selection-state.js | 45 ++++++++++ lib/gui/models/store.js | 17 +++- .../pages/settings/controllers/settings.js | 13 +-- lib/gui/pages/settings/settings.js | 3 +- lib/gui/pages/settings/styles/_settings.scss | 4 - .../settings/templates/settings.tpl.html | 2 +- lib/gui/scss/main.scss | 1 + tests/gui/models/drives.spec.js | 24 ++++- tests/gui/models/selection-state.spec.js | 88 +++++++++++++++++++ 17 files changed, 321 insertions(+), 32 deletions(-) rename lib/gui/{pages/settings/controllers/settings-dangerous-modal.js => components/warning-modal/controllers/warning-modal.js} (84%) create mode 100644 lib/gui/components/warning-modal/services/warning-modal.js create mode 100644 lib/gui/components/warning-modal/styles/_warning-modal.scss rename lib/gui/{pages/settings/templates/settings-dangerous-modal.tpl.html => components/warning-modal/templates/warning-modal.tpl.html} (87%) create mode 100644 lib/gui/components/warning-modal/warning-modal.js diff --git a/lib/gui/components/drive-selector/controllers/drive-selector.js b/lib/gui/components/drive-selector/controllers/drive-selector.js index 8ec1a003..d62528ae 100644 --- a/lib/gui/components/drive-selector/controllers/drive-selector.js +++ b/lib/gui/components/drive-selector/controllers/drive-selector.js @@ -18,7 +18,7 @@ const _ = require('lodash'); -module.exports = function($uibModalInstance, DrivesModel, SelectionStateModel) { +module.exports = function($uibModalInstance, DrivesModel, SelectionStateModel, WarningModalService) { /** * @summary The drive selector state @@ -40,6 +40,44 @@ module.exports = function($uibModalInstance, DrivesModel, SelectionStateModel) { */ this.drives = DrivesModel; + /** + * @summary Toggle a drive selection + * @function + * @public + * + * @param {Object} drive - drive + * + * @example + * DriveSelectorController.toggleDrive({ + * device: '/dev/disk2', + * size: 999999999, + * name: 'Cruzer USB drive' + * }); + */ + this.toggleDrive = (drive) => { + if (!SelectionStateModel.isDriveValid(drive)) { + return; + } + + if (_.some([ + SelectionStateModel.isDriveSizeRecommended(drive), + SelectionStateModel.isCurrentDrive(drive.device) + ])) { + SelectionStateModel.toggleSetDrive(drive.device); + return; + } + + WarningModalService.display([ + `This image recommends a ${SelectionStateModel.getImageRecommendedDriveSize()}`, + `bytes drive, however ${drive.device} is only ${drive.size} bytes.`, + 'Are you sure you want to continue?' + ].join(' ')).then((userAccepted) => { + if (userAccepted) { + SelectionStateModel.toggleSetDrive(drive.device); + } + }); + }; + /** * @summary Close the modal and resolve the selected drive * @function @@ -55,7 +93,6 @@ module.exports = function($uibModalInstance, DrivesModel, SelectionStateModel) { // the drive is then unplugged from the computer and the modal // is resolved with a non-existent drive. if (!selectedDrive || !_.includes(this.drives.getDrives(), selectedDrive)) { - $uibModalInstance.close(); } else { $uibModalInstance.close(selectedDrive); diff --git a/lib/gui/components/drive-selector/drive-selector.js b/lib/gui/components/drive-selector/drive-selector.js index 37b73600..c4e2ac89 100644 --- a/lib/gui/components/drive-selector/drive-selector.js +++ b/lib/gui/components/drive-selector/drive-selector.js @@ -24,6 +24,7 @@ const angular = require('angular'); const MODULE_NAME = 'Etcher.Components.DriveSelector'; const DriveSelector = angular.module(MODULE_NAME, [ require('../modal/modal'), + require('../warning-modal/warning-modal'), require('../../models/drives'), require('../../models/selection-state'), require('../../utils/byte-size/byte-size') diff --git a/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html b/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html index 17d65e6f..7817ceda 100644 --- a/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html +++ b/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html @@ -7,13 +7,18 @@