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>
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>
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>
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>
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>
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>
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>
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>
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>
* 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>
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>
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>
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>
- From `Etcher.analytics` to `Etcher.Modules.Analytics`.
- From `Etcher.image-writer` to `Etcher.Modules.ImageWriter`.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
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>
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>
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>
Referencing actions as properties of an object is more reliable than
just hardcoding strings everywhere.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
* 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>
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>
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>
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>
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>