diff --git a/README.md b/README.md index 1c0a8999..d8f2a2be 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,6 @@ zypper rr balena-etcher-source ```sh 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 diff --git a/SUPPORT.md b/SUPPORT.md index f276a8cd..7aee98f5 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -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 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 support: -- The Etcher version you're running. +- The BalenaEtcher version you're running. - The operating system you're running Etcher in. @@ -32,7 +32,7 @@ support: 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 one][new-issue]. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index a721b35b..7dc1fc76 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -91,7 +91,7 @@ make electron-develop ```sh # Build the GUI -make webpack +npm run webpack # Start Electron npm start ``` diff --git a/docs/USER-DOCUMENTATION.md b/docs/USER-DOCUMENTATION.md index 0fa329ed..47b9f3c4 100644 --- a/docs/USER-DOCUMENTATION.md +++ b/docs/USER-DOCUMENTATION.md @@ -159,6 +159,18 @@ pre-installed in all modern Windows versions. - Run `clean`. This command will completely clean your drive by erasing any 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 diff --git a/lib/gui/app/components/source-selector/source-selector.tsx b/lib/gui/app/components/source-selector/source-selector.tsx index f669b891..50902ed6 100644 --- a/lib/gui/app/components/source-selector/source-selector.tsx +++ b/lib/gui/app/components/source-selector/source-selector.tsx @@ -61,6 +61,7 @@ import ImageSvg from '../../../assets/image.svg'; import SrcSvg from '../../../assets/src.svg'; import { DriveSelector } from '../drive-selector/drive-selector'; import { DrivelistDrive } from '../../../../shared/drive-constraints'; +import axios, { AxiosRequestConfig } from 'axios'; const recentUrlImagesKey = 'recentUrlImages'; @@ -279,6 +280,7 @@ interface SourceSelectorState { showDriveSelector: boolean; defaultFlowActive: boolean; imageSelectorOpen: boolean; + imageLoading: boolean; } export class SourceSelector extends React.Component< @@ -297,6 +299,7 @@ export class SourceSelector extends React.Component< showDriveSelector: false, defaultFlowActive: true, imageSelectorOpen: false, + imageLoading: false, }; // 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) { + this.setState({ imageLoading: true }); await this.selectSource( imagePath, isURL(imagePath) ? sourceDestination.Http : sourceDestination.File, ).promise; + this.setState({ imageLoading: false }); } private async createSource(selected: string, SourceType: Source) { @@ -330,14 +335,34 @@ export class SourceSelector extends React.Component< 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) { return new sourceDestination.File({ path: selected, }); } + return new sourceDestination.Http({ url: selected }); } + public isJson(jsonString: string) { + try { + JSON.parse(jsonString); + } catch (e) { + return false; + } + return true; + } + private reselectSource() { analytics.logEvent('Reselect image', { previousImage: selectionState.getImage(), @@ -395,7 +420,7 @@ export class SourceSelector extends React.Component< } metadata.SourceType = SourceType; - if (!metadata.hasMBR) { + if (!metadata.hasMBR && this.state.warning === null) { analytics.logEvent('Missing partition table', { metadata }); this.setState({ warning: { @@ -567,7 +592,12 @@ export class SourceSelector extends React.Component< // TODO add a visual change when dragging a file over the selector public render() { const { flashing } = this.props; - const { showImageDetails, showURLSelector, showDriveSelector } = this.state; + const { + showImageDetails, + showURLSelector, + showDriveSelector, + imageLoading, + } = this.state; const selectionImage = selectionState.getImage(); let image: SourceMetadata | DrivelistDrive = selectionImage !== undefined ? selectionImage : ({} as SourceMetadata); @@ -605,16 +635,18 @@ export class SourceSelector extends React.Component< }} /> - {selectionImage !== undefined ? ( + {selectionImage !== undefined || imageLoading ? ( <> this.showSelectedImageDetails()} tooltip={imageName || imageBasename} > - {middleEllipsis(imageName || imageBasename, 20)} + + {middleEllipsis(imageName || imageBasename, 20)} + - {!flashing && ( + {!flashing && !imageLoading && ( )} - {!_.isNil(imageSize) && ( + {!_.isNil(imageSize) && !imageLoading && ( {prettyBytes(imageSize)} )} diff --git a/lib/gui/app/models/leds.ts b/lib/gui/app/models/leds.ts index d9bce75f..85940055 100644 --- a/lib/gui/app/models/leds.ts +++ b/lib/gui/app/models/leds.ts @@ -17,21 +17,24 @@ import * as _ from 'lodash'; 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 { getImage, getSelectedDrives } from './selection-state'; +import { getSelectedDrives } from './selection-state'; import * as settings from './settings'; import { observe, store } from './store'; const leds: Map = new Map(); const animator = new Animator([], 10); -const red: Color = [0.59, 0, 0]; -const green: Color = [0, 0.59, 0]; -const blue: Color = [0, 0, 0.59]; -const white: Color = [0.04, 0.04, 0.04]; +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]; -const purple: Color = [0.117, 0, 0.196]; function createAnimationFunction( intensityFunction: (t: number) => number, @@ -172,7 +175,9 @@ function stateObserver() { const availableDrives = getDrives().filter( (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( (d: DrivelistDrive) => d.devicePath, ); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 4dc4b80b..0e6a88e0 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -3535,11 +3535,11 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" - } + }, + "dev": true }, "buffer-alloc": { "version": "1.2.0", @@ -11635,6 +11635,15 @@ "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": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/polished/-/polished-3.7.0.tgz", @@ -14818,6 +14827,12 @@ "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": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", @@ -16828,4 +16843,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 04cdfd90..d2fb112a 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,7 @@ "scripts": { "lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts", "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 && npm run lint-spell", + "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", @@ -99,6 +98,7 @@ "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", diff --git a/requirements.txt b/requirements.txt index 408dc896..3f33e5f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ -codespell==1.12.0 awscli==1.11.87 shyaml==0.5.0 diff --git a/scripts/resin b/scripts/resin index d1b05ad3..8dfa21cf 160000 --- a/scripts/resin +++ b/scripts/resin @@ -1 +1 @@ -Subproject commit d1b05ad312e65ea82b1c16b31f5af3c0b5fa2777 +Subproject commit 8dfa21cfc23b1dbc0eaa22b5dbdf1f5c796b0c2c diff --git a/typings/pnp-webpack-plugin/index.d.ts b/typings/pnp-webpack-plugin/index.d.ts new file mode 100644 index 00000000..72019fa9 --- /dev/null +++ b/typings/pnp-webpack-plugin/index.d.ts @@ -0,0 +1 @@ +declare module 'pnp-webpack-plugin'; diff --git a/webpack.config.ts b/webpack.config.ts index 8f880f12..4ba7cca0 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -24,6 +24,7 @@ import { env } from 'process'; import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin'; import * as TerserPlugin from 'terser-webpack-plugin'; import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack'; +import * as PnpWebpackPlugin from 'pnp-webpack-plugin'; /** * Don't webpack package.json as mixpanel & sentry tokens @@ -293,6 +294,7 @@ const commonConfig = { extensions: ['.node', '.js', '.json', '.ts', '.tsx'], }, plugins: [ + PnpWebpackPlugin, new SimpleProgressWebpackPlugin({ format: process.env.WEBPACK_PROGRESS || 'verbose', }), @@ -303,6 +305,9 @@ const commonConfig = { './http.js', ), ], + resolveLoader: { + plugins: [PnpWebpackPlugin.moduleLoader(module)], + }, output: { path: path.join(__dirname, 'generated'), filename: '[name].js',