mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-25 07:47:18 +00:00
refactor(GUI): extract MainPage from lib/gui/app.js
(#607)
`lib/gui/app.js` contains a lot of code that should have been split long ago. This PR extracts the "main page" logic into an actual page component in `lib/gui/pages`. Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
parent
1febeda04e
commit
eef1d51a7a
@ -91,7 +91,7 @@ straightforward interfaces as AngularJS modules, and provide a single place
|
||||
where all the modules are tied together.
|
||||
|
||||
Therefore, if you want to get a rough idea of how the GUI works, the perfect
|
||||
place to start is [application controller][appcontroller] and the [main
|
||||
place to start is [main controller][maincontroller] and the [main
|
||||
view][mainview], and diving into specific modules depending on your interests.
|
||||
|
||||
Summary
|
||||
@ -106,8 +106,8 @@ be documented instead!
|
||||
[lego-blocks]: https://github.com/sindresorhus/ama/issues/10#issuecomment-117766328
|
||||
[etcher-image-write]: https://github.com/resin-io-modules/etcher-image-write
|
||||
[exit-codes]: https://github.com/resin-io/etcher/blob/master/lib/src/exit-codes.js
|
||||
[appcontroller]: https://github.com/resin-io/etcher/blob/master/lib/gui/app.js
|
||||
[mainview]: https://github.com/resin-io/etcher/blob/master/lib/gui/partials/main.html
|
||||
[maincontroller]: https://github.com/resin-io/etcher/blob/master/lib/gui/pages/main/controllers/main.js
|
||||
[mainview]: https://github.com/resin-io/etcher/blob/master/lib/gui/pages/main/templates/main.tpl.html
|
||||
[cli-dir]: https://github.com/resin-io/etcher/tree/master/lib/cli
|
||||
[gui-dir]: https://github.com/resin-io/etcher/tree/master/lib/gui
|
||||
|
||||
|
235
lib/gui/app.js
235
lib/gui/app.js
@ -26,51 +26,35 @@ var angular = require('angular');
|
||||
|
||||
/* eslint-enable no-var */
|
||||
|
||||
const _ = require('lodash');
|
||||
const Store = require('./models/store');
|
||||
|
||||
const app = angular.module('Etcher', [
|
||||
require('angular-ui-router'),
|
||||
require('angular-ui-bootstrap'),
|
||||
require('angular-moment'),
|
||||
require('angular-middle-ellipses'),
|
||||
require('angular-if-state'),
|
||||
require('angular-seconds-to-date'),
|
||||
|
||||
// Etcher modules
|
||||
require('./modules/drive-scanner'),
|
||||
require('./modules/image-writer'),
|
||||
require('./modules/analytics'),
|
||||
|
||||
// Models
|
||||
require('./models/selection-state'),
|
||||
require('./models/settings'),
|
||||
require('./models/supported-formats'),
|
||||
require('./models/drives'),
|
||||
require('./models/flash-state'),
|
||||
|
||||
// Components
|
||||
require('./components/progress-button/progress-button'),
|
||||
require('./components/drive-selector/drive-selector'),
|
||||
require('./components/svg-icon/svg-icon'),
|
||||
require('./components/update-notifier/update-notifier'),
|
||||
require('./components/tooltip-modal/tooltip-modal'),
|
||||
|
||||
// Pages
|
||||
require('./pages/main/main'),
|
||||
require('./pages/finish/finish'),
|
||||
require('./pages/settings/settings'),
|
||||
|
||||
// OS
|
||||
require('./os/notification/notification'),
|
||||
require('./os/window-progress/window-progress'),
|
||||
require('./os/open-external/open-external'),
|
||||
require('./os/dropzone/dropzone'),
|
||||
require('./os/dialog/dialog'),
|
||||
|
||||
// Utils
|
||||
require('./utils/path/path'),
|
||||
require('./utils/manifest-bind/manifest-bind'),
|
||||
require('./utils/byte-size/byte-size')
|
||||
require('./utils/manifest-bind/manifest-bind')
|
||||
]);
|
||||
|
||||
app.run((AnalyticsService, UpdateNotifierService, SelectionStateModel) => {
|
||||
@ -121,219 +105,6 @@ app.run((AnalyticsService, OSWindowProgressService, FlashStateModel) => {
|
||||
});
|
||||
});
|
||||
|
||||
app.config(($stateProvider, $urlRouterProvider) => {
|
||||
app.config(($urlRouterProvider) => {
|
||||
$urlRouterProvider.otherwise('/main');
|
||||
|
||||
$stateProvider
|
||||
.state('main', {
|
||||
url: '/main',
|
||||
controller: 'AppController as app',
|
||||
templateUrl: './partials/main.html'
|
||||
});
|
||||
});
|
||||
|
||||
app.controller('AppController', function(
|
||||
$state,
|
||||
DriveScannerService,
|
||||
SelectionStateModel,
|
||||
FlashStateModel,
|
||||
SettingsModel,
|
||||
SupportedFormatsModel,
|
||||
DrivesModel,
|
||||
ImageWriterService,
|
||||
AnalyticsService,
|
||||
DriveSelectorService,
|
||||
UpdateNotifierService,
|
||||
TooltipModalService,
|
||||
OSWindowProgressService,
|
||||
OSNotificationService,
|
||||
OSDialogService,
|
||||
OSOpenExternalService
|
||||
) {
|
||||
this.formats = SupportedFormatsModel;
|
||||
this.selection = SelectionStateModel;
|
||||
this.drives = DrivesModel;
|
||||
this.writer = ImageWriterService;
|
||||
this.state = FlashStateModel;
|
||||
this.settings = SettingsModel;
|
||||
this.tooltipModal = TooltipModalService;
|
||||
|
||||
this.handleError = (error) => {
|
||||
|
||||
// This particular error is handled by the alert ribbon
|
||||
// on the main application page.
|
||||
if (error.code === 'ENOSPC') {
|
||||
AnalyticsService.logEvent('Drive ran out of space');
|
||||
return;
|
||||
}
|
||||
|
||||
OSDialogService.showError(error);
|
||||
|
||||
// Also throw it so it gets displayed in DevTools
|
||||
// and its reported by TrackJS.
|
||||
throw error;
|
||||
};
|
||||
|
||||
// This catches the case where the user enters
|
||||
// the settings screen when a flash finished
|
||||
// and goes back to the main screen with the back button.
|
||||
if (!FlashStateModel.isFlashing()) {
|
||||
|
||||
this.selection.clear({
|
||||
|
||||
// Preserve image, in case there is one, otherwise
|
||||
// we revert the behaviour of "Use same image".
|
||||
preserveImage: true
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
DriveScannerService.start();
|
||||
|
||||
DriveScannerService.on('error', this.handleError);
|
||||
|
||||
DriveScannerService.on('drives', (drives) => {
|
||||
this.drives.setDrives(drives);
|
||||
|
||||
if (_.isEmpty(drives)) {
|
||||
DriveSelectorService.close();
|
||||
}
|
||||
});
|
||||
|
||||
this.selectImage = (image) => {
|
||||
if (!SupportedFormatsModel.isSupportedImage(image.path)) {
|
||||
OSDialogService.showError('Invalid image', `${image.path} is not a supported image type.`);
|
||||
AnalyticsService.logEvent('Invalid image', image);
|
||||
return;
|
||||
}
|
||||
|
||||
this.selection.setImage(image);
|
||||
AnalyticsService.logEvent('Select image', _.omit(image, 'logo'));
|
||||
};
|
||||
|
||||
this.openImageUrl = () => {
|
||||
const imageUrl = this.selection.getImageUrl();
|
||||
|
||||
if (imageUrl) {
|
||||
OSOpenExternalService.open(imageUrl);
|
||||
}
|
||||
};
|
||||
|
||||
this.openImageSelector = () => {
|
||||
return OSDialogService.selectImage().then((image) => {
|
||||
|
||||
// Avoid analytics and selection state changes
|
||||
// if no file was resolved from the dialog.
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectImage(image);
|
||||
}).catch(this.handleError);
|
||||
};
|
||||
|
||||
this.selectDrive = (drive) => {
|
||||
if (!drive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selection.setDrive(drive.device);
|
||||
|
||||
AnalyticsService.logEvent('Select drive', {
|
||||
device: drive.device
|
||||
});
|
||||
};
|
||||
|
||||
this.openDriveSelector = () => {
|
||||
DriveSelectorService.open()
|
||||
.then(this.selectDrive)
|
||||
.catch(this.handleError);
|
||||
};
|
||||
|
||||
this.reselectImage = () => {
|
||||
if (FlashStateModel.isFlashing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reselecting an image automatically
|
||||
// de-selects the current drive, if any.
|
||||
// This is made so the user effectively
|
||||
// "returns" to the first step.
|
||||
this.selection.clear();
|
||||
|
||||
this.openImageSelector();
|
||||
AnalyticsService.logEvent('Reselect image');
|
||||
};
|
||||
|
||||
this.reselectDrive = () => {
|
||||
if (FlashStateModel.isFlashing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.openDriveSelector();
|
||||
AnalyticsService.logEvent('Reselect drive');
|
||||
};
|
||||
|
||||
this.restartAfterFailure = () => {
|
||||
this.selection.clear({
|
||||
preserveImage: true
|
||||
});
|
||||
|
||||
FlashStateModel.resetState();
|
||||
AnalyticsService.logEvent('Restart after failure');
|
||||
};
|
||||
|
||||
this.wasLastFlashSuccessful = () => {
|
||||
const flashResults = FlashStateModel.getFlashResults();
|
||||
|
||||
if (_.get(flashResults, 'cancelled', false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return _.get(flashResults, 'passedValidation', true);
|
||||
};
|
||||
|
||||
this.flash = (image, drive) => {
|
||||
|
||||
if (FlashStateModel.isFlashing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop scanning drives when flashing
|
||||
// otherwise Windows throws EPERM
|
||||
DriveScannerService.stop();
|
||||
|
||||
AnalyticsService.logEvent('Flash', {
|
||||
image: image,
|
||||
device: drive.device
|
||||
});
|
||||
|
||||
return this.writer.flash(image, drive).then(() => {
|
||||
const results = FlashStateModel.getFlashResults();
|
||||
|
||||
if (results.cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.passedValidation) {
|
||||
OSNotificationService.send('Success!', 'Your flash is complete');
|
||||
AnalyticsService.logEvent('Done');
|
||||
$state.go('success');
|
||||
} else {
|
||||
OSNotificationService.send('Oops!', 'Looks like your flash has failed');
|
||||
AnalyticsService.logEvent('Validation error');
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
if (error.type === 'check') {
|
||||
AnalyticsService.logEvent('Validation error');
|
||||
} else {
|
||||
AnalyticsService.logEvent('Flash error');
|
||||
}
|
||||
|
||||
this.handleError(error);
|
||||
})
|
||||
.finally(OSWindowProgressService.clear);
|
||||
};
|
||||
});
|
||||
|
225
lib/gui/pages/main/controllers/main.js
Normal file
225
lib/gui/pages/main/controllers/main.js
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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(
|
||||
$state,
|
||||
DriveScannerService,
|
||||
SelectionStateModel,
|
||||
FlashStateModel,
|
||||
SettingsModel,
|
||||
SupportedFormatsModel,
|
||||
DrivesModel,
|
||||
ImageWriterService,
|
||||
AnalyticsService,
|
||||
DriveSelectorService,
|
||||
TooltipModalService,
|
||||
OSWindowProgressService,
|
||||
OSNotificationService,
|
||||
OSDialogService,
|
||||
OSOpenExternalService
|
||||
) {
|
||||
|
||||
this.formats = SupportedFormatsModel;
|
||||
this.selection = SelectionStateModel;
|
||||
this.drives = DrivesModel;
|
||||
this.state = FlashStateModel;
|
||||
this.settings = SettingsModel;
|
||||
this.tooltipModal = TooltipModalService;
|
||||
|
||||
const handleError = (error) => {
|
||||
|
||||
// This particular error is handled by the alert ribbon
|
||||
// on the main application page.
|
||||
if (error.code === 'ENOSPC') {
|
||||
AnalyticsService.logEvent('Drive ran out of space');
|
||||
return;
|
||||
}
|
||||
|
||||
OSDialogService.showError(error);
|
||||
|
||||
// Also throw it so it gets displayed in DevTools
|
||||
// and its reported by TrackJS.
|
||||
throw error;
|
||||
};
|
||||
|
||||
// This catches the case where the user enters
|
||||
// the settings screen when a flash finished
|
||||
// and goes back to the main screen with the back button.
|
||||
if (!FlashStateModel.isFlashing()) {
|
||||
|
||||
this.selection.clear({
|
||||
|
||||
// Preserve image, in case there is one, otherwise
|
||||
// we revert the behaviour of "Use same image".
|
||||
preserveImage: true
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
DriveScannerService.start();
|
||||
|
||||
DriveScannerService.on('error', handleError);
|
||||
|
||||
DriveScannerService.on('drives', (drives) => {
|
||||
this.drives.setDrives(drives);
|
||||
|
||||
if (_.isEmpty(drives)) {
|
||||
DriveSelectorService.close();
|
||||
}
|
||||
});
|
||||
|
||||
this.selectImage = (image) => {
|
||||
if (!SupportedFormatsModel.isSupportedImage(image.path)) {
|
||||
OSDialogService.showError('Invalid image', `${image.path} is not a supported image type.`);
|
||||
AnalyticsService.logEvent('Invalid image', image);
|
||||
return;
|
||||
}
|
||||
|
||||
this.selection.setImage(image);
|
||||
AnalyticsService.logEvent('Select image', _.omit(image, 'logo'));
|
||||
};
|
||||
|
||||
this.openImageUrl = () => {
|
||||
const imageUrl = this.selection.getImageUrl();
|
||||
|
||||
if (imageUrl) {
|
||||
OSOpenExternalService.open(imageUrl);
|
||||
}
|
||||
};
|
||||
|
||||
this.openImageSelector = () => {
|
||||
return OSDialogService.selectImage().then((image) => {
|
||||
|
||||
// Avoid analytics and selection state changes
|
||||
// if no file was resolved from the dialog.
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectImage(image);
|
||||
}).catch(handleError);
|
||||
};
|
||||
|
||||
this.selectDrive = (drive) => {
|
||||
if (!drive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selection.setDrive(drive.device);
|
||||
|
||||
AnalyticsService.logEvent('Select drive', {
|
||||
device: drive.device
|
||||
});
|
||||
};
|
||||
|
||||
this.openDriveSelector = () => {
|
||||
DriveSelectorService.open()
|
||||
.then(this.selectDrive)
|
||||
.catch(handleError);
|
||||
};
|
||||
|
||||
this.reselectImage = () => {
|
||||
if (FlashStateModel.isFlashing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reselecting an image automatically
|
||||
// de-selects the current drive, if any.
|
||||
// This is made so the user effectively
|
||||
// "returns" to the first step.
|
||||
this.selection.clear();
|
||||
|
||||
this.openImageSelector();
|
||||
AnalyticsService.logEvent('Reselect image');
|
||||
};
|
||||
|
||||
this.reselectDrive = () => {
|
||||
if (FlashStateModel.isFlashing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.openDriveSelector();
|
||||
AnalyticsService.logEvent('Reselect drive');
|
||||
};
|
||||
|
||||
this.restartAfterFailure = () => {
|
||||
this.selection.clear({
|
||||
preserveImage: true
|
||||
});
|
||||
|
||||
FlashStateModel.resetState();
|
||||
AnalyticsService.logEvent('Restart after failure');
|
||||
};
|
||||
|
||||
this.wasLastFlashSuccessful = () => {
|
||||
const flashResults = FlashStateModel.getFlashResults();
|
||||
|
||||
if (_.get(flashResults, 'cancelled', false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return _.get(flashResults, 'passedValidation', true);
|
||||
};
|
||||
|
||||
this.flash = (image, drive) => {
|
||||
|
||||
if (FlashStateModel.isFlashing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop scanning drives when flashing
|
||||
// otherwise Windows throws EPERM
|
||||
DriveScannerService.stop();
|
||||
|
||||
AnalyticsService.logEvent('Flash', {
|
||||
image: image,
|
||||
device: drive.device
|
||||
});
|
||||
|
||||
return ImageWriterService.flash(image, drive).then(() => {
|
||||
const results = FlashStateModel.getFlashResults();
|
||||
|
||||
if (results.cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.passedValidation) {
|
||||
OSNotificationService.send('Success!', 'Your flash is complete');
|
||||
AnalyticsService.logEvent('Done');
|
||||
$state.go('success');
|
||||
} else {
|
||||
OSNotificationService.send('Oops!', 'Looks like your flash has failed');
|
||||
AnalyticsService.logEvent('Validation error');
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
if (error.type === 'check') {
|
||||
AnalyticsService.logEvent('Validation error');
|
||||
} else {
|
||||
AnalyticsService.logEvent('Flash error');
|
||||
}
|
||||
|
||||
handleError(error);
|
||||
})
|
||||
.finally(OSWindowProgressService.clear);
|
||||
};
|
||||
|
||||
};
|
67
lib/gui/pages/main/main.js
Normal file
67
lib/gui/pages/main/main.js
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.Pages.Main
|
||||
*
|
||||
* The finish page represents the application main page.
|
||||
*/
|
||||
|
||||
const angular = require('angular');
|
||||
const MODULE_NAME = 'Etcher.Pages.Main';
|
||||
|
||||
const MainPage = angular.module(MODULE_NAME, [
|
||||
require('angular-ui-router'),
|
||||
require('angular-moment'),
|
||||
require('angular-middle-ellipses'),
|
||||
require('angular-seconds-to-date'),
|
||||
|
||||
require('../../components/drive-selector/drive-selector'),
|
||||
require('../../components/tooltip-modal/tooltip-modal'),
|
||||
require('../../components/progress-button/progress-button'),
|
||||
|
||||
require('../../os/window-progress/window-progress'),
|
||||
require('../../os/notification/notification'),
|
||||
require('../../os/dialog/dialog'),
|
||||
require('../../os/open-external/open-external'),
|
||||
|
||||
require('../../modules/drive-scanner'),
|
||||
require('../../modules/image-writer'),
|
||||
require('../../modules/analytics'),
|
||||
require('../../models/selection-state'),
|
||||
require('../../models/flash-state'),
|
||||
require('../../models/settings'),
|
||||
require('../../models/supported-formats'),
|
||||
require('../../models/drives'),
|
||||
|
||||
require('../../utils/path/path'),
|
||||
require('../../utils/byte-size/byte-size')
|
||||
]);
|
||||
|
||||
MainPage.controller('MainController', require('./controllers/main'));
|
||||
|
||||
MainPage.config(($stateProvider) => {
|
||||
$stateProvider
|
||||
.state('main', {
|
||||
url: '/main',
|
||||
controller: 'MainController as main',
|
||||
templateUrl: './pages/main/templates/main.tpl.html'
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = MODULE_NAME;
|
126
lib/gui/pages/main/templates/main.tpl.html
Normal file
126
lib/gui/pages/main/templates/main.tpl.html
Normal file
@ -0,0 +1,126 @@
|
||||
<div class="row around-xs">
|
||||
<div class="col-xs">
|
||||
<div class="box text-center" os-dropzone="main.selectImage($file)">
|
||||
<svg-icon class="center-block" path="{{ main.selection.getImageLogo() || '../../../assets/image.svg' }}"></svg-icon>
|
||||
<span class="icon-caption">SELECT IMAGE</span>
|
||||
<span class="badge space-top-medium">1</span>
|
||||
|
||||
<div class="space-vertical-large">
|
||||
<div ng-hide="main.selection.hasImage()">
|
||||
<button class="btn btn-primary btn-brick" ng-click="main.openImageSelector()">Select image</button>
|
||||
|
||||
<p class="step-footer">
|
||||
{{ ::main.formats.getAllExtensions().slice(0, 3).join(', ') }}, and
|
||||
<span class="step-footer-underline"
|
||||
uib-tooltip="{{ main.formats.getAllExtensions().slice(3).join(', ') }}">many more</span>
|
||||
</p>
|
||||
</div>
|
||||
<div ng-if="main.selection.hasImage()">
|
||||
<div ng-click="main.openImageUrl()"
|
||||
ng-bind="main.selection.getImageName() || main.selection.getImagePath() | basename | middleEllipses:25"></div>
|
||||
|
||||
<button class="btn btn-link step-tooltip"
|
||||
ng-click="main.tooltipModal.show({
|
||||
title: 'IMAGE FILE NAME',
|
||||
message: main.selection.getImagePath()
|
||||
})">SHOW IN FULL</button>
|
||||
|
||||
<button class="btn btn-link step-footer"
|
||||
ng-click="main.reselectImage()"
|
||||
ng-hide="main.state.isFlashing()">Change</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs">
|
||||
<div class="box text-center relative">
|
||||
<div class="step-border-left" ng-disabled="!main.selection.hasImage()"></div>
|
||||
<div class="step-border-right" ng-disabled="!main.selection.hasImage() || !main.selection.hasDrive()"></div>
|
||||
|
||||
<svg-icon class="center-block"
|
||||
path="../../../assets/drive.svg"
|
||||
ng-disabled="!main.selection.hasImage()"></svg-icon>
|
||||
<span class="icon-caption"
|
||||
ng-disabled="!main.selection.hasImage()">SELECT DRIVE</span>
|
||||
|
||||
<span class="badge space-top-medium" ng-disabled="!main.selection.hasImage()">2</span>
|
||||
|
||||
<div class="space-vertical-large">
|
||||
<div ng-hide="main.selection.hasDrive()">
|
||||
|
||||
<div ng-show="main.drives.hasAvailableDrives() || !main.selection.hasImage()">
|
||||
<button class="btn btn-primary btn-brick"
|
||||
ng-disabled="!main.selection.hasImage()"
|
||||
ng-click="main.openDriveSelector()">Select drive</button>
|
||||
</div>
|
||||
|
||||
<div ng-hide="main.drives.hasAvailableDrives() || !main.selection.hasImage()">
|
||||
<button class="btn btn-danger btn-brick">Connect a drive</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div ng-show="main.selection.hasDrive()">
|
||||
<div ng-class="{
|
||||
soft: !main.selection.hasImage()
|
||||
}">{{ main.selection.getDrive().name }} - {{ main.selection.getDrive().size | gigabyte | number:1 }} GB</div>
|
||||
<button class="btn btn-link step-footer"
|
||||
ng-click="main.reselectDrive()"
|
||||
ng-hide="main.state.isFlashing()">Change</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs">
|
||||
<div class="box text-center">
|
||||
<svg-icon class="center-block"
|
||||
path="../../../assets/flash.svg"
|
||||
ng-disabled="!main.selection.hasImage() || !main.selection.hasDrive()"></svg-icon>
|
||||
<span class="icon-caption"
|
||||
ng-disabled="!main.selection.hasImage() || !main.selection.hasDrive()">FLASH IMAGE</span>
|
||||
|
||||
<span class="badge space-top-medium" ng-disabled="!main.selection.hasImage() || !main.selection.hasDrive()">3</span>
|
||||
|
||||
<div class="space-vertical-large">
|
||||
<progress-button class="btn-brick"
|
||||
percentage="main.state.getFlashState().percentage"
|
||||
striped="{{ main.state.getFlashState().type == 'check' }}"
|
||||
ng-attr-active="{{ main.state.isFlashing() }}"
|
||||
ng-show="main.wasLastFlashSuccessful()"
|
||||
ng-click="main.flash(main.selection.getImagePath(), main.selection.getDrive())"
|
||||
ng-disabled="!main.selection.hasImage() || !main.selection.hasDrive()">
|
||||
<span ng-show="main.state.getFlashState().percentage == 100 && main.state.isFlashing()">Finishing...</span>
|
||||
<span ng-show="main.state.getFlashState().percentage == 0 && !main.state.isFlashing()">Flash!</span>
|
||||
<span ng-show="main.state.getFlashState().percentage == 0 && main.state.isFlashing() && !main.state.getFlashState().speed">Starting...</span>
|
||||
<span ng-show="main.state.getFlashState().speed && main.state.getFlashState().percentage != 100 && main.state.getFlashState().type != 'check'"
|
||||
ng-bind="main.state.getFlashState().percentage + '% '"></span>
|
||||
<span ng-show="main.state.getFlashState().speed && main.state.getFlashState().percentage != 100 && main.state.getFlashState().type == 'check'"
|
||||
ng-bind="main.state.getFlashState().percentage + '% Validating...'"></span>
|
||||
</progress-button>
|
||||
|
||||
<div class="alert-ribbon alert-warning" ng-class="{ 'alert-ribbon--open': !main.wasLastFlashSuccessful() }">
|
||||
<span class="glyphicon glyphicon-warning-sign"></span>
|
||||
<span ng-show="main.state.getFlashResults().errorCode === 'ENOSPC'">
|
||||
Not enough space on the drive.<br>Please insert larger one and <button class="btn btn-link" ng-click="main.restartAfterFailure()">try again</button>
|
||||
</span>
|
||||
<span ng-show="main.state.getFlashResults().errorCode !== 'ENOSPC' && main.settings.get('validateWriteOnSuccess')">
|
||||
Your removable drive may be corrupted.<br>Try inserting a different one and <button class="btn btn-link" ng-click="main.restartAfterFailure()">press "retry"</button>
|
||||
</span>
|
||||
<span ng-show="main.state.getFlashResults().errorCode !== 'ENOSPC' && !main.settings.get('validateWriteOnSuccess')">
|
||||
Oops, seems something went wrong. Click <button class="btn btn-link" ng-click="main.restartAfterFailure()">here</button> to retry
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-warning btn-brick" ng-hide="main.wasLastFlashSuccessful()" ng-click="main.restartAfterFailure()">
|
||||
<span class="glyphicon glyphicon-repeat"></span> Retry
|
||||
</button>
|
||||
|
||||
<p class="step-footer step-footer-split" ng-show="main.state.getFlashState().speed && main.state.getFlashState().percentage != 100">
|
||||
<span>ETA: {{ main.state.getFlashState().eta | secondsToDate | amDateFormat:'m[m]ss[s]' }}</span>
|
||||
<span ng-bind="main.state.getFlashState().speed.toFixed(2) + ' MB/s'"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,126 +0,0 @@
|
||||
<div class="row around-xs">
|
||||
<div class="col-xs">
|
||||
<div class="box text-center" os-dropzone="app.selectImage($file)">
|
||||
<svg-icon class="center-block" path="{{ app.selection.getImageLogo() || '../../../assets/image.svg' }}"></svg-icon>
|
||||
<span class="icon-caption">SELECT IMAGE</span>
|
||||
<span class="badge space-top-medium">1</span>
|
||||
|
||||
<div class="space-vertical-large">
|
||||
<div ng-hide="app.selection.hasImage()">
|
||||
<button class="btn btn-primary btn-brick" ng-click="app.openImageSelector()">Select image</button>
|
||||
|
||||
<p class="step-footer">
|
||||
{{ ::app.formats.getAllExtensions().slice(0, 3).join(', ') }}, and
|
||||
<span class="step-footer-underline"
|
||||
uib-tooltip="{{ app.formats.getAllExtensions().slice(3).join(', ') }}">many more</span>
|
||||
</p>
|
||||
</div>
|
||||
<div ng-if="app.selection.hasImage()">
|
||||
<div ng-click="app.openImageUrl()"
|
||||
ng-bind="app.selection.getImageName() || app.selection.getImagePath() | basename | middleEllipses:25"></div>
|
||||
|
||||
<button class="btn btn-link step-tooltip"
|
||||
ng-click="app.tooltipModal.show({
|
||||
title: 'IMAGE FILE NAME',
|
||||
message: app.selection.getImagePath()
|
||||
})">SHOW IN FULL</button>
|
||||
|
||||
<button class="btn btn-link step-footer"
|
||||
ng-click="app.reselectImage()"
|
||||
ng-hide="app.state.isFlashing()">Change</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs">
|
||||
<div class="box text-center relative">
|
||||
<div class="step-border-left" ng-disabled="!app.selection.hasImage()"></div>
|
||||
<div class="step-border-right" ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()"></div>
|
||||
|
||||
<svg-icon class="center-block"
|
||||
path="../../../assets/drive.svg"
|
||||
ng-disabled="!app.selection.hasImage()"></svg-icon>
|
||||
<span class="icon-caption"
|
||||
ng-disabled="!app.selection.hasImage()">SELECT DRIVE</span>
|
||||
|
||||
<span class="badge space-top-medium" ng-disabled="!app.selection.hasImage()">2</span>
|
||||
|
||||
<div class="space-vertical-large">
|
||||
<div ng-hide="app.selection.hasDrive()">
|
||||
|
||||
<div ng-show="app.drives.hasAvailableDrives() || !app.selection.hasImage()">
|
||||
<button class="btn btn-primary btn-brick"
|
||||
ng-disabled="!app.selection.hasImage()"
|
||||
ng-click="app.openDriveSelector()">Select drive</button>
|
||||
</div>
|
||||
|
||||
<div ng-hide="app.drives.hasAvailableDrives() || !app.selection.hasImage()">
|
||||
<button class="btn btn-danger btn-brick">Connect a drive</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div ng-show="app.selection.hasDrive()">
|
||||
<div ng-class="{
|
||||
soft: !app.selection.hasImage()
|
||||
}">{{ app.selection.getDrive().name }} - {{ app.selection.getDrive().size | gigabyte | number:1 }} GB</div>
|
||||
<button class="btn btn-link step-footer"
|
||||
ng-click="app.reselectDrive()"
|
||||
ng-hide="app.state.isFlashing()">Change</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs">
|
||||
<div class="box text-center">
|
||||
<svg-icon class="center-block"
|
||||
path="../../../assets/flash.svg"
|
||||
ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()"></svg-icon>
|
||||
<span class="icon-caption"
|
||||
ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">FLASH IMAGE</span>
|
||||
|
||||
<span class="badge space-top-medium" ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">3</span>
|
||||
|
||||
<div class="space-vertical-large">
|
||||
<progress-button class="btn-brick"
|
||||
percentage="app.state.getFlashState().percentage"
|
||||
striped="{{ app.state.getFlashState().type == 'check' }}"
|
||||
ng-attr-active="{{ app.state.isFlashing() }}"
|
||||
ng-show="app.wasLastFlashSuccessful()"
|
||||
ng-click="app.flash(app.selection.getImagePath(), app.selection.getDrive())"
|
||||
ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">
|
||||
<span ng-show="app.state.getFlashState().percentage == 100 && app.state.isFlashing()">Finishing...</span>
|
||||
<span ng-show="app.state.getFlashState().percentage == 0 && !app.state.isFlashing()">Flash!</span>
|
||||
<span ng-show="app.state.getFlashState().percentage == 0 && app.state.isFlashing() && !app.state.getFlashState().speed">Starting...</span>
|
||||
<span ng-show="app.state.getFlashState().speed && app.state.getFlashState().percentage != 100 && app.state.getFlashState().type != 'check'"
|
||||
ng-bind="app.state.getFlashState().percentage + '% '"></span>
|
||||
<span ng-show="app.state.getFlashState().speed && app.state.getFlashState().percentage != 100 && app.state.getFlashState().type == 'check'"
|
||||
ng-bind="app.state.getFlashState().percentage + '% Validating...'"></span>
|
||||
</progress-button>
|
||||
|
||||
<div class="alert-ribbon alert-warning" ng-class="{ 'alert-ribbon--open': !app.wasLastFlashSuccessful() }">
|
||||
<span class="glyphicon glyphicon-warning-sign"></span>
|
||||
<span ng-show="app.state.getFlashResults().errorCode === 'ENOSPC'">
|
||||
Not enough space on the drive.<br>Please insert larger one and <button class="btn btn-link" ng-click="app.restartAfterFailure()">try again</button>
|
||||
</span>
|
||||
<span ng-show="app.state.getFlashResults().errorCode !== 'ENOSPC' && app.settings.get('validateWriteOnSuccess')">
|
||||
Your removable drive may be corrupted.<br>Try inserting a different one and <button class="btn btn-link" ng-click="app.restartAfterFailure()">press "retry"</button>
|
||||
</span>
|
||||
<span ng-show="app.state.getFlashResults().errorCode !== 'ENOSPC' && !app.settings.get('validateWriteOnSuccess')">
|
||||
Oops, seems something went wrong. Click <button class="btn btn-link" ng-click="app.restartAfterFailure()">here</button> to retry
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-warning btn-brick" ng-hide="app.wasLastFlashSuccessful()" ng-click="app.restartAfterFailure()">
|
||||
<span class="glyphicon glyphicon-repeat"></span> Retry
|
||||
</button>
|
||||
|
||||
<p class="step-footer step-footer-split" ng-show="app.state.getFlashState().speed && app.state.getFlashState().percentage != 100">
|
||||
<span>ETA: {{ app.state.getFlashState().eta | secondsToDate | amDateFormat:'m[m]ss[s]' }}</span>
|
||||
<span ng-bind="app.state.getFlashState().speed.toFixed(2) + ' MB/s'"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
x
Reference in New Issue
Block a user