Compare commits

...

42 Commits

Author SHA1 Message Date
flowzone-app[bot]
85b1e3c2c2
v2.1.0 2025-02-27 16:16:59 +00:00
Matthew Yarmolinsky
e5d1b4ce23
Merge pull request #4406 from balena-io/add-analytics-alert
Add informational notice about how to disable analytics collection
2025-02-27 11:16:08 -05:00
myarmolinsky
aac092fd4d Add informational notice about how to disable analytics collection
Change-type: minor
2025-02-20 09:51:30 -05:00
flowzone-app[bot]
ff852c029e
v2.0.0 2025-02-20 14:27:03 +00:00
flowzone-app[bot]
4759bc7686
Merge pull request #4407 from balena-io/build-ubuntu22-macos13
major: build on ubuntu 22 and macos 13
2025-02-20 14:26:06 +00:00
Edwin Joassart
039a022353 major: build on ubuntu 22 and macos 13 2025-02-20 09:12:20 +01:00
flowzone-app[bot]
4375b960c2
v1.19.25 2024-10-10 10:03:36 +00:00
flowzone-app[bot]
ee5505d596
Merge pull request #4335 from balena-io/bump-etcher-sdk
patch: bump etcher-sdk to 9.1.2
2024-10-10 10:02:28 +00:00
Edwin Joassart
c726b51dca patch: bump etcher-sdk to 9.1.2 2024-10-09 17:42:19 +02:00
flowzone-app[bot]
676eaf82e7
v1.19.24 2024-10-09 14:22:59 +00:00
flowzone-app[bot]
87fb4df9eb
Merge pull request #4333 from balena-io/rglidden/rpm-fix-etcher-util
patch: etcher-util is corrupted in RPM package
2024-10-09 14:21:45 +00:00
Richard Glidden
e43ee788ec patch: etcher-util is corrupted in RPM package
rpmbuild strips executables by default when generating an rpm packge.
This was causing the JavaScript code bundled in the etcher-util file
to be removed, causing "Pkg: Error reading from file." whenever
etcher-util was called.

This in turn caused balena-etcher to generate the error message
`Error: (0, h.requestMetadata) is not a function` when attempting
to write an SD card.

This fixes the issue for RPM builds by replacing the `strip` command
with `true` so that rpmbuild no longer strips the executables and
the embeded code stays intact.

See: https://github.com/balena-io/etcher/issues/4150

Signed-off-by: Richard Glidden <richard@glidden.org>
2024-10-09 15:54:16 +02:00
flowzone-app[bot]
3dc17c89b4
v1.19.23 2024-10-09 13:52:59 +00:00
flowzone-app[bot]
5774dded7b
Merge pull request #4334 from balena-io/marcaurele/remove-gconf2
patch: remove gconf2 libgconf-2-4 deps
2024-10-09 13:52:04 +00:00
Edwin Joassart
9f408241f9
remove gcconf2 deps from docs 2024-10-09 13:55:44 +02:00
Marc-Aurèle Brothier
2ed779ef37 patch: remove gconf2 libgconf-2-4 deps
Closes #4096
2024-10-09 10:50:35 +02:00
flowzone-app[bot]
5fd6376f45
v1.19.22 2024-07-18 18:13:00 +00:00
flowzone-app[bot]
818dcd3b13
Merge pull request #4279 from balena-io/klutchell-patch-1
Replace deprecated Flowzone inputs
2024-07-18 18:12:06 +00:00
Kyle Harding
52d396aa7e
Replace deprecated Flowzone inputs
Change-type: patch
2024-07-17 09:37:12 -04:00
flowzone-app[bot]
c748c2a9c0
v1.19.21 2024-05-30 15:00:39 +00:00
Edwin Joassart
a5dac57b09
Merge pull request #4238 from balena-io/fix-win-2
patch: fix missing windows dependency
2024-05-30 16:59:45 +02:00
Edwin Joassart
8dad81ae34
patch: fix missing windows dependency 2024-05-30 16:28:56 +02:00
Edwin Joassart
d28719daf2
patch: fix missing windows dependency 2024-05-30 14:56:07 +02:00
Edwin Joassart
98db4df0dc patch: fix missing windows dependency 2024-05-30 14:35:02 +02:00
flowzone-app[bot]
52144f4a6e
v1.19.20 2024-05-30 10:17:34 +00:00
flowzone-app[bot]
39b02f2168
Merge pull request #4237 from balena-io/fix-win
patch: fix missing windows dependency
2024-05-30 10:16:39 +00:00
Edwin Joassart
c4d3f8db87 patch: fix missing windows dependency 2024-05-30 11:44:50 +02:00
flowzone-app[bot]
6d796df017
v1.19.19 2024-05-28 12:10:03 +00:00
flowzone-app[bot]
326a3c740f
Merge pull request #4233 from balena-io/sentry
patch: add sentry debug flag
2024-05-28 12:07:54 +00:00
Edwin Joassart
8223130e8d patch: add sentry debug flag 2024-05-28 12:22:34 +02:00
flowzone-app[bot]
3245439744
v1.19.18 2024-05-22 13:28:07 +00:00
flowzone-app[bot]
74854f1720
Merge pull request #4228 from balena-io/aethernet-patch-2
patch: fix sentry DSN
2024-05-22 13:27:17 +00:00
Edwin Joassart
4ffda6e208 patch: fix Sentry DSN for main process 2024-05-22 15:02:04 +02:00
flowzone-app[bot]
62ac0b98b9
v1.19.17 2024-05-09 06:33:47 +00:00
flowzone-app[bot]
ae70c20779
Merge pull request #4221 from balena-io/fix-analytics-imports
patch: fix injection of analytics key at build time
2024-05-09 06:33:00 +00:00
JOASSART Edwin
e94767aca7 patch: fix injection of analytics key at build time 2024-05-08 23:06:34 +02:00
flowzone-app[bot]
6a648e9215
v1.19.16 2024-04-26 14:33:23 +00:00
flowzone-app[bot]
fa8220d5ba
Merge pull request #4212 from balena-io/fix-race
patch: hold request for metadata while waiting for flasher
2024-04-26 14:32:11 +00:00
Edwin Joassart
2dfa795129 patch: hold request for metadata while waiting for flasher 2024-04-26 15:53:59 +02:00
flowzone-app[bot]
73afb2fc55
v1.19.15 2024-04-26 13:27:17 +00:00
flowzone-app[bot]
c5a8bfc0dc
Merge pull request #4211 from balena-io/fix-url-loading
patch: bump etcher-sdk to 9.0.11 to fix url loading using http/2
2024-04-26 13:24:43 +00:00
Edwin Joassart
cb03fb8375 patch: bump etcher-sdk to 9.0.11 to fix url loading using http/2 2024-04-26 14:51:16 +02:00
16 changed files with 8489 additions and 27626 deletions

View File

@ -53,6 +53,13 @@ runs:
shell: bash
run: sudo apt-get install -y --no-install-recommends fakeroot dpkg rpm
# rpmbuild will strip binaries by default, which breaks the sidecar.
# Use a macro to override the "strip" to bypass stripping.
- name: Configure rpmbuild to not strip executables
if: runner.os == 'Linux'
shell: bash
run: echo '%__strip /usr/bin/true' > ~/.rpmmacros
- name: Install host dependencies
if: runner.os == 'macOS'
# FIXME: Python 3.12 dropped distutils that node-gyp depends upon.
@ -131,7 +138,7 @@ runs:
PLATFORM=Windows
SHA256SUM_BIN=sha256sum
# Install DigiCert Signing Manager Tools
# Install DigiCert Signing Manager Tools
curl --silent --retry 3 --fail https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download \
-H "x-api-key:$SM_API_KEY" \
-o smtools-windows-x64.msi

View File

@ -55,6 +55,12 @@ runs:
# fi
npm ci
# as the shrinkwrap might have been done on mac/linux, this is ensure the package is there for windows
if [[ "$RUNNER_OS" == "Windows" ]]; then
npm i -D winusb-driver-generator
fi
npm run lint
npm run package
npm run wdio # test stage, note that it requires the package to be done first

View File

@ -18,7 +18,24 @@ jobs:
(github.event.pull_request.head.repo.full_name != github.repository && github.event_name == 'pull_request_target')
secrets: inherit
with:
custom_runs_on: '[["ubuntu-20.04"],["windows-2019"],["macos-12"],["macos-latest-xlarge"]]'
custom_test_matrix: >
{
"os": [
["ubuntu-22.04"],
["windows-2019"],
["macos-13"],
["macos-latest-xlarge"]
]
}
custom_publish_matrix: >
{
"os": [
["ubuntu-22.04"],
["windows-2019"],
["macos-13"],
["macos-latest-xlarge"]
]
}
restrict_custom_actions: false
github_prerelease: true
cloudflare_website: "etcher"

View File

@ -1,3 +1,165 @@
- commits:
- subject: Add informational notice about how to disable analytics collection
hash: aac092fd4df8750024c082b25dcbd0ae6ee618fd
body: ""
footer:
Change-type: minor
change-type: minor
author: myarmolinsky
nested: []
version: 2.1.0
title: ""
date: 2025-02-27T16:16:57.036Z
- commits:
- subject: "major: build on ubuntu 22 and macos 13"
hash: 039a022353d1980ef9ddd19166515c531e48aba4
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 2.0.0
title: ""
date: 2025-02-20T14:27:01.338Z
- commits:
- subject: "patch: bump etcher-sdk to 9.1.2"
hash: c726b51dca3383c76f4bf824fd5d594ac3069180
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 1.19.25
title: ""
date: 2024-10-10T10:03:29.519Z
- commits:
- subject: "patch: etcher-util is corrupted in RPM package"
hash: e43ee788ec5ec49e105ff804206919bb10a59ea7
body: |
rpmbuild strips executables by default when generating an rpm packge.
This was causing the JavaScript code bundled in the etcher-util file
to be removed, causing "Pkg: Error reading from file." whenever
etcher-util was called.
This in turn caused balena-etcher to generate the error message
`Error: (0, h.requestMetadata) is not a function` when attempting
to write an SD card.
This fixes the issue for RPM builds by replacing the `strip` command
with `true` so that rpmbuild no longer strips the executables and
the embeded code stays intact.
See: https://github.com/balena-io/etcher/issues/4150
footer:
Signed-off-by: Richard Glidden <richard@glidden.org>
signed-off-by: Richard Glidden <richard@glidden.org>
author: Richard Glidden
nested: []
version: 1.19.24
title: ""
date: 2024-10-09T14:22:56.623Z
- commits:
- subject: "patch: remove gconf2 libgconf-2-4 deps"
hash: 2ed779ef371db367e4e413c9d0d08fcd738edb5b
body: "Closes #4096"
footer: {}
author: Marc-Aurèle Brothier
nested: []
version: 1.19.23
title: ""
date: 2024-10-09T13:52:54.936Z
- commits:
- subject: Replace deprecated Flowzone inputs
hash: 52d396aa7ea9ae1ef6d68151f582f04f57191b14
body: ""
footer:
Change-type: patch
change-type: patch
author: Kyle Harding
nested: []
version: 1.19.22
title: ""
date: 2024-07-18T18:12:56.368Z
- commits:
- subject: "patch: fix missing windows dependency"
hash: 8dad81ae34b8d71f3d4f7151ee60717e6207ccd8
body: ""
footer: {}
author: Edwin Joassart
nested: []
- subject: "patch: fix missing windows dependency"
hash: d28719daf249f2994acdf94b4bb7ea937ffcab9b
body: ""
footer: {}
author: Edwin Joassart
nested: []
- subject: "patch: fix missing windows dependency"
hash: 98db4df0dc147e5fec9180c50f4e21acf1fd0a58
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 1.19.21
title: ""
date: 2024-05-30T15:00:35.706Z
- commits:
- subject: "patch: fix missing windows dependency"
hash: c4d3f8db8769418925a9909ac700edc5f425a068
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 1.19.20
title: ""
date: 2024-05-30T10:17:29.075Z
- commits:
- subject: "patch: add sentry debug flag"
hash: 8223130e8dfce180481550d77f022064255601e4
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 1.19.19
title: ""
date: 2024-05-28T12:09:51.167Z
- commits:
- subject: "patch: fix Sentry DSN for main process"
hash: 4ffda6e208a6e2f109f652d39e1248bec23a2ddf
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 1.19.18
title: ""
date: 2024-05-22T13:28:03.659Z
- commits:
- subject: "patch: fix injection of analytics key at build time"
hash: e94767aca7b07e674bd60176ef77c11440131ace
body: ""
footer: {}
author: JOASSART Edwin
nested: []
version: 1.19.17
title: ""
date: 2024-05-09T06:33:45.091Z
- commits:
- subject: "patch: hold request for metadata while waiting for flasher"
hash: 2dfa795129e287f887b9ea02f2eca717575d27ac
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 1.19.16
title: ""
date: 2024-04-26T14:33:19.111Z
- commits:
- subject: "patch: bump etcher-sdk to 9.0.11 to fix url loading using http/2"
hash: cb03fb83754f38d647fc951b94470725b46b2b31
body: ""
footer: {}
author: Edwin Joassart
nested: []
version: 1.19.15
title: ""
date: 2024-04-26T13:26:57.047Z
- commits:
- subject: "patch: pretty-bytes to 6.1.1"
hash: fa642270f7153f14e45ee03a73bad1f0797cbd51
@ -1114,13 +1276,10 @@
nested: []
- subject: "Patch: run linux build on ubuntu-20.04"
hash: adcd8e0325bc891460b3e51aa5403f8675189f13
body: >-
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/)
body: |-
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.
We cannot use `latest` as the glibc version will cause issue with older ubuntu version.
footer: {}
author: Edwin Joassart
nested: []
@ -11865,40 +12024,19 @@
changelog-entry: Don't include user paths in Mixpanel usage reports
link: https://github.com/resin-io-modules/etcher-image-stream/blob/master/CHANGELOG.md
subject: Fix uncaught exception if no file was selected from a dialog
body: >-
body: |-
The following error is thrown if the open file dialog is cancelled
without any selection:
Unhandled rejection TypeError: Cannot read property '0' of undefined
at Number.indexedGetter
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/call_get.js:106:15)
at Number.tryCatcher
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:503:31)
at Promise._settlePromise
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:560:18)
at Promise._settlePromise0
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:605:10)
at Promise._settlePromises
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:684:18)
at Async._drainQueue
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:126:16)
at Async._drainQueues
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:136:10)
at Immediate.Async.drainQueues [as _onImmediate]
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:16:14)
at Number.indexedGetter (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/call_get.js:106:15)
at Number.tryCatcher (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:503:31)
at Promise._settlePromise (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:560:18)
at Promise._settlePromise0 (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:605:10)
at Promise._settlePromises (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:684:18)
at Async._drainQueue (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:126:16)
at Async._drainQueues (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:136:10)
at Immediate.Async.drainQueues [as _onImmediate] (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:16:14)
at processImmediate [as _immediateCallback] (timers.js:383:17)
- hash: 6bd086f1c5c6654a47125cf2d46788655cae2553
author: Juan Cruz Viotti
@ -12495,21 +12633,14 @@
changelog-entry: Use info icon instead of "SHOW FULL FILE NAME" in first step.
fixes: https://github.com/resin-io/etcher/issues/458
subject: Make use of AppImage desktop integration script
body: >-
body: |-
This is useful to prompt the user to install the `.desktop` file.
The `Description` key in `Etcher.desktop` was changed to `Comment` since
`desktop-file-validate` complained with:
Etcher.desktop: error: file contains key "Description" in group "Desktop
Entry", but keys extending the format should start with "X-"
After checking the desktop file format specification, the correct key
should be "Comment"
(https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s05.html).
- hash: c3e360e61933ef0044c005b5e92c879ff9a47c49
author: Juan Cruz Viotti
@ -12722,17 +12853,12 @@
changelog-entry: Fix flashing never starting after elevation in GNU/Linux.
fixes: https://github.com/resin-io/etcher/issues/665
subject: Make all angular modules export the name of the module
body: >-
body: |-
This makes them very nicely require-able, for example:
angular.module('MyModule', [
require('my-dependency');
]);
From
https://medium.com/@kentcdodds/how-to-distribute-your-angularjs-module-e04d4dd58ddc#.yqg2zo8im
From https://medium.com/@kentcdodds/how-to-distribute-your-angularjs-module-e04d4dd58ddc#.yqg2zo8im
- hash: b8f63af3f81bca3abd055303bc91ab35eb126655
author: Juan Cruz Viotti
footers:

View File

@ -3,6 +3,73 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
# v2.1.0
## (2025-02-27)
* Add informational notice about how to disable analytics collection [myarmolinsky]
# v2.0.0
## (2025-02-20)
* major: build on ubuntu 22 and macos 13 [Edwin Joassart]
# v1.19.25
## (2024-10-10)
* patch: bump etcher-sdk to 9.1.2 [Edwin Joassart]
# v1.19.24
## (2024-10-09)
* patch: etcher-util is corrupted in RPM package [Richard Glidden]
# v1.19.23
## (2024-10-09)
* patch: remove gconf2 libgconf-2-4 deps [Marc-Aurèle Brothier]
# v1.19.22
## (2024-07-18)
* Replace deprecated Flowzone inputs [Kyle Harding]
# v1.19.21
## (2024-05-30)
* patch: fix missing windows dependency [Edwin Joassart]
* patch: fix missing windows dependency [Edwin Joassart]
* patch: fix missing windows dependency [Edwin Joassart]
# v1.19.20
## (2024-05-30)
* patch: fix missing windows dependency [Edwin Joassart]
# v1.19.19
## (2024-05-28)
* patch: add sentry debug flag [Edwin Joassart]
# v1.19.18
## (2024-05-22)
* patch: fix Sentry DSN for main process [Edwin Joassart]
# v1.19.17
## (2024-05-09)
* patch: fix injection of analytics key at build time [JOASSART Edwin]
# v1.19.16
## (2024-04-26)
* patch: hold request for metadata while waiting for flasher [Edwin Joassart]
# v1.19.15
## (2024-04-26)
* patch: bump etcher-sdk to 9.0.11 to fix url loading using http/2 [Edwin Joassart]
# v1.19.14
## (2024-04-25)

View File

@ -122,7 +122,6 @@ run Etcher on a GNU/Linux system.
- xrender
- xtst
- xscrnsaver
- gconf-2.0
- gmodule-2.0
- nss

View File

@ -136,25 +136,6 @@ const config: ForgeConfig = {
new sidecar.SidecarPlugin(),
],
hooks: {
readPackageJson: async (_config, packageJson) => {
packageJson.analytics = {};
if (process.env.SENTRY_TOKEN) {
packageJson.analytics.sentry = {
token: process.env.SENTRY_TOKEN,
};
}
if (process.env.AMPLITUDE_TOKEN) {
packageJson.analytics.amplitude = {
token: 'balena-etcher',
};
}
// packageJson.packageType = 'dmg' | 'AppImage' | 'rpm' | 'deb' | 'zip' | 'nsis' | 'portable'
return packageJson;
},
postPackage: async (_forgeConfig, options) => {
if (options.platform === 'linux') {
// symlink the etcher binary from balena-etcher to balenaEtcher to ensure compatibility with the wdio suite and the old name

View File

@ -142,25 +142,29 @@ export let requestMetadata: any;
// start the api and spawn the child process
spawnChildAndConnect({
withPrivileges: false,
}).then(({ emit, registerHandler }) => {
// start scanning
emit('scan', {});
})
.then(({ emit, registerHandler }) => {
// start scanning
emit('scan', {});
// make the sourceMetada awaitable to be used on source selection
requestMetadata = async (params: any): Promise<SourceMetadata> => {
emit('sourceMetadata', JSON.stringify(params));
// make the sourceMetada awaitable to be used on source selection
requestMetadata = async (params: any): Promise<SourceMetadata> => {
emit('sourceMetadata', JSON.stringify(params));
return new Promise((resolve) =>
registerHandler('sourceMetadata', (data: any) => {
resolve(JSON.parse(data));
}),
);
};
return new Promise((resolve) =>
registerHandler('sourceMetadata', (data: any) => {
resolve(JSON.parse(data));
}),
);
};
registerHandler('drives', (data: any) => {
setDrives(JSON.parse(data));
registerHandler('drives', (data: any) => {
setDrives(JSON.parse(data));
});
})
.catch((error: any) => {
throw new Error(`Failed to start the flasher process. error: ${error}`);
});
});
let popupExists = false;

View File

@ -308,6 +308,7 @@ const FlowSelector = styled(
interface SourceSelectorProps {
flashing: boolean;
hideAnalyticsAlert: () => void;
}
interface SourceSelectorState {
@ -359,6 +360,20 @@ export class SourceSelector extends React.Component<
ipcRenderer.removeListener('select-image', this.onSelectImage);
}
public componentDidUpdate(
_prevProps: Readonly<SourceSelectorProps>,
prevState: Readonly<SourceSelectorState>,
) {
if (
(!prevState.showDriveSelector && this.state.showDriveSelector) ||
(!prevState.showURLSelector && this.state.showURLSelector) ||
(!prevState.showImageDetails && this.state.showImageDetails) ||
(!prevState.imageSelectorOpen && this.state.imageSelectorOpen)
) {
this.props.hideAnalyticsAlert();
}
}
private async onSelectImage(_event: IpcRendererEvent, imagePath: string) {
this.setState({ imageLoading: true });
await this.selectSource(
@ -382,6 +397,7 @@ export class SourceSelector extends React.Component<
});
selectionState.deselectImage();
this.props.hideAnalyticsAlert();
}
private selectSource(
@ -423,6 +439,14 @@ export class SourceSelector extends React.Component<
// this will send an event down the ipcMain asking for metadata
// we'll get the response through an event
// FIXME: This is a poor man wait while loading to prevent a potential race condition without completely blocking the interface
// This should be addressed when refactoring the GUI
let retriesLeft = 10;
while (requestMetadata === undefined && retriesLeft > 0) {
await new Promise((resolve) => setTimeout(resolve, 1050)); // api is trying to connect every 1000, this is offset to make sure we fall between retries
retriesLeft--;
}
metadata = await requestMetadata({ selected, SourceType, auth });
if (!metadata?.hasMBR && this.state.warning === null) {

View File

@ -100,12 +100,14 @@ interface TargetSelectorProps {
disabled: boolean;
hasDrive: boolean;
flashing: boolean;
hideAnalyticsAlert: () => void;
}
export const TargetSelector = ({
disabled,
hasDrive,
flashing,
hideAnalyticsAlert,
}: TargetSelectorProps) => {
// TODO: inject these from redux-connector
const [{ driveListLabel, targets }, setStateSlice] = React.useState(
@ -137,6 +139,7 @@ export const TargetSelector = ({
tooltip={driveListLabel}
openDriveSelector={() => {
setShowTargetSelectorModal(true);
hideAnalyticsAlert();
}}
reselectDrive={() => {
analytics.logEvent('Reselect drive');

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
import * as _ from 'lodash';
import { findLastIndex, once } from 'lodash';
import type { Client } from 'analytics-client';
import { createClient, createNoopClient } from 'analytics-client';
import * as SentryRenderer from '@sentry/electron/renderer';
import * as settings from '../models/settings';
import { store } from '../models/store';
import * as packageJSON from '../../../../package.json';
import { version } from '../../../../package.json';
type AnalyticsPayload = _.Dictionary<any>;
@ -73,7 +73,7 @@ export const anonymizePath = (input: string) => {
const segments = mainPart.split(sep);
// Moving from the end, find the first marker and cut the path from there.
const startCutIndex = _.findLastIndex(segments, (segment) =>
const startCutIndex = findLastIndex(segments, (segment) =>
etcherSegmentMarkers.includes(segment),
);
return (
@ -119,21 +119,23 @@ let analyticsClient: Client;
/**
* @summary Init analytics configurations
*/
export const initAnalytics = _.once(() => {
export const initAnalytics = once(() => {
const dsn =
settings.getSync('analyticsSentryToken') ||
_.get(packageJSON, ['analytics', 'sentry', 'token']);
SentryRenderer.init({ dsn, beforeSend: anonymizeSentryData });
settings.getSync('analyticsSentryToken') || process.env.SENTRY_TOKEN;
SentryRenderer.init({
dsn,
beforeSend: anonymizeSentryData,
debug: process.env.ETCHER_SENTRY_DEBUG === 'true',
});
const projectName =
settings.getSync('analyticsAmplitudeToken') ||
_.get(packageJSON, ['analytics', 'amplitude', 'token']);
settings.getSync('analyticsAmplitudeToken') || process.env.AMPLITUDE_TOKEN;
const clientConfig = {
projectName,
endpoint: 'data.balena-cloud.com',
componentName: 'etcher',
componentVersion: packageJSON.version,
componentVersion: version,
};
analyticsClient = projectName
? createClient(clientConfig)

View File

@ -15,12 +15,13 @@
*/
import CogSvg from '@fortawesome/fontawesome-free/svgs/solid/gear.svg';
import CloseSvg from '@fortawesome/fontawesome-free/svgs/solid/x.svg';
import QuestionCircleSvg from '@fortawesome/fontawesome-free/svgs/solid/circle-question.svg';
import * as path from 'path';
import prettyBytes from 'pretty-bytes';
import * as React from 'react';
import { Flex } from 'rendition';
import { Alert, Flex, Link } from 'rendition';
import styled from 'styled-components';
import FinishPage from '../../components/finish/finish';
@ -35,6 +36,7 @@ import { observe } from '../../models/store';
import { open as openExternal } from '../../os/open-external/services/open-external';
import {
IconButton as BaseIcon,
IconButton,
ThemedProvider,
} from '../../styled-components';
@ -46,6 +48,7 @@ import { FlashStep } from './Flash';
import EtcherSvg from '../../../assets/etcher.svg';
import { SafeWebview } from '../../components/safe-webview/safe-webview';
import { theme } from '../../theme';
const Icon = styled(BaseIcon)`
margin-right: 20px;
@ -97,6 +100,8 @@ const StepBorder = styled.div<{
margin-left: ${(props) => (props.right ? '-120px' : undefined)};
`;
const ANALYTICS_ALERT_VISIBILITY_KEY = 'analytics_alert_visible';
interface MainPageStateFromStore {
isFlashing: boolean;
hasImage: boolean;
@ -113,6 +118,7 @@ interface MainPageState {
isWebviewShowing: boolean;
hideSettings: boolean;
featuredProjectURL?: string;
analyticsAlertIsVisible: boolean;
}
export class MainPage extends React.Component<
@ -125,6 +131,8 @@ export class MainPage extends React.Component<
current: 'main',
isWebviewShowing: false,
hideSettings: true,
analyticsAlertIsVisible:
localStorage.getItem(ANALYTICS_ALERT_VISIBILITY_KEY) !== 'false',
...this.stateHelper(),
};
}
@ -153,6 +161,13 @@ export class MainPage extends React.Component<
return url.toString();
}
private hideAnalyticsAlert = () => {
if (this.state.analyticsAlertIsVisible) {
localStorage.setItem(ANALYTICS_ALERT_VISIBILITY_KEY, 'false');
this.setState({ analyticsAlertIsVisible: false });
}
};
public async componentDidMount() {
observe(() => {
this.setState(this.stateHelper());
@ -160,6 +175,17 @@ export class MainPage extends React.Component<
this.setState({ featuredProjectURL: await this.getFeaturedProjectURL() });
}
public componentDidUpdate(
_prevProps: object,
prevState: Readonly<MainPageState & MainPageStateFromStore>,
) {
if (this.state.analyticsAlertIsVisible) {
if (prevState.hideSettings !== this.state.hideSettings) {
this.setState({ analyticsAlertIsVisible: false });
}
}
}
private renderMain() {
const state = flashState.getFlashState();
const shouldDriveStepBeDisabled = !this.state.hasImage;
@ -169,86 +195,127 @@ export class MainPage extends React.Component<
!this.state.isFlashing || !this.state.isWebviewShowing;
return (
<Flex
m={`110px ${this.state.isWebviewShowing ? 35 : 55}px`}
justifyContent="space-between"
m={`110px ${this.state.isWebviewShowing ? 35 : 55}px 18px ${this.state.isWebviewShowing ? 35 : 55}px`}
flexDirection="column"
>
{notFlashingOrSplitView && (
<>
<SourceSelector flashing={this.state.isFlashing} />
<Flex>
<StepBorder disabled={shouldDriveStepBeDisabled} left />
</Flex>
<TargetSelector
disabled={shouldDriveStepBeDisabled}
hasDrive={this.state.hasDrive}
flashing={this.state.isFlashing}
/>
<Flex>
<StepBorder disabled={shouldFlashStepBeDisabled} right />
</Flex>
</>
)}
<Flex
justifyContent="space-between"
mb={this.state.analyticsAlertIsVisible ? '0px' : '92px'}
>
{notFlashingOrSplitView && (
<>
<SourceSelector
flashing={this.state.isFlashing}
hideAnalyticsAlert={this.hideAnalyticsAlert}
/>
<Flex>
<StepBorder disabled={shouldDriveStepBeDisabled} left />
</Flex>
<TargetSelector
disabled={shouldDriveStepBeDisabled}
hasDrive={this.state.hasDrive}
flashing={this.state.isFlashing}
hideAnalyticsAlert={this.hideAnalyticsAlert}
/>
<Flex>
<StepBorder disabled={shouldFlashStepBeDisabled} right />
</Flex>
</>
)}
{this.state.isFlashing && this.state.isWebviewShowing && (
<Flex
style={{
position: 'absolute',
top: 0,
left: 0,
width: '36.2vw',
height: '100vh',
zIndex: 1,
boxShadow: '0 2px 15px 0 rgba(0, 0, 0, 0.2)',
}}
>
<ReducedFlashingInfos
imageLogo={this.state.imageLogo}
imageName={this.state.imageName}
imageSize={
typeof this.state.imageSize === 'number'
? prettyBytes(this.state.imageSize)
: ''
}
driveTitle={this.state.driveTitle}
driveLabel={this.state.driveLabel}
{this.state.isFlashing && this.state.isWebviewShowing && (
<Flex
style={{
position: 'absolute',
color: '#fff',
left: 35,
top: 72,
top: 0,
left: 0,
width: '36.2vw',
height: '100vh',
zIndex: 1,
boxShadow: '0 2px 15px 0 rgba(0, 0, 0, 0.2)',
}}
>
<ReducedFlashingInfos
imageLogo={this.state.imageLogo}
imageName={this.state.imageName}
imageSize={
typeof this.state.imageSize === 'number'
? prettyBytes(this.state.imageSize)
: ''
}
driveTitle={this.state.driveTitle}
driveLabel={this.state.driveLabel}
style={{
position: 'absolute',
color: '#fff',
left: 35,
top: 72,
}}
/>
</Flex>
)}
{this.state.isFlashing && this.state.featuredProjectURL && (
<SafeWebview
src={this.state.featuredProjectURL}
onWebviewShow={(isWebviewShowing: boolean) => {
this.setState({ isWebviewShowing });
}}
style={{
position: 'absolute',
right: 0,
bottom: 0,
width: '63.8vw',
height: '100vh',
}}
/>
</Flex>
)}
{this.state.isFlashing && this.state.featuredProjectURL && (
<SafeWebview
src={this.state.featuredProjectURL}
onWebviewShow={(isWebviewShowing: boolean) => {
this.setState({ isWebviewShowing });
}}
style={{
position: 'absolute',
right: 0,
bottom: 0,
width: '63.8vw',
height: '100vh',
}}
/>
)}
)}
<FlashStep
width={this.state.isWebviewShowing ? '220px' : '200px'}
goToSuccess={() => this.setState({ current: 'success' })}
shouldFlashStepBeDisabled={shouldFlashStepBeDisabled}
isFlashing={this.state.isFlashing}
step={state.type}
percentage={state.percentage}
position={state.position}
failed={state.failed}
speed={state.speed}
eta={state.eta}
style={{ zIndex: 1 }}
/>
<FlashStep
width={this.state.isWebviewShowing ? '220px' : '200px'}
goToSuccess={() => this.setState({ current: 'success' })}
shouldFlashStepBeDisabled={shouldFlashStepBeDisabled}
isFlashing={this.state.isFlashing}
step={state.type}
percentage={state.percentage}
position={state.position}
failed={state.failed}
speed={state.speed}
eta={state.eta}
style={{ zIndex: 1 }}
/>
</Flex>
{this.state.analyticsAlertIsVisible && (
<Alert mt="18px" style={{ boxShadow: 'none', fontSize: '12px' }}>
<Flex alignItems="center" justifyContent="space-between">
<Flex flexDirection="column">
<div>
Etcher collects a limited amount of anonymous data to help us
improve user experience. You can opt out in the{' '}
<Link onClick={() => this.setState({ hideSettings: false })}>
settings
</Link>
.
</div>
<div>
For more information about how we use this data, see our{' '}
<Link
onClick={(e) => {
e.stopPropagation();
openExternal('https://www.balena.io/privacy-policy');
}}
>
privacy policy
</Link>
.
</div>
</Flex>
{/* TODO: can we use onDismiss instead? */}
<IconButton onClick={this.hideAnalyticsAlert}>
<CloseSvg height="0.75rem" fill={theme.colors.text.main} />
</IconButton>
</Flex>
</Alert>
)}
</Flex>
);
}

View File

@ -27,7 +27,7 @@ import { promises as fs } from 'fs';
import { platform } from 'os';
import * as path from 'path';
import * as semver from 'semver';
import * as lodash from 'lodash';
import { once } from 'lodash';
import './app/i18n';
@ -37,7 +37,6 @@ import * as settings from './app/models/settings';
import { buildWindowMenu } from './menu';
import * as i18n from 'i18next';
import * as SentryMain from '@sentry/electron/main';
import * as packageJSON from '../../package.json';
import { anonymizeSentryData } from './app/modules/analytics';
import { delay } from '../shared/utils';
@ -115,12 +114,16 @@ async function getCommandLineURL(argv: string[]): Promise<string | undefined> {
}
}
const initSentryMain = lodash.once(() => {
const initSentryMain = once(() => {
const dsn =
settings.getSync('analyticsSentryToken') ||
lodash.get(packageJSON, ['analytics', 'sentry', 'token']);
settings.getSync('analyticsSentryToken') || process.env.SENTRY_TOKEN;
SentryMain.init({ dsn, beforeSend: anonymizeSentryData });
SentryMain.init({
dsn,
beforeSend: anonymizeSentryData,
debug: process.env.ETCHER_SENTRY_DEBUG === 'true',
});
console.log(SentryMain.getCurrentScope());
});
const sourceSelectorReady = new Promise((resolve) => {

35395
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
"private": true,
"displayName": "balenaEtcher",
"productName": "balenaEtcher",
"version": "1.19.14",
"version": "2.1.0",
"packageType": "local",
"main": ".webpack/main",
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
@ -40,7 +40,7 @@
"drivelist": "^12.0.2",
"electron-squirrel-startup": "^1.0.0",
"electron-updater": "6.1.8",
"etcher-sdk": "9.0.9",
"etcher-sdk": "9.1.2",
"i18next": "23.11.2",
"immutable": "3.8.2",
"lodash": "4.17.21",
@ -106,8 +106,6 @@
},
"hostDependencies": {
"debian": [
"gconf-service",
"gconf2",
"libasound2",
"libatk1.0-0",
"libc6",
@ -119,7 +117,6 @@
"libfreetype6",
"libgbm1",
"libgcc1",
"libgconf-2-4",
"libgdk-pixbuf2.0-0",
"libglib2.0-0",
"libgtk-3-0",
@ -147,10 +144,11 @@
"node": ">=20 <21"
},
"versionist": {
"publishedAt": "2024-04-25T21:11:35.832Z"
"publishedAt": "2025-02-27T16:16:57.534Z"
},
"optionalDependencies": {
"bufferutil": "^4.0.8",
"utf-8-validate": "^5.0.10"
"utf-8-validate": "^5.0.10",
"winusb-driver-generator": "2.1.2"
}
}

View File

@ -17,29 +17,7 @@
import type { Configuration, ModuleOptions } from 'webpack';
import { resolve } from 'path';
import {
BannerPlugin,
IgnorePlugin,
NormalModuleReplacementPlugin,
} from 'webpack';
interface ReplacementRule {
search: string;
replace: string | (() => string);
}
function slashOrAntislash(pattern: RegExp): RegExp {
return new RegExp(pattern.source.replace(/\\\//g, '(\\/|\\\\)'));
}
function replace(test: RegExp, ...replacements: ReplacementRule[]) {
return {
loader: 'string-replace-loader',
// Handle windows path separators
test: slashOrAntislash(test),
options: { multiple: replacements.map((r) => ({ ...r, strict: true })) },
};
}
import { BannerPlugin, IgnorePlugin, DefinePlugin } from 'webpack';
const rules: Required<ModuleOptions>['rules'] = [
// Add support for native node modules
@ -81,24 +59,20 @@ const rules: Required<ModuleOptions>['rules'] = [
test: /\.svg$/,
use: '@svgr/webpack',
},
// force axios to use http backend (not xhr) to support streams
replace(/node_modules\/axios\/lib\/defaults\.js$/, {
search: './adapters/xhr',
replace: './adapters/http',
}),
];
const injectAnalyticsToken = new DefinePlugin({
'process.env.SENTRY_TOKEN': JSON.stringify(process.env.SENTRY_TOKEN || ''),
'process.env.AMPLITUDE_TOKEN': JSON.stringify(
process.env.AMPLITUDE_TOKEN || '',
),
});
export const rendererConfig: Configuration = {
module: {
rules,
},
plugins: [
// Force axios to use http.js, not xhr.js as we need stream support
// (its package.json file replaces http with xhr for browser targets).
new NormalModuleReplacementPlugin(
slashOrAntislash(/node_modules\/axios\/lib\/adapters\/xhr\.js/),
'./http.js',
),
// Ignore `aws-crt` which is a dependency of (ultimately) `aws4-axios` which is used
// by etcher-sdk and does a runtime check to its availability. Were not currently
// using the “assume role” functionality (AFAIU) of aws4-axios and we dont care that
@ -112,6 +86,7 @@ export const rendererConfig: Configuration = {
banner: '__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };',
raw: true,
}),
injectAnalyticsToken,
],
resolve: {
@ -133,4 +108,5 @@ export const mainConfig: Configuration = {
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css', '.json'],
},
plugins: [injectAnalyticsToken],
};