1330 Commits

Author SHA1 Message Date
Juan Cruz Viotti
09b0affe14 refactor(GUI): store drive as a reference to available drives (#599)
Instead of storing the whole selected drive object, we barely store a
reference to the corresponding drive in the available drives array (the
reference being the drive device).

This greatly simplifies the application state in the following ways:

- The drive metadata (size, description, etc) is not duplicated in the
  state, enforcing a single source of truth.
- If the selected drive stops being available (e.g: is unplugged), the
  reference doesn't hold anymore, making this functionality very natural
  to implement.
- Makes `SelectionStateModel.isCurrentDrive()` much more inuitive, since
  we don't have to document that changes in the metadata of the drive
  object, or extra keys such as `$$hashKey` don't change the result of
  this function.
- Ensures the state never goes into a problematic state where we try to
  to write to an unavailable drive.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-26 20:42:54 -04:00
Juan Cruz Viotti
be8f4bfce7 fix(GUI): escape quotes from image paths (#598)
Consider a directory name such as `Juan's Files`. When passing such path
as an argument to the child writer proxy script, Bash will complain
with:

> Unexpected EOF while looking for matching `'`

The solution is to manually escape quotes on the image path.

Change-Type: patch
Changelog-Entry: Escape quotes from image paths to prevent Bash errors on GNU/Linux and OS X.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-26 08:50:58 -04:00
Juan Cruz Viotti
7e0f54e7d6 feat(GUI): rich image extensions (#597)
The following PRs add support for a custom `_info` directory containing
metadata such an image URL, display name, logo, etc in
`etcher-image-stream`:

- https://github.com/resin-io-modules/etcher-image-stream/pull/16
- https://github.com/resin-io-modules/etcher-image-stream/pull/14
- https://github.com/resin-io-modules/etcher-image-stream/pull/13

Now that this module supports such metadata, we make use of it in the
GUI as follows:

- The file name is replaced with the display name.
- The file name links to the image URL.
- The "Select Image" logo is replaced with the image logo.

Some miscellaneous changes introduces in this PR to support the changes
described above:

- Implement `SelectionStateModel.getImageUrl()`.
- Implement `SelectionStateModel.getImageLogo()`.
- Implement `SelectionStateModel.getImageName()`.
- Ignore the "logo" image property when displaying the "Select image"
  event, in order to not fill the console with SVG contents.
- Make `svg-icon` understand SVG strings as paths.
- Make `svg-icon` react to changes to the `path` attribute.
- Extract the core functionality of `openExternal` into
  `OSOpenExternalService`.
- Upgrade `etcher-image-stream` to v3.0.1.

Change-Type: minor
Changelog-Entry: Support rich image extensions.
Fixes: https://github.com/resin-io/etcher/issues/470
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-26 08:47:20 -04:00
Juan Cruz Viotti
5c4341ace7 minifix(GUI): improve validation error message (#595)
The current error message is a bit blurry. The new one is much more user
friendly and directly guides the user towards a possible "next action".

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-25 00:54:30 -04:00
Juan Cruz Viotti
b7d6d3d9a1 feat(GUI): display a nice alert ribbon if drive runs out of space (#588)
We try our best to check that the images the user select are too big for
the selected drive as early as possible, but this probes to be
problematic with certain compressed formats, like bzip2, which doesn't
store any information about the uncompressed size, requiring a ~50s
intensive computation as a minimum to find it out.

For these kinds of formats, we don't perform an early check, but instead
gracefully handle the case where the drive doesn't have any more space.

This PR handles an `ENOSPC` error by displaying the alert orange ribbon,
and prompting the user to retry with a larger drive. This is a huge
improvement over the cryptic `EIO` error what was thrown before, and
over having Etcher freeze at a certain percentage point.

Change-Type: minor
Changelog-Entry: Display a nice alert ribbon if drive runs out of space.
See: https://github.com/resin-io/etcher/issues/571
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-24 15:32:00 -04:00
Juan Cruz Viotti
5f943e98be feat(CLI): validate drive (#587)
The Etcher CLI doesn't care if the drive exists or not. The user will
eventually find out since the CLI will output an `ENOENT` when trying to
actually write data, however its nicer from a UX perspective to catch
this early on.

Change-Type: minor
Changelog-Entry: Validate the existence of the passed drive.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-21 18:31:08 -04:00
Juan Cruz Viotti
1762ea629f fix(GUI): check drive size against uncompressed image size (#582)
We were currently checking if a drive was large enough for an image by checking
the image file size, completely ignoring compression. This results on a small
chance of the uncompressed image not actually fitting in the drive, and
throwing more weird errors later on.

In order to mitigate this, we use the new `.getEstimatedFinalSize()` function
from `etcher-image-stream`, which returns the uncompressed size in the case of
compressed images.

We needed to update the build script for OS X to configure NPM correctly,
otherwise `lzma-native` throws some errors due to an ABI V8 incompatibility
issue.

Fixes: #571
See: https://github.com/addaleax/lzma-native/issues/25
Change-Type: patch
Changelog-Entry: Check if drive is large enough using the final uncompressed size of the image.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-19 23:17:09 -04:00
Juan Cruz Viotti
a3dc8624b1 feat(GUI): enable "unsafe" mode (#578)
This setting makes Etcher not filter non-removable drives, allowing you to
arbitrarily write to your system drives.

This is a dangerous option, therefore we present it in a separate section of
the settings page, and show an informative confirmation dialog.

Change-Type: minor
Changelog-Entry: Add an "unsafe" option to bypass drive protection.
Fixes: https://github.com/resin-io/etcher/issues/480
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-18 22:42:24 -04:00
Juan Cruz Viotti
b965b5d835 refactor(GUI): increase writer proxy logging (#576)
We were facing quite some issues that involved debugging the writer child
process, which proved to be a very difficult task given the lack of information
we're exposing to the parent.

This is an attempt to improve that situation.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-18 10:18:15 -04:00
Juan Cruz Viotti
fb893bec36 fix(GUI): ignore casing when checking an image extension validity (#568)
Currently, we take the image extension casing into account when
determining if the extension is a recognised one (e.g: `img`, `iso`,
etc). This causes an "Invalid image" error to be thrown when selecting
an image with an uppercase extension, like `UBUNTU.ISO`.

Change-Type: patch
Changelog-Entry: Don't throw an "Invalid image" error if the extension is not in lowercase.
Fixes: https://github.com/resin-io/etcher/issues/567
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-11 17:10:13 -04:00
Juan Cruz Viotti
4f49c4c9d0 fix(GUI): preserve original working directory in dialogs in GNU/Linux (#565)
The `$OWD` environment variable, which stands for "Original Working
Directory" is set in recent AppImageKit versions and equals the
directory from where the AppImage was run.

We set the open dialog default path to this environment variable for
consistency with other GNU/Linux applications.

Change-Type: patch,
Changelog-Entry: Set dialog default directory to the place where the AppImage was run from in GNU/Linux.
See: 1569d6f854
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-11 13:36:40 -04:00
Juan Cruz Viotti
adcc13d474 fix(GUI): escape image path spaces correctly on Windows (#560)
The `elevator` module passes its arguments directly to
`child_process.execFile()`, which handles escaping spaces and other
weird issues by default.

Instead of passing a separate argument for every word of the writer
proxy script command, we passed the whole thing at once, which means we
didn't get the escaping features by default.

Change-Type: patch
Changelog-Entry: Fix flashing not starting when an image name contains a space.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-07 13:31:44 -04:00
Juan Cruz Viotti
b384a1d974 fix(GUI): escape parens in image paths on Linux/OS X (#558)
Images may contain parenthesis. This is usually the case when you
re-download a file with a web browser, which atuaomtically appends `(N)`
to the path.

Not escaping parenthesis means that when passing the image path as an
argument to the write proxy script, bash will complain about it as a
syntax error on the command.

The fix is not necessary in Windows. I've been able to write images
containing parenthesis in that operating system without issues.

Change-Type: patch
Changelog-Entry: Fix error when writing images containing parenthesis in GNU/Linux and OS X.
Fixes: https://github.com/resin-io/etcher/issues/556
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-07 13:20:04 -04:00
Juan Cruz Viotti
57ad0ccc93 fix(GUI): uncaught error when cancelling an elevation request (#559)
Currently, if we cancel elevation, we'd get a big scary validation error
about `passedValidation` not being passed to the flash results object.

This fix also requires some adjustments to `wasLastFlashSuccessful()` in
order to adapt to the cancellation scenario.

Since a cancelled elevation request means the writing never took place,
`wasLastFlashSuccessful()` returns `true` if so, without even looking at
`passedValidation`.

Change-Type: patch
Changelog-Entry: Fix error when cancelling an elevation request.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-07 13:19:47 -04:00
Juan Cruz Viotti
c52addb13f chore: point to the new Gitter channel (#555)
We've created a new Gitter channel specifically for Etcher.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-04 11:51:20 -04:00
Juan Cruz Viotti
eb3ffbfd30 upgrade: etcher-image-stream to v2.3.0 (#551)
* upgrade: etcher-image-stream to v2.3.0

This version contains support for `hddimg` files.

Changelog-Entry: Add support for `hddimg` images.
Change-Type: minor
Fixes: https://github.com/resin-io/etcher/issues/549
Link: https://github.com/resin-io-modules/etcher-image-stream/blob/master/CHANGELOG.md#v230---2016-07-01
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>

* minifix(GUI): add a "many more" tooltip in the first step

The amount of image types we support is growing exponentially. Adding
the uncompressed extensions and the compressed ones in a tooltip gave us
room the breathe in the past, but its not enough anymore.

The current approach allows us to scale forever: we list the first three
extensions, and add a "many more" tooltip that shows all the rest.

Change-Type: patch
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-01 11:05:57 -04:00
Juan Cruz Viotti
c425632e27 minifix(GUI): use close() to dismiss drive selector modal (#550)
Using `dismiss()` causes the promise to be rejected, with no reason in
this case. Given we made sure we were handling errors from dialogs in a
previous commit, this issue manifested itself.

The `close()` function, without arguments, makes more sense in this
case.

See: https://github.com/resin-io/etcher/pull/548
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-07-01 10:56:30 -04:00
Juan Cruz Viotti
eb0d8d46cc minifix(GUI): handle image dialog and drive selector errors (#548)
Currently, if either `OSDialogService.selectImage()` or
`DriveSelectorService.open()` are rejected, we completely swallow the
errors, making very hard to debug certain problems.

This PR takes care of showing the usual error dialog for those cases.

Change-Type: patch
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-30 14:30:39 -04:00
Juan Cruz Viotti
c434746a49 refactor(GUI): make use of etcher-latest-version (#544)
The code that performs an HTTP request to the S3 bucket where released
are stored and determines which is the latest available version was
extracted to a separate module called `etcher-latest-version`, mainly
for the website to be able to re-use this functionality.

See: https://github.com/resin-io-modules/etcher-latest-version
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-30 13:17:03 -04:00
Juan Cruz Viotti
f277724749 fix(GUI): incorrect ETA on certain timezones (#545)
In certain timezones, like India's, the ETA would display very weird
numbers. The problem was that we passed a number of milliseconds to
MomentJS, which created a Date object based on it taking timezones into
consideration.

As a solution, we convert the seconds to a Date object containing the
lowest possible date values, and set its seconds to the ETA, since this
effectively represents just the number of seconds we're interested in.

Changelog-Entry: Fix incorrect ETA numbers in certain timezones.
Change-Type: patch
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-30 12:11:41 -04:00
Juan Cruz Viotti
a81fdbe16a fix(GUI): don't throw if state speed is 0 (#546)
There is a small flaw in the current state validation rules where a
speed that equals zero will be considered as if the speed was missing
giving that `!0 == true`.

Changelog-Entry: Fix state validation error when speed equals zero.
Change-Type: patch
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-30 12:11:35 -04:00
Juan Cruz Viotti
0eb0c99056 fix(GUI): display zip in supported images tooltip (#539)
The `SupportedFormatsModel` went through some changes recently, notably,
the distinction between compressed and archived formats.

This change introduced a subtle issue since we listed compressed and non
compressed supported formats on the main screen, but forgot about
archives.

Changelog-Entry: Display `*.zip` in the supported images tooltip.
Change-Type: patch
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-30 20:09:54 +05:30
Juan Cruz Viotti
ea1df5cc11 chore: make use of ESLint (#540)
JSCS has merged with ESLint. This is the perfect excuse to move to
ESLint and unify both JSHint and JSCS hints under ESLint.

This PR also deprecates `gulp lint` in favour of `npm run lint`.

See: https://medium.com/@markelog/jscs-end-of-the-line-bc9bf0b3fdb2#.zbuwvxa5y
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-30 20:09:44 +05:30
Juan Cruz Viotti
09424942a0 fix(GUI): uncaught exception in update notifier (#541)
Since the addition of Redux and ImmutableJS data structures, we store
the application settings in the Redux store.

This means that checkboxes on templates can no longer bind to the
setting properties directly.

This was fixed in the setting page, but we missed one of them in the
update notifier model.

```html
ng-model="modal.settings.get('sleepUpdateCheck')"
```

Won't lead any meaningful return, and in fact, throws an uncaught
exception.

Changelog-Entry: Fix uncaught exception when showing the update notifier modal.
Change-Type: patch
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-30 20:09:37 +05:30
Juan Cruz Viotti
3bf712b592 fix: don't throw if state percentage is zero (#536)
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-27 16:15:35 -04:00
Juan Cruz Viotti
49d89b4ace fix: prevent user from zooming in the whole application (#534)
Turns out the user can zoom-in the whole application, which we didn't
notice before.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-27 14:20:41 -04:00
Juan Cruz Viotti
c6ef5edda3 fix(progressButton): spiky diagonal lines (#533)
The progress button exhibits spiky diagonals when used it with the
"striped" modifier. This can be seen better when drastically reducing the animation
speed.

Turns out its a Webkit rendering bug. I've stumbled into dozens of
"workarounds" on the internet (mainly Stack Overflow), however none of
them fixed the issue.

After some crazy amount of experimentation, the issue is gone if we add
1% to certain stop positions. Weird stuff.

Fixes: https://github.com/resin-io/etcher/issues/472
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-27 14:18:54 -04:00
Juan Cruz Viotti
1a49b36a14 refactor: store settings in redux store (#530)
* refactor: getter/setter interface for SettingsModel

This PR introduces a getter/setter interface for `SettingsModel`, which
replaces the old way of managing setting values by simply assigning
properties to an object.

This is the first step towards moving the settings functionality to the
Redux store.

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

* refactor: store settings in redux store

The state data structure now contains a property called `settings`,
which is a map containing all setting values.

The list of supported settings can be calculated by retrieving the keys
from the `settings` object, which means that if we support a setting, we
must include a default.

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

* feat: store settings in localStorage

This functionality was deleted by acb0de2 when moving the settings
object to the redux store, promising that the feature will be added back
in a future commit.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-06-24 16:06:27 -04:00
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