Merge pull request #3590 from balena-io/various-fixes

Various fixes
This commit is contained in:
bulldozer-balena[bot] 2021-09-02 14:46:26 +00:00 committed by GitHub
commit 3ece1fd841
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 95 additions and 28 deletions

View File

@ -91,8 +91,6 @@ zypper rr balena-etcher-source
```sh ```sh
sudo dnf install -y balena-etcher-electron sudo dnf install -y balena-etcher-electron
rm /etc/yum.repos.d/balena-etcher.repo
rm /etc/yum.repos.d/balena-etcher-source.repo
``` ```
###### Uninstall ###### Uninstall

View File

@ -1,5 +1,5 @@
Getting help with Etcher Getting help with BalenaEtcher
======================== ===============================
There are various ways to get support for Etcher if you experience an issue or There are various ways to get support for Etcher if you experience an issue or
have an idea you'd like to share with us. have an idea you'd like to share with us.
@ -22,7 +22,7 @@ a look at the existing threads before opening a new one!
Make sure to mention the following information to help us provide better Make sure to mention the following information to help us provide better
support: support:
- The Etcher version you're running. - The BalenaEtcher version you're running.
- The operating system you're running Etcher in. - The operating system you're running Etcher in.
@ -32,7 +32,7 @@ support:
GitHub GitHub
------ ------
If you encounter an issue or have a suggestion, head on over to Etcher's [issue If you encounter an issue or have a suggestion, head on over to BalenaEtcher's [issue
tracker][issues] and if there isn't a ticket covering it, [create tracker][issues] and if there isn't a ticket covering it, [create
one][new-issue]. one][new-issue].

View File

@ -91,7 +91,7 @@ make electron-develop
```sh ```sh
# Build the GUI # Build the GUI
make webpack npm run webpack
# Start Electron # Start Electron
npm start npm start
``` ```

View File

@ -159,6 +159,18 @@ pre-installed in all modern Windows versions.
- Run `clean`. This command will completely clean your drive by erasing any - Run `clean`. This command will completely clean your drive by erasing any
existent filesystem. existent filesystem.
- Run `create partition primary`. This command will create a new partition.
- Run `active`. This command will active the partition.
- Run `list partition`. This command will show available partition.
- Run `select partition N`, where `N` corresponds to the id of the newly available partition.
- Run `format override quick`. This command will format the partition. You can choose a specific formatting by adding `FS=xx` where `xx` could be `NTFS or FAT or FAT32` after `format`. Example : `format FS=NTFS override quick`
- Run `exit` to quit diskpart.
### OS X ### OS X

View File

@ -61,6 +61,7 @@ import ImageSvg from '../../../assets/image.svg';
import SrcSvg from '../../../assets/src.svg'; import SrcSvg from '../../../assets/src.svg';
import { DriveSelector } from '../drive-selector/drive-selector'; import { DriveSelector } from '../drive-selector/drive-selector';
import { DrivelistDrive } from '../../../../shared/drive-constraints'; import { DrivelistDrive } from '../../../../shared/drive-constraints';
import axios, { AxiosRequestConfig } from 'axios';
const recentUrlImagesKey = 'recentUrlImages'; const recentUrlImagesKey = 'recentUrlImages';
@ -279,6 +280,7 @@ interface SourceSelectorState {
showDriveSelector: boolean; showDriveSelector: boolean;
defaultFlowActive: boolean; defaultFlowActive: boolean;
imageSelectorOpen: boolean; imageSelectorOpen: boolean;
imageLoading: boolean;
} }
export class SourceSelector extends React.Component< export class SourceSelector extends React.Component<
@ -297,6 +299,7 @@ export class SourceSelector extends React.Component<
showDriveSelector: false, showDriveSelector: false,
defaultFlowActive: true, defaultFlowActive: true,
imageSelectorOpen: false, imageSelectorOpen: false,
imageLoading: false,
}; };
// Bind `this` since it's used in an event's callback // Bind `this` since it's used in an event's callback
@ -317,10 +320,12 @@ export class SourceSelector extends React.Component<
} }
private async onSelectImage(_event: IpcRendererEvent, imagePath: string) { private async onSelectImage(_event: IpcRendererEvent, imagePath: string) {
this.setState({ imageLoading: true });
await this.selectSource( await this.selectSource(
imagePath, imagePath,
isURL(imagePath) ? sourceDestination.Http : sourceDestination.File, isURL(imagePath) ? sourceDestination.Http : sourceDestination.File,
).promise; ).promise;
this.setState({ imageLoading: false });
} }
private async createSource(selected: string, SourceType: Source) { private async createSource(selected: string, SourceType: Source) {
@ -330,14 +335,34 @@ export class SourceSelector extends React.Component<
analytics.logException(error); analytics.logException(error);
} }
if (this.isJson(decodeURIComponent(selected))) {
const config: AxiosRequestConfig = JSON.parse(
decodeURIComponent(selected),
);
return new sourceDestination.Http({
url: config.url!,
axiosInstance: axios.create(_.omit(config, ['url'])),
});
}
if (SourceType === sourceDestination.File) { if (SourceType === sourceDestination.File) {
return new sourceDestination.File({ return new sourceDestination.File({
path: selected, path: selected,
}); });
} }
return new sourceDestination.Http({ url: selected }); return new sourceDestination.Http({ url: selected });
} }
public isJson(jsonString: string) {
try {
JSON.parse(jsonString);
} catch (e) {
return false;
}
return true;
}
private reselectSource() { private reselectSource() {
analytics.logEvent('Reselect image', { analytics.logEvent('Reselect image', {
previousImage: selectionState.getImage(), previousImage: selectionState.getImage(),
@ -395,7 +420,7 @@ export class SourceSelector extends React.Component<
} }
metadata.SourceType = SourceType; metadata.SourceType = SourceType;
if (!metadata.hasMBR) { if (!metadata.hasMBR && this.state.warning === null) {
analytics.logEvent('Missing partition table', { metadata }); analytics.logEvent('Missing partition table', { metadata });
this.setState({ this.setState({
warning: { warning: {
@ -567,7 +592,12 @@ export class SourceSelector extends React.Component<
// TODO add a visual change when dragging a file over the selector // TODO add a visual change when dragging a file over the selector
public render() { public render() {
const { flashing } = this.props; const { flashing } = this.props;
const { showImageDetails, showURLSelector, showDriveSelector } = this.state; const {
showImageDetails,
showURLSelector,
showDriveSelector,
imageLoading,
} = this.state;
const selectionImage = selectionState.getImage(); const selectionImage = selectionState.getImage();
let image: SourceMetadata | DrivelistDrive = let image: SourceMetadata | DrivelistDrive =
selectionImage !== undefined ? selectionImage : ({} as SourceMetadata); selectionImage !== undefined ? selectionImage : ({} as SourceMetadata);
@ -605,16 +635,18 @@ export class SourceSelector extends React.Component<
}} }}
/> />
{selectionImage !== undefined ? ( {selectionImage !== undefined || imageLoading ? (
<> <>
<StepNameButton <StepNameButton
plain plain
onClick={() => this.showSelectedImageDetails()} onClick={() => this.showSelectedImageDetails()}
tooltip={imageName || imageBasename} tooltip={imageName || imageBasename}
> >
{middleEllipsis(imageName || imageBasename, 20)} <Spinner show={imageLoading}>
{middleEllipsis(imageName || imageBasename, 20)}
</Spinner>
</StepNameButton> </StepNameButton>
{!flashing && ( {!flashing && !imageLoading && (
<ChangeButton <ChangeButton
plain plain
mb={14} mb={14}
@ -623,7 +655,7 @@ export class SourceSelector extends React.Component<
Remove Remove
</ChangeButton> </ChangeButton>
)} )}
{!_.isNil(imageSize) && ( {!_.isNil(imageSize) && !imageLoading && (
<DetailsText>{prettyBytes(imageSize)}</DetailsText> <DetailsText>{prettyBytes(imageSize)}</DetailsText>
)} )}
</> </>

View File

@ -17,21 +17,24 @@
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Animator, AnimationFunction, Color, RGBLed } from 'sys-class-rgb-led'; import { Animator, AnimationFunction, Color, RGBLed } from 'sys-class-rgb-led';
import { DrivelistDrive } from '../../../shared/drive-constraints'; import {
DrivelistDrive,
isSourceDrive,
} from '../../../shared/drive-constraints';
import { getDrives } from './available-drives'; import { getDrives } from './available-drives';
import { getImage, getSelectedDrives } from './selection-state'; import { getSelectedDrives } from './selection-state';
import * as settings from './settings'; import * as settings from './settings';
import { observe, store } from './store'; import { observe, store } from './store';
const leds: Map<string, RGBLed> = new Map(); const leds: Map<string, RGBLed> = new Map();
const animator = new Animator([], 10); const animator = new Animator([], 10);
const red: Color = [0.59, 0, 0]; const red: Color = [0.78, 0, 0];
const green: Color = [0, 0.59, 0]; const green: Color = [0, 0.58, 0];
const blue: Color = [0, 0, 0.59]; const blue: Color = [0, 0, 0.1];
const white: Color = [0.04, 0.04, 0.04]; const purple: Color = [0.7, 0, 0.78];
const white: Color = [0.7, 0.7, 0.7];
const black: Color = [0, 0, 0]; const black: Color = [0, 0, 0];
const purple: Color = [0.117, 0, 0.196];
function createAnimationFunction( function createAnimationFunction(
intensityFunction: (t: number) => number, intensityFunction: (t: number) => number,
@ -172,7 +175,9 @@ function stateObserver() {
const availableDrives = getDrives().filter( const availableDrives = getDrives().filter(
(d: DrivelistDrive) => d.devicePath, (d: DrivelistDrive) => d.devicePath,
); );
const sourceDrivePath = getImage()?.drive?.devicePath; const sourceDrivePath = availableDrives.filter((d: DrivelistDrive) =>
isSourceDrive(d, s.selection.image),
)[0]?.devicePath;
const availableDrivesPaths = availableDrives.map( const availableDrivesPaths = availableDrives.map(
(d: DrivelistDrive) => d.devicePath, (d: DrivelistDrive) => d.devicePath,
); );

21
npm-shrinkwrap.json generated
View File

@ -3535,11 +3535,11 @@
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"dev": true,
"requires": { "requires": {
"base64-js": "^1.3.1", "base64-js": "^1.3.1",
"ieee754": "^1.1.13" "ieee754": "^1.1.13"
} },
"dev": true
}, },
"buffer-alloc": { "buffer-alloc": {
"version": "1.2.0", "version": "1.2.0",
@ -11635,6 +11635,15 @@
"semver-compare": "^1.0.0" "semver-compare": "^1.0.0"
} }
}, },
"pnp-webpack-plugin": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz",
"integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==",
"dev": true,
"requires": {
"ts-pnp": "^1.1.6"
}
},
"polished": { "polished": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/polished/-/polished-3.7.0.tgz", "resolved": "https://registry.npmjs.org/polished/-/polished-3.7.0.tgz",
@ -14818,6 +14827,12 @@
"yn": "3.1.1" "yn": "3.1.1"
} }
}, },
"ts-pnp": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
"integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==",
"dev": true
},
"tslib": { "tslib": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
@ -16828,4 +16843,4 @@
"dev": true "dev": true
} }
} }
} }

View File

@ -15,8 +15,7 @@
"scripts": { "scripts": {
"lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts", "lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts",
"lint-css": "prettier --write lib/**/*.css", "lint-css": "prettier --write lib/**/*.css",
"lint-spell": "codespell --dictionary - --dictionary dictionary.txt --skip *.ttf *.svg *.gz,*.bz2,*.xz,*.zip,*.img,*.dmg,*.iso,*.rpi-sdcard,*.wic,.DS_Store,*.dtb,*.dtbo,*.dat,*.elf,*.bin,*.foo,xz-without-extension lib tests docs Makefile *.md LICENSE", "lint": "npm run lint-ts && npm run lint-css",
"lint": "npm run lint-ts && npm run lint-css && npm run lint-spell",
"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-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-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-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",
@ -99,6 +98,7 @@
"omit-deep-lodash": "1.1.4", "omit-deep-lodash": "1.1.4",
"outdent": "^0.7.1", "outdent": "^0.7.1",
"path-is-inside": "^1.0.2", "path-is-inside": "^1.0.2",
"pnp-webpack-plugin": "^1.6.4",
"pretty-bytes": "^5.3.0", "pretty-bytes": "^5.3.0",
"react": "^16.8.5", "react": "^16.8.5",
"react-dom": "^16.8.5", "react-dom": "^16.8.5",

View File

@ -1,3 +1,2 @@
codespell==1.12.0
awscli==1.11.87 awscli==1.11.87
shyaml==0.5.0 shyaml==0.5.0

@ -1 +1 @@
Subproject commit d1b05ad312e65ea82b1c16b31f5af3c0b5fa2777 Subproject commit 8dfa21cfc23b1dbc0eaa22b5dbdf1f5c796b0c2c

1
typings/pnp-webpack-plugin/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'pnp-webpack-plugin';

View File

@ -24,6 +24,7 @@ import { env } from 'process';
import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin'; import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin';
import * as TerserPlugin from 'terser-webpack-plugin'; import * as TerserPlugin from 'terser-webpack-plugin';
import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack'; import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack';
import * as PnpWebpackPlugin from 'pnp-webpack-plugin';
/** /**
* Don't webpack package.json as mixpanel & sentry tokens * Don't webpack package.json as mixpanel & sentry tokens
@ -293,6 +294,7 @@ const commonConfig = {
extensions: ['.node', '.js', '.json', '.ts', '.tsx'], extensions: ['.node', '.js', '.json', '.ts', '.tsx'],
}, },
plugins: [ plugins: [
PnpWebpackPlugin,
new SimpleProgressWebpackPlugin({ new SimpleProgressWebpackPlugin({
format: process.env.WEBPACK_PROGRESS || 'verbose', format: process.env.WEBPACK_PROGRESS || 'verbose',
}), }),
@ -303,6 +305,9 @@ const commonConfig = {
'./http.js', './http.js',
), ),
], ],
resolveLoader: {
plugins: [PnpWebpackPlugin.moduleLoader(module)],
},
output: { output: {
path: path.join(__dirname, 'generated'), path: path.join(__dirname, 'generated'),
filename: '[name].js', filename: '[name].js',