mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-29 14:16:36 +00:00
commit
12cd8a39c1
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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 * as React from 'react';
|
||||
|
||||
import * as settings from '../../models/settings';
|
||||
import * as analytics from '../../modules/analytics';
|
||||
import { SafeWebview } from '../safe-webview/safe-webview';
|
||||
|
||||
interface FeaturedProjectProps {
|
||||
shouldShow: boolean;
|
||||
onWebviewShow: (isWebviewShowing: boolean) => void;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
interface FeaturedProjectState {
|
||||
endpoint: string | null;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export class FeaturedProject extends React.Component<
|
||||
FeaturedProjectProps,
|
||||
FeaturedProjectState
|
||||
> {
|
||||
constructor(props: FeaturedProjectProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
endpoint: null,
|
||||
show: false,
|
||||
};
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
try {
|
||||
const url = new URL(
|
||||
(await settings.get('featuredProjectEndpoint')) ||
|
||||
'https://assets.balena.io/etcher-featured/index.html',
|
||||
);
|
||||
url.searchParams.append('borderRight', 'false');
|
||||
url.searchParams.append('darkBackground', 'true');
|
||||
this.setState({ endpoint: url.toString() });
|
||||
} catch (error) {
|
||||
analytics.logException(error);
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { style = {} } = this.props;
|
||||
return this.state.endpoint ? (
|
||||
<SafeWebview
|
||||
src={this.state.endpoint}
|
||||
style={{
|
||||
display: this.state.show ? 'block' : 'none',
|
||||
...style,
|
||||
}}
|
||||
{...this.props}
|
||||
></SafeWebview>
|
||||
) : null;
|
||||
}
|
||||
}
|
@ -58,8 +58,6 @@ const API_VERSION = '2';
|
||||
interface SafeWebviewProps {
|
||||
// The website source URL
|
||||
src: string;
|
||||
// @summary Refresh the webview
|
||||
refreshNow?: boolean;
|
||||
// Webview lifecycle event
|
||||
onWebviewShow?: (isWebviewShowing: boolean) => void;
|
||||
style?: React.CSSProperties;
|
||||
|
@ -30,6 +30,7 @@ import {
|
||||
Txt,
|
||||
Card as BaseCard,
|
||||
Input,
|
||||
Spinner,
|
||||
} from 'rendition';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@ -137,8 +138,9 @@ const URLSelector = ({
|
||||
<Modal
|
||||
cancel={cancel}
|
||||
primaryButtonProps={{
|
||||
className: loading || !imageURL ? 'disabled' : '',
|
||||
disabled: loading || !imageURL,
|
||||
}}
|
||||
action={loading ? <Spinner /> : 'OK'}
|
||||
done={async () => {
|
||||
setLoading(true);
|
||||
const urlStrings = recentImages.map((url: URL) => url.href);
|
||||
@ -288,7 +290,7 @@ export class SourceSelector extends React.Component<
|
||||
await this.selectImageByPath({
|
||||
imagePath,
|
||||
SourceType: isURL ? sourceDestination.Http : sourceDestination.File,
|
||||
});
|
||||
}).promise;
|
||||
}
|
||||
|
||||
private reselectImage() {
|
||||
@ -344,74 +346,97 @@ export class SourceSelector extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
private async selectImageByPath({ imagePath, SourceType }: SourceOptions) {
|
||||
try {
|
||||
imagePath = await replaceWindowsNetworkDriveLetter(imagePath);
|
||||
} catch (error) {
|
||||
analytics.logException(error);
|
||||
}
|
||||
private selectImageByPath({
|
||||
imagePath,
|
||||
SourceType,
|
||||
}: SourceOptions): { promise: Promise<void>; cancel: () => void } {
|
||||
let cancelled = false;
|
||||
return {
|
||||
cancel: () => {
|
||||
cancelled = true;
|
||||
},
|
||||
promise: (async () => {
|
||||
try {
|
||||
imagePath = await replaceWindowsNetworkDriveLetter(imagePath);
|
||||
} catch (error) {
|
||||
analytics.logException(error);
|
||||
}
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let source;
|
||||
if (SourceType === sourceDestination.File) {
|
||||
source = new sourceDestination.File({
|
||||
path: imagePath,
|
||||
});
|
||||
} else {
|
||||
if (
|
||||
!imagePath.startsWith('https://') &&
|
||||
!imagePath.startsWith('http://')
|
||||
) {
|
||||
const invalidImageError = errors.createUserError({
|
||||
title: 'Unsupported protocol',
|
||||
description: messages.error.unsupportedProtocol(),
|
||||
});
|
||||
let source;
|
||||
if (SourceType === sourceDestination.File) {
|
||||
source = new sourceDestination.File({
|
||||
path: imagePath,
|
||||
});
|
||||
} else {
|
||||
if (
|
||||
!imagePath.startsWith('https://') &&
|
||||
!imagePath.startsWith('http://')
|
||||
) {
|
||||
const invalidImageError = errors.createUserError({
|
||||
title: 'Unsupported protocol',
|
||||
description: messages.error.unsupportedProtocol(),
|
||||
});
|
||||
|
||||
osDialog.showError(invalidImageError);
|
||||
analytics.logEvent('Unsupported protocol', { path: imagePath });
|
||||
return;
|
||||
}
|
||||
source = new sourceDestination.Http({ url: imagePath });
|
||||
}
|
||||
osDialog.showError(invalidImageError);
|
||||
analytics.logEvent('Unsupported protocol', { path: imagePath });
|
||||
return;
|
||||
}
|
||||
source = new sourceDestination.Http({ url: imagePath });
|
||||
}
|
||||
|
||||
try {
|
||||
const innerSource = await source.getInnerSource();
|
||||
const metadata = (await innerSource.getMetadata()) as sourceDestination.Metadata & {
|
||||
hasMBR: boolean;
|
||||
partitions: MBRPartition[] | GPTPartition[];
|
||||
path: string;
|
||||
extension: string;
|
||||
};
|
||||
const partitionTable = await innerSource.getPartitionTable();
|
||||
if (partitionTable) {
|
||||
metadata.hasMBR = true;
|
||||
metadata.partitions = partitionTable.partitions;
|
||||
} else {
|
||||
metadata.hasMBR = false;
|
||||
}
|
||||
metadata.path = imagePath;
|
||||
metadata.extension = path.extname(imagePath).slice(1);
|
||||
this.selectImage(metadata);
|
||||
this.afterSelected({
|
||||
imagePath,
|
||||
SourceType,
|
||||
});
|
||||
} catch (error) {
|
||||
const imageError = errors.createUserError({
|
||||
title: 'Error opening image',
|
||||
description: messages.error.openImage(
|
||||
path.basename(imagePath),
|
||||
error.message,
|
||||
),
|
||||
});
|
||||
osDialog.showError(imageError);
|
||||
analytics.logException(error);
|
||||
} finally {
|
||||
try {
|
||||
await source.close();
|
||||
} catch (error) {
|
||||
// Noop
|
||||
}
|
||||
}
|
||||
try {
|
||||
const innerSource = await source.getInnerSource();
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
const metadata = (await innerSource.getMetadata()) as sourceDestination.Metadata & {
|
||||
hasMBR: boolean;
|
||||
partitions: MBRPartition[] | GPTPartition[];
|
||||
path: string;
|
||||
extension: string;
|
||||
};
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
const partitionTable = await innerSource.getPartitionTable();
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
if (partitionTable) {
|
||||
metadata.hasMBR = true;
|
||||
metadata.partitions = partitionTable.partitions;
|
||||
} else {
|
||||
metadata.hasMBR = false;
|
||||
}
|
||||
metadata.path = imagePath;
|
||||
metadata.extension = path.extname(imagePath).slice(1);
|
||||
this.selectImage(metadata);
|
||||
this.afterSelected({
|
||||
imagePath,
|
||||
SourceType,
|
||||
});
|
||||
} catch (error) {
|
||||
const imageError = errors.createUserError({
|
||||
title: 'Error opening image',
|
||||
description: messages.error.openImage(
|
||||
path.basename(imagePath),
|
||||
error.message,
|
||||
),
|
||||
});
|
||||
osDialog.showError(imageError);
|
||||
analytics.logException(error);
|
||||
} finally {
|
||||
try {
|
||||
await source.close();
|
||||
} catch (error) {
|
||||
// Noop
|
||||
}
|
||||
}
|
||||
})(),
|
||||
};
|
||||
}
|
||||
|
||||
private async openImageSelector() {
|
||||
@ -425,22 +450,22 @@ export class SourceSelector extends React.Component<
|
||||
analytics.logEvent('Image selector closed');
|
||||
return;
|
||||
}
|
||||
this.selectImageByPath({
|
||||
await this.selectImageByPath({
|
||||
imagePath,
|
||||
SourceType: sourceDestination.File,
|
||||
});
|
||||
}).promise;
|
||||
} catch (error) {
|
||||
exceptionReporter.report(error);
|
||||
}
|
||||
}
|
||||
|
||||
private onDrop(event: React.DragEvent<HTMLDivElement>) {
|
||||
private async onDrop(event: React.DragEvent<HTMLDivElement>) {
|
||||
const [file] = event.dataTransfer.files;
|
||||
if (file) {
|
||||
this.selectImageByPath({
|
||||
await this.selectImageByPath({
|
||||
imagePath: file.path,
|
||||
SourceType: sourceDestination.File,
|
||||
});
|
||||
}).promise;
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,6 +509,9 @@ export class SourceSelector extends React.Component<
|
||||
const imageName = selectionState.getImageName();
|
||||
const imageSize = selectionState.getImageSize();
|
||||
const imageLogo = selectionState.getImageLogo();
|
||||
let cancelURLSelection = () => {
|
||||
// noop
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -585,6 +613,7 @@ export class SourceSelector extends React.Component<
|
||||
{showURLSelector && (
|
||||
<URLSelector
|
||||
cancel={() => {
|
||||
cancelURLSelection();
|
||||
this.setState({
|
||||
showURLSelector: false,
|
||||
});
|
||||
@ -594,16 +623,17 @@ export class SourceSelector extends React.Component<
|
||||
// if no file was resolved from the dialog.
|
||||
if (!imageURL) {
|
||||
analytics.logEvent('URL selector closed');
|
||||
this.setState({
|
||||
showURLSelector: false,
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
let promise;
|
||||
({
|
||||
promise,
|
||||
cancel: cancelURLSelection,
|
||||
} = this.selectImageByPath({
|
||||
imagePath: imageURL,
|
||||
SourceType: sourceDestination.Http,
|
||||
}));
|
||||
await promise;
|
||||
}
|
||||
|
||||
await this.selectImageByPath({
|
||||
imagePath: imageURL,
|
||||
SourceType: sourceDestination.Http,
|
||||
});
|
||||
this.setState({
|
||||
showURLSelector: false,
|
||||
});
|
||||
|
@ -49,11 +49,6 @@ body {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* Allow window to be dragged from header */
|
||||
#app-header {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
/* Prevent blue outline */
|
||||
a:focus,
|
||||
input:focus,
|
||||
|
@ -146,7 +146,6 @@ interface FlashStepProps {
|
||||
goToSuccess: () => void;
|
||||
source: SourceOptions;
|
||||
isFlashing: boolean;
|
||||
isWebviewShowing: boolean;
|
||||
style?: React.CSSProperties;
|
||||
// TODO: factorize
|
||||
step: 'decompressing' | 'flashing' | 'verifying';
|
||||
|
@ -24,7 +24,6 @@ import * as React from 'react';
|
||||
import { Flex } from 'rendition';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { FeaturedProject } from '../../components/featured-project/featured-project';
|
||||
import FinishPage from '../../components/finish/finish';
|
||||
import { ReducedFlashingInfos } from '../../components/reduced-flashing-infos/reduced-flashing-infos';
|
||||
import { SafeWebview } from '../../components/safe-webview/safe-webview';
|
||||
@ -114,6 +113,7 @@ interface MainPageState {
|
||||
isWebviewShowing: boolean;
|
||||
hideSettings: boolean;
|
||||
source: SourceOptions;
|
||||
featuredProjectURL?: string;
|
||||
}
|
||||
|
||||
export class MainPage extends React.Component<
|
||||
@ -147,10 +147,21 @@ export class MainPage extends React.Component<
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
private async getFeaturedProjectURL() {
|
||||
const url = new URL(
|
||||
(await settings.get('featuredProjectEndpoint')) ||
|
||||
'https://assets.balena.io/etcher-featured/index.html',
|
||||
);
|
||||
url.searchParams.append('borderRight', 'false');
|
||||
url.searchParams.append('darkBackground', 'true');
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
observe(() => {
|
||||
this.setState(this.stateHelper());
|
||||
});
|
||||
this.setState({ featuredProjectURL: await this.getFeaturedProjectURL() });
|
||||
}
|
||||
|
||||
private renderMain() {
|
||||
@ -163,41 +174,42 @@ export class MainPage extends React.Component<
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
id="app-header"
|
||||
justifyContent="center"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
paddingTop="14px"
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '50px',
|
||||
padding: '13px 14px',
|
||||
textAlign: 'center',
|
||||
// Allow window to be dragged from header
|
||||
// @ts-ignore
|
||||
'-webkit-app-region': 'drag',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<EtcherSvg
|
||||
width="123px"
|
||||
height="22px"
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
onClick={() =>
|
||||
openExternal('https://www.balena.io/etcher?ref=etcher_footer')
|
||||
}
|
||||
tabIndex={100}
|
||||
/>
|
||||
<Flex width="100%" />
|
||||
<Flex width="100%" alignItems="center" justifyContent="center">
|
||||
<EtcherSvg
|
||||
width="123px"
|
||||
height="22px"
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
onClick={() =>
|
||||
openExternal('https://www.balena.io/etcher?ref=etcher_footer')
|
||||
}
|
||||
tabIndex={100}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
style={{
|
||||
float: 'right',
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
}}
|
||||
>
|
||||
<Flex width="100%" alignItems="center" justifyContent="flex-end">
|
||||
<Icon
|
||||
icon={<CogSvg height="1em" fill="currentColor" />}
|
||||
plain
|
||||
tabIndex={5}
|
||||
onClick={() => this.setState({ hideSettings: false })}
|
||||
style={{
|
||||
// Make touch events click instead of dragging
|
||||
'-webkit-app-region': 'no-drag',
|
||||
}}
|
||||
/>
|
||||
{!settings.getSync('disableExternalLinks') && (
|
||||
<Icon
|
||||
@ -209,6 +221,10 @@ export class MainPage extends React.Component<
|
||||
)
|
||||
}
|
||||
tabIndex={6}
|
||||
style={{
|
||||
// Make touch events click instead of dragging
|
||||
'-webkit-app-region': 'no-drag',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
@ -226,80 +242,72 @@ export class MainPage extends React.Component<
|
||||
justifyContent="space-between"
|
||||
>
|
||||
{notFlashingOrSplitView && (
|
||||
<SourceSelector
|
||||
flashing={this.state.isFlashing}
|
||||
afterSelected={(source: SourceOptions) =>
|
||||
this.setState({ source })
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{notFlashingOrSplitView && (
|
||||
<Flex>
|
||||
<StepBorder disabled={shouldDriveStepBeDisabled} left />
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{notFlashingOrSplitView && (
|
||||
<DriveSelector
|
||||
disabled={shouldDriveStepBeDisabled}
|
||||
hasDrive={this.state.hasDrive}
|
||||
flashing={this.state.isFlashing}
|
||||
/>
|
||||
)}
|
||||
|
||||
{notFlashingOrSplitView && (
|
||||
<Flex>
|
||||
<StepBorder disabled={shouldFlashStepBeDisabled} right />
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{this.state.isFlashing && (
|
||||
<>
|
||||
<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)',
|
||||
display: this.state.isWebviewShowing ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<ReducedFlashingInfos
|
||||
imageLogo={this.state.imageLogo}
|
||||
imageName={this.state.imageName}
|
||||
imageSize={
|
||||
_.isNumber(this.state.imageSize)
|
||||
? (bytesToClosestUnit(this.state.imageSize) as string)
|
||||
: ''
|
||||
}
|
||||
driveTitle={this.state.driveTitle}
|
||||
driveLabel={this.state.driveLabel}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
color: '#fff',
|
||||
left: 35,
|
||||
top: 72,
|
||||
}}
|
||||
/>
|
||||
<SourceSelector
|
||||
flashing={this.state.isFlashing}
|
||||
afterSelected={(source: SourceOptions) =>
|
||||
this.setState({ source })
|
||||
}
|
||||
/>
|
||||
<Flex>
|
||||
<StepBorder disabled={shouldDriveStepBeDisabled} left />
|
||||
</Flex>
|
||||
<FeaturedProject
|
||||
shouldShow={this.state.isWebviewShowing}
|
||||
onWebviewShow={(isWebviewShowing: boolean) => {
|
||||
this.setState({ isWebviewShowing });
|
||||
}}
|
||||
<DriveSelector
|
||||
disabled={shouldDriveStepBeDisabled}
|
||||
hasDrive={this.state.hasDrive}
|
||||
flashing={this.state.isFlashing}
|
||||
/>
|
||||
<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={
|
||||
_.isNumber(this.state.imageSize)
|
||||
? (bytesToClosestUnit(this.state.imageSize) as string)
|
||||
: ''
|
||||
}
|
||||
driveTitle={this.state.driveTitle}
|
||||
driveLabel={this.state.driveLabel}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: '63.8vw',
|
||||
height: '100vh',
|
||||
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',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FlashStep
|
||||
@ -307,7 +315,6 @@ export class MainPage extends React.Component<
|
||||
shouldFlashStepBeDisabled={shouldFlashStepBeDisabled}
|
||||
source={this.state.source}
|
||||
isFlashing={this.state.isFlashing}
|
||||
isWebviewShowing={this.state.isWebviewShowing}
|
||||
step={state.type}
|
||||
percentage={state.percentage}
|
||||
position={state.position}
|
||||
|
44
npm-shrinkwrap.json
generated
44
npm-shrinkwrap.json
generated
@ -2174,9 +2174,9 @@
|
||||
}
|
||||
},
|
||||
"@types/react-native": {
|
||||
"version": "0.63.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.63.8.tgz",
|
||||
"integrity": "sha512-QRwGFRTyGafRVTUS+0GYyJrlpmS3boyBaFI0ULSc+mh/lQNxrzbdQvoL2k5X7+t9hxyqA4dTQAlP6l0ir/fNJQ==",
|
||||
"version": "0.63.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.63.9.tgz",
|
||||
"integrity": "sha512-6ec/z9zjAkFH3rD1RYqbrA/Lj+jux6bumWCte4yRy3leyelTdqtmOd2Ph+86IXQQzsIArEMBwmraAbNQ0J3UAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
@ -6677,9 +6677,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"etcher-sdk": {
|
||||
"version": "4.1.24",
|
||||
"resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.24.tgz",
|
||||
"integrity": "sha512-lRAKhXuXD7y68eA+bHJJn4MJpncbybeoH7FaIlXTcISuzdh9lr8NlguKnxvxkX35v1sWN7Ke6REloQY7oqqlvQ==",
|
||||
"version": "4.1.26",
|
||||
"resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.26.tgz",
|
||||
"integrity": "sha512-0Mb2EVoBn5dZdXer2sjINkvsccbfSYwm3Bgv0sYARyLazim+BljmsIFV9bNg8jmM8/h/Qxk+xLSJAyyOiSKyiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@balena/udif": "^1.1.0",
|
||||
@ -7800,9 +7800,9 @@
|
||||
}
|
||||
},
|
||||
"grommet": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/grommet/-/grommet-2.14.0.tgz",
|
||||
"integrity": "sha512-G/LTkr+uFri4NUNQGJMx8TtWWe9+KSpIHCXC9WgRaICI73R3+BvhLSNSzWMQ6YIQC+7PJFtruebeWjdUqR3Ykw==",
|
||||
"version": "2.15.0",
|
||||
"resolved": "https://registry.npmjs.org/grommet/-/grommet-2.15.0.tgz",
|
||||
"integrity": "sha512-5TVbiLrMpZOoB9oZAqWVttj6lO4rcKqBW1rWr4iovTuyyfYYOUQbuNfcFtUqp+MdB0fsQ1Vvci4PiTBvhRJqHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"grommet-icons": "^4.2.0",
|
||||
@ -12821,9 +12821,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"rendition": {
|
||||
"version": "18.1.0",
|
||||
"resolved": "https://registry.npmjs.org/rendition/-/rendition-18.1.0.tgz",
|
||||
"integrity": "sha512-B65e7VJadU+cxtXOn4eGBg8wql57I376NfUYWiu4zs4sf8l6/0h+P6FctoRdrZGX8RRRMToGLHnVC+3411Tmiw==",
|
||||
"version": "18.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rendition/-/rendition-18.4.1.tgz",
|
||||
"integrity": "sha512-mV/0p+M8XR/Xa/ZFzgflZPHelpuONiTSa/CMMuHkmXR7vhF7tB2ORxLRc/DbymmdN6cWQwXAyA81t9TDAOhgVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.25",
|
||||
@ -15030,9 +15030,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.1.tgz",
|
||||
"integrity": "sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q==",
|
||||
"version": "3.10.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.2.tgz",
|
||||
"integrity": "sha512-GXCYNwqoo0MbLARghYjxVBxDCnU0tLqN7IPLdHHbibCb1NI5zBkU2EPcy/GaVxc0BtTjqyGXJCINe6JMR2Dpow==",
|
||||
"dev": true
|
||||
},
|
||||
"unbzip2-stream": {
|
||||
@ -15079,9 +15079,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"unified": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-9.1.0.tgz",
|
||||
"integrity": "sha512-VXOv7Ic6twsKGJDeZQ2wwPqXs2hM0KNu5Hkg9WgAZbSD1pxhZ7p8swqg583nw1Je2fhwHy6U8aEjiI79x1gvag==",
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
|
||||
"integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bail": "^1.0.0",
|
||||
@ -15543,9 +15543,9 @@
|
||||
}
|
||||
},
|
||||
"vfile-location": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.0.1.tgz",
|
||||
"integrity": "sha512-yYBO06eeN/Ki6Kh1QAkgzYpWT1d3Qln+ZCtSbJqFExPl1S3y2qqotJQXoh6qEvl/jDlgpUJolBn3PItVnnZRqQ==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.1.0.tgz",
|
||||
"integrity": "sha512-FCZ4AN9xMcjFIG1oGmZKo61PjwJHRVA+0/tPUP2ul4uIwjGGndIxavEMRpWn5p4xwm/ZsdXp9YNygf1ZyE4x8g==",
|
||||
"dev": true
|
||||
},
|
||||
"vfile-message": {
|
||||
@ -16769,4 +16769,4 @@
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -77,7 +77,7 @@
|
||||
"electron-notarize": "^1.0.0",
|
||||
"electron-rebuild": "^1.11.0",
|
||||
"electron-updater": "^4.3.2",
|
||||
"etcher-sdk": "^4.1.24",
|
||||
"etcher-sdk": "^4.1.26",
|
||||
"file-loader": "^6.0.0",
|
||||
"husky": "^4.2.5",
|
||||
"immutable": "^3.8.1",
|
||||
@ -94,7 +94,7 @@
|
||||
"react": "^16.8.5",
|
||||
"react-dom": "^16.8.5",
|
||||
"redux": "^4.0.5",
|
||||
"rendition": "^18.1.0",
|
||||
"rendition": "^18.4.1",
|
||||
"resin-corvus": "^2.0.5",
|
||||
"semver": "^7.3.2",
|
||||
"simple-progress-webpack-plugin": "^1.1.2",
|
||||
|
Loading…
x
Reference in New Issue
Block a user