952 Commits

Author SHA1 Message Date
Juan Cruz Viotti
714b165c0c refactor: move flash results state to Redux store (#529)
This is a rather big PR that moves the flash results information to the
Redux store, which simplifies and improves a lot of things as throughly
described in the commits that introduced Redux.

Here's a summary of the changes:

- Add a `flashResults` property to the store.

- Validate the contents of `flashResults`, handling certain edge cases
that make the modal incoherent.

- Split `ImageWriterService.setFlashing()` to
`ImageWriterService.setFlashingFlag()` and
`ImageWriterService.unsetFlashingFlag()`.

- Require the flash results to be passed to
`ImageWriterService.unsetFlashingFlag()`.

- Stop resolving the flash results from `ImageWriterService.flash()`.

- Implement `ImageWriterService.getFlashResults()`.

- Make the `RESET_FLASH_STATE` action reset the flash results.

- Access the source checksum from the store in the "finish" page,
  instead of requiring the controller to pass it as a state parameter.

- Implement `.wasLastFlashSuccessful()` function in the main controller
to replace the `.success` property.

- Completely remove the `.success` property in the main controller.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-24 12:52:40 -04:00
Juan Cruz Viotti
d16d5469fd fix: don't throw missing eta if eta is zero (#528)
The commit 0f8136f, which enforced validation for the state object,
introduced a subtle bug where `Missing state eta` would be thrown if
`eta === 0`, since `!0` evaluates to `true`.

This would cause the flashing to stop right at the end (when eta is
zero).

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-24 09:47:24 -04:00
Juan Cruz Viotti
60b68d775b refactor: rename progress property to percentage (#527)
So the property is consistent from what we get from `etcher-image-write`
and we don't have to unnecessarily rename ourselves to pass it to the
model.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-24 09:47:10 -04:00
Juan Cruz Viotti
4708401260 test: validate contents of flash state object (#526)
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-24 09:16:15 -04:00
Juan Cruz Viotti
ff8e16b4ac refactor: improve analytics and image-writer module names (#524)
- From `Etcher.analytics` to `Etcher.Modules.Analytics`.
- From `Etcher.image-writer` to `Etcher.Modules.ImageWriter`.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 18:39:20 -04:00
Juan Cruz Viotti
c291a9067d fix: emit progress even when not in the main screen (#523)
We have logic that displays useful log messages about the state of the
flashing, as well as update the window progress in each oeprating system
(dock in OS X, task bar in Windows, etc), however since this logic lives
in the controller, the progress reports are completely frozen if the
user navigates away from the main screen (to the settings page for
example).

As a solution, we move the code that subscribes to the state change
events to a global `.run()` so it can persist page changes.

Since making sure the listeners are unregistered is not relevant anymore
(since the code is not running in a controller anymore), we get rid of
`NotifierService`, a module we built for this purpose, and directly
subscribe to the Redux store instead.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 18:39:15 -04:00
Juan Cruz Viotti
c44594b45e refactor: use ES6 fat arrows in application code (#522)
ES6 fat arrows provide reasonable `this` behaviour, which protects us
from some subtle accidental bugs, and erradicates `const self = this`
from the codebase.

Far arrows were not applied in Mocha code and AngularJS
controllers/services constructors since these frameworks rely on
`.bind()` on those functions.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 17:41:41 -04:00
Juan Cruz Viotti
4d89b1b1f7 refactor: flatten "flash" data structure property (#521)
Currently, the "flash" property of the application state containing both
the actual flashing state, and the flashing flag.

To simplify things, the following changes have been introduced:

- Move `flash.flashing` to `isFlashing`.
- Move `flash.state` to `flashState`.
- Rename `SET_FLASHING` to `SET_FLASHING_FLAG`.
- Extract `UNSET_FLASHING_FLAG` from `SET_FLASHING_FLAG`.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 17:12:25 -04:00
Juan Cruz Viotti
78da500816 refactor: expose an object of available actions (#520)
Referencing actions as properties of an object is more reliable than
just hardcoding strings everywhere.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 16:10:22 -04:00
Juan Cruz Viotti
5ac5f3a423 fix: don't allow to set the flashing state if not flashing (#519)
Currently, we allow updating the flashing state independently on the
value of the `flashing` property.

In order to maintain the application state coherent, we deny updating
the flashing state if we're not currently flashing, which lets us safely
assume that the state will be in a reset state if we're not flashing.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 15:38:40 -04:00
Juan Cruz Viotti
2ecf9d32a7 refactor: reset state when the flashing flag is set to false (#518)
Currently, we were taking care of resetting the flashing state manually
across several controllers. Now that data mutations live in a single
place, we trigger a flash state reset whenever the flashing flag is set
to false, which reliably handles every case and allows us to forget
about it.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 15:12:57 -04:00
Juan Cruz Viotti
c845fe10b0 fix: check for updates only once at startup (#517)
Currently, the update check runs every single time the main application
controller is instantiated, meaning that the update check would run
again when you visit the settings screen and go back to the main page,
or return to the main page after finishing a flash.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 12:19:32 -04:00
Juan Cruz Viotti
321c653d74 refactor: move auto-select logic to redux store (#516)
Now that we have a central source of truth for state mutations, the
auto-select feature fits really well in the redux store, particularly
inside the `SET_AVAILABLE_DRIVES` action.

This also has the great benefit that we can unit test the auto-selection
logic, which was not particularly trivial before, when such code lived
in the controller instead.

The only downside of this approach is that we lose the nice "Auto-select
drive" analytics event, which will be re-added very soon in a future PR.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 12:19:27 -04:00
Juan Cruz Viotti
77f2b1d1cc fix: infinite digest loop with ngRepeat + ImmutableJS (#514)
The addition of `ImmutableJS` caused some issues with Angular's digest
loop. Since `Immutable#toJS()` returns a new object/array every time
(that is, different references), it caused AngularJS to get stuck in an
infinite digest loop when using `ngRepeat` over a function that called
`Immutable#toJS()`.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 11:41:24 -04:00
Juan Cruz Viotti
2b9f0b5003 refactor: apply REMOVE_DRIVE recursively in SET_AVAILABLE_DRIVES (#515)
We were duplicating the remove drive logic in the `SET_AVAILABLE_DRIVES`
case when the currently selected drive didn't exist anymore.

A better way to handle this without coding repetition is to recursively
apply the reduced with the new state.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 11:20:10 -04:00
Juan Cruz Viotti
c2c5eb59b9 fix: deselect drive if its not available anymore (#513)
If the user has a selected drive, but a new scan shows that such drive
is no longer available, then the selected drive should be de-selected.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 09:26:35 -04:00
Juan Cruz Viotti
e16139af03 fix: throw if attempting to select a locked drive (#512)
We shouldn't allow a write-protected drive from being selected, since
users will get confusing `EPERM` errors later on.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-23 09:26:23 -04:00
Juan Cruz Viotti
c4c8e2c038 refactor: manage application state with redux (#508)
Currently, Etcher's application state is stored among various models,
making it a bit hard to mentually visualise the application state at a
certain point of execution. This also means that some quirky bugs
appear, and we have to take non-elegant measures to mitigate them, for
example:

- The current drive selection might be invalid if the current available
drive list doesn't contain it anymore.

- The progress state might be modified while there is no flashing in
process.

- We have to rely on event emission to propagate the current state to
the application progress bar.

- The validity of a selected drive might depend on the currently
selected image.

While all these issues can be addressed with common programming
techniques, Redux introduces a new way of thinking about the application
state that make the above problems non-existent, or trivial to fix.

This PR creates a Redux store containing the logic used to mutate state
from:

- `SelectionStateModel`.
- `DrivesMode`.
- `ImageWriterService`.

We are also making extra effort to preserve the public APIs from the
models, which we will be simplifying in later commits.

There is still much to be done, but we're happy to be taking the first
steo towards a much cleaner architecture.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-22 16:22:59 -04:00
Juan Cruz Viotti
991b69c17e refactor(DriveScannerService): use RxJS (#505)
The concept of a drive scanner lends itself very well to the concept of
"reactive programming", since the "available drives" make perfect sense
as an "Observable".

For this reason, the module was re-implemented using RxJS, which greatly
simplifies things and erradicates certain edge cases we were protecting
ourselves from automatically.

Other changes made in this PR:

- `DriveScannerService` no longer requires `DrivesModel`. The
`DriveScannerService` is the one in charge of populating the model.

- `DriveScannerService.scan()` no longer returns an `EventEmitter`. The
service itself is now an `EventEmitter`.

- `DriveScannerService` now emits a `drives`, not a `scan` event.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-22 10:41:36 -04:00
Juan Cruz Viotti
b923008f7c refactor: make use of angular-if-state (#506)
We'll use this external module rather than our local `if-state`
implementation.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-22 10:41:02 -04:00
Juan Cruz Viotti
4670ae125b fix: ensure dialog.showErrorBox() arguments are strings (#497)
If for some reason either the error title or message are not strings,
the user gets a very obscure error that looks something like this:

```
Error: Could not call remote function ''.
Check that the function signature is correct.
Underlying error:
  Error processing argument at index 0, conversion failure
```

What's even worse is that the above error is thrown when we attempt to
display an `Error` object, therefore completely hiding the real error.

In this commit, we make sure both parameters to `showErrorBox()` are
strings, as a safety measure to prevent this from happening again.

See: https://github.com/resin-io/etcher/issues/127
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-22 10:40:51 -04:00
Juan Cruz Viotti
acde20cee1 refactor(cli): make --robot option output JSON (#500)
The Etcher CLI `--robot` option outputs space separated lines including
useful information in a predefined order, for example:

```sh
progress write 50% 15s 65536
```

While this is very easy to parse, a stringified JSON line is much more
convenient since:

- We don't have to write any parsing logic.
- We don't have to guess the value types (string, number, boolean, etc).
- We don't have to hardcode property names.
- We don't have to extend the parsing code if we decide to send new
commands from the CLI, or make any change to the data we output.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-22 10:40:17 -04:00
Juan Cruz Viotti
1e3db916e6 style: fix lint warning in exit-codes.js (#499)
The lint complained that there were two consequent empty lines.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-22 10:40:10 -04:00
Juan Cruz Viotti
95deab0b0d Get rid of application-wide elevation (#423)
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-20 21:49:16 -04:00
Juan Cruz Viotti
16c3750b15 Don't check extensions before the first non compressed extension (#493)
Currently, we extract all the extensions from an image path and report
back that the image is invalid if *any* of the extensions is not a
valida extension, however this can cause trouble with images including
information between dots that are not strictly extensions.

For example:

```
elementaryos-0.3.2-stable-i386.20151209.iso
```

Etcher will consider `20151209` to be an invalid extension and therefore
will prevent such image from being selected.

As a way to allow these corner cases but will make use of our enforced
check controls, the validation routine will only consider extensions
starting from the first non compressed extension.

This PR also includes logic to show a nice GUI dialog saying that the
image is invalid in order to provide a much better experience than just
silently failing.

Fixes: https://github.com/resin-io/etcher/issues/492
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-20 12:05:33 -04:00
Juan Cruz Viotti
abdf26066c Open DevTools in "undocked" mode by default (#489)
Otherwise, DevTools gets opened inside the Etcher window, causing the
GUI to get completely messed up.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-17 17:53:03 -04:00
Juan Cruz Viotti
cd87586cee Fix application wide vertical scroll bar (#487)
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-15 15:41:42 -04:00
Juan Cruz Viotti
df24388c3d Move update notifier modal style to the component (#486)
Currently, the modal style style used in this component was declared in
`components/_modal.scss`, however since this srule is very specific to
the update notifier component, its better declared in
`update-notifier/styles`.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-15 11:26:38 -04:00
Juan Cruz Viotti
21b6e1aabc Prevent an invalid drive from being auto-selected (#484)
Currently we have logic in the drive selector dialog to prevent invalid
drives (too small, locked, etc) from being selected, however we are not
protecting auto-selection from these invalid devices.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-15 11:26:03 -04:00
Juan Cruz Viotti
a5fbe40b2d Move drive selector warning labels below the drive (#483)
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-15 11:25:50 -04:00
Juan Cruz Viotti
8aa7bcd952 Prevent a very long image name from breaking the UI (#479)
This PR introduces two changes to mitigate this problem and overall
provide a better UX:

- Show ellipses in the middle of the image name in the first step if
needed.

- Add a tooltip below the image selection label in the first step to
show a little modal displaying the full path to the image.

Fixes: https://github.com/resin-io/etcher/issues/418
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-15 10:31:07 -04:00
Juan Cruz Viotti
34ab982b24 Remove body display hidden white flash workaround (#478)
In older versions of Electron, the application would display a quick
flash of white before running caused by the WebView loading up.

This workaround doesn't seem necessary anymore.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-13 10:58:01 -04:00
Juan Cruz Viotti
fbe6fe1142 Show a "Locked" label if the drive is write-protected (#475)
* Implement SelectionStateModel.isDriveLocked()

Notice we also increase the maximum number of lines JSCS check, since
the `SelectionStateModel` test suite already met that limit.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>

* Show a "Locked" label if the drive is write-protected

Fixes: https://github.com/resin-io/etcher/issues/458
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-11 15:45:46 -04:00
Juan Cruz Viotti
51b6de4634 Show an informative label if a drive is not large enough (#474)
This is a huge improvement over our current approach, which was simply
to cross out the drive without further explanation.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-11 13:52:38 -04:00
Juan Cruz Viotti
dc7b31f061 Apply checksum label padding as a custom modifier (#473)
We want to re-use the `label` component without big paddings in other
areas of the application, therefore we move the custom padding to a
separate label modifier.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-11 13:44:02 -04:00
Juan Cruz Viotti
608cb5d74a Cleanup CSS (#471)
This is by no means a complete CSS refactoring. There still a lot to be
done. This encompasses mostly:

- Move "Finish page" specific styles to that module.
- Remove unused CSS rules.
- Move generic Bootstrap rules to `_bootstrap.scss`.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-11 13:21:22 -04:00
Juan Cruz Viotti
f674f3d706 Fix image containing dots in the filename considered unsupported (#468)
Currently, we detect the extensions of an image path by finding the
first dot, and splitting everything afterwards, however this will fail
with image paths containing dots, like `foo.1.2.3-bar.iso.gz`.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-10 10:19:26 -04:00
Juan Cruz Viotti
5ae5a1915d Refactor supported image logic to SupportedFormatsModel (#467)
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-09 13:08:01 -04:00
Juan Cruz Viotti
b950136deb Extract DrivesModel from DriveScannerService (#466)
Currently, `DriveScannerService` is in charge of both scanning the
available drives and maintaining the state of the currently detected
drives.

To honour the single responsibility principle, we split this service
into a `DrivesModel`, which is incharge of maintaining the state without
caring how they are detected, and `DriveScannerService`, which only
scans the available drives and modified `DrivesModel` accordingly.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-09 12:42:09 -04:00
Juan Cruz Viotti
fc6ccf70dd Prevent selection of invalid images (#462)
The user might attempt to select an invalid image by dropping on the
first step, which would cause Etcher to blindly select it, possibly
causing errors later on the process.

This PR makes use of the list of supported extensions provided by
`SupportedFormatsModel` and prevents the selection if necessary, logging
an event that might help us determine which unsupported image types
users try to burn most often.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-08 15:49:55 -04:00
Juan Cruz Viotti
7d5f42f38c Try to get more information about error messages (#464)
If the error object is not well-formed, try to get as most information
about it as we can instead of just realying on generic error messages.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-08 15:49:42 -04:00
Juan Cruz Viotti
8de4be1897 Display ETA during flash and check (#460)
* Show speed during check

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>

* Display ETA during flash and check

Fixes: https://github.com/resin-io/etcher/issues/256
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-08 13:35:44 -04:00
Juan Cruz Viotti
0c94de7fcf Prevent exernal resources from being loaded by the WebView (#456)
If a user drags and drops an image, an HTML file, or other resource the
WebView understands, Electron will navigate away from the application
and load it up in the WebView, making the application unusable unless
the user restarts it.

Fixes: https://github.com/resin-io/etcher/issues/430
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-08 11:10:46 -04:00
Juan Cruz Viotti
6c936a5192 Document can-ignore module.require annotation (#455)
* Document `can-ignore` module.require annotation

This annotation was introduced in: 1872d1f

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>

* Trigger CI build
2016-06-08 11:10:32 -04:00
Igor Klopov
a27e246cc9 Annotation for EncloseJS to ignore missing dependency (#454) 2016-06-07 14:52:51 -04:00
Juan Cruz Viotti
052bb00be9 Fix CI tests (#452)
- Fix lint warning.
- Set the correct electron version in `appveyor.yml`

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-06 18:12:38 -04:00
Juan Cruz Viotti
31728801f5 Don't show a progress bar in update notifier modal (#445)
Fixes: https://github.com/resin-io/etcher/issues/442
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-05-26 21:18:13 -04:00
Juan Cruz Viotti
b14e94fc3b Fix GNU/Linux not opening an external resource when elevated (#446)
We currently had a workaround in place to make use of `node-open`
instead of Electron's built-in `shell` module since the latter didn't
work on older Electron versions on GNU/Linux for some reason.

After some experimentation, `node-open` doesn't seem to be working for
elevated applications anymore. I honestly didn't chase the issue further
since Electron `shell` has been fixed, and works fine when elevated,
therefore this PR basically undoes the previous workaround.

Fixes: https://github.com/resin-io/etcher/issues/443
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-05-26 21:18:03 -04:00
Juan Cruz Viotti
7d0ea21567 Run linter as part of npm test (#436)
* Fix lint warnings

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>

* Run linter as part of `npm test`

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-05-24 15:35:51 -04:00
Juan Cruz Viotti
abb7dc6469 Prevent pressing "space" to re-click the "Flash" button (#435)
Currently we disable pointer events on the "Flash" button once a flash
is in progress to prevent the user from clicking it, but we didn't
consider that if the user kept focus on the button, he can press the
"space" bar for the same effect.

Fixes: https://github.com/resin-io/etcher/issues/431
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-05-24 14:21:31 -04:00