Compare commits

...

334 Commits

Author SHA1 Message Date
Edwin Joassart
ec7e0b745e patch: send sourcemap to sentry at build 2023-01-12 17:46:00 +01:00
balenaCI
d5ba1ea5e1 v1.13.4 2023-01-12 15:10:51 +00:00
Balena CI
54d3636a22 Merge pull request #3890 from balena-io/wolvi-lataniere/adding-serial-number-etcher-pro
Adding EtcherPro device serial number to the Settings modal
2023-01-12 17:09:11 +02:00
Aurelien VALADE
45f6ee667d Cleaning-up EtcherPro specific code 2023-01-12 14:52:08 +01:00
Aurelien VALADE
d25eda9a7d Adding EtcherPro device serial number to the Settings modal
Change-type: patch
2023-01-12 12:12:10 +01:00
balenaCI
7420283249 v1.13.3 2023-01-11 14:30:46 +00:00
Balena CI
453952440f Merge pull request #3971 from balena-io/mcraa/win-cm4
patch: progress cm4 to second stage
2023-01-11 16:28:49 +02:00
Peter Makra
2475d576c7 patch: progress cm4 to second stage 2023-01-11 13:36:11 +01:00
balenaCI
8cd6da1260 v1.13.2 2023-01-02 20:55:59 +00:00
Balena CI
82dd4fc1d1 Merge pull request #3964 from balena-io/fix-winget-releaser
patch: fixed winget parameter name
2023-01-02 15:54:20 -05:00
mcraa
33fe4b2c1a patch: fixed winget parameter name 2023-01-02 21:17:55 +01:00
balenaCI
b1c1188107 v1.13.1 2023-01-02 17:26:57 +00:00
Balena CI
63b45aefae Merge pull request #3959 from balena-io/update-copyright
patch: update copyright in electron-builder
2023-01-02 12:25:24 -05:00
Peter Makra
f79cb0fac5 patch: updated sdk to fix bz2 issue 2023-01-02 17:44:42 +01:00
JOASSART Edwin
ec42892c7c patch: update copyright in electron-builder 2023-01-02 12:45:42 +01:00
balenaCI
371716fe6a v1.13.0 2022-12-28 16:48:14 +00:00
Balena CI
d5fb6bec15 Merge pull request #3945 from balena-io/update-sdk-for-cm4
Patch: update etcher-sdk version to fix CM4 issues
2022-12-28 11:46:52 -05:00
Peter Makra
c5e7bf26d7 bump electron deps 2022-12-23 21:32:30 +01:00
Peter Makra
e3072ac416 minor: electron version bump 2022-12-23 21:32:30 +01:00
Peter Makra
dfaf06e4cf sdk version bump 2022-12-23 21:32:29 +01:00
Peter Makra
6e24d25576 fixed ext2fs regex 2022-12-23 21:32:29 +01:00
Peter Makra
b59b171e43 patch: handle ext2fs with webpack 2022-12-23 21:32:29 +01:00
Peter Makra
28726584c2 prerelease etcher-compat etcher-sdk 2022-12-23 21:32:29 +01:00
Peter Makra
00b151311a alignerd webpack to ext2fs 2022-12-23 21:32:28 +01:00
builder555
36c813714b Patch: update etcher-sdk version to fix CM4 issues
Change-type: patch
2022-12-23 21:32:28 +01:00
balenaCI
2ae6764dd9 v1.12.7 2022-12-20 19:35:13 +00:00
Balena CI
debefc9652 Merge pull request #3954 from balena-io/renovate/i18next-21.x
Update dependency i18next to 21.10.0
2022-12-20 14:33:35 -05:00
Renovate Bot
b068b847c7 Update dependency i18next to 21.10.0
Update i18next to 21.10.0

Update i18next from 21.8.14 to 21.10.0

Change-type: patch
2022-12-20 18:56:45 +00:00
balenaCI
6c410c07ce v1.12.6 2022-12-20 18:00:05 +00:00
Balena CI
c01206c1f3 Merge pull request #3953 from balena-io/renovate/react-i18next-11.x
Update dependency react-i18next to 11.18.6
2022-12-20 12:58:30 -05:00
Renovate Bot
2e85fb45de Update dependency react-i18next to 11.18.6
Update react-i18next to 11.18.6

Update react-i18next from 11.18.1 to 11.18.6

Change-type: patch
2022-12-20 17:02:05 +00:00
balenaCI
67513e384d v1.12.5 2022-12-20 12:27:35 +00:00
Balena CI
828dafa493 Merge pull request #3950 from balena-io/easier-text-settings
Patch: made trim setting more readable
2022-12-20 07:26:13 -05:00
builder555
5c5a761222 Patch: made trim setting more readable
Change-type: patch
2022-12-20 06:52:06 -05:00
balenaCI
fab10e5fc5 v1.12.4 2022-12-19 19:42:01 +00:00
Balena CI
797345fc1c Merge pull request #3780 from balena-io/actions
patch: introducing github actions (WinGet)
2022-12-19 14:40:29 -05:00
Anton Belodedenko
a0388a43c3 Update winget.yml 2022-12-19 11:05:16 -08:00
mcraa
f5b0a3023b Update winget.yml 2022-12-19 11:05:16 -08:00
mcraa
dc1d7bd1fd fixed version of action to v1 2022-12-19 11:05:16 -08:00
Vedant
9d674321b6 Update winget.yml 2022-12-19 11:05:16 -08:00
Begula
f9c8378d6a patch: publish to winget with gh action 2022-12-19 11:05:16 -08:00
balenaCI
65da751a52 v1.12.3 2022-12-19 09:51:53 +00:00
Balena CI
72142be0de Merge pull request #3948 from balena-io/fix-i18n-settings
Patch: replaced plain text with i18n in settings
2022-12-19 04:50:25 -05:00
builder555
11cea7c926 Patch: replaced plain text with i18n in settings
Change-type: patch
2022-12-16 14:42:28 -05:00
balenaCI
8d46ee4c22 v1.12.2 2022-12-16 16:59:05 +00:00
Balena CI
d63c09e2c2 Merge pull request #3944 from balena-io/renovate/webpack-dev-server-4.x
Update dependency webpack-dev-server to 4.11.1
2022-12-16 11:56:45 -05:00
Renovate Bot
c9e9d7d109 Update dependency webpack-dev-server to 4.11.1
Update webpack-dev-server to 4.11.1

Update webpack-dev-server from 4.5.0 to 4.11.1

Change-type: patch
2022-12-16 15:57:46 +00:00
balenaCI
2412d20eb4 v1.12.1 2022-12-16 15:02:36 +00:00
Balena CI
7f90d23a12 Merge pull request #3947 from balena-io/expose-trim-setting
Patch: expose trim ext{2,3,4} setting
2022-12-16 09:59:32 -05:00
builder555
b9a82be29b Patch: expose trim ext{2,3,4} setting
Change-type: patch
2022-12-16 09:24:49 -05:00
balenaCI
638673ba5e v1.12.0 2022-12-14 16:17:32 +00:00
Balena CI
898fe4f216 Merge pull request #3936 from balena-io/i18n-conflict-resolve
I18n conflict resolve
2022-12-14 11:15:48 -05:00
Peter Makra
7e805662d1 check if modal children is aray 2022-12-14 15:48:48 +01:00
Peter Makra
baf59c73ac populated lockfile 2022-12-14 12:24:40 +01:00
mcraa
38ad9c97c6 added i18next to devDependencies 2022-12-14 12:03:30 +01:00
ab77
8fc574f059 i18n support and Chinese translation
Change-type: minor
2022-12-12 18:36:32 -08:00
r-q
78b0f00e88 chore: bind some translations
according to a suggestion of @lurch
2022-12-12 18:36:32 -08:00
r-q
0f10f2d483 fix: suit i18n with mocha and optimize translation
- use `import * as i18next from 'i18next';` instead of `import i18next from 'i18next';` and add an specific env to bypass mocha test
- optimized several translations
2022-12-12 18:36:32 -08:00
r-q
eb5f5bbb9e fix: optimize translations
more direct string-concatenation, thanks to @lurch
2022-12-12 18:36:32 -08:00
r-q
67d26ff790 minor: optimize i18n
Optimized several translations.
This commit itself is only a patch, but as a pull request must have at least one commit with a change-type.

Change-Type: minor
2022-12-12 18:36:32 -08:00
r-q
17f2008d88 refactor: split translations to files
- split translations from i18n.ts to several .ts files in lib/gui/app/i18n
- make a README for new language changes
- add zh-TW instead of only zh-CN
2022-12-12 18:36:32 -08:00
r-q
db1bf7e488 feat: make i18n and add Chinese support
- make i18n using i18next
- add Chinese (Simplified) support
2022-12-12 18:36:32 -08:00
balenaCI
4b786b8a9f v1.11.10 2022-12-13 02:27:43 +00:00
Balena CI
fdfa0d3258 Merge pull request #3943 from balena-io/renovate/webpack-cli-4.x
Update dependency webpack-cli to 4.10.0
2022-12-12 21:26:03 -05:00
Renovate Bot
757aa77d89 Update dependency webpack-cli to 4.10.0
Update webpack-cli to 4.10.0

Update webpack-cli from 4.2.0 to 4.10.0

Change-type: patch
2022-12-13 01:18:03 +00:00
balenaCI
d70ea06565 v1.11.9 2022-12-12 23:58:11 +00:00
Balena CI
f2ebd10053 Merge pull request #3941 from balena-io/renovate/webpack-5.x
Update dependency webpack to 5.75.0
2022-12-12 18:56:06 -05:00
Renovate Bot
cd67b442c9 Update dependency webpack to 5.75.0
Update webpack to 5.75.0

Update webpack from 5.11.0 to 5.75.0

Change-type: patch
2022-12-12 22:55:21 +00:00
balenaCI
852c83c4fb v1.11.8 2022-12-12 21:55:30 +00:00
Balena CI
e3b2ee3b83 Merge pull request #3940 from balena-io/renovate/awscli-1.x
Update dependency awscli to 1.27.28
2022-12-12 16:54:15 -05:00
Renovate Bot
927a026b86 Update dependency awscli to 1.27.28
Update awscli to 1.27.28

Update awscli from 1.27.27 to 1.27.28

Change-type: patch
2022-12-12 20:57:48 +00:00
balenaCI
c851e1d54f v1.11.7 2022-12-12 19:57:33 +00:00
Balena CI
e6fdca171f Merge pull request #3939 from balena-io/renovate/uuid-8.x
Update dependency uuid to 8.3.2
2022-12-12 14:56:00 -05:00
Renovate Bot
c9cfb87733 Update dependency uuid to 8.3.2
Update uuid to 8.3.2

Update uuid from 8.1.0 to 8.3.2

Change-type: patch
2022-12-12 18:56:41 +00:00
balenaCI
b0b7c53294 v1.11.6 2022-12-12 17:59:45 +00:00
Balena CI
e8dc6579fe Merge pull request #3933 from balena-io/renovate/tslib-2.x
Update dependency tslib to 2.4.1
2022-12-12 12:57:52 -05:00
Renovate Bot
f0747abe3f Update dependency tslib to 2.4.1
Update tslib to 2.4.1

Update tslib from 2.0.0 to 2.4.1

Change-type: patch
2022-12-12 16:59:52 +00:00
Balena CI
32fab87340 Merge pull request #3935 from balena-io/aethernet-buildUbuntu20
Patch: run linux build on ubuntu-20.04
2022-12-12 11:10:38 -05:00
Edwin Joassart
adcd8e0325 Patch: run linux build on ubuntu-20.04
as [`18.04` has been removed](https://github.blog/changelog/2022-08-09-github-actions-the-ubuntu-18-04-actions-runner-image-is-being-deprecated-and-will-be-removed-by-12-1-22/)

We cannot use `latest` as the glibc version will cause issue with older ubuntu version.
2022-12-12 12:09:01 +01:00
balenaCI
7b5808eb2b v1.11.5 2022-12-10 12:28:20 +00:00
Balena CI
a8f7422cf5 Merge pull request #3932 from balena-io/renovate/ts-loader-8.x
Update dependency ts-loader to 8.4.0
2022-12-10 07:26:55 -05:00
Renovate Bot
5ae9a26361 Update dependency ts-loader to 8.4.0
Update ts-loader to 8.4.0

Update ts-loader from 8.0.12 to 8.4.0

Change-type: patch
2022-12-10 11:57:20 +00:00
balenaCI
cf1fdb8c5f v1.11.4 2022-12-10 10:57:12 +00:00
Balena CI
bf7ebde100 Merge pull request #3930 from balena-io/renovate/styled-components-5.x
Update dependency styled-components to 5.3.6
2022-12-10 05:55:52 -05:00
Renovate Bot
88c5fa5035 Update dependency styled-components to 5.3.6
Update styled-components to 5.3.6

Update styled-components from 5.1.0 to 5.3.6

Change-type: patch
2022-12-10 09:57:26 +00:00
balenaCI
887b0dd538 v1.11.3 2022-12-10 08:54:54 +00:00
Balena CI
364d1db56a Merge pull request #3931 from balena-io/renovate/terser-webpack-plugin-5.x
Update dependency terser-webpack-plugin to 5.3.6
2022-12-10 03:53:34 -05:00
Renovate Bot
c431222909 Update dependency terser-webpack-plugin to 5.3.6
Update terser-webpack-plugin to 5.3.6

Update terser-webpack-plugin from 5.2.5 to 5.3.6

Change-type: patch
2022-12-10 07:54:55 +00:00
balenaCI
55a0f68b97 v1.11.2 2022-12-10 07:32:27 +00:00
Balena CI
af2563dfc2 Merge pull request #3929 from balena-io/renovate/string-replace-loader-3.x
Update dependency string-replace-loader to 3.1.0
2022-12-10 02:31:00 -05:00
Renovate Bot
33f8851083 Update dependency string-replace-loader to 3.1.0
Update string-replace-loader to 3.1.0

Update string-replace-loader from 3.0.1 to 3.1.0

Change-type: patch
2022-12-10 06:58:36 +00:00
balenaCI
fe1f19b9fa v1.11.1 2022-12-10 06:19:32 +00:00
Balena CI
871cf3ec0a Merge pull request #3928 from balena-io/renovate/sinon-9.x
Update dependency sinon to 9.2.4
2022-12-10 01:17:59 -05:00
Renovate Bot
686a5837b6 Update dependency sinon to 9.2.4
Update sinon to 9.2.4

Update sinon from 9.0.2 to 9.2.4

Change-type: patch
2022-12-10 04:58:08 +00:00
balenaCI
23f2dd5ce5 v1.11.0 2022-12-10 04:27:20 +00:00
Balena CI
d5d39b395b Merge pull request #3927 from balena-io/renovate/shyaml-0.x
Update dependency shyaml to 0.6.2
2022-12-09 23:25:51 -05:00
Renovate Bot
2acad790d3 Update dependency shyaml to 0.6.2
Update shyaml to 0.6.2

Update shyaml from 0.5.0 to 0.6.2

Change-type: minor
2022-12-10 03:56:23 +00:00
balenaCI
30133306d6 v1.10.29 2022-12-10 03:05:04 +00:00
Balena CI
04a62f2ad8 Merge pull request #3925 from balena-io/renovate/awscli-1.x
Update dependency awscli to 1.27.27
2022-12-09 22:03:25 -05:00
Renovate Bot
17858a7d72 Update dependency awscli to 1.27.27
Update awscli to 1.27.27

Update awscli from 1.27.26 to 1.27.27

Change-type: patch
2022-12-10 02:19:49 +00:00
balenaCI
620307568f v1.10.28 2022-12-10 02:10:44 +00:00
Balena CI
a349c5d9ac Merge pull request #3926 from balena-io/renovate/rendition-19.x
Update dependency rendition to 19.3.2
2022-12-09 21:08:52 -05:00
Renovate Bot
0d740ad12d Update dependency rendition to 19.3.2
Update rendition to 19.3.2

Update rendition from 19.2.0 to 19.3.2

Change-type: patch
2022-12-09 23:58:04 +00:00
balenaCI
85a3f28869 v1.10.27 2022-12-09 20:59:25 +00:00
Balena CI
dbd5397405 Merge pull request #3924 from balena-io/renovate/redux-4.x
Update dependency redux to 4.2.0
2022-12-09 15:57:56 -05:00
Renovate Bot
85c183b9ef Update dependency redux to 4.2.0
Update redux to 4.2.0

Update redux from 4.0.5 to 4.2.0

Change-type: patch
2022-12-09 19:58:31 +00:00
balenaCI
0d0af1d1dd v1.10.26 2022-12-09 18:58:23 +00:00
Balena CI
ad423fc187 Merge pull request #3923 from balena-io/renovate/pretty-bytes-5.x
Update dependency pretty-bytes to 5.6.0
2022-12-09 13:56:50 -05:00
Renovate Bot
d8b2a7a236 Update dependency pretty-bytes to 5.6.0
Update pretty-bytes to 5.6.0

Update pretty-bytes from 5.3.0 to 5.6.0

Change-type: patch
2022-12-09 18:00:18 +00:00
balenaCI
13ec8cbe98 v1.10.25 2022-12-09 17:01:54 +00:00
Balena CI
a7cae23612 Merge pull request #3922 from balena-io/renovate/pnp-webpack-plugin-1.x
Update dependency pnp-webpack-plugin to 1.7.0
2022-12-09 12:00:09 -05:00
Renovate Bot
86bb093f3d Update dependency pnp-webpack-plugin to 1.7.0
Update pnp-webpack-plugin to 1.7.0

Update pnp-webpack-plugin from 1.6.4 to 1.7.0

Change-type: patch
2022-12-09 16:01:26 +00:00
balenaCI
997e1eb2f2 v1.10.24 2022-12-09 14:59:56 +00:00
Balena CI
34cc8b8933 Merge pull request #3921 from balena-io/renovate/node-ipc-9.x
Update dependency node-ipc to 9.2.1
2022-12-09 09:58:26 -05:00
Renovate Bot
f26b074811 Update dependency node-ipc to 9.2.1
Update node-ipc to 9.2.1

Update node-ipc from 9.1.1 to 9.2.1

Change-type: patch
2022-12-09 13:56:52 +00:00
balenaCI
adaa07b4b0 v1.10.23 2022-12-09 13:05:54 +00:00
Balena CI
96f4569342 Merge pull request #3919 from balena-io/renovate/mocha-8.x
Update dependency mocha to 8.4.0
2022-12-09 08:04:01 -05:00
Renovate Bot
be190c6c80 Update dependency mocha to 8.4.0
Update mocha to 8.4.0

Update mocha from 8.0.1 to 8.4.0

Change-type: patch
2022-12-09 11:59:55 +00:00
balenaCI
809617a82d v1.10.22 2022-12-09 10:57:45 +00:00
Balena CI
df02732002 Merge pull request #3918 from balena-io/renovate/mini-css-extract-plugin-1.x
Update dependency mini-css-extract-plugin to 1.6.2
2022-12-09 05:56:17 -05:00
Renovate Bot
d35f3c3049 Update dependency mini-css-extract-plugin to 1.6.2
Update mini-css-extract-plugin to 1.6.2

Update mini-css-extract-plugin from 1.3.3 to 1.6.2

Change-type: patch
2022-12-09 09:59:39 +00:00
balenaCI
8b047e3b14 v1.10.21 2022-12-09 08:58:01 +00:00
Balena CI
fa41d21e27 Merge pull request #3917 from balena-io/renovate/lint-staged-10.x
Update dependency lint-staged to 10.5.4
2022-12-09 03:56:44 -05:00
Renovate Bot
54e6c5e2c1 Update dependency lint-staged to 10.5.4
Update lint-staged to 10.5.4

Update lint-staged from 10.2.2 to 10.5.4

Change-type: patch
2022-12-09 07:57:13 +00:00
balenaCI
43fc3dd7eb v1.10.20 2022-12-09 06:59:32 +00:00
Balena CI
12a1340c8e Merge pull request #3916 from balena-io/renovate/husky-4.x
Update dependency husky to 4.3.8
2022-12-09 01:58:11 -05:00
Renovate Bot
cf8b5790a1 Update dependency husky to 4.3.8
Update husky to 4.3.8

Update husky from 4.2.5 to 4.3.8

Change-type: patch
2022-12-09 05:56:33 +00:00
balenaCI
659d85a833 v1.10.19 2022-12-09 04:58:50 +00:00
Balena CI
96c44d31c9 Merge pull request #3915 from balena-io/renovate/esbuild-loader-2.x
Update dependency esbuild-loader to 2.20.0
2022-12-08 23:56:57 -05:00
Renovate Bot
ba812b4f64 Update dependency esbuild-loader to 2.20.0
Update esbuild-loader to 2.20.0

Update esbuild-loader from 2.16.0 to 2.20.0

Change-type: patch
2022-12-09 03:59:40 +00:00
balenaCI
4087258fbd v1.10.18 2022-12-09 03:07:59 +00:00
Balena CI
955be13129 Merge pull request #3914 from balena-io/renovate/electron-updater-4.x
Update dependency electron-updater to 4.6.5
2022-12-08 22:06:19 -05:00
Renovate Bot
32011c0dea Update dependency electron-updater to 4.6.5
Update electron-updater to 4.6.5

Update electron-updater from 4.3.5 to 4.6.5

Change-type: patch
2022-12-09 02:21:28 +00:00
balenaCI
b68325c71c v1.10.17 2022-12-09 01:21:27 +00:00
Balena CI
84bce86fce Merge pull request #3913 from balena-io/renovate/electron-notarize-1.x
Update dependency electron-notarize to 1.2.2
2022-12-08 20:19:51 -05:00
Renovate Bot
d68eab1dda Update dependency electron-notarize to 1.2.2
Update electron-notarize to 1.2.2

Update electron-notarize from 1.0.0 to 1.2.2

Change-type: patch
2022-12-08 23:57:37 +00:00
balenaCI
09cf014d14 v1.10.16 2022-12-08 22:58:43 +00:00
Balena CI
d5bab5805f Merge pull request #3912 from balena-io/renovate/awscli-1.x
Update dependency awscli to 1.27.26
2022-12-08 17:57:07 -05:00
Renovate Bot
b5ab500a14 Update dependency awscli to 1.27.26
Update awscli to 1.27.26

Update awscli from 1.27.25 to 1.27.26

Change-type: patch
2022-12-08 21:59:13 +00:00
balenaCI
49253d37c9 v1.10.15 2022-12-08 21:37:02 +00:00
Balena CI
97cf3b25ad Merge pull request #3911 from balena-io/renovate/electron-builder-22.x
Update dependency electron-builder to 22.14.13
2022-12-08 16:35:33 -05:00
Renovate Bot
99862b95a5 Update dependency electron-builder to 22.14.13
Update electron-builder to 22.14.13

Update electron-builder from 22.10.5 to 22.14.13

Change-type: patch
2022-12-08 20:56:08 +00:00
balenaCI
8b765d58e5 v1.10.14 2022-12-08 19:55:07 +00:00
Balena CI
8f566e45b8 Merge pull request #3910 from balena-io/renovate/debug-4.x
Update dependency debug to 4.3.4
2022-12-08 14:53:44 -05:00
Renovate Bot
b8af86e30c Update dependency debug to 4.3.4
Update debug to 4.3.4

Update debug from 4.2.0 to 4.3.4

Change-type: patch
2022-12-08 18:58:28 +00:00
balenaCI
784f193b6d v1.10.13 2022-12-08 17:57:08 +00:00
Balena CI
3967adb1b5 Merge pull request #3909 from balena-io/renovate/awscli-1.x
Update dependency awscli to 1.27.25
2022-12-08 12:55:28 -05:00
Renovate Bot
0667d1110f Update dependency awscli to 1.27.25
Update awscli to 1.27.25

Update awscli from 1.27.24 to 1.27.25

Change-type: patch
2022-12-08 16:59:48 +00:00
balenaCI
61dd22bdf3 v1.10.12 2022-12-08 15:56:15 +00:00
Anton Belodedenko
24eb8b05b0 Merge pull request #3907 from balena-io/renovate/css-loader-5.x
Update dependency css-loader to 5.2.7
2022-12-08 07:54:36 -08:00
Renovate Bot
6991a4950b Update dependency css-loader to 5.2.7
Update css-loader to 5.2.7

Update css-loader from 5.0.1 to 5.2.7

Change-type: patch
2022-12-07 03:55:56 +00:00
balenaCI
bb169cf674 v1.10.11 2022-12-07 03:22:00 +00:00
Anton Belodedenko
e5d0d2e262 Merge pull request #3906 from balena-io/renovate/awscli-1.x
Update dependency awscli to 1.27.24
2022-12-06 19:20:29 -08:00
Renovate Bot
72b4d4f4fa Update dependency awscli to 1.27.24
Update awscli to 1.27.24

Update awscli from 1.27.5 to 1.27.24

Change-type: patch
2022-12-07 02:27:18 +00:00
balenaCI
9b2f2eb4c3 v1.10.10 2022-12-07 02:19:19 +00:00
Anton Belodedenko
ce52ef95a9 Merge pull request #3905 from balena-io/renovate/node-14.x
Update dependency @types/node to 14.18.34
2022-12-06 18:17:44 -08:00
Renovate Bot
aa3756ad17 Update dependency @types/node to 14.18.34
Update @types/node to 14.18.34

Update @types/node from 14.18.33 to 14.18.34

Change-type: patch
2022-12-07 01:17:15 +00:00
balenaCI
73081e726d v1.10.9 2022-12-06 23:59:23 +00:00
Anton Belodedenko
d53dc4149b Merge pull request #3903 from balena-io/ab77/operational
Enable repository configuration
2022-12-06 15:57:58 -08:00
ab77
0d5bb4935f Enable repository configuration
Change-type: patch
2022-12-06 14:59:31 -08:00
balenaCI
14aeb0060b v1.10.8 2022-12-05 21:38:43 +00:00
Anton Belodedenko
239726f3ce Merge pull request #3864 from balena-io/renovate/chai-4.x
Update dependency chai to 4.3.7
2022-12-05 13:37:20 -08:00
Renovate Bot
4ed3002716 Update dependency chai to 4.3.7
Update chai to 4.3.7

Update chai from 4.2.0 to 4.3.7

Change-type: patch
2022-12-05 13:04:10 -08:00
balenaCI
7286fba240 v1.10.7 2022-12-05 19:39:09 +00:00
Anton Belodedenko
895c306fb7 Merge pull request #3868 from balena-io/ab77/operational
Use core workflow for GitHub publish
2022-12-05 11:37:16 -08:00
ab77
f3844d56e2 Use core workflow for GitHub publish
Change-type: patch
2022-12-05 10:51:35 -08:00
balenaCI
540dc3150a v1.10.6 2022-12-02 14:05:00 +00:00
Edwin Joassart
035c8dfec3 Merge pull request #3897 from balena-io/aethernet-assetv
Dummy update to fix asset version issue
2022-12-02 15:03:34 +01:00
Edwin Joassart
03d6a011db Dummy update to fix asset version issue
Due to a race between two patch, 1.10.5 assets are labelled 1.10.3.
This dummy PR should fix this.

Change-type: patch
2022-12-02 14:17:31 +01:00
balenaCI
27f64650f9 v1.10.5 2022-12-02 12:41:21 +00:00
Edwin Joassart
ccca009972 Merge pull request #3893 from balena-io/aethernet-fix-ubuntu
Patch: run linux build on ubuntu-18.04
2022-12-02 13:39:56 +01:00
Edwin Joassart
57a6ceff0e Patch: run linux build on ubuntu-18.04
Running on ubuntu-latest means you need a more recent version of glibc which breaks on older ubuntu.

Thanks to @theofficialgman for suggesting the fix.
2022-12-02 13:00:01 +01:00
balenaCI
30c4baa58b v1.10.4 2022-12-01 23:27:57 +00:00
Anton Belodedenko
a930d77064 Merge pull request #3875 from p-linnane/brew-remove
Remove Homebrew instructions
2022-12-01 15:26:24 -08:00
Patrick Linnane
0d1cfffa5c patch: remove Homebrew instructions in README
Homebrew no longer supports etcher, so removing install instructions.

Change-type: patch
2022-12-01 14:35:59 -08:00
balenaCI
3c7422764c v1.10.3 2022-12-01 22:31:26 +00:00
Anton Belodedenko
55176b9f8f Merge pull request #3895 from balena-io/ab77/external-contributors
Allow external contributors
2022-12-01 14:29:59 -08:00
ab77
156b9314b5 Allow external contributors
Change-type: patch
2022-12-01 13:50:27 -08:00
balenaCI
76d22280dc v1.10.2 2022-11-25 19:22:51 +00:00
bulldozer-balena[bot]
e4251a3862 Merge pull request #3886 from balena-io/aethernet-patch-analytics
Fix missing analytics token
2022-11-25 19:21:35 +00:00
Edwin Joassart
831339bd2c Fix missing analytics token
Change-type: patch
Signed-off-by: Edwin Joassart edwin.joassart@balena.io
2022-11-25 19:14:58 +01:00
balenaCI
952ea80e15 v1.10.1 2022-11-21 16:50:16 +00:00
bulldozer-balena[bot]
813c497e4b Merge pull request #3882 from balena-io/wolvi-lataniere/fix-screensaver-methods-calls
Fixing call to electron block screensaver methods invocation
2022-11-21 16:48:50 +00:00
Aurelien VALADE
1b5b647135 Fixing call to electron block screensaver methods invocation
Replacing `send` calls to `invoke` for `enable/disable-screensaver` calls.

Change-type: patch
Signed-off-by: Aurelien VALADE <aurelien.valade@balena.io>
2022-11-21 16:26:15 +01:00
balenaCI
7de99003ca v1.10.0 2022-11-10 20:54:14 +00:00
bulldozer-balena[bot]
e09bdd734b Merge pull request #3871 from balena-io/test
testing renovate
2022-11-10 20:52:37 +00:00
builder555
306e087ec6 testing renovate
Change-Type: minor
2022-11-10 15:12:39 -05:00
balenaCI
c6b0178a87 v1.9.0 2022-11-08 21:37:26 +00:00
bulldozer-balena[bot]
4e581ea1ce Merge pull request #3861 from balena-io/renovate/awscli-1.x
Update dependency awscli to 1.27.5
2022-11-08 21:36:02 +00:00
Renovate Bot
26dc2d19e5 Update dependency awscli to 1.27.5
Update awscli to 1.27.5

Update awscli from 1.11.87 to 1.27.5

Change-type: minor
2022-11-08 20:50:05 +00:00
balenaCI
b99282acfb v1.8.17 2022-11-08 20:38:29 +00:00
bulldozer-balena[bot]
4e48724d0c Merge pull request #3860 from balena-io/renovate/react-dom-16.x
Update dependency @types/react-dom to 16.9.17
2022-11-08 20:36:50 +00:00
Renovate Bot
448ce141d5 Update dependency @types/react-dom to 16.9.17
Update @types/react-dom to 16.9.17

Update @types/react-dom from 16.8.4 to 16.9.17

Change-type: patch
2022-11-08 19:50:12 +00:00
balenaCI
695f287190 v1.8.16 2022-11-08 19:39:44 +00:00
bulldozer-balena[bot]
4de3271e15 Merge pull request #3858 from balena-io/renovate/react-16.x
Update dependency @types/react to 16.14.34
2022-11-08 19:38:16 +00:00
Renovate Bot
77b33b127d Update dependency @types/react to 16.14.34
Update @types/react to 16.14.34

Update @types/react from 16.8.5 to 16.14.34

Change-type: patch
2022-11-08 18:37:18 +00:00
balenaCI
9cd13ba381 v1.8.15 2022-11-08 18:21:06 +00:00
bulldozer-balena[bot]
9df23c8a3f Merge pull request #3859 from balena-io/ab77/operational
CI: generalise artefact handling
2022-11-08 18:19:29 +00:00
ab77
e3618b939e CI: generalise artefact handling
* on PR syncs, delete draft releases on Linux runners only
* delete draft releases when unmerged PRs are closed

Change-type: patch
2022-11-08 09:41:03 -08:00
balenaCI
6a39f5869a v1.8.14 2022-11-08 13:57:20 +00:00
bulldozer-balena[bot]
fd472efadc Merge pull request #3857 from balena-io/renovate/node-14.x
Update dependency @types/node to 14.18.33
2022-11-08 13:56:11 +00:00
Renovate Bot
7e2c2eae63 Update dependency @types/node to 14.18.33
Update @types/node to 14.18.33

Update @types/node from 14.14.41 to 14.18.33

Change-type: patch
2022-11-08 13:01:36 +00:00
balenaCI
5266571ca4 v1.8.13 2022-11-08 12:39:29 +00:00
bulldozer-balena[bot]
797868c474 Merge pull request #3856 from balena-io/renovate/copy-webpack-plugin-6.x
Update dependency @types/copy-webpack-plugin to 6.4.3
2022-11-08 12:38:11 +00:00
Renovate Bot
2c2a5c7c2b Update dependency @types/copy-webpack-plugin to 6.4.3
Update @types/copy-webpack-plugin to 6.4.3

Update @types/copy-webpack-plugin from 6.0.0 to 6.4.3

Change-type: patch
2022-11-08 11:47:28 +00:00
balenaCI
9e536d5337 v1.8.12 2022-11-08 11:33:03 +00:00
bulldozer-balena[bot]
860e680dd9 Merge pull request #3855 from balena-io/renovate/font-awesome
Update dependency @fortawesome/fontawesome-free to 5.15.4
2022-11-08 11:31:46 +00:00
Renovate Bot
7bb52aa170 Update dependency @fortawesome/fontawesome-free to 5.15.4
Update @fortawesome/fontawesome-free to 5.15.4

Update @fortawesome/fontawesome-free from 5.13.1 to 5.15.4

Change-type: patch
2022-11-08 10:50:37 +00:00
balenaCI
1c370f9100 v1.8.11 2022-11-08 10:38:49 +00:00
bulldozer-balena[bot]
ec7c772d0b Merge pull request #3854 from balena-io/renovate/balena-lint-5.x
Update dependency @balena/lint to 5.4.2
2022-11-08 10:37:18 +00:00
Renovate Bot
cc0285a77d Update dependency @balena/lint to 5.4.2
Update @balena/lint to 5.4.2

Update @balena/lint from 5.3.0 to 5.4.2

Change-type: patch
2022-11-08 09:46:20 +00:00
balenaCI
256d3550d1 v1.8.10 2022-11-08 09:35:05 +00:00
bulldozer-balena[bot]
db3a5f3b0a Merge pull request #3852 from balena-io/renovate/sys-class-rgb-led-3.x
Update dependency sys-class-rgb-led to 3.0.1
2022-11-08 09:33:38 +00:00
Renovate Bot
0e58edf113 Update dependency sys-class-rgb-led to 3.0.1
Update sys-class-rgb-led to 3.0.1

Update sys-class-rgb-led from 3.0.0 to 3.0.1

Change-type: patch
2022-11-08 08:54:54 +00:00
balenaCI
db136926a9 v1.8.9 2022-11-08 08:40:23 +00:00
bulldozer-balena[bot]
d84e7211be Merge pull request #3851 from balena-io/renovate/semver-7.x
Update dependency semver to 7.3.8
2022-11-08 08:38:44 +00:00
Renovate Bot
8357cc19d2 Update dependency semver to 7.3.8
Update semver to 7.3.8

Update semver from 7.3.2 to 7.3.8

Change-type: patch
2022-11-08 07:45:37 +00:00
balenaCI
2752b9fa95 v1.8.8 2022-11-08 07:33:39 +00:00
bulldozer-balena[bot]
0214be4953 Merge pull request #3850 from balena-io/renovate/omit-deep-lodash-1.x
Update dependency omit-deep-lodash to 1.1.7
2022-11-08 07:32:29 +00:00
Renovate Bot
a4f944e795 Update dependency omit-deep-lodash to 1.1.7
Update omit-deep-lodash to 1.1.7

Update omit-deep-lodash from 1.1.4 to 1.1.7

Change-type: patch
2022-11-08 06:35:41 +00:00
balenaCI
cd2ebf15fc v1.8.7 2022-11-08 06:19:14 +00:00
bulldozer-balena[bot]
7a7ea374e9 Merge pull request #3849 from balena-io/renovate/immutable-3.x
Update dependency immutable to 3.8.2
2022-11-08 06:17:03 +00:00
Renovate Bot
330df325f9 Update dependency immutable to 3.8.2
Update immutable to 3.8.2

Update immutable from 3.8.1 to 3.8.2

Change-type: patch
2022-11-08 05:22:49 +00:00
balenaCI
2fc0882b2e v1.8.6 2022-11-08 05:18:30 +00:00
bulldozer-balena[bot]
4dd779e010 Merge pull request #3847 from balena-io/renovate/electron-rebuild-3.x
Update dependency electron-rebuild to 3.2.9
2022-11-08 05:17:09 +00:00
Renovate Bot
3dc54405fe Update dependency electron-rebuild to 3.2.9
Update electron-rebuild to 3.2.9

Update electron-rebuild from 3.2.5 to 3.2.9

Change-type: patch
2022-11-08 04:39:11 +00:00
balenaCI
3f1aa5bac3 v1.8.5 2022-11-08 04:22:24 +00:00
bulldozer-balena[bot]
8f52fdb900 Merge pull request #3846 from balena-io/renovate/electron-mocha-9.x
Update dependency electron-mocha to 9.3.3
2022-11-08 04:21:09 +00:00
Renovate Bot
1b93891ed8 Update dependency electron-mocha to 9.3.3
Update electron-mocha to 9.3.3

Update electron-mocha from 9.3.2 to 9.3.3

Change-type: patch
2022-11-08 03:23:58 +00:00
balenaCI
33adc8ecf8 v1.8.4 2022-11-08 02:41:38 +00:00
bulldozer-balena[bot]
0455f7ea58 Merge pull request #3845 from balena-io/renovate/webpack-node-externals-2.x
Update dependency @types/webpack-node-externals to 2.5.3
2022-11-08 02:39:47 +00:00
Renovate Bot
ea5a167f4f Update dependency @types/webpack-node-externals to 2.5.3
Update @types/webpack-node-externals to 2.5.3

Update @types/webpack-node-externals from 2.5.0 to 2.5.3

Change-type: patch
2022-11-08 01:45:44 +00:00
balenaCI
8a1c4a4cc8 v1.8.3 2022-11-08 01:36:35 +00:00
bulldozer-balena[bot]
bd8bc81713 Merge pull request #3844 from balena-io/renovate/tmp-0.x
Update dependency @types/tmp to 0.2.3
2022-11-08 01:35:19 +00:00
Renovate Bot
98a5ddf58a Update dependency @types/tmp to 0.2.3
Update @types/tmp to 0.2.3

Update @types/tmp from 0.2.0 to 0.2.3

Change-type: patch
2022-11-08 00:34:31 +00:00
balenaCI
6223dbc541 v1.8.2 2022-11-08 00:19:28 +00:00
bulldozer-balena[bot]
7c56621c57 Merge pull request #3843 from balena-io/ab77/operational
Generate release notes with git
2022-11-08 00:18:08 +00:00
ab77
a61aa8e2be Generate release notes with git
Change-type: patch
2022-11-07 15:39:26 -08:00
balenaCI
7df4f9615b v1.8.1 2022-11-07 23:35:28 +00:00
bulldozer-balena[bot]
5742452fdf Merge pull request #3842 from balena-io/renovate/mime-types-2.x
Update dependency @types/mime-types to 2.1.1
2022-11-07 23:34:08 +00:00
Renovate Bot
fe09f9f862 Update dependency @types/mime-types to 2.1.1
Update @types/mime-types to 2.1.1

Update @types/mime-types from 2.1.0 to 2.1.1

Change-type: patch
2022-11-07 22:36:54 +00:00
balenaCI
3a4687ea0f v1.8.0 2022-11-07 22:27:05 +00:00
bulldozer-balena[bot]
db6490fb1b Merge pull request #3840 from balena-io/renovate/scripts-resin-digest
Update scripts/resin digest to 652fdd4
2022-11-07 22:25:48 +00:00
Renovate Bot
1642297101 Update scripts/resin digest to 652fdd4
Update scripts/resin to

Update scripts/resin from  to

Change-type: minor
2022-11-07 21:46:35 +00:00
balenaCI
5ecd223cfc v1.7.15 2022-11-07 21:36:38 +00:00
bulldozer-balena[bot]
306e40fd7b Merge pull request #3838 from balena-io/ab77/operational
Build targets individually
2022-11-07 21:34:46 +00:00
ab77
b58249b9c8 Build targets individually
Change-type: patch
2022-11-07 12:57:51 -08:00
balenaCI
b23b4b34d0 v1.7.14 2022-11-07 20:17:55 +00:00
bulldozer-balena[bot]
73bc921713 Merge pull request #3833 from balena-io/renovate/npm-lodash-vulnerability
Update dependency lodash to 4.17.21 [SECURITY]
2022-11-07 20:16:20 +00:00
Renovate Bot
f356e4c303 Update dependency lodash to 4.17.21 [SECURITY]
Update lodash to 4.17.21

Update lodash from 4.17.10 to 4.17.21

Change-type: patch
2022-11-07 19:31:58 +00:00
balenaCI
9888167f2e v1.7.13 2022-11-07 19:17:08 +00:00
bulldozer-balena[bot]
4561690478 Merge pull request #3837 from balena-io/ab77/operational
Update release notes on finalize
2022-11-07 19:15:38 +00:00
ab77
576113febf Update release notes on finalize
Change-type: patch
2022-11-07 10:33:38 -08:00
balenaCI
cc139bf750 v1.7.12 2022-11-07 18:32:20 +00:00
bulldozer-balena[bot]
ae91958c06 Merge pull request #3836 from balena-io/ab77/operational
Avoid duplicate releases
2022-11-07 18:30:56 +00:00
ab77
33dea6267f Avoid duplicate releases
Change-type: patch
2022-11-07 09:47:19 -08:00
balenaCI
c9a8bca96f v1.7.11 2022-11-07 17:32:27 +00:00
bulldozer-balena[bot]
8af376e608 Merge pull request #3832 from balena-io/ab77/operational
Only run finalize on Linux runners
2022-11-07 17:30:49 +00:00
ab77
9ab307df4f Only run finalize on Linux runners
Change-type: patch
2022-11-07 08:39:52 -08:00
balenaCI
e8a716f8bb v1.7.10 2022-11-07 15:59:42 +00:00
bulldozer-balena[bot]
a40e64f6cd Merge pull request #3819 from balena-io/ab77/operational
Switch to Flowzone
2022-11-07 15:58:11 +00:00
ab77
2e53feb38c Switch to Flowzone
Change-type: patch
2022-11-07 07:11:18 -08:00
Balena CI
5945ab1f50 v1.7.9 2022-04-22 16:47:29 +03:00
bulldozer-balena[bot]
59d67220d4 Merge pull request #3747 from balena-io/next-release
patch: deb afterinstall and readme updates
2022-04-22 13:45:50 +00:00
mcraa
61610ded84 patch: update allowed extensions to include deb afterinstall in build 2022-04-22 15:08:04 +02:00
Peter Makra
c87a132f40 patch: add update notification 2022-04-22 14:44:36 +02:00
Andrew Scheller
350d4de32b patch: fix usb-device-boot link in README
Change-type: patch
2022-03-31 17:46:08 +02:00
Ken Bannister
f5f9025d6d Fix application directory for Debian postinst script
Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2022-03-31 17:45:10 +02:00
Balena CI
549d744d04 v1.7.8 2022-03-18 19:22:12 +02:00
bulldozer-balena[bot]
6194460dc2 Merge pull request #3723 from balena-io/v1.7.8-draft
small ui updates
2022-03-18 17:20:11 +00:00
Peter Makra
8370f638b4 patch: complete suse uninstall readme
Change-Type: patch
2022-03-11 00:40:20 +01:00
Peter Makra
ac34c51125 patch: completed suse instructions
Change-Type: patch
2022-03-11 00:33:29 +01:00
Peter Makra
b241470fe1 patch: order rpm instrictions
Change-Type: patch
2022-03-10 17:00:43 +01:00
Peter Makra
179697040c Merge branch 'v1.7.8-draft' of github.com:balena-io/etcher into v1.7.8-draft 2022-03-10 16:37:01 +01:00
Peter Makra
335766ed12 patch: enabled update notification for version 1.7.8
Change-Type: patch
2022-03-10 16:36:24 +01:00
Peter Makra
4c5d052a71 patch: updated title to balenaEtcher
fixes #3592

Change-Type: patch
2022-03-10 16:35:03 +01:00
Peter Makra
86423342a8 patch: cleanup and organize readme
Change-Type: patch
2022-03-10 16:27:38 +01:00
Peter Makra
d8b41552e3 patch: extend cloudsmith attribution in readme
Change-Type: patch
2022-03-10 16:08:43 +01:00
Logicer
11c65fb392 Update macOS Icon to Big Sur Style
Change-type: patch
2022-03-10 15:55:27 +01:00
Balena CI
bed126506f v1.7.7 2022-02-22 11:25:43 +02:00
bulldozer-balena[bot]
f6aeb52b16 Merge pull request #3711 from balena-io/fix-auto-update
patch: Fix auto update
2022-02-22 09:23:16 +00:00
Peter Makra
a5201942b8 patch: clarified update check 2022-02-22 09:50:34 +01:00
Peter Makra
c1f7164273 patch: autoupdate stagingPercentage check, include default
Change-Type: patch
2022-02-21 21:09:49 +01:00
Balena CI
6774bf784c v1.7.6 2022-02-21 18:00:46 +02:00
bulldozer-balena[bot]
56ec8b4eac Merge pull request #3699 from balena-io/update-issue-template
patch: add requirements and help to issue template
2022-02-21 15:59:05 +00:00
Peter Makra
35868509af patch: version number notification 2022-02-21 15:21:58 +01:00
Peter Makra
3ab6749f49 Merge branch 'master' into update-issue-template 2022-02-21 14:33:16 +01:00
Balena CI
7a012a92bc v1.7.5 2022-02-21 15:19:52 +02:00
bulldozer-balena[bot]
aba01825a0 Merge pull request #3700 from flec/fix-basic-auth
patch: fix flashing from URL when using basic auth
2022-02-21 13:17:31 +00:00
Peter Makra
907a3308de updated branch with 1.7.4 2022-02-21 13:53:16 +01:00
Peter Makra
4366bb372f patch: fixed typos in template 2022-02-21 13:49:18 +01:00
Marco Füllemann
a6f6cd4a19 patch: fix flashing from URL when using basic auth 2022-02-21 13:36:40 +01:00
Balena CI
03ee428039 v1.7.4 2022-02-21 13:44:44 +02:00
bulldozer-balena[bot]
8d652d064d Merge pull request #3704 from balena-io/update-electron-12.2.3
patch: updated electron to 12.2.3
2022-02-21 11:42:46 +00:00
Peter Makra
28adc34239 patch: set version update notification 1.7.3 2022-02-17 14:15:46 +01:00
Peter Makra
120e9bf42f Merge branch 'update-electron-12.2.3' of github.com:balena-io/etcher into update-electron-12.2.3 2022-02-17 13:47:02 +01:00
Peter Makra
59f54e194b patch: updated electron to 12.2.3
Change-Type: patch
2022-02-17 13:46:35 +01:00
Peter Makra
c4834e61a7 patch: updated electron to 12.2.3
Change-Type: patch
2022-02-17 13:37:17 +01:00
mcraa
e4d02bc561 patch: add requirements and help to issue template 2022-02-08 08:19:55 +00:00
mcraa
b9e54e39f7 patch: add requirements and help to issue template 2022-02-08 09:19:55 +01:00
Balena CI
f3c32eac65 v1.7.3 2021-12-29 17:09:42 +02:00
bulldozer-balena[bot]
9a303ab344 Merge pull request #3667 from balena-io/fix-message-of.null
patch: fix mesage of null
2021-12-29 15:06:59 +00:00
Peter Makra
9c1b55bebc patch: fix mesage of null
Change-Type: patch
2021-12-29 15:23:21 +01:00
Balena CI
30ae4bbd86 v1.7.2 2021-12-21 20:38:54 +02:00
bulldozer-balena[bot]
c6126a980a Merge pull request #3661 from balena-io/fix-windows-open-from-web
patch: fixed open from browser on windows
2021-12-21 18:36:22 +00:00
Peter Makra
ef90d048ca patch: fixed open from browser on windows
Change-type: patch
Signed-off-by: Peter Makra <peter@balena.io>
2021-12-21 17:47:10 +01:00
Balena CI
b938132038 v1.7.1 2021-11-29 11:05:10 +02:00
bulldozer-balena[bot]
3cb2e78fe7 Merge pull request #3630 from balena-io/improve-webpack-build
patch: Improve webpack build time
2021-11-29 09:02:29 +00:00
Lorenzo Alberto Maria Ambrosi
ea9875ddf0 patch: Revert back to electron-rebuild
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-22 12:24:26 +01:00
Lorenzo Alberto Maria Ambrosi
65dacd2ff2 patch: Disallow TS in JS
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-16 20:08:11 +01:00
Lorenzo Alberto Maria Ambrosi
a190818827 patch: Remove esInterop TS flag
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-11 14:39:33 +01:00
Lorenzo Alberto Maria Ambrosi
98e33b619b patch: Use @balena/sudo-prompt
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-11 14:39:07 +01:00
Lorenzo Alberto Maria Ambrosi
685ed715ac patch: Update rpiboot guide link
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-11 11:47:11 +01:00
Lorenzo Alberto Maria Ambrosi
3cf3c4b398 patch: Improve webpack build time
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-11 10:45:00 +01:00
Balena CI
1c2ef4b1d4 v1.7.0 2021-11-09 18:09:26 +02:00
bulldozer-balena[bot]
d22fc91585 Merge pull request #3628 from balena-io/device-info-draft
Device info draft
2021-11-09 16:07:20 +00:00
Lorenzo Alberto Maria Ambrosi
0a28af5c35 patch: Add missing @types/react@16.8.5
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-09 14:10:18 +01:00
Lorenzo Alberto Maria Ambrosi
0c1e5b88ef patch: Use npm ci in Makefile
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-11-09 13:53:04 +01:00
Lorenzo Alberto Maria Ambrosi
790201be90 patch: Add draft info boxes for system information
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-27 10:41:56 +02:00
Lorenzo Alberto Maria Ambrosi
d8d379f05e patch: Remove electron-rebuild package
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-21 16:42:46 +02:00
Lorenzo Alberto Maria Ambrosi
b5e9701048 patch: Make electron a dev. dependency
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-21 16:40:37 +02:00
Lorenzo Alberto Maria Ambrosi
292f86d6f5 patch: Remove electron-rebuild package
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-21 16:40:15 +02:00
Lorenzo Alberto Maria Ambrosi
76ca9934c8 patch: Use exact modules versions
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-21 11:24:32 +02:00
Lorenzo Alberto Maria Ambrosi
37b826ee4e patch: Update etcher-sdk from v6.2.5 to v6.3.0
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-13 17:27:32 +02:00
JSReds
1e1bd3c508 Fix write step for Http file process
Change-type: patch
Signed-off-by: Andrea Rosci <andrear@balena.io>
2021-10-13 17:22:57 +02:00
Lorenzo Alberto Maria Ambrosi
00e8f11913 patch: Fix linting errors
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-13 17:21:48 +02:00
Lorenzo Alberto Maria Ambrosi
a3c24a26a0 minor: Refactor dependencies installation to avoid custom scripts
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-10-13 17:16:11 +02:00
Lorenzo Alberto Maria Ambrosi
4232928ad8 patch: Fix LEDs init error
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-09-30 13:05:47 +02:00
Balena CI
b165fb78da v1.6.0 2021-09-24 20:12:18 +03:00
bulldozer-balena[bot]
e9f6c5ead9 Merge pull request #3599 from balena-io/led-color-settings
Led color settings
2021-09-24 17:10:00 +00:00
Marco Füllemann
b2d0c1c9dd add support for basic auth when downloading images from URL
When selecting "Flash from URL" the user can optionally provide a username and password for basic authentication. The authentication input fields are collapsed by default. When the authentication input fields are collapsed after entering values the values are cleared to ensure that the user sees all parameter passed to the server.

Change-Type: minor
Changelog-Entry: Add support for basic auth when downloading images from URL.
2021-09-17 11:16:29 +02:00
Lorenzo Alberto Maria Ambrosi
14d91400a4 patch: Update etcher-sdk from v6.2.1 to v6.2.5
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-09-17 11:11:36 +02:00
David Gaspar
d0114aece7 Update Makefile to Apple M1 info
Expanding host architecture detection.

Change-type: patch
2021-09-07 16:56:10 +02:00
Lorenzo Alberto Maria Ambrosi
dff2df4aab Add LED settings for potentially different hardware
Change-type: patch
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-09-07 15:20:56 +02:00
82 changed files with 11799 additions and 7696 deletions

View File

@@ -7,7 +7,6 @@ indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

8
.gitattributes vendored
View File

@@ -1,3 +1,6 @@
# default
* text
# Javascript files must retain LF line-endings (to keep eslint happy)
*.js text eol=lf
*.jsx text eol=lf
@@ -27,6 +30,7 @@ Makefile text
*.yml text
*.patch text
*.txt text
*.tpl text
CODEOWNERS text
*.plist text
@@ -58,3 +62,7 @@ CODEOWNERS text
*.ttf binary diff=hex
xz-without-extension binary diff=hex
wmic-output.txt binary diff=hex
# gitsecret
*.secret binary
.gitsecret/** binary

View File

@@ -1,6 +1,11 @@
- **Etcher version:**
- **Operating system and architecture:**
- **Image flashed:**
- **What do you think should have happened:** <!-- or a step by step reproduction process -->
- **What happened:**
- **Do you see any meaningful error information in the DevTools?**
<!-- You can open DevTools by pressing `Ctrl+Shift+I` (`Ctrl+Alt+I` for Etcher before v1.3.x), or `Cmd+Opt+I` if you're on macOS. -->
<!-- issues with missing information will be labeled as not-enough-info and closed shortly -->
<!-- please try to include as many influencing elements as possible are you root, does any other process block the device, etc. -->
<!-- if you find a solution in the meantime thank you for sharing the fix and not just closing / abandoning your issue -->

221
.github/actions/publish/action.yml vendored Normal file
View File

@@ -0,0 +1,221 @@
---
name: package and publish GitHub (draft) release
# https://github.com/product-os/flowzone/tree/master/.github/actions
inputs:
json:
description: "JSON stringified object containing all the inputs from the calling workflow"
required: true
secrets:
description: "JSON stringified object containing all the secrets from the calling workflow"
required: true
# --- custom environment
XCODE_APP_LOADER_EMAIL:
type: string
default: "accounts+apple@balena.io"
NODE_VERSION:
type: string
default: "14.x"
VERBOSE:
type: string
default: "true"
runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: "composite"
steps:
- name: Download custom source artifact
uses: actions/download-artifact@v3
with:
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
path: ${{ runner.temp }}
- name: Extract custom source artifact
shell: pwsh
working-directory: .
run: tar -xf ${{ runner.temp }}/custom.tgz
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ inputs.NODE_VERSION }}
cache: npm
- name: Install yq
shell: bash --noprofile --norc -eo pipefail -x {0}
run: choco install yq
if: runner.os == 'Windows'
# FIXME: resinci-deploy is not actively maintained
# https://github.com/product-os/resinci-deploy
- name: Checkout resinci-deploy
uses: actions/checkout@v3
with:
repository: product-os/resinci-deploy
token: ${{ fromJSON(inputs.secrets).FLOWZONE_TOKEN }}
path: resinci-deploy
- name: Build and install resinci-deploy
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
rm -rf ../resinci-deploy && mv resinci-deploy ..
pushd ../resinci-deploy && npm ci && npm link && popd
if [[ $runner_os =~ linux|macos ]]; then
chmod +x "$(dirname "$(which node)")/resinci-deploy" && which resinci-deploy
fi
# Upload sourcemaps to sentry
- name: Generate Sentry DSN
id: sentry
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
branch="$(echo '${{ github.event.pull_request.head.ref }}' | sed 's/[^[:alnum:]]/-/g')"
stdout="$(resinci-deploy store sentry \
--branch="${branch}" \
--name="$(jq -r '.name' package.json)" \
--team="$(yq e '.sentry.team' repo.yml)" \
--org="$(yq e '.sentry.org' repo.yml)" \
--type="$(yq e '.sentry.type' repo.yml)")"
echo "dsn=$(echo "${stdout}" | tail -n 1)" >> $GITHUB_OUTPUT
env:
SENTRY_TOKEN: ${{ fromJSON(inputs.secrets).SENTRY_AUTH_TOKEN }}
# https://www.electron.build/code-signing.html
# https://github.com/Apple-Actions/import-codesign-certs
- name: Import Apple code signing certificate
if: runner.os == 'macOS'
uses: apple-actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
p12-password: ${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
- name: Import Windows code signing certificate
if: runner.os == 'Windows'
shell: powershell
run: |
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:WINDOWS_CERTIFICATE
certutil -decode ${{ runner.temp }}/certificate.base64 ${{ runner.temp }}/certificate.pfx
Remove-Item -path ${{ runner.temp }} -include certificate.base64
Import-PfxCertificate `
-FilePath ${{ runner.temp }}/certificate.pfx `
-CertStoreLocation Cert:\CurrentUser\My `
-Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
Remove-Item -path ${{ runner.temp }} -include certificate.pfx
env:
WINDOWS_CERTIFICATE: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
# ... or refactor (e.g.) https://github.com/samuelmeuli/action-electron-builder
# https://github.com/product-os/scripts/tree/master/electron
# https://github.com/product-os/scripts/tree/master/shared
# https://github.com/product-os/balena-concourse/blob/master/pipelines/github-events/template.yml
- name: Package release
id: package_release
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
runner_arch="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
ELECTRON_BUILDER_ARCHITECTURE="${runner_arch}"
APPLICATION_VERSION="$(jq -r '.version' package.json)"
ARCHITECTURE_FLAGS="--${ELECTRON_BUILDER_ARCHITECTURE}"
if [[ $runner_os =~ linux ]]; then
ELECTRON_BUILDER_OS='--linux'
TARGETS="$(yq e .linux.target[] electron-builder.yml)"
elif [[ $runner_os =~ darwin|macos|osx ]]; then
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
CSC_KEYCHAIN=signing_temp
CSC_LINK=${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
ELECTRON_BUILDER_OS='--mac'
TARGETS="$(yq e .mac.target[] electron-builder.yml)"
elif [[ $runner_os =~ windows|win ]]; then
ARCHITECTURE_FLAGS="--ia32 ${ARCHITECTURE_FLAGS}"
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
CSC_LINK=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
ELECTRON_BUILDER_OS='--win'
TARGETS="$(yq e .win.target[] electron-builder.yml)"
else
exit 1
fi
npm link electron-builder
for target in ${TARGETS}; do
electron-builder ${ELECTRON_BUILDER_OS} ${target} ${ARCHITECTURE_FLAGS} \
--c.extraMetadata.analytics.sentry.token='${{ steps.sentry.outputs.dsn }}' \
--c.extraMetadata.analytics.mixpanel.token='balena-etcher' \
--c.extraMetadata.packageType="${target}"
find dist -type f -maxdepth 1
done
echo "version=${APPLICATION_VERSION}" >> $GITHUB_OUTPUT
env:
# Apple notarization (afterSignHook.js)
XCODE_APP_LOADER_EMAIL: ${{ inputs.XCODE_APP_LOADER_EMAIL }}
XCODE_APP_LOADER_PASSWORD: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_PASSWORD }}
# https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/#improvements-for-public-repository-forks
# https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks#about-workflow-runs-from-public-forks
CSC_FOR_PULL_REQUEST: true
# https://www.electron.build/auto-update.html#staged-rollouts
- name: Configure staged rollout(s)
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
percentage="$(cat < repo.yml | yq e .triggerNotification.stagingPercentage)"
find dist -type f -maxdepth 1 \
-name "latest*.yml" \
-exec yq -i e .version=\"${{ steps.package_release.outputs.version }}\" {} \;
find dist -type f -maxdepth 1 \
-name "latest*.yml" \
-exec yq -i e .stagingPercentage=\"$percentage\" {} \;
- name: Upload sourcemap to Sentry
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
VERSION=${{ steps.package_release.outputs.version }} npm run uploadSourcemap
env:
SENTRY_AUTH_TOKEN: ${{ fromJSON(inputs.secrets).SENTRY_AUTH_TOKEN }}
npm_config_SENTRY_ORG: balenaEtcher
npm_config_SENTRY_PROJECT: balenaetcher
npm_config_SENTRY_VERSION: ${{ steps.package_release.outputs.version }}
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}
path: dist
retention-days: 1

58
.github/actions/test/action.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
---
name: test release
# https://github.com/product-os/flowzone/tree/master/.github/actions
inputs:
json:
description: "JSON stringified object containing all the inputs from the calling workflow"
required: true
secrets:
description: "JSON stringified object containing all the secrets from the calling workflow"
required: true
# --- custom environment
NODE_VERSION:
type: string
default: "14.x"
VERBOSE:
type: string
default: "true"
runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: "composite"
steps:
# https://github.com/actions/setup-node#caching-global-packages-data
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ inputs.NODE_VERSION }}
cache: npm
- name: Test release
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
npm run flowzone-preinstall-${runner_os}
npm ci
npm run build
npm run test-${runner_os}
env:
# https://www.electronjs.org/docs/latest/api/environment-variables
ELECTRON_NO_ATTACH_CONSOLE: true
- name: Compress custom source
shell: pwsh
run: tar -acf ${{ runner.temp }}/custom.tgz .
- name: Upload custom artifact
uses: actions/upload-artifact@v3
with:
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
path: ${{ runner.temp }}/custom.tgz
retention-days: 1

29
.github/workflows/flowzone.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: Flowzone
on:
pull_request:
types: [opened, synchronize, closed]
branches: [main, master]
# allow external contributions to use secrets within trusted code
pull_request_target:
types: [opened, synchronize, closed]
branches: [main, master]
jobs:
flowzone:
name: Flowzone
uses: product-os/flowzone/.github/workflows/flowzone.yml@master
# prevent duplicate workflows and only allow one `pull_request` or `pull_request_target` for
# internal or external contributions respectively
if: |
(github.event.pull_request.head.repo.full_name == github.repository && github.event_name == 'pull_request') ||
(github.event.pull_request.head.repo.full_name != github.repository && github.event_name == 'pull_request_target')
secrets: inherit
with:
tests_run_on: '["ubuntu-20.04","macos-latest","windows-2019"]'
restrict_custom_actions: false
github_prerelease: true
repo_config: true
repo_description: "Flash OS images to SD cards & USB drives, safely and easily."
repo_homepage: https://etcher.io/
repo_enable_wiki: true

13
.github/workflows/winget.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: Publish to WinGet
on:
release:
types: [released]
jobs:
publish:
runs-on: windows-latest # action can only be run on windows
steps:
- uses: vedantmgoyal2009/winget-releaser@v1
with:
identifier: Balena.Etcher
installers-regex: 'balenaEtcher-Setup.*.exe$'
token: ${{ secrets.WINGET_PAT }}

6
.gitignore vendored
View File

@@ -51,3 +51,9 @@ node_modules
# VSCode files
.vscode
.gitsecret/keys/random_seed
!*.secret
secrets/APPLE_SIGNING_PASSWORD.txt
secrets/WINDOWS_SIGNING_PASSWORD.txt
secrets/XCODE_APP_LOADER_PASSWORD.txt
secrets/WINDOWS_SIGNING.pfx

BIN
.gitsecret/keys/pubring.kbx Normal file

Binary file not shown.

Binary file not shown.

BIN
.gitsecret/keys/trustdb.gpg Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
secrets/APPLE_SIGNING_PASSWORD.txt:5c9cfeb1ea5142b547bc842cc6e0b4a932641ae9811ee47abe2c3953f2a4de5d
secrets/WINDOWS_SIGNING_PASSWORD.txt:852e431628494f2559793c39cf09c34e9406dd79bb15b90c9f88194020470568
secrets/XCODE_APP_LOADER_PASSWORD.txt:005eb9a3c7035c77232973c9355468fc396b94e62783fb8e6dce16bce95b94a1
secrets/WINDOWS_SIGNING.pfx:929f401db38733ffc41572539de7c0d938023af51ed06c205a72a71c1f815714
secrets/APPLE_SIGNING.p12:61abf7b4ff2eec76ce889d71bcdd568b99a6a719b4947ac20f03966265b0946a

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
14

View File

@@ -1,75 +0,0 @@
{
"electron": {
"npm_version": "6.14.5",
"dependencies": {
"linux": [
"libudev-dev",
"libusb-1.0-0-dev",
"libyaml-dev",
"libgtk-3-0",
"libatk-bridge2.0-0",
"libdbus-1-3",
"libgbm1",
"libc6"
]
},
"builder": {
"appId": "io.balena.etcher",
"copyright": "Copyright 2016-2021 Balena Ltd",
"productName": "balenaEtcher",
"nodeGypRebuild": false,
"afterPack": "./afterPack.js",
"asar": false,
"files": [
"generated",
"lib/shared/catalina-sudo/sudo-askpass.osascript.js"
],
"beforeBuild": "./beforeBuild.js",
"afterSign": "./afterSignHook.js",
"mac": {
"category": "public.app-category.developer-tools",
"hardenedRuntime": true,
"entitlements": "entitlements.mac.plist",
"entitlementsInherit": "entitlements.mac.plist",
"artifactName": "${productName}-${version}.${ext}"
},
"dmg": {
"iconSize": 110,
"contents": [
{
"x": 140,
"y": 245
},
{
"x": 415,
"y": 245,
"type": "link",
"path": "/Applications"
}
],
"window": {
"width": 544,
"height": 407
}
},
"linux": {
"category": "Utility",
"packageCategory": "utils",
"synopsis": "balenaEtcher is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience. It protects you from accidentally writing to your hard-drives, ensures every byte of data was written correctly and much more."
},
"deb": {
"compression": "bzip2",
"priority": "optional",
"depends": [
"polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1"
]
},
"protocols": {
"name": "etcher",
"schemes": [
"etcher"
]
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,525 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
# v1.13.4
## (2023-01-12)
* Adding EtcherPro device serial number to the Settings modal [Aurelien VALADE]
# v1.13.3
## (2023-01-11)
* patch: progress cm4 to second stage [Peter Makra]
# v1.13.2
## (2023-01-02)
* patch: fixed winget parameter name [mcraa]
# v1.13.1
## (2023-01-02)
* patch: updated sdk to fix bz2 issue [Peter Makra]
* patch: update copyright in electron-builder [JOASSART Edwin]
# v1.13.0
## (2022-12-28)
* minor: electron version bump [Peter Makra]
* patch: handle ext2fs with webpack [Peter Makra]
* Patch: update etcher-sdk version to fix CM4 issues [builder555]
# v1.12.7
## (2022-12-20)
* Update dependency i18next to 21.10.0 [Renovate Bot]
# v1.12.6
## (2022-12-20)
* Update dependency react-i18next to 11.18.6 [Renovate Bot]
# v1.12.5
## (2022-12-20)
* Patch: made trim setting more readable [builder555]
# v1.12.4
## (2022-12-19)
* patch: publish to winget with gh action [Begula]
# v1.12.3
## (2022-12-19)
* Patch: replaced plain text with i18n in settings [builder555]
# v1.12.2
## (2022-12-16)
* Update dependency webpack-dev-server to 4.11.1 [Renovate Bot]
# v1.12.1
## (2022-12-16)
* Patch: expose trim ext{2,3,4} setting [builder555]
# v1.12.0
## (2022-12-14)
* i18n support and Chinese translation [ab77]
* minor: optimize i18n [r-q]
# v1.11.10
## (2022-12-13)
* Update dependency webpack-cli to 4.10.0 [Renovate Bot]
# v1.11.9
## (2022-12-12)
* Update dependency webpack to 5.75.0 [Renovate Bot]
# v1.11.8
## (2022-12-12)
* Update dependency awscli to 1.27.28 [Renovate Bot]
# v1.11.7
## (2022-12-12)
* Update dependency uuid to 8.3.2 [Renovate Bot]
# v1.11.6
## (2022-12-12)
* Update dependency tslib to 2.4.1 [Renovate Bot]
* Patch: run linux build on ubuntu-20.04 [Edwin Joassart]
# v1.11.5
## (2022-12-10)
* Update dependency ts-loader to 8.4.0 [Renovate Bot]
# v1.11.4
## (2022-12-10)
* Update dependency styled-components to 5.3.6 [Renovate Bot]
# v1.11.3
## (2022-12-10)
* Update dependency terser-webpack-plugin to 5.3.6 [Renovate Bot]
# v1.11.2
## (2022-12-10)
* Update dependency string-replace-loader to 3.1.0 [Renovate Bot]
# v1.11.1
## (2022-12-10)
* Update dependency sinon to 9.2.4 [Renovate Bot]
# v1.11.0
## (2022-12-10)
* Update dependency shyaml to 0.6.2 [Renovate Bot]
# v1.10.29
## (2022-12-10)
* Update dependency awscli to 1.27.27 [Renovate Bot]
# v1.10.28
## (2022-12-10)
<details>
<summary> Update dependency rendition to 19.3.2 [Renovate Bot] </summary>
> ## rendition-19.3.2
> ### (2020-12-29)
>
> * Add Breadcrumbs component export [JSReds]
>
> ## rendition-19.3.1
> ### (2020-12-29)
>
> * Fix max-width on breadcrumbs container [JSReds]
>
> ## rendition-19.3.0
> ### (2020-12-29)
>
> * Add Breadcrumbs component [JSReds]
>
</details>
# v1.10.27
## (2022-12-09)
* Update dependency redux to 4.2.0 [Renovate Bot]
# v1.10.26
## (2022-12-09)
* Update dependency pretty-bytes to 5.6.0 [Renovate Bot]
# v1.10.25
## (2022-12-09)
* Update dependency pnp-webpack-plugin to 1.7.0 [Renovate Bot]
# v1.10.24
## (2022-12-09)
* Update dependency node-ipc to 9.2.1 [Renovate Bot]
# v1.10.23
## (2022-12-09)
* Update dependency mocha to 8.4.0 [Renovate Bot]
# v1.10.22
## (2022-12-09)
* Update dependency mini-css-extract-plugin to 1.6.2 [Renovate Bot]
# v1.10.21
## (2022-12-09)
* Update dependency lint-staged to 10.5.4 [Renovate Bot]
# v1.10.20
## (2022-12-09)
* Update dependency husky to 4.3.8 [Renovate Bot]
# v1.10.19
## (2022-12-09)
* Update dependency esbuild-loader to 2.20.0 [Renovate Bot]
# v1.10.18
## (2022-12-09)
* Update dependency electron-updater to 4.6.5 [Renovate Bot]
# v1.10.17
## (2022-12-09)
* Update dependency electron-notarize to 1.2.2 [Renovate Bot]
# v1.10.16
## (2022-12-08)
* Update dependency awscli to 1.27.26 [Renovate Bot]
# v1.10.15
## (2022-12-08)
* Update dependency electron-builder to 22.14.13 [Renovate Bot]
# v1.10.14
## (2022-12-08)
* Update dependency debug to 4.3.4 [Renovate Bot]
# v1.10.13
## (2022-12-08)
* Update dependency awscli to 1.27.25 [Renovate Bot]
# v1.10.12
## (2022-12-08)
* Update dependency css-loader to 5.2.7 [Renovate Bot]
# v1.10.11
## (2022-12-07)
* Update dependency awscli to 1.27.24 [Renovate Bot]
# v1.10.10
## (2022-12-07)
* Update dependency @types/node to 14.18.34 [Renovate Bot]
# v1.10.9
## (2022-12-06)
* Enable repository configuration [ab77]
# v1.10.8
## (2022-12-05)
* Update dependency chai to 4.3.7 [Renovate Bot]
# v1.10.7
## (2022-12-05)
* Use core workflow for GitHub publish [ab77]
# v1.10.6
## (2022-12-02)
* Dummy update to fix asset version issue [Edwin Joassart]
# v1.10.5
## (2022-12-02)
* Patch: run linux build on ubuntu-18.04 [Edwin Joassart]
# v1.10.4
## (2022-12-01)
* patch: remove Homebrew instructions in README [Patrick Linnane]
# v1.10.3
## (2022-12-01)
* Allow external contributors [ab77]
# v1.10.2
## (2022-11-25)
* Fix missing analytics token [Edwin Joassart]
# v1.10.1
## (2022-11-21)
* Fixing call to electron block screensaver methods invocation [Aurelien VALADE]
# v1.10.0
## (2022-11-10)
* testing renovate [builder555]
# v1.9.0
## (2022-11-08)
* Update dependency awscli to 1.27.5 [Renovate Bot]
# v1.8.17
## (2022-11-08)
* Update dependency @types/react-dom to 16.9.17 [Renovate Bot]
# v1.8.16
## (2022-11-08)
* Update dependency @types/react to 16.14.34 [Renovate Bot]
# v1.8.15
## (2022-11-08)
* CI: generalise artefact handling [ab77]
# v1.8.14
## (2022-11-08)
* Update dependency @types/node to 14.18.33 [Renovate Bot]
# v1.8.13
## (2022-11-08)
* Update dependency @types/copy-webpack-plugin to 6.4.3 [Renovate Bot]
# v1.8.12
## (2022-11-08)
* Update dependency @fortawesome/fontawesome-free to 5.15.4 [Renovate Bot]
# v1.8.11
## (2022-11-08)
* Update dependency @balena/lint to 5.4.2 [Renovate Bot]
# v1.8.10
## (2022-11-08)
<details>
<summary> Update dependency sys-class-rgb-led to 3.0.1 [Renovate Bot] </summary>
> ## sys-class-rgb-led-3.0.1
> ### (2021-07-01)
>
> * patch: Delete Codeowners [Vipul Gupta]
>
</details>
# v1.8.9
## (2022-11-08)
* Update dependency semver to 7.3.8 [Renovate Bot]
# v1.8.8
## (2022-11-08)
* Update dependency omit-deep-lodash to 1.1.7 [Renovate Bot]
# v1.8.7
## (2022-11-08)
* Update dependency immutable to 3.8.2 [Renovate Bot]
# v1.8.6
## (2022-11-08)
* Update dependency electron-rebuild to 3.2.9 [Renovate Bot]
# v1.8.5
## (2022-11-08)
* Update dependency electron-mocha to 9.3.3 [Renovate Bot]
# v1.8.4
## (2022-11-08)
* Update dependency @types/webpack-node-externals to 2.5.3 [Renovate Bot]
# v1.8.3
## (2022-11-08)
* Update dependency @types/tmp to 0.2.3 [Renovate Bot]
# v1.8.2
## (2022-11-08)
* Generate release notes with git [ab77]
# v1.8.1
## (2022-11-07)
* Update dependency @types/mime-types to 2.1.1 [Renovate Bot]
# v1.8.0
## (2022-11-07)
* Update scripts/resin digest to 652fdd4 [Renovate Bot]
# v1.7.15
## (2022-11-07)
* Build targets individually [ab77]
# v1.7.14
## (2022-11-07)
* Update dependency lodash to 4.17.21 [SECURITY] [Renovate Bot]
# v1.7.13
## (2022-11-07)
* Update release notes on finalize [ab77]
# v1.7.12
## (2022-11-07)
* Avoid duplicate releases [ab77]
# v1.7.11
## (2022-11-07)
* Only run finalize on Linux runners [ab77]
# v1.7.10
## (2022-11-07)
* Switch to Flowzone [ab77]
# v1.7.9
## (2022-04-22)
* patch: update allowed extensions to include deb afterinstall in build [mcraa]
* patch: add update notification [Peter Makra]
* patch: fix usb-device-boot link in README [Andrew Scheller]
* Fix application directory for Debian postinst script [Ken Bannister]
# v1.7.8
## (2022-03-18)
* patch: complete suse uninstall readme [Peter Makra]
* patch: completed suse instructions [Peter Makra]
* patch: order rpm instrictions [Peter Makra]
* patch: enabled update notification for version 1.7.8 [Peter Makra]
* patch: updated title to balenaEtcher [Peter Makra]
* patch: cleanup and organize readme [Peter Makra]
* patch: extend cloudsmith attribution in readme [Peter Makra]
* Update macOS Icon to Big Sur Style [Logicer]
# v1.7.7
## (2022-02-22)
* patch: clarified update check [Peter Makra]
* patch: autoupdate stagingPercentage check, include default [Peter Makra]
# v1.7.6
## (2022-02-21)
* patch: version number notification [Peter Makra]
* patch: fixed typos in template [Peter Makra]
* patch: add requirements and help to issue template [mcraa]
* patch: add requirements and help to issue template [mcraa]
# v1.7.5
## (2022-02-21)
* patch: fix flashing from URL when using basic auth [Marco Füllemann]
# v1.7.4
## (2022-02-21)
* patch: set version update notification 1.7.3 [Peter Makra]
* patch: updated electron to 12.2.3 [Peter Makra]
* patch: updated electron to 12.2.3 [Peter Makra]
# v1.7.3
## (2021-12-29)
* patch: fix mesage of null [Peter Makra]
# v1.7.2
## (2021-12-21)
* patch: fixed open from browser on windows [Peter Makra]
# v1.7.1
## (2021-11-22)
* patch: Revert back to electron-rebuild [Lorenzo Alberto Maria Ambrosi]
* patch: Disallow TS in JS [Lorenzo Alberto Maria Ambrosi]
* patch: Remove esInterop TS flag [Lorenzo Alberto Maria Ambrosi]
* patch: Use @balena/sudo-prompt [Lorenzo Alberto Maria Ambrosi]
* patch: Update rpiboot guide link [Lorenzo Alberto Maria Ambrosi]
* patch: Improve webpack build time [Lorenzo Alberto Maria Ambrosi]
# v1.7.0
## (2021-11-09)
* patch: Add missing @types/react@16.8.5 [Lorenzo Alberto Maria Ambrosi]
* patch: Use npm ci in Makefile [Lorenzo Alberto Maria Ambrosi]
* patch: Add draft info boxes for system information [Lorenzo Alberto Maria Ambrosi]
* patch: Remove electron-rebuild package [Lorenzo Alberto Maria Ambrosi]
* patch: Make electron a dev. dependency [Lorenzo Alberto Maria Ambrosi]
* patch: Remove electron-rebuild package [Lorenzo Alberto Maria Ambrosi]
* patch: Use exact modules versions [Lorenzo Alberto Maria Ambrosi]
* patch: Update etcher-sdk from v6.2.5 to v6.3.0 [Lorenzo Alberto Maria Ambrosi]
* Fix write step for Http file process [JSReds]
* patch: Fix linting errors [Lorenzo Alberto Maria Ambrosi]
* minor: Refactor dependencies installation to avoid custom scripts [Lorenzo Alberto Maria Ambrosi]
* patch: Fix LEDs init error [Lorenzo Alberto Maria Ambrosi]
# v1.6.0
## (2021-09-20)
* Add support for basic auth when downloading images from URL. [Marco Füllemann]
* patch: Update etcher-sdk from v6.2.1 to v6.2.5 [Lorenzo Alberto Maria Ambrosi]
* Update Makefile to Apple M1 info [David Gaspar]
* Add LED settings for potentially different hardware [Lorenzo Alberto Maria Ambrosi]
# v1.5.122
## (2021-09-02)

View File

@@ -66,6 +66,9 @@ else
ifeq ($(shell uname -m),x86_64)
HOST_ARCH = x64
endif
ifeq ($(shell uname -m),arm64)
HOST_ARCH = aarch64
endif
endif
endif
@@ -87,11 +90,8 @@ TARGET_ARCH ?= $(HOST_ARCH)
# ---------------------------------------------------------------------
electron-develop:
git submodule update --init && \
$(RESIN_SCRIPTS)/electron/install.sh \
-b $(shell pwd) \
-r $(TARGET_ARCH) \
-s $(PLATFORM) \
-m $(NPM_VERSION)
npm ci && \
npm run webpack
electron-test:
$(RESIN_SCRIPTS)/electron/test.sh \

View File

@@ -5,11 +5,10 @@
Etcher is a powerful OS image flasher built with web technologies to ensure
flashing an SDCard or USB drive is a pleasant and safe experience. It protects
you from accidentally writing to your hard-drives, ensures every byte of data
was written correctly, and much more. It can also directly flash Raspberry Pi devices that support [USB device boot mode](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/device.md).
was written correctly, and much more. It can also directly flash Raspberry Pi devices that support [USB device boot mode](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#usb-device-boot-mode).
[![Current Release](https://img.shields.io/github/release/balena-io/etcher.svg?style=flat-square)](https://balena.io/etcher)
[![License](https://img.shields.io/github/license/balena-io/etcher.svg?style=flat-square)](https://github.com/balena-io/etcher/blob/master/LICENSE)
[![Dependency status](https://img.shields.io/david/balena-io/etcher.svg?style=flat-square)](https://david-dm.org/balena-io/etcher)
[![Balena.io Forums](https://img.shields.io/discourse/https/forums.balena.io/topics.svg?style=flat-square&label=balena.io%20forums)](https://forums.balena.io/c/etcher)
---
@@ -31,10 +30,18 @@ was written correctly, and much more. It can also directly flash Raspberry Pi de
Refer to the [downloads page][etcher] for the latest pre-made
installers for all supported operating systems.
> Note: Our deb and rpm packages are now hosted on [Cloudsmith](https://cloudsmith.com)!
## Packages
> [![Hosted By: Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=for-the-badge)](https://cloudsmith.com) \
Package repository hosting is graciously provided by [Cloudsmith](https://cloudsmith.com).
Cloudsmith is the only fully hosted, cloud-native, universal package management solution, that
enables your organization to create, store and share packages in any format, to any place, with total
confidence.
#### Debian and Ubuntu based Package Repository (GNU/Linux x86/x64)
> Detailed or alternative steps in the [instructions by Cloudsmith](https://cloudsmith.io/~balena/repos/etcher/setup/#formats-deb)
1. Add Etcher Debian repository:
```sh
@@ -60,23 +67,11 @@ rm -rf /var/lib/apt/lists/*
apt-get update
```
##### OpenSUSE LEAP & Tumbleweed install
```sh
curl -1sLf \
'https://dl.cloudsmith.io/public/balena/etcher/setup.rpm.sh' \
| sudo -E bash
```
##### Uninstall
```sh
zypper rr balena-etcher
zypper rr balena-etcher-source
```
#### Redhat (RHEL) and Fedora-based Package Repository (GNU/Linux x86/x64)
> Detailed or alternative steps in the [instructions by Cloudsmith](https://cloudsmith.io/~balena/repos/etcher/setup/#formats-rpm)
##### DNF
1. Add Etcher rpm repository:
@@ -124,6 +119,31 @@ rm /etc/yum.repos.d/balena-etcher.repo
rm /etc/yum.repos.d/balena-etcher-source.repo
```
#### OpenSUSE LEAP & Tumbleweed install (zypper)
1. Add the repo
```sh
curl -1sLf \
'https://dl.cloudsmith.io/public/balena/etcher/setup.rpm.sh' \
| sudo -E bash
```
2. Update and install
```sh
sudo zypper up
sudo zypper install balena-etcher-electron
```
##### Uninstall
```sh
sudo zypper rm balena-etcher-electron
# remove the repo
sudo zypper rr balena-etcher
sudo zypper rr balena-etcher-source
```
#### Solus (GNU/Linux x64)
```sh
@@ -150,22 +170,6 @@ yay -S balena-etcher
yay -R balena-etcher
```
#### Brew (macOS)
**Note**: Etcher has to be updated manually to point to new versions,
so it might not refer to the latest version immediately after an Etcher
release.
```sh
brew install balenaetcher
```
##### Uninstall
```sh
brew uninstall balenaetcher
```
#### Chocolatey (Windows)
This package is maintained by [@majkinetor](https://github.com/majkinetor), and
@@ -200,3 +204,5 @@ the [license].
[milestones]: https://github.com/balena-io/etcher/milestones
[newissue]: https://github.com/balena-io/etcher/issues/new
[license]: https://github.com/balena-io/etcher/blob/master/LICENSE

11
after-install.tpl Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
# Link to the binary
# Must hardcode balenaEtcher directory; no variable available
ln -sf '/opt/balenaEtcher/${executable}' '/usr/bin/${executable}'
# SUID chrome-sandbox for Electron 5+
chmod 4755 '/opt/balenaEtcher/chrome-sandbox' || true
update-mime-database /usr/share/mime || true
update-desktop-database /usr/share/applications || true

View File

@@ -10,13 +10,15 @@ async function main(context) {
}
const appName = context.packager.appInfo.productFilename
const appleId = 'accounts+apple@balena.io'
const appleId = process.env.XCODE_APP_LOADER_EMAIL || 'accounts+apple@balena.io'
const appleIdPassword = process.env.XCODE_APP_LOADER_PASSWORD
// https://github.com/electron/notarize/blob/main/README.md
await notarize({
appBundleId: 'io.balena.etcher',
appPath: `${appOutDir}/${appName}.app`,
appleId,
appleIdPassword: `@keychain:Application Loader: ${appleId}`
appleIdPassword
})
}

Binary file not shown.

View File

@@ -1,33 +0,0 @@
'use strict'
const cp = require('child_process');
const rimraf = require('rimraf');
const process = require('process');
// Rebuild native modules for ia32 and run webpack again for the ia32 part of windows packages
exports.default = function(context) {
if (['windows', 'mac'].includes(context.platform.name)) {
const run = context.platform.name === 'windows' ? 'sh' : 'node';
cp.execFileSync(
run,
['node_modules/.bin/electron-rebuild', '--types', 'dev', '--arch', context.arch],
{
env: {
...process.env,
npm_config_msvs_version: '2019',
},
},
);
rimraf.sync('generated');
cp.execFileSync(
run,
['node_modules/.bin/webpack'],
{
env: {
...process.env,
npm_config_target_arch: context.arch,
},
},
);
}
}

View File

@@ -1,15 +1,14 @@
# https://www.electron.build/configuration/configuration
appId: io.balena.etcher
copyright: Copyright 2016-2021 Balena Ltd
copyright: Copyright 2016-2023 Balena Ltd
productName: balenaEtcher
npmRebuild: true
nodeGypRebuild: false
publish: null
beforeBuild: "./beforeBuild.js"
afterPack: "./afterPack.js"
afterPack: ./afterPack.js
afterSign: ./afterSignHook.js
asar: false
files:
- generated
- lib/shared/catalina-sudo/sudo-askpass.osascript.js
- lib/shared/catalina-sudo/sudo-askpass.osascript-zh.js
- lib/shared/catalina-sudo/sudo-askpass.osascript-en.js
mac:
icon: assets/icon.icns
category: public.app-category.developer-tools
@@ -17,6 +16,8 @@ mac:
entitlements: "entitlements.mac.plist"
entitlementsInherit: "entitlements.mac.plist"
artifactName: "${productName}-${version}.${ext}"
target:
- dmg
dmg:
background: assets/dmg/background.tiff
icon: assets/icon.icns
@@ -33,6 +34,10 @@ dmg:
height: 405
win:
icon: assets/icon.ico
target:
- zip
- nsis
- portable
nsis:
oneClick: true
runAfterFinish: true
@@ -45,16 +50,23 @@ portable:
artifactName: "${productName}-Portable-${version}.${ext}"
requestExecutionLevel: user
linux:
icon: assets/iconset
target:
- AppImage
- rpm
- deb
category: Utility
packageCategory: utils
executableName: balena-etcher-electron
executableName: balena-etcher
synopsis: balenaEtcher is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience. It protects you from accidentally writing to your hard-drives, ensures every byte of data was written correctly and much more.
icon: assets/iconset
appImage:
artifactName: ${productName}-${version}-${env.ELECTRON_BUILDER_ARCHITECTURE}.${ext}
deb:
priority: optional
compression: bzip2
depends:
- gconf2
- gconf-service
- gconf2
- libasound2
- libatk1.0-0
- libc6
@@ -88,6 +100,7 @@ deb:
- libxss1
- libxtst6
- polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1
afterInstall: "./after-install.tpl"
rpm:
depends:
- util-linux

View File

@@ -28,7 +28,6 @@ import * as EXIT_CODES from '../../shared/exit-codes';
import * as messages from '../../shared/messages';
import * as availableDrives from './models/available-drives';
import * as flashState from './models/flash-state';
import { init as ledsInit } from './models/leds';
import { deselectImage, getImage } from './models/selection-state';
import * as settings from './models/settings';
import { Actions, observe, store } from './models/store';
@@ -39,6 +38,7 @@ import * as osDialog from './os/dialog';
import * as windowProgress from './os/window-progress';
import MainPage from './pages/main/MainPage';
import './css/main.css';
import * as i18next from 'i18next';
window.addEventListener(
'unhandledrejection',
@@ -217,8 +217,7 @@ function prepareDrive(drive: Drive) {
disabled: true,
icon: 'warning',
size: null,
link:
'https://www.raspberrypi.org/documentation/hardware/computemodule/cm-emmc-flashing.md',
link: 'https://www.raspberrypi.com/documentation/computers/compute-module.html#flashing-the-compute-module-emmc',
linkCTA: 'Install',
linkTitle: 'Install missing drivers',
linkMessage: outdent`
@@ -315,9 +314,9 @@ window.addEventListener('beforeunload', async (event) => {
try {
const confirmed = await osDialog.showWarning({
confirmationLabel: 'Yes, quit',
rejectionLabel: 'Cancel',
title: 'Are you sure you want to close Etcher?',
confirmationLabel: i18next.t('yesExit'),
rejectionLabel: i18next.t('cancel'),
title: i18next.t('reallyExit'),
description: messages.warning.exitWhileFlashing(),
});
if (confirmed) {
@@ -335,13 +334,19 @@ window.addEventListener('beforeunload', async (event) => {
flashingWorkflowUuid,
});
popupExists = false;
} catch (error) {
} catch (error: any) {
exceptionReporter.report(error);
}
});
export async function main() {
await ledsInit();
try {
const { init: ledsInit } = require('./models/leds');
await ledsInit();
} catch (error: any) {
exceptionReporter.report(error);
}
ReactDOM.render(
React.createElement(MainPage),
document.getElementById('main'),

View File

@@ -44,6 +44,7 @@ import {
import { SourceMetadata } from '../source-selector/source-selector';
import { middleEllipsis } from '../../utils/middle-ellipsis';
import * as i18next from 'i18next';
interface UsbbootDrive extends sourceDestination.UsbbootDrive {
progress: number;
@@ -189,7 +190,7 @@ export class DriveSelector extends React.Component<
this.tableColumns = [
{
field: 'description',
label: 'Name',
label: i18next.t('drives.name'),
render: (description: string, drive: Drive) => {
if (isDrivelistDrive(drive)) {
const isLargeDrive = isDriveSizeLarge(drive);
@@ -215,7 +216,7 @@ export class DriveSelector extends React.Component<
{
field: 'description',
key: 'size',
label: 'Size',
label: i18next.t('drives.size'),
render: (_description: string, drive: Drive) => {
if (isDrivelistDrive(drive) && drive.size !== null) {
return prettyBytes(drive.size);
@@ -225,7 +226,7 @@ export class DriveSelector extends React.Component<
{
field: 'description',
key: 'link',
label: 'Location',
label: i18next.t('drives.location'),
render: (_description: string, drive: Drive) => {
return (
<Txt>
@@ -379,8 +380,8 @@ export class DriveSelector extends React.Component<
const displayedDrives = this.getDisplayedDrives(drives);
const disabledDrives = this.getDisabledDrives(drives, image);
const numberOfSystemDrives = drives.filter(isSystemDrive).length;
const numberOfDisplayedSystemDrives = displayedDrives.filter(isSystemDrive)
.length;
const numberOfDisplayedSystemDrives =
displayedDrives.filter(isSystemDrive).length;
const numberOfHiddenSystemDrives =
numberOfSystemDrives - numberOfDisplayedSystemDrives;
const hasSystemDrives = selectedList.filter(isSystemDrive).length;
@@ -399,14 +400,14 @@ export class DriveSelector extends React.Component<
color="#5b82a7"
style={{ fontWeight: 600 }}
>
{drives.length} found
{i18next.t('drives.find', { length: drives.length })}
</Txt>
</Flex>
}
titleDetails={<Txt fontSize={11}>{getDrives().length} found</Txt>}
cancel={() => cancel(this.originalList)}
done={() => done(selectedList)}
action={`Select (${selectedList.length})`}
action={i18next.t('drives.select', { select: selectedList.length })}
primaryButtonProps={{
primary: !showWarnings,
warning: showWarnings,
@@ -512,7 +513,11 @@ export class DriveSelector extends React.Component<
>
<Flex alignItems="center">
<ChevronDownSvg height="1em" fill="currentColor" />
<Txt ml={8}>Show {numberOfHiddenSystemDrives} hidden</Txt>
<Txt ml={8}>
{i18next.t('drives.showHidden', {
num: numberOfHiddenSystemDrives,
})}
</Txt>
</Flex>
</Link>
)}
@@ -520,7 +525,7 @@ export class DriveSelector extends React.Component<
)}
{this.props.showWarnings && hasSystemDrives ? (
<Alert className="system-drive-alert" style={{ width: '67%' }}>
Selecting your system drive is dangerous and will erase your drive!
{i18next.t('drives.systemDriveDanger')}
</Alert>
) : null}
@@ -534,19 +539,21 @@ export class DriveSelector extends React.Component<
if (missingDriversModal.drive !== undefined) {
openExternal(missingDriversModal.drive.link);
}
} catch (error) {
} catch (error: any) {
logException(error);
} finally {
this.setState({ missingDriversModal: {} });
}
}}
action="Yes, continue"
action={i18next.t('yesContinue')}
cancelButtonProps={{
children: 'Cancel',
children: i18next.t('cancel'),
}}
children={
missingDriversModal.drive.linkMessage ||
`Etcher will open ${missingDriversModal.drive.link} in your browser`
i18next.t('drives.openInBrowser', {
link: missingDriversModal.drive.link,
})
}
/>
)}

View File

@@ -7,6 +7,7 @@ import { middleEllipsis } from '../../utils/middle-ellipsis';
import * as prettyBytes from 'pretty-bytes';
import { DriveWithWarnings } from '../../pages/main/Flash';
import * as i18next from 'i18next';
const DriveStatusWarningModal = ({
done,
@@ -17,12 +18,12 @@ const DriveStatusWarningModal = ({
isSystem: boolean;
drivesWithWarnings: DriveWithWarnings[];
}) => {
let warningSubtitle = 'You are about to erase an unusually large drive';
let warningCta = 'Are you sure the selected drive is not a storage drive?';
let warningSubtitle = i18next.t('drives.largeDriveWarning');
let warningCta = i18next.t('drives.largeDriveWarningMsg');
if (isSystem) {
warningSubtitle = "You are about to erase your computer's drives";
warningCta = 'Are you sure you want to flash your system drive?';
warningSubtitle = i18next.t('drives.systemDriveWarning');
warningCta = i18next.t('drives.systemDriveWarningMsg');
}
return (
<Modal
@@ -33,9 +34,9 @@ const DriveStatusWarningModal = ({
cancelButtonProps={{
primary: false,
warning: true,
children: 'Change target',
children: i18next.t('drives.changeTarget'),
}}
action={"Yes, I'm sure"}
action={i18next.t('sure')}
primaryButtonProps={{
primary: false,
outline: true,
@@ -50,7 +51,7 @@ const DriveStatusWarningModal = ({
<Flex flexDirection="column">
<ExclamationTriangleSvg height="2em" fill="#fca321" />
<Txt fontSize="24px" color="#fca321">
WARNING!
{i18next.t('warning')}
</Txt>
</Flex>
<Txt fontSize="24px">{warningSubtitle}</Txt>

View File

@@ -59,13 +59,8 @@ function FinishPage({ goToMain }: { goToMain: () => void }) {
).map(([, error]: [string, FlashError]) => ({
...error,
}));
const {
averageSpeed,
blockmappedSize,
bytesWritten,
failed,
size,
} = flashState.getFlashState();
const { averageSpeed, blockmappedSize, bytesWritten, failed, size } =
flashState.getFlashState();
const {
skip,
results = {

View File

@@ -17,6 +17,7 @@
import * as React from 'react';
import { BaseButton } from '../../styled-components';
import * as i18next from 'i18next';
export interface FlashAnotherProps {
onClick: () => void;
@@ -25,7 +26,7 @@ export interface FlashAnotherProps {
export const FlashAnother = (props: FlashAnotherProps) => {
return (
<BaseButton primary onClick={props.onClick}>
Flash another
{i18next.t('flash.another')}
</BaseButton>
);
};

View File

@@ -31,6 +31,7 @@ import { resetState } from '../../models/flash-state';
import * as selection from '../../models/selection-state';
import { middleEllipsis } from '../../utils/middle-ellipsis';
import { Modal, Table } from '../../styled-components';
import * as i18next from 'i18next';
const ErrorsTable = styled((props) => <Table<FlashError> {...props} />)`
&&& [data-display='table-head'],
@@ -88,15 +89,15 @@ function formattedErrors(errors: FlashError[]) {
const columns: Array<TableColumn<FlashError>> = [
{
field: 'description',
label: 'Target',
label: i18next.t('flash.target'),
},
{
field: 'device',
label: 'Location',
label: i18next.t('flash.location'),
},
{
field: 'message',
label: 'Error',
label: i18next.t('flash.error'),
render: (message: string, { code }: FlashError) => {
return message ?? code;
},
@@ -162,9 +163,11 @@ export function FlashResults({
<Txt>{middleEllipsis(image, 24)}</Txt>
</Flex>
<Txt fontSize={24} color="#fff" mb="17px">
Flash {allFailed ? 'Failed' : 'Complete'}!
{allFailed
? i18next.t('flash.flashFailed')
: i18next.t('flash.flashCompleted')}
</Txt>
{skip ? <Txt color="#7e8085">Validation has been skipped</Txt> : null}
{skip ? <Txt color="#7e8085">{i18next.t('flash.skip')}</Txt> : null}
</Flex>
<Flex flexDirection="column" color="#7e8085">
{results.devices.successful !== 0 ? (
@@ -188,7 +191,7 @@ export function FlashResults({
{progress.failed(errors.length)}
</Txt>
<Link ml="10px" onClick={() => setShowErrorsInfo(true)}>
more info
{i18next.t('flash.moreInfo')}
</Link>
</Flex>
) : null}
@@ -199,12 +202,9 @@ export function FlashResults({
fontWeight: 500,
textAlign: 'center',
}}
tooltip={outdent({ newline: ' ' })`
The speed is calculated by dividing the image size by the flashing time.
Disk images with ext partitions flash faster as we are able to skip unused parts.
`}
tooltip={i18next.t('flash.speedTip')}
>
Effective speed: {effectiveSpeed} MB/s
{i18next.t('flash.speed', { speed: effectiveSpeed })}
</Txt>
)}
</Flex>
@@ -214,11 +214,11 @@ export function FlashResults({
titleElement={
<Flex alignItems="baseline" mb={18}>
<Txt fontSize={24} align="left">
Failed targets
{i18next.t('failedTarget')}
</Txt>
</Flex>
}
action="Retry failed targets"
action={i18next.t('failedRetry')}
cancel={() => setShowErrorsInfo(false)}
done={() => {
setShowErrorsInfo(false);

View File

@@ -20,6 +20,7 @@ import { default as styled } from 'styled-components';
import { fromFlashState } from '../../modules/progress-status';
import { StepButton } from '../../styled-components';
import * as i18next from 'i18next';
const FlashProgressBar = styled(ProgressBar)`
> div {
@@ -28,6 +29,7 @@ const FlashProgressBar = styled(ProgressBar)`
color: white !important;
text-shadow: none !important;
transition-duration: 0s;
> div {
transition-duration: 0s;
}
@@ -61,7 +63,7 @@ const colors = {
} as const;
const CancelButton = styled(({ type, onClick, ...props }) => {
const status = type === 'verifying' ? 'Skip' : 'Cancel';
const status = type === 'verifying' ? i18next.t('skip') : i18next.t('cancel');
return (
<Button plain onClick={() => onClick(status)} {...props}>
{status}
@@ -69,6 +71,7 @@ const CancelButton = styled(({ type, onClick, ...props }) => {
);
})`
font-weight: 600;
&&& {
width: auto;
height: auto;
@@ -126,7 +129,7 @@ export class ProgressButton extends React.PureComponent<ProgressButtonProps> {
marginTop: 30,
}}
>
Flash!
{i18next.t('flash.flashNow')}
</StepButton>
);
}

View File

@@ -17,13 +17,15 @@
import GithubSvg from '@fortawesome/fontawesome-free/svgs/brands/github.svg';
import * as _ from 'lodash';
import * as React from 'react';
import { Flex, Checkbox, Txt } from 'rendition';
import { Box, Checkbox, Flex, TextWithCopy, Txt } from 'rendition';
import { version, packageType } from '../../../../../package.json';
import * as settings from '../../models/settings';
import * as analytics from '../../modules/analytics';
import { open as openExternal } from '../../os/open-external/services/open-external';
import { Modal } from '../../styled-components';
import * as i18next from 'i18next';
import { etcherProInfo } from '../../utils/etcher-pro-specific';
interface Setting {
name: string;
@@ -34,13 +36,17 @@ async function getSettingsList(): Promise<Setting[]> {
const list: Setting[] = [
{
name: 'errorReporting',
label: 'Anonymously report errors and usage statistics to balena.io',
label: i18next.t('settings.errorReporting'),
},
{
name: 'autoBlockmapping',
label: i18next.t('settings.trimExtPartitions'),
},
];
if (['appimage', 'nsis', 'dmg'].includes(packageType)) {
list.push({
name: 'updatesEnabled',
label: 'Auto-updates enabled',
label: i18next.t('settings.autoUpdate'),
});
}
return list;
@@ -50,6 +56,15 @@ interface SettingsModalProps {
toggleModal: (value: boolean) => void;
}
const EPInfo = etcherProInfo();
const InfoBox = (props: any) => (
<Box fontSize={14}>
<Txt>{props.label}</Txt>
<TextWithCopy code text={props.value} copy={props.value} />
</Box>
);
export function SettingsModal({ toggleModal }: SettingsModalProps) {
const [settingsList, setCurrentSettingsList] = React.useState<Setting[]>([]);
React.useEffect(() => {
@@ -84,7 +99,7 @@ export function SettingsModal({ toggleModal }: SettingsModalProps) {
<Modal
titleElement={
<Txt fontSize={24} mb={24}>
Settings
{i18next.t('settings.settings')}
</Txt>
}
done={() => toggleModal(false)}
@@ -103,6 +118,16 @@ export function SettingsModal({ toggleModal }: SettingsModalProps) {
</Flex>
);
})}
{EPInfo !== undefined && (
<Flex flexDirection="column">
<Txt fontSize={24}>{i18next.t('settings.systemInformation')}</Txt>
{EPInfo.get_serial() === undefined ? (
<InfoBox label="UUID" value={EPInfo.uuid} />
) : (
<InfoBox label="Serial" value={EPInfo.get_serial()} />
)}
</Flex>
)}
<Flex
mt={18}
alignItems="center"

View File

@@ -18,6 +18,8 @@ import CopySvg from '@fortawesome/fontawesome-free/svgs/solid/copy.svg';
import FileSvg from '@fortawesome/fontawesome-free/svgs/solid/file.svg';
import LinkSvg from '@fortawesome/fontawesome-free/svgs/solid/link.svg';
import ExclamationTriangleSvg from '@fortawesome/fontawesome-free/svgs/solid/exclamation-triangle.svg';
import ChevronDownSvg from '@fortawesome/fontawesome-free/svgs/solid/chevron-down.svg';
import ChevronRightSvg from '@fortawesome/fontawesome-free/svgs/solid/chevron-right.svg';
import { sourceDestination } from 'etcher-sdk';
import { ipcRenderer, IpcRendererEvent } from 'electron';
import * as _ from 'lodash';
@@ -33,6 +35,7 @@ import {
Card as BaseCard,
Input,
Spinner,
Link,
} from 'rendition';
import styled from 'styled-components';
@@ -62,6 +65,8 @@ import SrcSvg from '../../../assets/src.svg';
import { DriveSelector } from '../drive-selector/drive-selector';
import { DrivelistDrive } from '../../../../shared/drive-constraints';
import axios, { AxiosRequestConfig } from 'axios';
import { isJson } from '../../../../shared/utils';
import * as i18next from 'i18next';
const recentUrlImagesKey = 'recentUrlImages';
@@ -73,7 +78,7 @@ function normalizeRecentUrlImages(urls: any[]): URL[] {
.map((url) => {
try {
return new URL(url);
} catch (error) {
} catch (error: any) {
// Invalid URL, skip
}
})
@@ -134,12 +139,15 @@ const URLSelector = ({
done,
cancel,
}: {
done: (imageURL: string) => void;
done: (imageURL: string, auth?: Authentication) => void;
cancel: () => void;
}) => {
const [imageURL, setImageURL] = React.useState('');
const [recentImages, setRecentImages] = React.useState<URL[]>([]);
const [loading, setLoading] = React.useState(false);
const [showBasicAuth, setShowBasicAuth] = React.useState(false);
const [username, setUsername] = React.useState('');
const [password, setPassword] = React.useState('');
React.useEffect(() => {
const fetchRecentUrlImages = async () => {
const recentUrlImages: URL[] = await getRecentUrlImages();
@@ -153,7 +161,7 @@ const URLSelector = ({
primaryButtonProps={{
disabled: loading || !imageURL,
}}
action={loading ? <Spinner /> : 'OK'}
action={loading ? <Spinner /> : i18next.t('ok')}
done={async () => {
setLoading(true);
const urlStrings = recentImages.map((url: URL) => url.href);
@@ -162,22 +170,66 @@ const URLSelector = ({
imageURL,
]);
setRecentUrlImages(normalizedRecentUrls);
await done(imageURL);
const auth = username ? { username, password } : undefined;
await done(imageURL, auth);
}}
>
<Flex flexDirection="column">
<Flex style={{ width: '100%' }} flexDirection="column">
<Flex mb={15} style={{ width: '100%' }} flexDirection="column">
<Txt mb="10px" fontSize="24px">
Use Image URL
{i18next.t('source.useSourceURL')}
</Txt>
<Input
value={imageURL}
placeholder="Enter a valid URL"
placeholder={i18next.t('source.enterValidURL')}
type="text"
onChange={(evt: React.ChangeEvent<HTMLInputElement>) =>
setImageURL(evt.target.value)
}
/>
<Link
mt={15}
mb={15}
fontSize="14px"
onClick={() => {
if (showBasicAuth) {
setUsername('');
setPassword('');
}
setShowBasicAuth(!showBasicAuth);
}}
>
<Flex alignItems="center">
{showBasicAuth && (
<ChevronDownSvg height="1em" fill="currentColor" />
)}
{!showBasicAuth && (
<ChevronRightSvg height="1em" fill="currentColor" />
)}
<Txt ml={8}>{i18next.t('source.auth')}</Txt>
</Flex>
</Link>
{showBasicAuth && (
<React.Fragment>
<Input
mb={15}
value={username}
placeholder={i18next.t('source.username')}
type="text"
onChange={(evt: React.ChangeEvent<HTMLInputElement>) =>
setUsername(evt.target.value)
}
/>
<Input
value={password}
placeholder={i18next.t('source.password')}
type="password"
onChange={(evt: React.ChangeEvent<HTMLInputElement>) =>
setPassword(evt.target.value)
}
/>
</React.Fragment>
)}
</Flex>
{recentImages.length > 0 && (
<Flex flexDirection="column" height="78.6%">
@@ -244,7 +296,7 @@ const FlowSelector = styled(
font-weight: 600;
svg {
color: ${colors.primary.foreground}!important;
color: ${colors.primary.foreground} !important;
}
}
`;
@@ -264,6 +316,7 @@ export interface SourceMetadata extends sourceDestination.Metadata {
drive?: DrivelistDrive;
extension?: string;
archiveExtension?: string;
auth?: Authentication;
}
interface SourceSelectorProps {
@@ -283,6 +336,11 @@ interface SourceSelectorState {
imageLoading: boolean;
}
interface Authentication {
username: string;
password: string;
}
export class SourceSelector extends React.Component<
SourceSelectorProps,
SourceSelectorState
@@ -323,19 +381,25 @@ export class SourceSelector extends React.Component<
this.setState({ imageLoading: true });
await this.selectSource(
imagePath,
isURL(imagePath) ? sourceDestination.Http : sourceDestination.File,
isURL(this.normalizeImagePath(imagePath))
? sourceDestination.Http
: sourceDestination.File,
).promise;
this.setState({ imageLoading: false });
}
private async createSource(selected: string, SourceType: Source) {
private async createSource(
selected: string,
SourceType: Source,
auth?: Authentication,
) {
try {
selected = await replaceWindowsNetworkDriveLetter(selected);
} catch (error) {
} catch (error: any) {
analytics.logException(error);
}
if (this.isJson(decodeURIComponent(selected))) {
if (isJson(decodeURIComponent(selected))) {
const config: AxiosRequestConfig = JSON.parse(
decodeURIComponent(selected),
);
@@ -351,16 +415,15 @@ export class SourceSelector extends React.Component<
});
}
return new sourceDestination.Http({ url: selected });
return new sourceDestination.Http({ url: selected, auth });
}
public isJson(jsonString: string) {
try {
JSON.parse(jsonString);
} catch (e) {
return false;
public normalizeImagePath(imgPath: string) {
const decodedPath = decodeURIComponent(imgPath);
if (isJson(decodedPath)) {
return JSON.parse(decodedPath).url ?? decodedPath;
}
return true;
return decodedPath;
}
private reselectSource() {
@@ -374,6 +437,7 @@ export class SourceSelector extends React.Component<
private selectSource(
selected: string | DrivelistDrive,
SourceType: Source,
auth?: Authentication,
): { promise: Promise<void>; cancel: () => void } {
let cancelled = false;
return {
@@ -385,9 +449,12 @@ export class SourceSelector extends React.Component<
let source;
let metadata: SourceMetadata | undefined;
if (isString(selected)) {
if (SourceType === sourceDestination.Http && !isURL(selected)) {
if (
SourceType === sourceDestination.Http &&
!isURL(this.normalizeImagePath(selected))
) {
this.handleError(
'Unsupported protocol',
i18next.t('source.unsupportedProtocol'),
selected,
messages.error.unsupportedProtocol(),
);
@@ -399,11 +466,11 @@ export class SourceSelector extends React.Component<
this.setState({
warning: {
message: messages.warning.looksLikeWindowsImage(),
title: 'Possible Windows image detected',
title: i18next.t('source.windowsImage'),
},
});
}
source = await this.createSource(selected, SourceType);
source = await this.createSource(selected, SourceType, auth);
if (cancelled) {
return;
@@ -425,13 +492,13 @@ export class SourceSelector extends React.Component<
this.setState({
warning: {
message: messages.warning.missingPartitionTable(),
title: 'Missing partition table',
title: i18next.t('source.partitionTable'),
},
});
}
} catch (error) {
} catch (error: any) {
this.handleError(
'Error opening source',
i18next.t('source.errorOpen'),
sourcePath,
messages.error.openSource(sourcePath, error.message),
error,
@@ -439,7 +506,7 @@ export class SourceSelector extends React.Component<
} finally {
try {
await source.close();
} catch (error) {
} catch (error: any) {
// Noop
}
}
@@ -449,7 +516,7 @@ export class SourceSelector extends React.Component<
this.setState({
warning: {
message: messages.warning.driveMissingPartitionTable(),
title: 'Missing partition table',
title: i18next.t('source.partitionTable'),
},
});
}
@@ -464,6 +531,7 @@ export class SourceSelector extends React.Component<
}
if (metadata !== undefined) {
metadata.auth = auth;
selectionState.selectSource(metadata);
analytics.logEvent('Select image', {
// An easy way so we can quickly identify if we're making use of
@@ -529,7 +597,7 @@ export class SourceSelector extends React.Component<
return;
}
await this.selectSource(imagePath, sourceDestination.File).promise;
} catch (error) {
} catch (error: any) {
exceptionReporter.report(error);
} finally {
this.setState({ imageSelectorOpen: false });
@@ -652,7 +720,7 @@ export class SourceSelector extends React.Component<
mb={14}
onClick={() => this.reselectSource()}
>
Remove
{i18next.t('cancel')}
</ChangeButton>
)}
{!_.isNil(imageSize) && !imageLoading && (
@@ -667,7 +735,7 @@ export class SourceSelector extends React.Component<
key="Flash from file"
flow={{
onClick: () => this.openImageSelector(),
label: 'Flash from file',
label: i18next.t('source.fromFile'),
icon: <FileSvg height="1em" fill="currentColor" />,
}}
onMouseEnter={() => this.setDefaultFlowActive(false)}
@@ -677,7 +745,7 @@ export class SourceSelector extends React.Component<
key="Flash from URL"
flow={{
onClick: () => this.openURLSelector(),
label: 'Flash from URL',
label: i18next.t('source.fromURL'),
icon: <LinkSvg height="1em" fill="currentColor" />,
}}
onMouseEnter={() => this.setDefaultFlowActive(false)}
@@ -687,7 +755,7 @@ export class SourceSelector extends React.Component<
key="Clone drive"
flow={{
onClick: () => this.openDriveSelector(),
label: 'Clone drive',
label: i18next.t('source.clone'),
icon: <CopySvg height="1em" fill="currentColor" />,
}}
onMouseEnter={() => this.setDefaultFlowActive(false)}
@@ -708,7 +776,7 @@ export class SourceSelector extends React.Component<
<span>{this.state.warning.title}</span>
</span>
}
action="Continue"
action={i18next.t('continue')}
cancel={() => {
this.setState({ warning: null });
this.reselectSource();
@@ -726,17 +794,17 @@ export class SourceSelector extends React.Component<
{showImageDetails && (
<SmallModal
title="Image"
title={i18next.t('source.image')}
done={() => {
this.setState({ showImageDetails: false });
}}
>
<Txt.p>
<Txt.span bold>Name: </Txt.span>
<Txt.span bold>{i18next.t('source.name')}</Txt.span>
<Txt.span>{imageName || imageBasename}</Txt.span>
</Txt.p>
<Txt.p>
<Txt.span bold>Path: </Txt.span>
<Txt.span bold>{i18next.t('source.path')}</Txt.span>
<Txt.span>{imagePath}</Txt.span>
</Txt.p>
</SmallModal>
@@ -750,7 +818,7 @@ export class SourceSelector extends React.Component<
showURLSelector: false,
});
}}
done={async (imageURL: string) => {
done={async (imageURL: string, auth?: Authentication) => {
// Avoid analytics and selection state changes
// if no file was resolved from the dialog.
if (!imageURL) {
@@ -760,6 +828,7 @@ export class SourceSelector extends React.Component<
({ promise, cancel: cancelURLSelection } = this.selectSource(
imageURL,
sourceDestination.Http,
auth,
));
await promise;
}
@@ -774,8 +843,8 @@ export class SourceSelector extends React.Component<
<DriveSelector
write={false}
multipleSelection={false}
titleLabel="Select source"
emptyListLabel="Plug a source drive"
titleLabel={i18next.t('source.selectSource')}
emptyListLabel={i18next.t('source.plugSource')}
emptyListIcon={<SrcSvg width="40px" />}
cancel={(originalList) => {
if (originalList.length) {

View File

@@ -32,6 +32,7 @@ import {
StepNameButton,
} from '../../styled-components';
import { middleEllipsis } from '../../utils/middle-ellipsis';
import * as i18next from 'i18next';
interface TargetSelectorProps {
targets: any[];
@@ -95,7 +96,7 @@ export function TargetSelectorButton(props: TargetSelectorProps) {
</StepNameButton>
{!props.flashing && (
<ChangeButton plain mb={14} onClick={props.reselectDrive}>
Change
{i18next.t('target.change')}
</ChangeButton>
)}
{target.size != null && (
@@ -132,11 +133,11 @@ export function TargetSelectorButton(props: TargetSelectorProps) {
return (
<>
<StepNameButton plain tooltip={props.tooltip}>
{targets.length} Targets
{targets.length} {i18next.t('target.targets')}
</StepNameButton>
{!props.flashing && (
<ChangeButton plain onClick={props.reselectDrive} mb={14}>
Change
{i18next.t('target.change')}
</ChangeButton>
)}
{targetsTemplate}
@@ -151,7 +152,7 @@ export function TargetSelectorButton(props: TargetSelectorProps) {
disabled={props.disabled}
onClick={props.openDriveSelector}
>
Select target
{i18next.t('target.selectTarget')}
</StepButton>
);
}

View File

@@ -14,7 +14,6 @@
* limitations under the License.
*/
import { scanner } from 'etcher-sdk';
import * as React from 'react';
import { Flex, Txt } from 'rendition';
@@ -37,6 +36,8 @@ import { TargetSelectorButton } from './target-selector-button';
import TgtSvg from '../../../assets/tgt.svg';
import DriveSvg from '../../../assets/drive.svg';
import { warning } from '../../../../shared/messages';
import { DrivelistDrive } from '../../../../shared/drive-constraints';
import * as i18next from 'i18next';
export const getDriveListLabel = () => {
return getSelectedDrives()
@@ -60,8 +61,8 @@ export const TargetSelectorModal = (
) => (
<DriveSelector
multipleSelection={true}
titleLabel="Select target"
emptyListLabel="Plug a target drive"
titleLabel={i18next.t('target.selectTarget')}
emptyListLabel={i18next.t('target.plugTarget')}
emptyListIcon={<TgtSvg width="40px" />}
showWarnings={true}
selectedList={getSelectedDrives()}
@@ -70,9 +71,7 @@ export const TargetSelectorModal = (
/>
);
export const selectAllTargets = (
modalTargets: scanner.adapters.DrivelistDrive[],
) => {
export const selectAllTargets = (modalTargets: DrivelistDrive[]) => {
const selectedDrivesFromState = getSelectedDrives();
const deselected = selectedDrivesFromState.filter(
(drive) =>
@@ -114,9 +113,8 @@ export const TargetSelector = ({
const [{ driveListLabel, targets }, setStateSlice] = React.useState(
getDriveSelectionStateSlice(),
);
const [showTargetSelectorModal, setShowTargetSelectorModal] = React.useState(
false,
);
const [showTargetSelectorModal, setShowTargetSelectorModal] =
React.useState(false);
React.useEffect(() => {
return observe(() => {

42
lib/gui/app/i18n.ts Normal file
View File

@@ -0,0 +1,42 @@
import * as i18next from 'i18next';
import { initReactI18next } from 'react-i18next';
import zh_CN_translation from './i18n/zh-CN';
import zh_TW_translation from './i18n/zh-TW';
import en_translation from './i18n/en';
export function langParser() {
if (process.env.LANG !== undefined) {
// Bypass mocha, where lang-detect don't works
return 'en';
}
const lang = Intl.DateTimeFormat().resolvedOptions().locale;
switch (lang.substr(0, 2)) {
case 'zh':
if (lang === 'zh-CN' || lang === 'zh-SG') {
return 'zh-CN';
} // Simplified Chinese
else {
return 'zh-TW';
} // Traditional Chinese
default:
return lang.substr(0, 2);
}
}
i18next.use(initReactI18next).init({
lng: langParser(),
fallbackLng: 'en',
nonExplicitSupportedLngs: true,
interpolation: {
escapeValue: false,
},
resources: {
'zh-CN': zh_CN_translation,
'zh-TW': zh_TW_translation,
en: en_translation,
},
});
export default i18next;

View File

@@ -0,0 +1,23 @@
# i18n
## How it was done
Using the open-source lib [i18next](https://www.i18next.com/).
## How to add your own language
1. Go to `lib/gui/app/i18n` and add a file named `xx.ts` (use the codes mentioned
in [the link](https://www.science.co.il/language/Locale-codes.php), and we support styles as `fr`, `de`, `es-ES`
and `pt-BR`)
.
2. Copy the content from an existing translation and start to translate.
3. Once done, go to `lib/gui/app/i18n.ts` and add a line of `import xx_translation from './i18n/xx'` after the
already-added imports and add `xx: xx_translation` in the `resources` section of `i18next.init()` function.
4. Now go to `lib/shared/catalina-sudo/` and copy the `sudo-askpass.osascript-en.js`, change it to
be `sudo-askpass.osascript-xx.js` and edit
the `'balenaEtcher needs privileged access in order to flash disks.\n\nType your password to allow this.'` line and
those `Ok`s and `Cancel`s to your own language.
5. If, your language has several variations when they are used in several countries/regions, such as `zh-CN` and `zh-TW`
, or `pt-BR` and `pt-PT`, edit
the `langParser()` in the `lib/gui/app/i18n.ts` file to meet your need.
6. Make a commit, and then a pull request on GitHub.

161
lib/gui/app/i18n/en.ts Normal file
View File

@@ -0,0 +1,161 @@
const translation = {
translation: {
continue: 'Continue',
ok: 'OK',
cancel: 'Cancel',
skip: 'Skip',
sure: "Yes, I'm sure",
warning: 'WARNING! ',
attention: 'Attention',
failed: 'Failed',
completed: 'Completed',
yesContinue: 'Yes, continue',
reallyExit: 'Are you sure you want to close Etcher?',
yesExit: 'Yes, quit',
progress: {
starting: 'Starting...',
decompressing: 'Decompressing...',
flashing: 'Flashing...',
finishing: 'Finishing...',
verifying: 'Validating...',
failing: 'Failed',
},
message: {
sizeNotRecommended: 'Not recommended',
tooSmall: 'Too small',
locked: 'Locked',
system: 'System drive',
containsImage: 'Source drive',
largeDrive: 'Large drive',
sourceLarger: 'The selected source is {{byte}} larger than this drive.',
flashSucceed_one: 'Successful target',
flashSucceed_other: 'Successful targets',
flashFail_one: 'Failed target',
flashFail_other: 'Failed targets',
toDrive: 'to {{description}} ({{name}})',
toTarget_one: 'to {{num}} target',
toTarget_other: 'to {{num}} targets',
andFailTarget_one: 'and failed to be flashed to {{num}} target',
andFailTarget_other: 'and failed to be flashed to {{num}} targets',
succeedTo: '{{name}} was successfully flashed {{target}}',
exitWhileFlashing:
'You are currently flashing a drive. Closing Etcher may leave your drive in an unusable state.',
looksLikeWindowsImage:
'It looks like you are trying to burn a Windows image.\n\nUnlike other images, Windows images require special processing to be made bootable. We suggest you use a tool specially designed for this purpose, such as <a href="https://rufus.akeo.ie">Rufus</a> (Windows), <a href="https://github.com/slacka/WoeUSB">WoeUSB</a> (Linux), or Boot Camp Assistant (macOS).',
image: 'image',
drive: 'drive',
missingPartitionTable:
'It looks like this is not a bootable {{type}}.\n\nThe {{type}} does not appear to contain a partition table, and might not be recognized or bootable by your device.',
largeDriveSize:
"This is a large drive! Make sure it doesn't contain files that you want to keep.",
systemDrive:
'Selecting your system drive is dangerous and will erase your drive!',
sourceDrive: 'Contains the image you chose to flash',
noSpace:
'Not enough space on the drive. Please insert larger one and try again.',
genericFlashError:
'Something went wrong. If it is a compressed image, please check that the archive is not corrupted.\n{{error}}',
validation:
'The write has been completed successfully but Etcher detected potential corruption issues when reading the image back from the drive. \n\nPlease consider writing the image to a different drive.',
openError:
'Something went wrong while opening {{source}}.\n\nError: {{error}}',
flashError: 'Something went wrong while writing {{image}} {{targets}}.',
unplug:
"Looks like Etcher lost access to the drive. Did it get unplugged accidentally?\n\nSometimes this error is caused by faulty readers that don't provide stable access to the drive.",
cannotWrite:
'Looks like Etcher is not able to write to this location of the drive. This error is usually caused by a faulty drive, reader, or port. \n\nPlease try again with another drive, reader, or port.',
childWriterDied:
'The writer process ended unexpectedly. Please try again, and contact the Etcher team if the problem persists.',
badProtocol: 'Only http:// and https:// URLs are supported.',
},
target: {
selectTarget: 'Select target',
plugTarget: 'Plug a target drive',
targets: 'Targets',
change: 'Change',
},
source: {
useSourceURL: 'Use Image URL',
auth: 'Authentication',
username: 'Enter username',
password: 'Enter password',
unsupportedProtocol: 'Unsupported protocol',
windowsImage: 'Possible Windows image detected',
partitionTable: 'Missing partition table',
errorOpen: 'Error opening source',
fromFile: 'Flash from file',
fromURL: 'Flash from URL',
clone: 'Clone drive',
image: 'Image',
name: 'Name: ',
path: 'Path: ',
selectSource: 'Select source',
plugSource: 'Plug a source drive',
osImages: 'OS Images',
allFiles: 'All',
enterValidURL: 'Enter a valid URL',
},
drives: {
name: 'Name',
size: 'Size',
location: 'Location',
find: '{{length}} found',
select: 'Select {{select}}',
showHidden: 'Show {{num}} hidden',
systemDriveDanger:
'Selecting your system drive is dangerous and will erase your drive!',
openInBrowser: '`Etcher will open {{link}} in your browser`',
changeTarget: 'Change target',
largeDriveWarning: 'You are about to erase an unusually large drive',
largeDriveWarningMsg:
'Are you sure the selected drive is not a storage drive?',
systemDriveWarning: "You are about to erase your computer's drives",
systemDriveWarningMsg:
'Are you sure you want to flash your system drive?',
},
flash: {
another: 'Flash another',
target: 'Target',
location: 'Location',
error: 'Error',
flash: 'Flash',
flashNow: 'Flash!',
skip: 'Validation has been skipped',
moreInfo: 'more info',
speedTip:
'The speed is calculated by dividing the image size by the flashing time.\nDisk images with ext partitions flash faster as we are able to skip unused parts.',
speed: 'Effective speed: {{speed}} MB/s',
speedShort: '{{speed}} MB/s',
eta: 'ETA: {{eta}}',
failedTarget: 'Failed targets',
failedRetry: 'Retry failed targets',
flashFailed: 'Flash Failed.',
flashCompleted: 'Flash Completed!',
},
settings: {
errorReporting:
'Anonymously report errors and usage statistics to balena.io',
autoUpdate: 'Auto-updates enabled',
settings: 'Settings',
systemInformation: 'System Information',
trimExtPartitions: 'Trim unallocated space on raw images (in ext-type partitions)',
},
menu: {
edit: 'Edit',
view: 'View',
devTool: 'Toggle Developer Tools',
window: 'Window',
help: 'Help',
pro: 'Etcher Pro',
website: 'Etcher Website',
issue: 'Report an issue',
about: 'About Etcher',
hide: 'Hide Etcher',
hideOthers: 'Hide Others',
unhide: 'Unhide All',
quit: 'Quit Etcher',
},
},
};
export default translation;

152
lib/gui/app/i18n/zh-CN.ts Normal file
View File

@@ -0,0 +1,152 @@
const translation = {
translation: {
ok: '好',
cancel: '取消',
continue: '继续',
skip: '跳过',
sure: '我确定',
warning: '请注意!',
attention: '请注意',
failed: '失败',
completed: '完毕',
yesExit: '是的,可以退出',
reallyExit: '真的要现在退出 Etcher 吗?',
yesContinue: '是的,继续',
progress: {
starting: '正在启动……',
decompressing: '正在解压……',
flashing: '正在烧录……',
finishing: '正在结束……',
verifying: '正在验证……',
failing: '失败……',
},
message: {
sizeNotRecommended: '大小不推荐',
tooSmall: '空间太小',
locked: '被锁定',
system: '系统盘',
containsImage: '存放源镜像',
largeDrive: '很大的磁盘',
sourceLarger: '所选的镜像比目标盘大了 {{byte}} 比特。',
flashSucceed_one: '烧录成功',
flashSucceed_other: '烧录成功',
flashFail_one: '烧录失败',
flashFail_other: '烧录失败',
toDrive: '到 {{description}} ({{name}})',
toTarget_one: '到 {{num}} 个目标',
toTarget_other: '到 {{num}} 个目标',
andFailTarget_one: '并烧录失败了 {{num}} 个目标',
andFailTarget_other: '并烧录失败了 {{num}} 个目标',
succeedTo: '{{name}} 被成功烧录 {{target}}',
exitWhileFlashing:
'您当前正在刷机。 关闭 Etcher 可能会导致您的磁盘无法使用。',
looksLikeWindowsImage:
'看起来您正在尝试刻录 Windows 镜像。\n\n与其他镜像不同Windows 镜像需要特殊处理才能使其可启动。 我们建议您使用专门为此目的设计的工具,例如 <a href="https://rufus.akeo.ie">Rufus</a> (Windows)、<a href="https://github. com/slacka/WoeUSB">WoeUSB</a> (Linux) 或 Boot Camp 助理 (macOS)。',
image: '镜像',
drive: '磁盘',
missingPartitionTable:
'看起来这不是一个可启动的{{type}}。\n\n这个{{type}}似乎不包含分区表,因此您的设备可能无法识别或无法正确启动。',
largeDriveSize: '这是个很大的磁盘!请检查并确认它不包含对您很重要的信息',
systemDrive: '选择系统盘很危险,因为这将会删除你的系统',
sourceDrive: '源镜像位于这个分区中',
noSpace: '磁盘空间不足。 请插入另一个较大的磁盘并重试。',
genericFlashError:
'出了点问题。如果源镜像曾被压缩过,请检查它是否已损坏。\n{{error}}',
validation:
'写入已成功完成,但 Etcher 在从磁盘读取镜像时检测到潜在的损坏问题。 \n\n请考虑将镜像写入其他磁盘。',
openError: '打开 {{source}} 时出错。\n\n错误信息 {{error}}',
flashError: '烧录 {{image}} {{targets}} 失败。',
unplug:
'看起来 Etcher 失去了对磁盘的连接。 它是不是被意外拔掉了?\n\n有时这个错误是因为读卡器出了故障。',
cannotWrite:
'看起来 Etcher 无法写入磁盘的这个位置。 此错误通常是由故障的磁盘、读取器或端口引起的。 \n\n请使用其他磁盘、读卡器或端口重试。',
childWriterDied:
'写入进程意外崩溃。请再试一次,如果问题仍然存在,请联系 Etcher 团队。',
badProtocol: '仅支持 http:// 和 https:// 开头的网址。',
},
target: {
selectTarget: '选择目标磁盘',
plugTarget: '请插入目标磁盘',
targets: '个目标',
change: '更改',
},
menu: {
edit: '编辑',
view: '视图',
devTool: '打开开发者工具',
window: '窗口',
help: '帮助',
pro: 'Etcher 专业版',
website: 'Etcher 的官网',
issue: '提交一个 issue',
about: '关于 Etcher',
hide: '隐藏 Etcher',
hideOthers: '隐藏其它窗口',
unhide: '取消隐藏',
quit: '退出 Etcher',
},
source: {
useSourceURL: '使用镜像网络地址',
auth: '验证',
username: '输入用户名',
password: '输入密码',
unsupportedProtocol: '不支持的协议',
windowsImage: '这可能是 Windows 系统镜像',
partitionTable: '找不到分区表',
errorOpen: '打开源镜像时出错',
fromFile: '从文件烧录',
fromURL: '从在线地址烧录',
clone: '克隆磁盘',
image: '镜像信息',
name: '名称:',
path: '路径:',
selectSource: '选择源',
plugSource: '请插入源磁盘',
osImages: '系统镜像格式',
allFiles: '任何文件格式',
enterValidURL: '请输入一个正确的地址',
},
drives: {
name: '名称',
size: '大小',
location: '位置',
find: '找到 {{length}} 个',
select: '选定 {{select}}',
showHidden: '显示 {{num}} 个隐藏的磁盘',
systemDriveDanger: '选择系统盘很危险,因为这将会删除你的系统!',
openInBrowser: 'Etcher 会在浏览器中打开 {{link}}',
changeTarget: '改变目标',
largeDriveWarning: '您即将擦除一个非常大的磁盘',
largeDriveWarningMsg: '您确定所选磁盘不是存储磁盘吗?',
systemDriveWarning: '您将要擦除系统盘',
systemDriveWarningMsg: '您确定要烧录到系统盘吗?',
},
flash: {
another: '烧录另一目标',
target: '目标',
location: '位置',
error: '错误',
flash: '烧录',
flashNow: '现在烧录!',
skip: '跳过了验证',
moreInfo: '更多信息',
speedTip:
'通过将镜像大小除以烧录时间来计算速度。\n由于我们能够跳过未使用的部分因此具有EXT分区的磁盘镜像烧录速度更快。',
speed: '速度:{{speed}} MB/秒',
speedShort: '{{speed}} MB/秒',
eta: '预计还需要:{{eta}}',
failedTarget: '失败的烧录目标',
failedRetry: '重试烧录失败目标',
flashFailed: '烧录失败。',
flashCompleted: '烧录成功!',
},
settings: {
errorReporting: '匿名地向 balena.io 报告运行错误和使用统计',
autoUpdate: '自动更新',
settings: '软件设置',
systemInformation: '系统信息',
},
},
};
export default translation;

152
lib/gui/app/i18n/zh-TW.ts Normal file
View File

@@ -0,0 +1,152 @@
const translation = {
translation: {
ok: '好',
cancel: '取消',
continue: '繼續',
skip: '跳過',
sure: '我確定',
warning: '請注意!',
attention: '請注意',
failed: '失敗',
completed: '完畢',
yesExit: '是的,可以退出',
reallyExit: '真的要現在退出 Etcher 嗎?',
yesContinue: '是的,繼續',
progress: {
starting: '正在啓動……',
decompressing: '正在解壓……',
flashing: '正在燒錄……',
finishing: '正在結束……',
verifying: '正在驗證……',
failing: '失敗……',
},
message: {
sizeNotRecommended: '大小不推薦',
tooSmall: '空間太小',
locked: '被鎖定',
system: '系統盤',
containsImage: '存放源鏡像',
largeDrive: '很大的磁盤',
sourceLarger: '所選的鏡像比目標盤大了 {{byte}} 比特。',
flashSucceed_one: '燒錄成功',
flashSucceed_other: '燒錄成功',
flashFail_one: '燒錄失敗',
flashFail_other: '燒錄失敗',
toDrive: '到 {{description}} ({{name}})',
toTarget_one: '到 {{num}} 個目標',
toTarget_other: '到 {{num}} 個目標',
andFailTarget_one: '並燒錄失敗了 {{num}} 個目標',
andFailTarget_other: '並燒錄失敗了 {{num}} 個目標',
succeedTo: '{{name}} 被成功燒錄 {{target}}',
exitWhileFlashing:
'您當前正在刷機。 關閉 Etcher 可能會導致您的磁盤無法使用。',
looksLikeWindowsImage:
'看起來您正在嘗試刻錄 Windows 鏡像。\n\n與其他鏡像不同Windows 鏡像需要特殊處理才能使其可啓動。 我們建議您使用專門爲此目的設計的工具,例如 <a href="https://rufus.akeo.ie">Rufus</a> (Windows)、<a href="https://github. com/slacka/WoeUSB">WoeUSB</a> (Linux) 或 Boot Camp 助理 (macOS)。',
image: '鏡像',
drive: '磁盤',
missingPartitionTable:
'看起來這不是一個可啓動的{{type}}。\n\n這個{{type}}似乎不包含分區表,因此您的設備可能無法識別或無法正確啓動。',
largeDriveSize: '這是個很大的磁盤!請檢查並確認它不包含對您很重要的信息',
systemDrive: '選擇系統盤很危險,因爲這將會刪除你的系統',
sourceDrive: '源鏡像位於這個分區中',
noSpace: '磁盤空間不足。 請插入另一個較大的磁盤並重試。',
genericFlashError:
'出了點問題。如果源鏡像曾被壓縮過,請檢查它是否已損壞。\n{{error}}',
validation:
'寫入已成功完成,但 Etcher 在從磁盤讀取鏡像時檢測到潛在的損壞問題。 \n\n請考慮將鏡像寫入其他磁盤。',
openError: '打開 {{source}} 時出錯。\n\n錯誤信息 {{error}}',
flashError: '燒錄 {{image}} {{targets}} 失敗。',
unplug:
'看起來 Etcher 失去了對磁盤的連接。 它是不是被意外拔掉了?\n\n有時這個錯誤是因爲讀卡器出了故障。',
cannotWrite:
'看起來 Etcher 無法寫入磁盤的這個位置。 此錯誤通常是由故障的磁盤、讀取器或端口引起的。 \n\n請使用其他磁盤、讀卡器或端口重試。',
childWriterDied:
'寫入進程意外崩潰。請再試一次,如果問題仍然存在,請聯繫 Etcher 團隊。',
badProtocol: '僅支持 http:// 和 https:// 開頭的網址。',
},
target: {
selectTarget: '選擇目標磁盤',
plugTarget: '請插入目標磁盤',
targets: '個目標',
change: '更改',
},
menu: {
edit: '編輯',
view: '視圖',
devTool: '打開開發者工具',
window: '窗口',
help: '幫助',
pro: 'Etcher 專業版',
website: 'Etcher 的官網',
issue: '提交一個 issue',
about: '關於 Etcher',
hide: '隱藏 Etcher',
hideOthers: '隱藏其它窗口',
unhide: '取消隱藏',
quit: '退出 Etcher',
},
source: {
useSourceURL: '使用鏡像網絡地址',
auth: '驗證',
username: '輸入用戶名',
password: '輸入密碼',
unsupportedProtocol: '不支持的協議',
windowsImage: '這可能是 Windows 系統鏡像',
partitionTable: '找不到分區表',
errorOpen: '打開源鏡像時出錯',
fromFile: '從文件燒錄',
fromURL: '從在線地址燒錄',
clone: '克隆磁盤',
image: '鏡像信息',
name: '名稱:',
path: '路徑:',
selectSource: '選擇源',
plugSource: '請插入源磁盤',
osImages: '系統鏡像格式',
allFiles: '任何文件格式',
enterValidURL: '請輸入一個正確的地址',
},
drives: {
name: '名稱',
size: '大小',
location: '位置',
find: '找到 {{length}} 個',
select: '選定 {{select}}',
showHidden: '顯示 {{num}} 個隱藏的磁盤',
systemDriveDanger: '選擇系統盤很危險,因爲這將會刪除你的系統!',
openInBrowser: 'Etcher 會在瀏覽器中打開 {{link}}',
changeTarget: '改變目標',
largeDriveWarning: '您即將擦除一個非常大的磁盤',
largeDriveWarningMsg: '您確定所選磁盤不是存儲磁盤嗎?',
systemDriveWarning: '您將要擦除系統盤',
systemDriveWarningMsg: '您確定要燒錄到系統盤嗎?',
},
flash: {
another: '燒錄另一目標',
target: '目標',
location: '位置',
error: '錯誤',
flash: '燒錄',
flashNow: '現在燒錄!',
skip: '跳過了驗證',
moreInfo: '更多信息',
speedTip:
'通過將鏡像大小除以燒錄時間來計算速度。\n由於我們能夠跳過未使用的部分因此具有EXT分區的磁盤鏡像燒錄速度更快。',
speed: '速度:{{speed}} MB/秒',
speedShort: '{{speed}} MB/秒',
eta: '預計還需要:{{eta}}',
failedTarget: '失敗的燒錄目標',
failedRetry: '重試燒錄失敗目標',
flashFailed: '燒錄失敗。',
flashCompleted: '燒錄成功!',
},
settings: {
errorReporting: '匿名地向 balena.io 報告運行錯誤和使用統計',
autoUpdate: '自動更新',
settings: '軟件設置',
systemInformation: '系統信息',
},
},
};
export default translation;

View File

@@ -2,7 +2,7 @@
<html>
<head>
<meta charset="UTF-8">
<title>Etcher</title>
<title>balenaEtcher</title>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>

View File

@@ -2,7 +2,7 @@
<html>
<head>
<meta charset="UTF-8">
<title>Etcher</title>
<title>balenaEtcher</title>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>

View File

@@ -17,7 +17,7 @@
import * as electron from 'electron';
import * as sdk from 'etcher-sdk';
import * as _ from 'lodash';
import { DrivelistDrive } from '../../../shared/drive-constraints';
import { bytesToMegabytes } from '../../../shared/units';
import { Actions, store } from './store';
@@ -47,7 +47,7 @@ export function isFlashing(): boolean {
*/
export function setFlashingFlag() {
// see https://github.com/balenablocks/balena-electron-env/blob/4fce9c461f294d4a768db8f247eea6f75d7b08b0/README.md#remote-methods
electron.ipcRenderer.send('disable-screensaver');
electron.ipcRenderer.invoke('disable-screensaver');
store.dispatch({
type: Actions.SET_FLASHING_FLAG,
data: {},
@@ -70,7 +70,7 @@ export function unsetFlashingFlag(results: {
data: results,
});
// see https://github.com/balenablocks/balena-electron-env/blob/4fce9c461f294d4a768db8f247eea6f75d7b08b0/README.md#remote-methods
electron.ipcRenderer.send('enable-screensaver');
electron.ipcRenderer.invoke('enable-screensaver');
}
export function setDevicePaths(devicePaths: string[]) {
@@ -84,7 +84,7 @@ export function addFailedDeviceError({
device,
error,
}: {
device: sdk.scanner.adapters.DrivelistDrive;
device: DrivelistDrive;
error: Error;
}) {
const failedDeviceErrorsMap = new Map(

View File

@@ -29,13 +29,6 @@ import { observe, store } from './store';
const leds: Map<string, RGBLed> = new Map();
const animator = new Animator([], 10);
const red: Color = [0.78, 0, 0];
const green: Color = [0, 0.58, 0];
const blue: Color = [0, 0, 0.1];
const purple: Color = [0.7, 0, 0.78];
const white: Color = [0.7, 0.7, 0.7];
const black: Color = [0, 0, 0];
function createAnimationFunction(
intensityFunction: (t: number) => number,
color: Color,
@@ -54,13 +47,27 @@ function one(_t: number) {
return 1;
}
const blinkGreen = createAnimationFunction(blink, green);
const blinkPurple = createAnimationFunction(blink, purple);
const staticRed = createAnimationFunction(one, red);
const staticGreen = createAnimationFunction(one, green);
const staticBlue = createAnimationFunction(one, blue);
const staticWhite = createAnimationFunction(one, white);
const staticBlack = createAnimationFunction(one, black);
type LEDColors = {
green: Color;
purple: Color;
red: Color;
blue: Color;
white: Color;
black: Color;
};
type LEDAnimationFunctions = {
blinkGreen: AnimationFunction;
blinkPurple: AnimationFunction;
staticRed: AnimationFunction;
staticGreen: AnimationFunction;
staticBlue: AnimationFunction;
staticWhite: AnimationFunction;
staticBlack: AnimationFunction;
};
let ledColors: LEDColors;
let ledAnimationFunctions: LEDAnimationFunctions;
interface LedsState {
step: 'main' | 'flashing' | 'verifying' | 'finish';
@@ -132,31 +139,48 @@ export function updateLeds({
if (sourceDrive !== undefined) {
if (plugged.has(sourceDrive)) {
plugged.delete(sourceDrive);
mapping.push(setLeds(staticBlue, new Set([sourceDrive])));
mapping.push(
setLeds(ledAnimationFunctions.staticBlue, new Set([sourceDrive])),
);
}
}
if (step === 'main') {
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(staticWhite, new Set([...selectedOk, ...selectedFailed])),
setLeds(
ledAnimationFunctions.staticBlack,
new Set([...unplugged, ...plugged]),
),
setLeds(
ledAnimationFunctions.staticWhite,
new Set([...selectedOk, ...selectedFailed]),
),
);
} else if (step === 'flashing') {
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(blinkPurple, selectedOk),
setLeds(staticRed, selectedFailed),
setLeds(
ledAnimationFunctions.staticBlack,
new Set([...unplugged, ...plugged]),
),
setLeds(ledAnimationFunctions.blinkPurple, selectedOk),
setLeds(ledAnimationFunctions.staticRed, selectedFailed),
);
} else if (step === 'verifying') {
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(blinkGreen, selectedOk),
setLeds(staticRed, selectedFailed),
setLeds(
ledAnimationFunctions.staticBlack,
new Set([...unplugged, ...plugged]),
),
setLeds(ledAnimationFunctions.blinkGreen, selectedOk),
setLeds(ledAnimationFunctions.staticRed, selectedFailed),
);
} else if (step === 'finish') {
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(staticGreen, selectedOk),
setLeds(staticRed, selectedFailed),
setLeds(
ledAnimationFunctions.staticBlack,
new Set([...unplugged, ...plugged]),
),
setLeds(ledAnimationFunctions.staticGreen, selectedOk),
setLeds(ledAnimationFunctions.staticRed, selectedFailed),
);
}
animator.mapping = mapping;
@@ -221,6 +245,16 @@ export async function init(): Promise<void> {
for (const [drivePath, ledsNames] of Object.entries(ledsMapping)) {
leds.set('/dev/disk/by-path/' + drivePath, new RGBLed(ledsNames));
}
ledColors = (await settings.get('ledColors')) || {};
ledAnimationFunctions = {
blinkGreen: createAnimationFunction(blink, ledColors['green']),
blinkPurple: createAnimationFunction(blink, ledColors['purple']),
staticRed: createAnimationFunction(one, ledColors['red']),
staticGreen: createAnimationFunction(one, ledColors['green']),
staticBlue: createAnimationFunction(one, ledColors['blue']),
staticWhite: createAnimationFunction(one, ledColors['white']),
staticBlack: createAnimationFunction(one, ledColors['black']),
};
observe(_.debounce(stateObserver, 1000, { maxWait: 1000 }));
}
}

View File

@@ -51,7 +51,7 @@ async function readConfigFile(filename: string): Promise<_.Dictionary<any>> {
let contents = '{}';
try {
contents = await fs.readFile(filename, { encoding: 'utf8' });
} catch (error) {
} catch (error: any) {
// noop
}
try {
@@ -104,7 +104,7 @@ export async function set(
settings[key] = value;
try {
await writeConfigFileFn(CONFIG_PATH, settings);
} catch (error) {
} catch (error: any) {
// Revert to previous value if persisting settings failed
settings[key] = previousValue;
throw error;

View File

@@ -102,10 +102,9 @@ function validateMixpanelConfig(config: {
* This function sends the debug message to product analytics services.
*/
export function logEvent(message: string, data: _.Dictionary<any> = {}) {
const {
applicationSessionUuid,
flashingWorkflowUuid,
} = store.getState().toJS();
const { applicationSessionUuid, flashingWorkflowUuid } = store
.getState()
.toJS();
resinCorvus.logEvent(message, {
...data,
sample: mixpanelSample,

View File

@@ -15,10 +15,15 @@
*/
import * as sdk from 'etcher-sdk';
import {
Adapter,
BlockDeviceAdapter,
UsbbootDeviceAdapter,
} from 'etcher-sdk/build/scanner/adapters';
import { geteuid, platform } from 'process';
const adapters: sdk.scanner.adapters.Adapter[] = [
new sdk.scanner.adapters.BlockDeviceAdapter({
const adapters: Adapter[] = [
new BlockDeviceAdapter({
includeSystemDrives: () => true,
}),
];
@@ -26,14 +31,15 @@ const adapters: sdk.scanner.adapters.Adapter[] = [
// Can't use permissions.isElevated() here as it returns a promise and we need to set
// module.exports = scanner right now.
if (platform !== 'linux' || geteuid() === 0) {
adapters.push(new sdk.scanner.adapters.UsbbootDeviceAdapter());
adapters.push(new UsbbootDeviceAdapter());
}
if (
platform === 'win32' &&
sdk.scanner.adapters.DriverlessDeviceAdapter !== undefined
) {
adapters.push(new sdk.scanner.adapters.DriverlessDeviceAdapter());
if (platform === 'win32') {
const {
DriverlessDeviceAdapter: driverless,
// tslint:disable-next-line:no-var-requires
} = require('etcher-sdk/build/scanner/adapters/driverless');
adapters.push(new driverless());
}
export const scanner = new sdk.scanner.Scanner(adapters);

View File

@@ -218,7 +218,7 @@ async function performWrite(
});
flashResults.cancelled = cancelled || results.cancelled;
flashResults.skip = skip;
} catch (error) {
} catch (error: any) {
// This happens when the child is killed using SIGKILL
const SIGKILL_EXIT_CODE = 137;
if (error.code === SIGKILL_EXIT_CODE) {
@@ -287,7 +287,7 @@ export async function flash(
try {
const result = await write(image, drives, flashState.setProgressState);
await flashState.unsetFlashingFlag(result);
} catch (error) {
} catch (error: any) {
await flashState.unsetFlashingFlag({
cancelled: false,
errorCode: error.code,
@@ -349,7 +349,7 @@ export async function cancel(type: string) {
if (socket !== undefined) {
ipc.server.emit(socket, status);
}
} catch (error) {
} catch (error: any) {
analytics.logException(error);
}
}

View File

@@ -15,6 +15,7 @@
*/
import * as prettyBytes from 'pretty-bytes';
import * as i18next from 'i18next';
export interface FlashState {
active: number;
@@ -34,36 +35,45 @@ export function fromFlashState({
position?: string;
} {
if (type === undefined) {
return { status: 'Starting...' };
return { status: i18next.t('progress.starting') };
} else if (type === 'decompressing') {
if (percentage == null) {
return { status: 'Decompressing...' };
return { status: i18next.t('progress.decompressing') };
} else {
return { position: `${percentage}%`, status: 'Decompressing...' };
return {
position: `${percentage}%`,
status: i18next.t('progress.decompressing'),
};
}
} else if (type === 'flashing') {
if (percentage != null) {
if (percentage < 100) {
return { position: `${percentage}%`, status: 'Flashing...' };
return {
position: `${percentage}%`,
status: i18next.t('progress.flashing'),
};
} else {
return { status: 'Finishing...' };
return { status: i18next.t('progress.finishing') };
}
} else {
return {
status: 'Flashing...',
status: i18next.t('progress.flashing'),
position: `${position ? prettyBytes(position) : ''}`,
};
}
} else if (type === 'verifying') {
if (percentage == null) {
return { status: 'Validating...' };
return { status: i18next.t('progress.verifying') };
} else if (percentage < 100) {
return { position: `${percentage}%`, status: 'Validating...' };
return {
position: `${percentage}%`,
status: i18next.t('progress.verifying'),
};
} else {
return { status: 'Finishing...' };
return { status: i18next.t('progress.finishing') };
}
}
return { status: 'Failed' };
return { status: i18next.t('progress.failing') };
}
export function titleFromFlashState(

View File

@@ -20,6 +20,7 @@ import * as _ from 'lodash';
import * as errors from '../../../shared/errors';
import * as settings from '../../../gui/app/models/settings';
import { SUPPORTED_EXTENSIONS } from '../../../shared/supported-formats';
import * as i18next from 'i18next';
async function mountSourceDrive() {
// sourceDrivePath is the name of the link in /dev/disk/by-path
@@ -27,7 +28,7 @@ async function mountSourceDrive() {
if (sourceDrivePath) {
try {
await electron.ipcRenderer.invoke('mount-drive', sourceDrivePath);
} catch (error) {
} catch (error: any) {
// noop
}
}
@@ -53,11 +54,11 @@ export async function selectImage(): Promise<string | undefined> {
properties: ['openFile', 'treatPackageAsDirectory'],
filters: [
{
name: 'OS Images',
name: i18next.t('source.osImages'),
extensions: SUPPORTED_EXTENSIONS,
},
{
name: 'All',
name: i18next.t('source.allFiles'),
extensions: ['*'],
},
],
@@ -79,8 +80,8 @@ export async function showWarning(options: {
description: string;
}): Promise<boolean> {
_.defaults(options, {
confirmationLabel: 'OK',
rejectionLabel: 'Cancel',
confirmationLabel: i18next.t('ok'),
rejectionLabel: i18next.t('cancel'),
});
const BUTTONS = [options.confirmationLabel, options.rejectionLabel];
@@ -98,7 +99,7 @@ export async function showWarning(options: {
buttons: BUTTONS,
defaultId: BUTTON_REJECTION_INDEX,
cancelId: BUTTON_REJECTION_INDEX,
title: 'Attention',
title: i18next.t('attention'),
message: options.title,
detail: options.description,
},

View File

@@ -37,6 +37,7 @@ import {
import FlashSvg from '../../../assets/flash.svg';
import DriveStatusWarningModal from '../../components/drive-status-warning-modal/drive-status-warning-modal';
import * as i18next from 'i18next';
const COMPLETED_PERCENTAGE = 100;
const SPEED_PRECISION = 2;
@@ -117,7 +118,7 @@ async function flashImageToDrive(
}
goToSuccess();
}
} catch (error) {
} catch (error: any) {
notifyFailure(iconPath, basename, drives);
let errorMessage = getErrorMessageFromCode(error.code);
if (!errorMessage) {
@@ -293,9 +294,17 @@ export class FlashStep extends React.PureComponent<
color="#7e8085"
width="100%"
>
<Txt>{this.props.speed.toFixed(SPEED_PRECISION)} MB/s</Txt>
<Txt>
{i18next.t('flash.speedShort', {
speed: this.props.speed.toFixed(SPEED_PRECISION),
})}
</Txt>
{!_.isNil(this.props.eta) && (
<Txt>ETA: {formatSeconds(this.props.eta)}</Txt>
<Txt>
{i18next.t('flash.eta', {
eta: formatSeconds(this.props.eta),
})}
</Txt>
)}
</Flex>
)}

View File

@@ -1,5 +1,10 @@
// @ts-nocheck
import { main } from './app';
import './i18n';
import { langParser } from './i18n';
import { ipcRenderer } from 'electron';
ipcRenderer.send('change-lng', langParser());
if (module.hot) {
module.hot.accept('./app', () => {

View File

@@ -142,7 +142,7 @@ export const Modal = styled(({ style, children, ...props }) => {
{...props}
>
<ScrollableFlex flexDirection="column" width="100%" height="90%">
{...children}
{children.length ? children.map((c: any) => <>{c}</>) : children}
</ScrollableFlex>
</ModalBase>
);

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2022 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Dictionary } from 'lodash';
type BalenaTag = {
id: number,
name: string,
value: string
}
export class EtcherPro {
private supervisorAddr: string;
private supervisorKey: string;
private tags: Dictionary<string> | undefined;
public uuid: string;
constructor(supervisorAddr: string, supervisorKey: string) {
this.supervisorAddr = supervisorAddr;
this.supervisorKey = supervisorKey;
this.uuid = (process.env.BALENA_DEVICE_UUID ?? 'NO-UUID').substring(0, 7);
this.tags = undefined;
this.get_tags().then((tags) => (this.tags = tags));
}
async get_tags(): Promise<Dictionary<string>> {
const result = await fetch(
this.supervisorAddr + '/v2/device/tags?apikey=' + this.supervisorKey,
);
const parsed = await result.json();
if (parsed['status'] === 'success') {
return Object.assign(
{},
...parsed['tags'].map((tag: BalenaTag) => {
return { [tag.name]: tag.value };
}),
);
} else {
return {};
}
}
public get_serial(): string | undefined {
if (this.tags) {
return this.tags['Serial'];
} else {
return undefined;
}
}
}
export function etcherProInfo(): EtcherPro | undefined {
const BALENA_SUPERVISOR_ADDRESS = process.env.BALENA_SUPERVISOR_ADDRESS;
const BALENA_SUPERVISOR_API_KEY = process.env.BALENA_SUPERVISOR_API_KEY;
if (BALENA_SUPERVISOR_ADDRESS && BALENA_SUPERVISOR_API_KEY) {
return new EtcherPro(BALENA_SUPERVISOR_ADDRESS, BALENA_SUPERVISOR_API_KEY);
}
return undefined;
}

View File

@@ -21,18 +21,22 @@ import { platform } from 'os';
import * as path from 'path';
import * as semver from 'semver';
import './app/i18n';
import { packageType, version } from '../../package.json';
import * as EXIT_CODES from '../shared/exit-codes';
import { delay, getConfig } from '../shared/utils';
import * as settings from './app/models/settings';
import { logException } from './app/modules/analytics';
import { buildWindowMenu } from './menu';
import * as i18n from 'i18next';
const customProtocol = 'etcher';
const scheme = `${customProtocol}://`;
const updatablePackageTypes = ['appimage', 'nsis', 'dmg'];
const packageUpdatable = updatablePackageTypes.includes(packageType);
let packageUpdated = false;
let mainWindow: any = null;
async function checkForUpdates(interval: number) {
// We use a while loop instead of a setInterval to preserve
@@ -43,7 +47,7 @@ async function checkForUpdates(interval: number) {
const release = await autoUpdater.checkForUpdates();
const isOutdated =
semver.compare(release.updateInfo.version, version) > 0;
const shouldUpdate = release.updateInfo.stagingPercentage || 0 > 0;
const shouldUpdate = release.updateInfo.stagingPercentage !== 0; // undefinded (default) means 100%
if (shouldUpdate && isOutdated) {
await autoUpdater.downloadUpdate();
packageUpdated = true;
@@ -97,6 +101,7 @@ const sourceSelectorReady = new Promise((resolve) => {
async function selectImageURL(url?: string) {
// 'data:,' is the default chromedriver url that is passed as last argument when running spectron tests
if (url !== undefined && url !== 'data:,') {
url = url.replace(/\/$/, ''); // on windows the url ends with an extra slash
url = url.startsWith(scheme) ? url.slice(scheme.length) : url;
await sourceSelectorReady;
electron.BrowserWindow.getAllWindows().forEach((window) => {
@@ -129,7 +134,7 @@ async function createMainWindow() {
if (fullscreen) {
({ width, height } = electron.screen.getPrimaryDisplay().bounds);
}
const mainWindow = new electron.BrowserWindow({
mainWindow = new electron.BrowserWindow({
width,
height,
frame: !fullscreen,
@@ -156,7 +161,6 @@ async function createMainWindow() {
electron.app.setAsDefaultProtocolClient(customProtocol);
buildWindowMenu(mainWindow);
mainWindow.setFullScreen(true);
// Prevent flash of white when starting the application
@@ -239,6 +243,17 @@ async function main(): Promise<void> {
await selectImageURL(await getCommandLineURL(argv));
});
await selectImageURL(await getCommandLineURL(process.argv));
electron.ipcMain.on('change-lng', function (event, args) {
i18n.changeLanguage(args, () => {
console.log('Language changed to: ' + args);
});
if (mainWindow != null) {
buildWindowMenu(mainWindow);
} else {
console.log('Build menu failed. ');
}
});
}
}

View File

@@ -17,6 +17,8 @@
import * as electron from 'electron';
import { displayName } from '../../package.json';
import * as i18next from 'i18next';
/**
* @summary Builds a native application menu for a given window
*/
@@ -42,12 +44,13 @@ export function buildWindowMenu(window: electron.BrowserWindow) {
const menuTemplate: electron.MenuItemConstructorOptions[] = [
{
role: 'editMenu',
label: i18next.t('menu.edit'),
},
{
label: 'View',
label: i18next.t('menu.view'),
submenu: [
{
label: 'Toggle Developer Tools',
label: i18next.t('menu.devTool'),
accelerator:
process.platform === 'darwin' ? 'Command+Alt+I' : 'Control+Shift+I',
click: toggleDevTools,
@@ -56,12 +59,14 @@ export function buildWindowMenu(window: electron.BrowserWindow) {
},
{
role: 'windowMenu',
label: i18next.t('menu.window'),
},
{
role: 'help',
label: i18next.t('menu.help'),
submenu: [
{
label: 'Etcher Pro',
label: i18next.t('menu.pro'),
click() {
electron.shell.openExternal(
'https://etcher.io/pro?utm_source=etcher_menu&ref=etcher_menu',
@@ -69,13 +74,13 @@ export function buildWindowMenu(window: electron.BrowserWindow) {
},
},
{
label: 'Etcher Website',
label: i18next.t('menu.website'),
click() {
electron.shell.openExternal('https://etcher.io?ref=etcher_menu');
},
},
{
label: 'Report an issue',
label: i18next.t('menu.issue'),
click() {
electron.shell.openExternal(
'https://github.com/balena-io/etcher/issues',
@@ -92,25 +97,29 @@ export function buildWindowMenu(window: electron.BrowserWindow) {
submenu: [
{
role: 'about' as const,
label: 'About Etcher',
label: i18next.t('menu.about'),
},
{
type: 'separator' as const,
},
{
role: 'hide' as const,
label: i18next.t('menu.hide'),
},
{
role: 'hideOthers' as const,
label: i18next.t('menu.hideOthers'),
},
{
role: 'unhide' as const,
label: i18next.t('menu.unhide'),
},
{
type: 'separator' as const,
},
{
role: 'quit' as const,
label: i18next.t('menu.quit'),
},
],
});

View File

@@ -35,8 +35,10 @@ import { totalmem } from 'os';
import { toJSON } from '../../shared/errors';
import { GENERAL_ERROR, SUCCESS } from '../../shared/exit-codes';
import { delay } from '../../shared/utils';
import { delay, isJson } from '../../shared/utils';
import { SourceMetadata } from '../app/components/source-selector/source-selector';
import axios from 'axios';
import * as _ from 'lodash';
ipc.config.id = process.env.IPC_CLIENT_ID as string;
ipc.config.socketRoot = process.env.IPC_SOCKET_ROOT as string;
@@ -171,6 +173,7 @@ interface WriteOptions {
autoBlockmapping: boolean;
decompressFirst: boolean;
SourceType: string;
httpRequest?: any;
}
ipc.connectTo(IPC_SERVER_ID, () => {
@@ -281,7 +284,22 @@ ipc.connectTo(IPC_SERVER_ID, () => {
path: imagePath,
});
} else {
source = new Http({ url: imagePath, avoidRandomAccess: true });
const decodedImagePath = decodeURIComponent(imagePath);
if (isJson(decodedImagePath)) {
const imagePathObject = JSON.parse(decodedImagePath);
source = new Http({
url: imagePathObject.url,
avoidRandomAccess: true,
axiosInstance: axios.create(_.omit(imagePathObject, ['url'])),
auth: options.image.auth,
});
} else {
source = new Http({
url: imagePath,
avoidRandomAccess: true,
auth: options.image.auth,
});
}
}
}
const results = await writeAndValidate({
@@ -300,7 +318,7 @@ ipc.connectTo(IPC_SERVER_ID, () => {
ipc.of[IPC_SERVER_ID].emit('done', { results });
await delay(DISCONNECT_DELAY);
await terminate(exitCode);
} catch (error) {
} catch (error: any) {
exitCode = GENERAL_ERROR;
ipc.of[IPC_SERVER_ID].emit('error', toJSON(error));
}

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env osascript -l JavaScript
ObjC.import('stdlib')
const app = Application.currentApplication()
app.includeStandardAdditions = true
const result = app.displayDialog('balenaEtcher 需要来自管理员的权限才能烧录镜像到磁盘。\n\n输入您的密码以允许此操作。', {
defaultAnswer: '',
withIcon: 'caution',
buttons: ['取消', '好'],
defaultButton: '好',
hiddenAnswer: true,
})
if (result.buttonReturned === '好') {
result.textReturned
} else {
$.exit(255)
}

View File

@@ -30,6 +30,9 @@ export async function sudo(
command: string,
): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> {
try {
let lang = Intl.DateTimeFormat().resolvedOptions().locale;
lang = lang.substr(0, 2);
const { stdout, stderr } = await execFileAsync(
'sudo',
['--askpass', 'sh', '-c', `echo ${SUCCESSFUL_AUTH_MARKER} && ${command}`],
@@ -40,7 +43,7 @@ export async function sudo(
SUDO_ASKPASS: join(
getAppPath(),
__dirname,
'sudo-askpass.osascript.js',
'sudo-askpass.osascript-' + lang + '.js',
),
},
},
@@ -50,7 +53,7 @@ export async function sudo(
stdout: stdout.slice(EXPECTED_SUCCESSFUL_AUTH_MARKER.length),
stderr,
};
} catch (error) {
} catch (error: any) {
if (error.code === 1) {
if (!error.stdout.startsWith(EXPECTED_SUCCESSFUL_AUTH_MARKER)) {
return { cancelled: true };

View File

@@ -17,16 +17,16 @@
import { Dictionary } from 'lodash';
import { outdent } from 'outdent';
import * as prettyBytes from 'pretty-bytes';
import '../gui/app/i18n';
import * as i18next from 'i18next';
export const progress: Dictionary<(quantity: number) => string> = {
successful: (quantity: number) => {
const plural = quantity === 1 ? '' : 's';
return `Successful target${plural}`;
return i18next.t('message.flashSucceed', { count: quantity });
},
failed: (quantity: number) => {
const plural = quantity === 1 ? '' : 's';
return `Failed target${plural}`;
return i18next.t('message.flashFail', { count: quantity });
},
};
@@ -38,129 +38,121 @@ export const info = {
) => {
const targets = [];
if (failed + successful === 1) {
targets.push(`to ${drive.description} (${drive.displayName})`);
targets.push(
i18next.t('message.toDrive', {
description: drive.description,
name: drive.displayName,
}),
);
} else {
if (successful) {
const plural = successful === 1 ? '' : 's';
targets.push(`to ${successful} target${plural}`);
targets.push(
i18next.t('message.toTarget', {
count: successful,
num: successful,
}),
);
}
if (failed) {
const plural = failed === 1 ? '' : 's';
targets.push(`and failed to be flashed to ${failed} target${plural}`);
targets.push(
i18next.t('message.andFailTarget', { count: failed, num: failed }),
);
}
}
return `${imageBasename} was successfully flashed ${targets.join(' ')}`;
return i18next.t('message.succeedTo', {
name: imageBasename,
target: targets.join(' '),
});
},
};
export const compatibility = {
sizeNotRecommended: () => {
return 'Not recommended';
return i18next.t('message.sizeNotRecommended');
},
tooSmall: () => {
return 'Too small';
return i18next.t('message.tooSmall');
},
locked: () => {
return 'Locked';
return i18next.t('message.locked');
},
system: () => {
return 'System drive';
return i18next.t('message.system');
},
containsImage: () => {
return 'Source drive';
return i18next.t('message.containsImage');
},
// The drive is large and therefore likely not a medium you want to write to.
largeDrive: () => {
return 'Large drive';
return i18next.t('message.largeDrive');
},
} as const;
export const warning = {
tooSmall: (source: { size: number }, target: { size: number }) => {
return outdent({ newline: ' ' })`
The selected source is ${prettyBytes(source.size - target.size)}
larger than this drive.
${i18next.t('message.sourceLarger', {
byte: prettyBytes(source.size - target.size),
})}
`;
},
exitWhileFlashing: () => {
return [
'You are currently flashing a drive.',
'Closing Etcher may leave your drive in an unusable state.',
].join(' ');
return i18next.t('message.exitWhileFlashing');
},
looksLikeWindowsImage: () => {
return [
'It looks like you are trying to burn a Windows image.\n\n',
'Unlike other images, Windows images require special processing to be made bootable.',
'We suggest you use a tool specially designed for this purpose, such as',
'<a href="https://rufus.akeo.ie">Rufus</a> (Windows),',
'<a href="https://github.com/slacka/WoeUSB">WoeUSB</a> (Linux),',
'or Boot Camp Assistant (macOS).',
].join(' ');
return i18next.t('message.looksLikeWindowsImage');
},
missingPartitionTable: () => {
return [
'It looks like this is not a bootable image.\n\n',
'The image does not appear to contain a partition table,',
'and might not be recognized or bootable by your device.',
].join(' ');
return i18next.t('message.missingPartitionTable', {
type: i18next.t('message.image'),
});
},
driveMissingPartitionTable: () => {
return outdent({ newline: ' ' })`
It looks like this is not a bootable drive.
The drive does not appear to contain a partition table,
and might not be recognized or bootable by your device.
`;
return i18next.t('message.missingPartitionTable', {
type: i18next.t('message.drive'),
});
},
largeDriveSize: () => {
return "This is a large drive! Make sure it doesn't contain files that you want to keep.";
return i18next.t('message.largeDriveSize');
},
systemDrive: () => {
return 'Selecting your system drive is dangerous and will erase your drive!';
return i18next.t('message.systemDrive');
},
sourceDrive: () => {
return 'Contains the image you chose to flash';
return i18next.t('message.sourceDrive');
},
};
export const error = {
notEnoughSpaceInDrive: () => {
return [
'Not enough space on the drive.',
'Please insert larger one and try again.',
].join(' ');
return i18next.t('message.noSpace');
},
genericFlashError: (err: Error) => {
return `Something went wrong. If it is a compressed image, please check that the archive is not corrupted.\n${err.message}`;
return i18next.t('message.genericFlashError', { error: err.message });
},
validation: () => {
return [
'The write has been completed successfully but Etcher detected potential',
'corruption issues when reading the image back from the drive.',
'\n\nPlease consider writing the image to a different drive.',
].join(' ');
return i18next.t('message.validation');
},
openSource: (sourceName: string, errorMessage: string) => {
return outdent`
Something went wrong while opening ${sourceName}
Error: ${errorMessage}
`;
return i18next.t('message.openError', {
source: sourceName,
error: errorMessage,
});
},
flashFailure: (
@@ -169,35 +161,33 @@ export const error = {
) => {
const target =
drives.length === 1
? `${drives[0].description} (${drives[0].displayName})`
: `${drives.length} targets`;
return `Something went wrong while writing ${imageBasename} to ${target}.`;
? i18next.t('message.toDrive', {
description: drives[0].description,
name: drives[0].displayName,
})
: i18next.t('message.toTarget', {
count: drives.length,
num: drives.length,
});
return i18next.t('message.flashError', {
image: imageBasename,
targets: target,
});
},
driveUnplugged: () => {
return [
'Looks like Etcher lost access to the drive.',
'Did it get unplugged accidentally?',
"\n\nSometimes this error is caused by faulty readers that don't provide stable access to the drive.",
].join(' ');
return i18next.t('message.unplug');
},
inputOutput: () => {
return [
'Looks like Etcher is not able to write to this location of the drive.',
'This error is usually caused by a faulty drive, reader, or port.',
'\n\nPlease try again with another drive, reader, or port.',
].join(' ');
return i18next.t('message.cannotWrite');
},
childWriterDied: () => {
return [
'The writer process ended unexpectedly.',
'Please try again, and contact the Etcher team if the problem persists.',
].join(' ');
return i18next.t('message.childWriterDied');
},
unsupportedProtocol: () => {
return 'Only http:// and https:// URLs are supported.';
return i18next.t('message.badProtocol');
},
};

View File

@@ -20,7 +20,7 @@ import { promises as fs } from 'fs';
import * as _ from 'lodash';
import * as os from 'os';
import * as semver from 'semver';
import * as sudoPrompt from 'sudo-prompt';
import * as sudoPrompt from '@balena/sudo-prompt';
import { promisify } from 'util';
import { sudo as catalinaSudo } from './catalina-sudo/sudo';
@@ -29,16 +29,18 @@ import * as errors from './errors';
const execAsync = promisify(childProcess.exec);
const execFileAsync = promisify(childProcess.execFile);
type Std = string | Buffer | undefined;
function sudoExecAsync(
cmd: string,
options: { name: string },
): Promise<{ stdout: string; stderr: string }> {
): Promise<{ stdout: Std; stderr: Std }> {
return new Promise((resolve, reject) => {
sudoPrompt.exec(
cmd,
options,
(error: Error | null, stdout: string, stderr: string) => {
if (error != null) {
(error: Error | undefined, stdout: Std, stderr: Std) => {
if (error) {
reject(error);
} else {
resolve({ stdout, stderr });
@@ -60,7 +62,7 @@ export async function isElevated(): Promise<boolean> {
// See http://stackoverflow.com/a/28268802
try {
await execAsync('fltmc');
} catch (error) {
} catch (error: any) {
if (error.code === os.constants.errno.EPERM) {
return false;
}
@@ -146,7 +148,7 @@ async function elevateScriptCatalina(
try {
const { cancelled } = await catalinaSudo(cmd);
return { cancelled };
} catch (error) {
} catch (error: any) {
throw errors.createError({ title: error.stderr });
}
}
@@ -190,7 +192,7 @@ export async function elevateCommand(
}
try {
return await elevateScriptUnix(path, options.applicationName);
} catch (error) {
} catch (error: any) {
// We're hardcoding internal error messages declared by `sudo-prompt`.
// There doesn't seem to be a better way to handle these errors, so
// for now, we should make sure we double check if the error messages

View File

@@ -61,3 +61,12 @@ export function getAppPath(): string {
)
);
}
export function isJson(jsonString: string) {
try {
JSON.parse(jsonString);
} catch (e) {
return false;
}
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "balena-etcher",
"private": true,
"displayName": "balenaEtcher",
"version": "1.5.122",
"version": "1.13.4",
"packageType": "local",
"main": "generated/etcher.js",
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
@@ -13,21 +13,27 @@
"url": "git@github.com:balena-io/etcher.git"
},
"scripts": {
"lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts",
"build": "npm run webpack",
"flowzone-preinstall-linux": "sudo apt-get install -y xvfb libudev-dev && cat < electron-builder.yml | yq e .deb.depends[] - | xargs -L1 echo | sed 's/|//g' | xargs -L1 sudo apt-get --ignore-missing install || true",
"flowzone-preinstall-macos": "true",
"flowzone-preinstall-windows": "true",
"flowzone-preinstall": "npm run flowzone-preinstall-linux",
"lint-css": "prettier --write lib/**/*.css",
"lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts",
"lint": "npm run lint-ts && npm run lint-css",
"test-spectron": "mocha --recursive --reporter spec --require ts-node/register --require-main tests/gui/allow-renderer-process-reuse.ts tests/spectron/runner.spec.ts",
"test-gui": "electron-mocha --recursive --reporter spec --require ts-node/register --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox --renderer tests/gui/**/*.ts",
"test-shared": "electron-mocha --recursive --reporter spec --require ts-node/register --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox tests/shared/**/*.ts",
"test": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
"postinstall": "electron-rebuild -t prod,dev,optional",
"sanity-checks": "bash scripts/ci/ensure-all-file-extensions-in-gitattributes.sh",
"start": "./node_modules/.bin/electron .",
"postshrinkwrap": "ts-node ./scripts/clean-shrinkwrap.ts",
"webpack": "webpack",
"test-macos": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
"test-gui": "electron-mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox --renderer tests/gui/**/*.ts",
"test-linux": "npm run lint && xvfb-run --auto-servernum npm run test-gui && xvfb-run --auto-servernum npm run test-shared && xvfb-run --auto-servernum npm run test-spectron && npm run sanity-checks",
"test-shared": "electron-mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox tests/shared/**/*.ts",
"test-spectron": "mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts tests/spectron/runner.spec.ts",
"test-windows": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
"test": "echo npm run test-{linux,windows,macos}",
"uploadSourcemap": "sentry-cli releases files $npm_config_SENTRY_VERSION upload-sourcemaps ./generated/*.js.map --org $npm_config_SENTRY_ORG --project $npm_config_SENTRY_PROJECT",
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
"concourse-build-electron": "npm run webpack",
"concourse-test": "npx npm@6.14.8 test",
"concourse-test-electron": "npx npm@6.14.8 test"
"webpack": "webpack"
},
"husky": {
"hooks": {
@@ -44,87 +50,84 @@
},
"author": "Balena Inc. <hello@etcher.io>",
"license": "Apache-2.0",
"platformSpecificDependencies": [
"xmlbuilder",
"xmldom",
"@types/plist",
"@types/verror",
"crc",
"iconv-corefoundation",
"plist",
"dmg-license",
"fsevents",
"winusb-driver-generator"
],
"devDependencies": {
"@balena/lint": "^5.3.0",
"@fortawesome/fontawesome-free": "^5.13.1",
"@svgr/webpack": "^5.5.0",
"@types/chai": "^4.2.7",
"@types/copy-webpack-plugin": "^6.0.0",
"@types/mime-types": "^2.1.0",
"@types/mini-css-extract-plugin": "^1.2.2",
"@types/mocha": "^8.0.3",
"@types/node": "^14.14.41",
"@types/node-ipc": "^9.1.2",
"@types/react-dom": "^16.8.4",
"@types/semver": "^7.1.0",
"@types/sinon": "^9.0.0",
"@types/terser-webpack-plugin": "^5.0.2",
"@types/tmp": "^0.2.0",
"@types/webpack-node-externals": "^2.5.0",
"aws4-axios": "2.2.1",
"chai": "^4.2.0",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.1",
"d3": "^4.13.0",
"debug": "^4.2.0",
"electron": "12.0.2",
"electron-builder": "^22.10.5",
"electron-mocha": "^9.3.2",
"electron-notarize": "^1.0.0",
"electron-rebuild": "^2.3.2",
"electron-updater": "^4.3.5",
"etcher-sdk": "^6.2.1",
"file-loader": "^6.2.0",
"husky": "^4.2.5",
"immutable": "^3.8.1",
"lint-staged": "^10.2.2",
"lodash": "^4.17.10",
"mini-css-extract-plugin": "^1.3.3",
"mocha": "^8.0.1",
"native-addon-loader": "^2.0.1",
"node-ipc": "^9.1.1",
"omit-deep-lodash": "1.1.4",
"outdent": "^0.7.1",
"path-is-inside": "^1.0.2",
"pnp-webpack-plugin": "^1.6.4",
"pretty-bytes": "^5.3.0",
"react": "^16.8.5",
"react-dom": "^16.8.5",
"redux": "^4.0.5",
"rendition": "^19.2.0",
"resin-corvus": "^2.0.5",
"semver": "^7.3.2",
"simple-progress-webpack-plugin": "^1.1.2",
"sinon": "^9.0.2",
"spectron": "^14.0.0",
"string-replace-loader": "^3.0.1",
"style-loader": "^2.0.0",
"styled-components": "^5.1.0",
"sudo-prompt": "github:zvin/sudo-prompt#7cdede2f0da28fbcc2db48402d7d935f3a825c91",
"sys-class-rgb-led": "^3.0.0",
"ts-loader": "^8.0.12",
"ts-node": "^9.1.1",
"tslib": "^2.0.0",
"typescript": "^4.2.2",
"url-loader": "^4.1.1",
"uuid": "^8.1.0",
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.2"
"@balena/lint": "5.4.2",
"@balena/sudo-prompt": "9.2.1-workaround-windows-amperstand-in-username-0849e215b947987a643fe5763902aea201255534",
"@fortawesome/fontawesome-free": "5.15.4",
"@sentry/cli": "^2.11.0",
"@svgr/webpack": "5.5.0",
"@types/chai": "4.3.4",
"@types/copy-webpack-plugin": "6.4.3",
"@types/mime-types": "2.1.1",
"@types/mini-css-extract-plugin": "1.4.3",
"@types/mocha": "8.2.3",
"@types/node": "14.18.34",
"@types/node-ipc": "9.2.0",
"@types/react": "16.14.34",
"@types/react-dom": "16.9.17",
"@types/semver": "7.3.13",
"@types/sinon": "9.0.11",
"@types/terser-webpack-plugin": "5.0.4",
"@types/tmp": "0.2.3",
"@types/webpack-node-externals": "2.5.3",
"aws4-axios": "2.4.9",
"chai": "4.3.7",
"copy-webpack-plugin": "7.0.0",
"css-loader": "5.2.7",
"d3": "4.13.0",
"debug": "4.3.4",
"electron": "^13.5.0",
"electron-builder": "^23.0.9",
"electron-mocha": "9.3.3",
"electron-notarize": "1.2.2",
"electron-rebuild": "3.2.9",
"electron-updater": "5.3.0",
"esbuild-loader": "2.20.0",
"etcher-sdk": "^7.4.7",
"file-loader": "6.2.0",
"husky": "4.3.8",
"i18next": "21.10.0",
"immutable": "3.8.2",
"lint-staged": "10.5.4",
"lodash": "4.17.21",
"mini-css-extract-plugin": "1.6.2",
"mocha": "8.4.0",
"native-addon-loader": "2.0.1",
"node-ipc": "9.2.1",
"omit-deep-lodash": "1.1.7",
"outdent": "0.8.0",
"path-is-inside": "1.0.2",
"pnp-webpack-plugin": "1.7.0",
"pretty-bytes": "5.6.0",
"react": "16.8.5",
"react-dom": "16.8.5",
"react-i18next": "11.18.6",
"redux": "4.2.0",
"rendition": "19.3.2",
"resin-corvus": "2.0.5",
"semver": "7.3.8",
"simple-progress-webpack-plugin": "1.1.2",
"sinon": "9.2.4",
"spectron": "15.0.0",
"string-replace-loader": "3.1.0",
"style-loader": "2.0.0",
"styled-components": "5.3.6",
"sys-class-rgb-led": "3.0.1",
"terser-webpack-plugin": "5.3.6",
"ts-loader": "8.4.0",
"ts-node": "9.1.1",
"tslib": "2.4.1",
"typescript": "4.4.4",
"url-loader": "4.1.1",
"uuid": "8.3.2",
"webpack": "5.75.0",
"webpack-cli": "4.10.0",
"webpack-dev-server": "4.11.1"
},
"engines": {
"node": ">=14 < 16"
},
"versionist": {
"publishedAt": "2021-09-02T12:20:23.119Z"
"publishedAt": "2023-01-12T15:10:50.986Z"
}
}

View File

@@ -1,17 +1,18 @@
---
type: electron
release: github
publishMetadata: true
sentry:
org: balenaetcher
team: resinio
type: electron
org: balenaetcher
team: resinio
type: electron
triggerNotification:
version: 1.5.81
stagingPercentage: 100
version: 1.7.9
stagingPercentage: 100
upstream:
- repo: etcher-sdk
url: https://github.com/balena-io-modules/etcher-sdk
module: 'etcher-sdk'
module: etcher-sdk
- repo: sys-class-rgb-led
url: https://github.com/balena-io-modules/sys-class-rgb-led
module: sys-class-rgb-led

View File

@@ -1,2 +1,2 @@
awscli==1.11.87
shyaml==0.5.0
awscli==1.27.28
shyaml==0.6.2

View File

@@ -37,7 +37,7 @@ async function main() {
SHRINKWRAP_FILENAME,
JSON.stringify(cleaned, null, JSON_INDENT),
);
} catch (error) {
} catch (error: any) {
console.log(`[ERROR] Couldn't write shrinkwrap file: ${error.stack}`);
process.exitCode = 1;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -573,7 +573,8 @@ describe('Model: flashState', function () {
});
describe('.getFlashUuid()', function () {
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
const UUID_REGEX =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
it('should be initially undefined', function () {
expect(flashState.getFlashUuid()).to.be.undefined;

View File

@@ -23,7 +23,7 @@ import * as settings from '../../../lib/gui/app/models/settings';
async function checkError(promise: Promise<any>, fn: (err: Error) => any) {
try {
await promise;
} catch (error) {
} catch (error: any) {
await fn(error);
return;
}

View File

@@ -83,7 +83,7 @@ describe('Browser: imageWriter', () => {
imageWriter.flash(image, [fakeDrive], performWriteStub),
]);
assert.fail('Writing twice should fail');
} catch (error) {
} catch (error: any) {
expect(error.message).to.equal(
'There is already a flash in progress',
);
@@ -133,7 +133,7 @@ describe('Browser: imageWriter', () => {
});
try {
await imageWriter.flash(image, [fakeDrive], performWriteStub);
} catch (error) {
} catch (error: any) {
expect(error).to.be.an.instanceof(Error);
expect(error.message).to.equal('write error');
}

View File

@@ -1158,7 +1158,7 @@ describe('Shared: DriveConstraints', function () {
'/dev/disk6',
];
const drives = [
({
{
device: drivePaths[0],
description: 'My Drive',
size: 123456789,
@@ -1166,8 +1166,8 @@ describe('Shared: DriveConstraints', function () {
mountpoints: [{ path: __dirname }],
isSystem: false,
isReadOnly: false,
} as unknown) as constraints.DrivelistDrive,
({
} as unknown as constraints.DrivelistDrive,
{
device: drivePaths[1],
description: 'My Other Drive',
size: 123456789,
@@ -1175,8 +1175,8 @@ describe('Shared: DriveConstraints', function () {
mountpoints: [],
isSystem: false,
isReadOnly: true,
} as unknown) as constraints.DrivelistDrive,
({
} as unknown as constraints.DrivelistDrive,
{
device: drivePaths[2],
description: 'My Drive',
size: 1234567,
@@ -1184,8 +1184,8 @@ describe('Shared: DriveConstraints', function () {
mountpoints: [],
isSystem: false,
isReadOnly: false,
} as unknown) as constraints.DrivelistDrive,
({
} as unknown as constraints.DrivelistDrive,
{
device: drivePaths[3],
description: 'My Drive',
size: 123456789,
@@ -1193,8 +1193,8 @@ describe('Shared: DriveConstraints', function () {
mountpoints: [],
isSystem: true,
isReadOnly: false,
} as unknown) as constraints.DrivelistDrive,
({
} as unknown as constraints.DrivelistDrive,
{
device: drivePaths[4],
description: 'My Drive',
size: 128000000001,
@@ -1202,8 +1202,8 @@ describe('Shared: DriveConstraints', function () {
mountpoints: [],
isSystem: false,
isReadOnly: false,
} as unknown) as constraints.DrivelistDrive,
({
} as unknown as constraints.DrivelistDrive,
{
device: drivePaths[5],
description: 'My Drive',
size: 12345678,
@@ -1211,8 +1211,8 @@ describe('Shared: DriveConstraints', function () {
mountpoints: [],
isSystem: false,
isReadOnly: false,
} as unknown) as constraints.DrivelistDrive,
({
} as unknown as constraints.DrivelistDrive,
{
device: drivePaths[6],
description: 'My Drive',
size: 123456789,
@@ -1220,7 +1220,7 @@ describe('Shared: DriveConstraints', function () {
mountpoints: [],
isSystem: false,
isReadOnly: false,
} as unknown) as constraints.DrivelistDrive,
} as unknown as constraints.DrivelistDrive,
];
const image: SourceMetadata = {

View File

@@ -30,9 +30,8 @@ describe('Shared: SupportedFormats', function () {
],
(imagePath) => {
it(`should return true if filename is ${imagePath}`, function () {
const looksLikeWindowsImage = supportedFormats.looksLikeWindowsImage(
imagePath,
);
const looksLikeWindowsImage =
supportedFormats.looksLikeWindowsImage(imagePath);
expect(looksLikeWindowsImage).to.be.true;
});
},
@@ -45,9 +44,8 @@ describe('Shared: SupportedFormats', function () {
],
(imagePath) => {
it(`should return false if filename is ${imagePath}`, function () {
const looksLikeWindowsImage = supportedFormats.looksLikeWindowsImage(
imagePath,
);
const looksLikeWindowsImage =
supportedFormats.looksLikeWindowsImage(imagePath);
expect(looksLikeWindowsImage).to.be.false;
});
},

View File

@@ -28,7 +28,7 @@ if (platform() !== 'darwin') {
this.timeout(40000);
const app = new Application({
path: (electronPath as unknown) as string,
path: electronPath as unknown as string,
args: ['--no-sandbox', '.'],
});
@@ -59,7 +59,7 @@ if (platform() !== 'darwin') {
it('should set a proper title', async () => {
// @ts-ignore (SpectronClient.getTitle exists)
return expect(await app.client.getTitle()).to.equal('Etcher');
return expect(await app.client.getTitle()).to.equal('balenaEtcher');
});
});
});

View File

@@ -1,12 +1,21 @@
{
"compilerOptions": {
"strict": true,
"target": "es2019",
"typeRoots": ["./node_modules/@types", "./typings"],
"module": "commonjs",
"lib": ["dom", "esnext"],
"declaration": true,
"declarationMap": true,
"jsx": "react",
"pretty": true,
"sourceMap": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"target": "es2019",
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"typeRoots": ["./node_modules/@types", "./typings"]
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
}
}

View File

@@ -10,7 +10,16 @@
"jsx": "react",
"typeRoots": ["./node_modules/@types", "./typings"],
"importHelpers": true,
"allowSyntheticDefaultImports": true
"allowSyntheticDefaultImports": true,
"lib": ["dom", "esnext"],
"declaration": true,
"declarationMap": true,
"pretty": true,
"sourceMap": true,
"baseUrl": "./src",
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"allowJs": true
},
"include": [
"lib/**/*.ts",

View File

@@ -1 +1 @@
declare module 'sudo-prompt';
declare module '@balena/sudo-prompt';

View File

@@ -15,7 +15,7 @@
*/
import * as CopyPlugin from 'copy-webpack-plugin';
import { readdirSync } from 'fs';
import { readdirSync, existsSync } from 'fs';
import * as _ from 'lodash';
import * as os from 'os';
import outdent from 'outdent';
@@ -26,6 +26,8 @@ import * as TerserPlugin from 'terser-webpack-plugin';
import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack';
import * as PnpWebpackPlugin from 'pnp-webpack-plugin';
import * as tsconfigRaw from './tsconfig.webpack.json';
/**
* Don't webpack package.json as mixpanel & sentry tokens
* will be inserted in it after webpacking
@@ -75,11 +77,80 @@ function renameNodeModules(resourcePath: string) {
);
}
function findExt2fsFolder(): string {
const ext2fs = 'node_modules/ext2fs';
const biFsExt2fs = 'node_modules/balena-image-fs/node_modules/ext2fs';
if (existsSync(ext2fs)) {
return ext2fs;
} else if (existsSync(biFsExt2fs)) {
return biFsExt2fs;
} else {
throw Error('ext2fs not found');
}
}
function makeExt2FsRegex(): RegExp {
const folder = findExt2fsFolder();
const libpath = '/lib/libext2fs\\.js$';
return new RegExp(folder.concat(libpath));
}
function findUsbPrebuild(): string[] {
const usbPrebuildsFolder = path.join('node_modules', 'usb', 'prebuilds');
const prebuildFolders = readdirSync(usbPrebuildsFolder);
let bindingFile: string | undefined = 'node.napi.node';
const platformFolder = prebuildFolders.find(
(f) => f.startsWith(os.platform()) && f.indexOf(os.arch()) > -1,
);
if (platformFolder === undefined) {
throw new Error(
'Could not find usb prebuild. Should try fallback to node-gyp and use /build/Release instead of /prebuilds',
);
}
const bindingFiles = readdirSync(
path.join(usbPrebuildsFolder, platformFolder),
);
if (!bindingFiles.length) {
throw new Error('Could not find usb prebuild for platform');
}
if (bindingFiles.length === 1) {
bindingFile = bindingFiles[0];
}
// armv6 vs v7 in linux-arm and
// glibc vs musl in linux-x64
if (bindingFiles.length > 1) {
bindingFile = bindingFiles.find((file) => {
if (bindingFiles.indexOf('arm') > -1) {
const process = require('process');
return file.indexOf(process.config.variables.arm_version) > -1;
} else {
return file.indexOf('glibc') > -1;
}
});
}
if (bindingFile === undefined) {
throw new Error('Could not find usb prebuild for platform');
}
return [platformFolder, bindingFile];
}
const [USB_BINDINGS_FOLDER, USB_BINDINGS_FILE] = findUsbPrebuild();
function findLzmaNativeBindingsFolder(): string {
const files = readdirSync(path.join('node_modules', 'lzma-native'));
const files = readdirSync(
path.join('node_modules', 'lzma-native', 'prebuilds'),
);
const bindingsFolder = files.find(
(f) =>
f.startsWith('binding-') &&
f.startsWith(os.platform()) &&
f.endsWith(env.npm_config_target_arch || os.arch()),
);
if (bindingsFolder === undefined) {
@@ -141,13 +212,13 @@ const commonConfig = {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
compress: false,
mangle: false,
output: {
beautify: true,
format: {
comments: false,
ecma: 2018,
ecma: 2020,
},
},
extractComments: false,
@@ -173,9 +244,11 @@ const commonConfig = {
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
loader: 'esbuild-loader',
options: {
configFile: 'tsconfig.webpack.json',
loader: 'tsx',
target: 'es2021',
tsconfigRaw,
},
},
],
@@ -206,8 +279,8 @@ const commonConfig = {
/node_modules\/lzma-native\/index\.js$/,
// remove node-pre-gyp magic from lzma-native
{
search: 'require(binding_path)',
replace: `require('./${LZMA_BINDINGS_FOLDER}/lzma_native.node')`,
search: `require('node-gyp-build')(__dirname);`,
replace: `require('./prebuilds/${LZMA_BINDINGS_FOLDER}/electron.napi.node')`,
},
// use regular stream module instead of readable-stream
{
@@ -216,9 +289,9 @@ const commonConfig = {
},
),
// remove node-pre-gyp magic from usb
replace(/node_modules\/@balena.io\/usb\/usb\.js$/, {
search: 'require(binding_path)',
replace: "require('./build/Release/usb_bindings.node')",
replace(/node_modules\/usb\/dist\/usb\/bindings\.js$/, {
search: `require('node-gyp-build')(path_1.join(__dirname, '..', '..'));`,
replace: `require('../../prebuilds/${USB_BINDINGS_FOLDER}/${USB_BINDINGS_FILE}')`,
}),
// remove bindings magic from mountutils
replace(/node_modules\/mountutils\/index\.js$/, {
@@ -269,8 +342,8 @@ const commonConfig = {
// Use the libext2fs.wasm file in the generated folder
// The way to find the app directory depends on whether we run in the renderer or in the child-writer
// We use __dirname in the child-writer and electron.remote.app.getAppPath() in the renderer
replace(/node_modules\/ext2fs\/lib\/libext2fs\.js$/, {
search: 'scriptDirectory=__dirname+"/"',
replace(makeExt2FsRegex(), {
search: 'scriptDirectory = __dirname + "/";',
replace: fetchWasm('ext2fs', 'lib'),
}),
// Same for node-crc-utils
@@ -332,7 +405,7 @@ const guiConfigCopyPatterns = [
to: 'modules/node-raspberrypi-usbboot/blobs',
},
{
from: 'node_modules/ext2fs/lib/libext2fs.wasm',
from: `${findExt2fsFolder()}/lib/libext2fs.wasm`,
to: 'modules/ext2fs/lib/libext2fs.wasm',
},
{
@@ -344,8 +417,8 @@ const guiConfigCopyPatterns = [
if (os.platform() === 'win32') {
// liblzma.dll is required on Windows for lzma-native
guiConfigCopyPatterns.push({
from: `node_modules/lzma-native/${LZMA_BINDINGS_FOLDER}/liblzma.dll`,
to: `modules/lzma-native/${LZMA_BINDINGS_FOLDER_RENAMED}/liblzma.dll`,
from: `node_modules/lzma-native/prebuilds/${LZMA_BINDINGS_FOLDER}/liblzma.dll`,
to: `modules/lzma-native/prebuilds/${LZMA_BINDINGS_FOLDER_RENAMED}/liblzma.dll`,
});
}
@@ -382,6 +455,7 @@ const guiConfig = {
const mainConfig = {
...commonConfig,
target: 'electron-main',
devtool: 'source-map',
node: {
__dirname: false,
__filename: true,