mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-25 12:16:37 +00:00
Merge pull request #172 from resin-io/feat/router
Make use of UI Router
This commit is contained in:
commit
7899e2ed59
@ -1250,7 +1250,7 @@ mark,
|
|||||||
.text-left {
|
.text-left {
|
||||||
text-align: left; }
|
text-align: left; }
|
||||||
|
|
||||||
.text-right {
|
.text-right, .section-header {
|
||||||
text-align: right; }
|
text-align: right; }
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
@ -5854,23 +5854,13 @@ button.close {
|
|||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
margin-bottom: 15px; }
|
margin-bottom: 15px; }
|
||||||
|
|
||||||
.space-top-huge {
|
|
||||||
margin-top: 45px; }
|
|
||||||
|
|
||||||
.space-vertical-large {
|
.space-vertical-large {
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
margin-bottom: 30px; }
|
margin-bottom: 30px; }
|
||||||
|
|
||||||
.space-horizontal-large {
|
|
||||||
margin-left: 30px;
|
|
||||||
margin-right: 30px; }
|
|
||||||
|
|
||||||
.space-bottom-large {
|
.space-bottom-large {
|
||||||
margin-bottom: 30px; }
|
margin-bottom: 30px; }
|
||||||
|
|
||||||
.space-bottom-huge {
|
|
||||||
margin-bottom: 45px; }
|
|
||||||
|
|
||||||
.space-right-tiny {
|
.space-right-tiny {
|
||||||
margin-right: 5px; }
|
margin-right: 5px; }
|
||||||
|
|
||||||
@ -5981,8 +5971,13 @@ body {
|
|||||||
.checkbox input[type="checkbox"]:not(:checked) + * {
|
.checkbox input[type="checkbox"]:not(:checked) + * {
|
||||||
color: #ddd; }
|
color: #ddd; }
|
||||||
|
|
||||||
.btn-navigation {
|
.wrapper {
|
||||||
position: fixed;
|
height: 100%;
|
||||||
top: 10px;
|
margin: 20px 60px; }
|
||||||
right: 10px;
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 0; }
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
padding: 5px;
|
||||||
font-size: 15px; }
|
font-size: 15px; }
|
||||||
|
@ -29,6 +29,7 @@ const BrowserWindow = electron.remote.BrowserWindow;
|
|||||||
const currentWindow = BrowserWindow.fromId(1);
|
const currentWindow = BrowserWindow.fromId(1);
|
||||||
|
|
||||||
require('angular-ui-bootstrap');
|
require('angular-ui-bootstrap');
|
||||||
|
require('angular-ui-router');
|
||||||
require('./browser/modules/selection-state');
|
require('./browser/modules/selection-state');
|
||||||
require('./browser/modules/settings');
|
require('./browser/modules/settings');
|
||||||
require('./browser/modules/drive-scanner');
|
require('./browser/modules/drive-scanner');
|
||||||
@ -37,6 +38,7 @@ require('./browser/modules/path');
|
|||||||
require('./browser/modules/analytics');
|
require('./browser/modules/analytics');
|
||||||
|
|
||||||
const app = angular.module('Etcher', [
|
const app = angular.module('Etcher', [
|
||||||
|
'ui.router',
|
||||||
'ui.bootstrap',
|
'ui.bootstrap',
|
||||||
|
|
||||||
// Etcher modules
|
// Etcher modules
|
||||||
@ -48,55 +50,71 @@ const app = angular.module('Etcher', [
|
|||||||
'Etcher.analytics'
|
'Etcher.analytics'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
app.config(function($stateProvider, $urlRouterProvider) {
|
||||||
|
$urlRouterProvider.otherwise('/main');
|
||||||
|
|
||||||
|
$stateProvider
|
||||||
|
.state('main', {
|
||||||
|
url: '/main',
|
||||||
|
controller: 'AppController as app',
|
||||||
|
templateUrl: './partials/main.html'
|
||||||
|
})
|
||||||
|
.state('success', {
|
||||||
|
url: '/success',
|
||||||
|
controller: 'FinishController as finish',
|
||||||
|
templateUrl: './partials/success.html'
|
||||||
|
})
|
||||||
|
.state('settings', {
|
||||||
|
url: '/settings',
|
||||||
|
controller: 'SettingsController as settings',
|
||||||
|
templateUrl: './partials/settings.html'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.controller('AppController', function(
|
app.controller('AppController', function(
|
||||||
$q,
|
$q,
|
||||||
|
$state,
|
||||||
DriveScannerService,
|
DriveScannerService,
|
||||||
SettingsService,
|
|
||||||
SelectionStateService,
|
SelectionStateService,
|
||||||
ImageWriterService,
|
ImageWriterService,
|
||||||
AnalyticsService
|
AnalyticsService
|
||||||
) {
|
) {
|
||||||
let self = this;
|
let self = this;
|
||||||
this.settings = SettingsService;
|
|
||||||
this.selection = SelectionStateService;
|
this.selection = SelectionStateService;
|
||||||
this.writer = ImageWriterService;
|
this.writer = ImageWriterService;
|
||||||
this.scanner = DriveScannerService;
|
this.scanner = DriveScannerService;
|
||||||
|
|
||||||
this.restart = function(options) {
|
AnalyticsService.logEvent('Restart');
|
||||||
AnalyticsService.logEvent('Restart');
|
|
||||||
this.selection.clear(options);
|
|
||||||
|
|
||||||
self.state = {
|
if (!this.writer.isBurning()) {
|
||||||
|
this.state = {
|
||||||
progress: 0,
|
progress: 0,
|
||||||
percentage: 0
|
percentage: 0
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this.scanner.start(2000).on('scan', function(drives) {
|
this.scanner.start(2000).on('scan', function(drives) {
|
||||||
|
|
||||||
// Notice we only autoselect the drive if there is an image,
|
// Notice we only autoselect the drive if there is an image,
|
||||||
// which means that the first step was completed successfully,
|
// which means that the first step was completed successfully,
|
||||||
// otherwise the drive is selected while the drive step is disabled
|
// otherwise the drive is selected while the drive step is disabled
|
||||||
// which looks very weird.
|
// which looks very weird.
|
||||||
if (drives.length === 1 && self.selection.hasImage()) {
|
if (drives.length === 1 && self.selection.hasImage()) {
|
||||||
const drive = _.first(drives);
|
const 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)) {
|
|
||||||
AnalyticsService.logEvent('Auto-select drive', {
|
|
||||||
device: drive.device
|
|
||||||
});
|
|
||||||
self.selectDrive(drive);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
AnalyticsService.logEvent('Auto-select drive', {
|
||||||
|
device: drive.device
|
||||||
|
});
|
||||||
|
self.selectDrive(drive);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
this.restart();
|
|
||||||
|
|
||||||
// We manually add `style="display: none;"` to <body>
|
// We manually add `style="display: none;"` to <body>
|
||||||
// and unset it here instead of using ngCloak since
|
// and unset it here instead of using ngCloak since
|
||||||
@ -167,6 +185,7 @@ app.controller('AppController', function(
|
|||||||
|
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
AnalyticsService.logEvent('Done');
|
AnalyticsService.logEvent('Done');
|
||||||
|
$state.go('success');
|
||||||
}).catch(dialog.showError).finally(function() {
|
}).catch(dialog.showError).finally(function() {
|
||||||
|
|
||||||
// Remove progress bar from task bar
|
// Remove progress bar from task bar
|
||||||
@ -179,3 +198,18 @@ app.controller('AppController', function(
|
|||||||
|
|
||||||
this.open = shell.openExternal;
|
this.open = shell.openExternal;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.controller('SettingsController', function(SettingsService) {
|
||||||
|
this.storage = SettingsService.data;
|
||||||
|
});
|
||||||
|
|
||||||
|
app.controller('NavigationController', function($state) {
|
||||||
|
this.isState = $state.is;
|
||||||
|
});
|
||||||
|
|
||||||
|
app.controller('FinishController', function($state, SelectionStateService) {
|
||||||
|
this.restart = function(options) {
|
||||||
|
SelectionStateService.clear(options);
|
||||||
|
$state.go('main');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
@ -38,57 +38,4 @@ settings.service('SettingsService', function($localStorage) {
|
|||||||
errorReporting: true
|
errorReporting: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// All this functionality should be gone once
|
|
||||||
// we make use of a real router on the application.
|
|
||||||
// This is not the case yet since when the application
|
|
||||||
// was first prototyped there was only one screen
|
|
||||||
// and therefore a router would have been overkill.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Configuring state
|
|
||||||
* @type Boolean
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
let configuring = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Check if the user is configuring
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @returns {Boolean} whether is configuring
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* if (SettingsService.isConfiguring()) {
|
|
||||||
* console.log('User is on settings screen');
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
this.isConfiguring = function() {
|
|
||||||
return configuring;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Enter settings screen
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* SettingsService.enter();
|
|
||||||
*/
|
|
||||||
this.enter = function() {
|
|
||||||
configuring = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Leave settings screen
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* SettingsService.leave();
|
|
||||||
*/
|
|
||||||
this.leave = function() {
|
|
||||||
configuring = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,8 @@ body {
|
|||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prevent blue outline */
|
||||||
|
input:focus,
|
||||||
button:focus {
|
button:focus {
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
|
142
lib/index.html
142
lib/index.html
@ -24,142 +24,20 @@
|
|||||||
|
|
||||||
<script src="./browser/app.js"></script>
|
<script src="./browser/app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body ng-app="Etcher" ng-controller="AppController as app" style="display: none">
|
<body ng-app="Etcher" style="display: none">
|
||||||
<div class="content row middle-xs space-horizontal-large" ng-hide="app.settings.isConfiguring()">
|
<header class="section-header" ng-controller="NavigationController as navigation">
|
||||||
<button class="btn btn-link btn-navigation" ng-click="app.settings.enter()">
|
<button class="btn btn-link" ui-sref="settings" ng-hide="navigation.isState('settings')">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="col-xs">
|
<button class="btn btn-link" ui-sref="main" ng-show="navigation.isState('settings')">
|
||||||
<div class="row around-xs space-bottom-huge" ng-hide="app.state.progress == 100 && !app.writer.isBurning()">
|
<span class="glyphicon glyphicon-chevron-left"></span> Back
|
||||||
<div class="col-xs">
|
</button>
|
||||||
<div class="box text-center">
|
</header>
|
||||||
<hero-icon path="images/image.svg" label="SELECT IMAGE"></hero-icon>
|
|
||||||
<hero-badge class="block space-vertical-medium">1</hero-badge>
|
|
||||||
|
|
||||||
<div class="space-vertical-large">
|
<main class="wrapper" ui-view></main>
|
||||||
<div ng-hide="app.selection.hasImage()">
|
|
||||||
<hero-button ng-click="app.selectImage()">Select image</hero-button>
|
|
||||||
<p class="step-footer tiny">*supported files: .img, .iso</p>
|
|
||||||
</div>
|
|
||||||
<div ng-show="app.selection.hasImage()">
|
|
||||||
<span ng-bind="app.selection.getImage() | basename" ng-click="app.reselectImage()"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xs">
|
<footer class="section-footer row between-xs middle-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>
|
|
||||||
|
|
||||||
<hero-icon path="images/drive.svg" ng-disabled="!app.selection.hasImage()" label="SELECT DRIVE"></hero-icon>
|
|
||||||
<hero-badge class="block space-vertical-medium" ng-disabled="!app.selection.hasImage()">2</hero-badge>
|
|
||||||
|
|
||||||
<div class="space-vertical-large">
|
|
||||||
<div ng-hide="app.selection.hasDrive()">
|
|
||||||
|
|
||||||
<div ng-show="app.scanner.hasAvailableDrives() || !app.selection.hasImage()">
|
|
||||||
<div class="btn-group" uib-dropdown>
|
|
||||||
<hero-button ng-disabled="!app.selection.hasImage()"
|
|
||||||
uib-dropdown-toggle>Select drive</hero-button>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li ng-repeat="drive in app.scanner.drives">
|
|
||||||
<a href="#" ng-click="app.selectDrive(drive)" ng-bind="drive.name + ' - ' + drive.size"></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div ng-hide="app.scanner.hasAvailableDrives() || !app.selection.hasImage()">
|
|
||||||
<hero-button type="danger">Connect a drive</hero-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div ng-show="app.selection.hasDrive()" ng-bind="app.selection.getDrive().name" ng-click="app.reselectDrive()"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xs">
|
|
||||||
<div class="box text-center">
|
|
||||||
<hero-icon path="images/burn.svg" ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()" label="BURN IMAGE"></hero-icon>
|
|
||||||
<hero-badge class="block space-vertical-medium" ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">3</hero-badge>
|
|
||||||
|
|
||||||
<div class="space-vertical-large">
|
|
||||||
<hero-progress-button percentage="{{ app.state.progress }}" ng-attr-active="{{ app.writer.isBurning() }}"
|
|
||||||
ng-click="app.burn(app.selection.getImage(), app.selection.getDrive())"
|
|
||||||
ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">
|
|
||||||
<span ng-show="app.state.progress == 100 && app.writer.isBurning()">Finishing...</span>
|
|
||||||
<span ng-show="app.state.progress == 0 && !app.writer.isBurning()">Burn!</span>
|
|
||||||
<span ng-show="app.state.progress == 0 && app.writer.isBurning() && !app.state.speed">Starting...</span>
|
|
||||||
<span ng-show="app.state.speed && app.state.progress != 100"
|
|
||||||
ng-bind="app.state.progress + '% '"></span>
|
|
||||||
</hero-progress-button>
|
|
||||||
|
|
||||||
<p class="step-footer" ng-bind="app.state.speed.toFixed(2) + ' MB/s'" ng-show="app.state.speed && app.state.progress != 100"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row around-xs space-bottom-huge" ng-show="app.state.progress == 100 && !app.writer.isBurning()">
|
|
||||||
<div class="col-xs">
|
|
||||||
<div class="box text-center">
|
|
||||||
<h3><hero-tick type="success" class="space-right-tiny"></hero-tick> Burn Complete!</h3>
|
|
||||||
<p class="soft">Safely ejected and ready for use</p>
|
|
||||||
|
|
||||||
<div class="row center-xs space-vertical-large">
|
|
||||||
<div class="col-xs-4 space-medium">
|
|
||||||
<div class="box">
|
|
||||||
<p class="soft button-label">Would you like to burn the same image?</p>
|
|
||||||
|
|
||||||
<hero-button ng-click="app.restart({ preserveImage: true })">
|
|
||||||
Use <b>same</b> image
|
|
||||||
</hero-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xs separator-xs"></div>
|
|
||||||
|
|
||||||
<div class="col-xs-4 space-medium">
|
|
||||||
<div class="box">
|
|
||||||
<p class="soft button-label">Would you like to burn a new image?</p>
|
|
||||||
|
|
||||||
<hero-button ng-click="app.restart()">
|
|
||||||
Use <b>new</b> image
|
|
||||||
</hero-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content row space-horizontal-large space-top-huge" ng-show="app.settings.isConfiguring()">
|
|
||||||
<div class="col-xs" ng-show="app.settings.isConfiguring()">
|
|
||||||
<button class="btn btn-link btn-navigation" ng-click="app.settings.leave()">
|
|
||||||
<span class="glyphicon glyphicon-chevron-left"></span> Back
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="box text-left space-horizontal-large">
|
|
||||||
<h1 class="space-bottom-large">Settings</h1>
|
|
||||||
|
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" ng-model="app.settings.data.errorReporting">
|
|
||||||
<span>Enable error reporting</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section-footer row between-xs middle-xs">
|
|
||||||
<div class="col-xs">
|
<div class="col-xs">
|
||||||
<div class="box text-left">
|
<div class="box text-left">
|
||||||
<hero-icon path="images/resin.svg" width="85px" height="auto" ng-click="app.open('https://resin.io')"></hero-icon>
|
<hero-icon path="images/resin.svg" width="85px" height="auto" ng-click="app.open('https://resin.io')"></hero-icon>
|
||||||
@ -171,6 +49,6 @@
|
|||||||
<hero-caption><span ng-click="app.open('https://github.com/resin-io/etcher')">AN OPEN SOURCE PROJECT</span> BY <span ng-click="app.open('https://resin.io')">RESIN.IO</span></hero-caption>
|
<hero-caption><span ng-click="app.open('https://github.com/resin-io/etcher')">AN OPEN SOURCE PROJECT</span> BY <span ng-click="app.open('https://resin.io')">RESIN.IO</span></hero-caption>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
73
lib/partials/main.html
Normal file
73
lib/partials/main.html
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<div class="row around-xs">
|
||||||
|
<div class="col-xs">
|
||||||
|
<div class="box text-center">
|
||||||
|
<hero-icon path="images/image.svg" label="SELECT IMAGE"></hero-icon>
|
||||||
|
<hero-badge class="block space-vertical-medium">1</hero-badge>
|
||||||
|
|
||||||
|
<div class="space-vertical-large">
|
||||||
|
<div ng-hide="app.selection.hasImage()">
|
||||||
|
<hero-button ng-click="app.selectImage()">Select image</hero-button>
|
||||||
|
<p class="step-footer tiny">*supported files: .img, .iso</p>
|
||||||
|
</div>
|
||||||
|
<div ng-show="app.selection.hasImage()">
|
||||||
|
<span ng-bind="app.selection.getImage() | basename" ng-click="app.reselectImage()"></span>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<hero-icon path="images/drive.svg" ng-disabled="!app.selection.hasImage()" label="SELECT DRIVE"></hero-icon>
|
||||||
|
<hero-badge class="block space-vertical-medium" ng-disabled="!app.selection.hasImage()">2</hero-badge>
|
||||||
|
|
||||||
|
<div class="space-vertical-large">
|
||||||
|
<div ng-hide="app.selection.hasDrive()">
|
||||||
|
|
||||||
|
<div ng-show="app.scanner.hasAvailableDrives() || !app.selection.hasImage()">
|
||||||
|
<div class="btn-group" uib-dropdown>
|
||||||
|
<hero-button ng-disabled="!app.selection.hasImage()"
|
||||||
|
uib-dropdown-toggle>Select drive</hero-button>
|
||||||
|
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li ng-repeat="drive in app.scanner.drives">
|
||||||
|
<a href="#" ng-click="app.selectDrive(drive)" ng-bind="drive.name + ' - ' + drive.size"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-hide="app.scanner.hasAvailableDrives() || !app.selection.hasImage()">
|
||||||
|
<hero-button type="danger">Connect a drive</hero-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div ng-show="app.selection.hasDrive()" ng-bind="app.selection.getDrive().name" ng-click="app.reselectDrive()"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs">
|
||||||
|
<div class="box text-center">
|
||||||
|
<hero-icon path="images/burn.svg" ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()" label="BURN IMAGE"></hero-icon>
|
||||||
|
<hero-badge class="block space-vertical-medium" ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">3</hero-badge>
|
||||||
|
|
||||||
|
<div class="space-vertical-large">
|
||||||
|
<hero-progress-button percentage="{{ app.state.progress }}" ng-attr-active="{{ app.writer.isBurning() }}"
|
||||||
|
ng-click="app.burn(app.selection.getImage(), app.selection.getDrive())"
|
||||||
|
ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">
|
||||||
|
<span ng-show="app.state.progress == 100 && app.writer.isBurning()">Finishing...</span>
|
||||||
|
<span ng-show="app.state.progress == 0 && !app.writer.isBurning()">Burn!</span>
|
||||||
|
<span ng-show="app.state.progress == 0 && app.writer.isBurning() && !app.state.speed">Starting...</span>
|
||||||
|
<span ng-show="app.state.speed && app.state.progress != 100"
|
||||||
|
ng-bind="app.state.progress + '% '"></span>
|
||||||
|
</hero-progress-button>
|
||||||
|
|
||||||
|
<p class="step-footer" ng-bind="app.state.speed.toFixed(2) + ' MB/s'" ng-show="app.state.speed && app.state.progress != 100"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
10
lib/partials/settings.html
Normal file
10
lib/partials/settings.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<div class="text-left">
|
||||||
|
<h1 class="space-bottom-large">Settings</h1>
|
||||||
|
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ng-model="settings.storage.errorReporting">
|
||||||
|
<span>Enable error reporting</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
32
lib/partials/success.html
Normal file
32
lib/partials/success.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<div class="row around-xs">
|
||||||
|
<div class="col-xs">
|
||||||
|
<div class="box text-center">
|
||||||
|
<h3><hero-tick type="success" class="space-right-tiny"></hero-tick> Burn Complete!</h3>
|
||||||
|
<p class="soft">Safely ejected and ready for use</p>
|
||||||
|
|
||||||
|
<div class="row center-xs space-vertical-large">
|
||||||
|
<div class="col-xs-4 space-medium">
|
||||||
|
<div class="box">
|
||||||
|
<p class="soft button-label">Would you like to burn the same image?</p>
|
||||||
|
|
||||||
|
<hero-button ng-click="finish.restart({ preserveImage: true })">
|
||||||
|
Use <b>same</b> image
|
||||||
|
</hero-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs separator-xs"></div>
|
||||||
|
|
||||||
|
<div class="col-xs-4 space-medium">
|
||||||
|
<div class="box">
|
||||||
|
<p class="soft button-label">Would you like to burn a new image?</p>
|
||||||
|
|
||||||
|
<hero-button ng-click="finish.restart()">
|
||||||
|
Use <b>new</b> image
|
||||||
|
</hero-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -184,9 +184,17 @@ body {
|
|||||||
color: $gray-light;
|
color: $gray-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-navigation {
|
.wrapper {
|
||||||
position: fixed;
|
height: 100%;
|
||||||
top: 10px;
|
margin: 20px 60px;
|
||||||
right: 10px;
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
@extend .text-right;
|
||||||
|
padding: 5px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$spacing-huge: 45px;
|
|
||||||
$spacing-large: 30px;
|
$spacing-large: 30px;
|
||||||
$spacing-medium: 15px;
|
$spacing-medium: 15px;
|
||||||
$spacing-tiny: 5px;
|
$spacing-tiny: 5px;
|
||||||
@ -28,28 +27,15 @@ $spacing-tiny: 5px;
|
|||||||
margin-bottom: $spacing-medium;
|
margin-bottom: $spacing-medium;
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-top-huge {
|
|
||||||
margin-top: $spacing-huge;
|
|
||||||
}
|
|
||||||
|
|
||||||
.space-vertical-large {
|
.space-vertical-large {
|
||||||
margin-top: $spacing-large;
|
margin-top: $spacing-large;
|
||||||
margin-bottom: $spacing-large;
|
margin-bottom: $spacing-large;
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-horizontal-large {
|
|
||||||
margin-left: $spacing-large;
|
|
||||||
margin-right: $spacing-large;
|
|
||||||
}
|
|
||||||
|
|
||||||
.space-bottom-large {
|
.space-bottom-large {
|
||||||
margin-bottom: $spacing-large;
|
margin-bottom: $spacing-large;
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-bottom-huge {
|
|
||||||
margin-bottom: $spacing-huge;
|
|
||||||
}
|
|
||||||
|
|
||||||
.space-right-tiny {
|
.space-right-tiny {
|
||||||
margin-right: $spacing-tiny;
|
margin-right: $spacing-tiny;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"angular": "^1.4.6",
|
"angular": "^1.4.6",
|
||||||
"angular-ui-bootstrap": "^1.2.1",
|
"angular-ui-bootstrap": "^1.2.1",
|
||||||
|
"angular-ui-router": "^0.2.18",
|
||||||
"bluebird": "^3.0.5",
|
"bluebird": "^3.0.5",
|
||||||
"bootstrap-sass": "^3.3.5",
|
"bootstrap-sass": "^3.3.5",
|
||||||
"drivelist": "^2.0.7",
|
"drivelist": "^2.0.7",
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const m = require('mochainon');
|
|
||||||
const angular = require('angular');
|
|
||||||
require('angular-mocks');
|
|
||||||
require('../../../lib/browser/modules/settings');
|
|
||||||
|
|
||||||
describe('Browser: Settings', function() {
|
|
||||||
|
|
||||||
beforeEach(angular.mock.module('Etcher.settings'));
|
|
||||||
|
|
||||||
describe('SettingsService', function() {
|
|
||||||
|
|
||||||
let SettingsService;
|
|
||||||
|
|
||||||
beforeEach(angular.mock.inject(function(_SettingsService_) {
|
|
||||||
SettingsService = _SettingsService_;
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('.isConfiguring()', function() {
|
|
||||||
|
|
||||||
it('should initially return false', function() {
|
|
||||||
m.chai.expect(SettingsService.isConfiguring()).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.enter()', function() {
|
|
||||||
|
|
||||||
it('should be able to enter settings', function() {
|
|
||||||
m.chai.expect(SettingsService.isConfiguring()).to.be.false;
|
|
||||||
SettingsService.enter();
|
|
||||||
m.chai.expect(SettingsService.isConfiguring()).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.leave()', function() {
|
|
||||||
|
|
||||||
it('should be able to leave settings', function() {
|
|
||||||
SettingsService.enter();
|
|
||||||
m.chai.expect(SettingsService.isConfiguring()).to.be.true;
|
|
||||||
SettingsService.leave();
|
|
||||||
m.chai.expect(SettingsService.isConfiguring()).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
Loading…
x
Reference in New Issue
Block a user