/* * Copyright 2019 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 { faCog, faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { sourceDestination } from 'etcher-sdk'; import * as _ from 'lodash'; import * as path from 'path'; 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'; import { SettingsModal } from '../../components/settings/settings'; import { SourceOptions, SourceSelector, } from '../../components/source-selector/source-selector'; import * as flashState from '../../models/flash-state'; import * as selectionState from '../../models/selection-state'; import * as settings from '../../models/settings'; import { observe } from '../../models/store'; import { open as openExternal } from '../../os/open-external/services/open-external'; import { IconButton as BaseIcon, ThemedProvider, } from '../../styled-components'; import { middleEllipsis } from '../../utils/middle-ellipsis'; import { bytesToClosestUnit } from '../../../../shared/units'; import { DriveSelector } from './DriveSelector'; import { FlashStep } from './Flash'; import EtcherSvg from '../../../assets/etcher.svg'; const Icon = styled(BaseIcon)` margin-right: 20px; `; function getDrivesTitle() { const drives = selectionState.getSelectedDrives(); if (drives.length === 1) { return drives[0].description || 'Untitled Device'; } if (drives.length === 0) { return 'No targets found'; } return `${drives.length} Targets`; } function getImageBasename() { if (!selectionState.hasImage()) { return ''; } const selectionImageName = selectionState.getImageName(); const imageBasename = path.basename(selectionState.getImagePath()); return selectionImageName || imageBasename; } const StepBorder = styled.div<{ disabled: boolean; left?: boolean; right?: boolean; }>` position: relative; height: 2px; background-color: ${(props) => props.disabled ? props.theme.colors.dark.disabled.foreground : props.theme.colors.dark.foreground}; width: 120px; top: 19px; left: ${(props) => (props.left ? '-67px' : undefined)}; margin-right: ${(props) => (props.left ? '-120px' : undefined)}; right: ${(props) => (props.right ? '-67px' : undefined)}; margin-left: ${(props) => (props.right ? '-120px' : undefined)}; `; interface MainPageStateFromStore { isFlashing: boolean; hasImage: boolean; hasDrive: boolean; imageLogo: string; imageSize: number; imageName: string; driveTitle: string; } interface MainPageState { current: 'main' | 'success'; isWebviewShowing: boolean; hideSettings: boolean; source: SourceOptions; } export class MainPage extends React.Component< {}, MainPageState & MainPageStateFromStore > { constructor(props: {}) { super(props); this.state = { current: 'main', isWebviewShowing: false, hideSettings: true, source: { imagePath: '', SourceType: sourceDestination.File, }, ...this.stateHelper(), }; } private stateHelper(): MainPageStateFromStore { return { isFlashing: flashState.isFlashing(), hasImage: selectionState.hasImage(), hasDrive: selectionState.hasDrive(), imageLogo: selectionState.getImageLogo(), imageSize: selectionState.getImageSize(), imageName: getImageBasename(), driveTitle: getDrivesTitle(), }; } public componentDidMount() { observe(() => { this.setState(this.stateHelper()); }); } private renderMain() { const state = flashState.getFlashState(); const shouldDriveStepBeDisabled = !this.state.hasImage; const shouldFlashStepBeDisabled = !this.state.hasImage || !this.state.hasDrive; return ( <>
openExternal('https://www.balena.io/etcher?ref=etcher_footer') } tabIndex={100} > } plain tabIndex={5} onClick={() => this.setState({ hideSettings: false })} /> {!settings.getSync('disableExternalLinks') && ( } onClick={() => openExternal( selectionState.getImageSupportUrl() || 'https://github.com/balena-io/etcher/blob/master/SUPPORT.md', ) } tabIndex={6} /> )}
{this.state.hideSettings ? null : ( { this.setState({ hideSettings: !value }); }} /> )} this.setState({ source })} /> {(!this.state.isWebviewShowing || !this.state.isFlashing) && ( )} {(!this.state.isWebviewShowing || !this.state.isFlashing) && ( )} {this.state.isFlashing && this.state.isWebviewShowing && ( <> { this.setState({ isWebviewShowing }); }} /> )} this.setState({ current: 'success' })} shouldFlashStepBeDisabled={shouldFlashStepBeDisabled} source={this.state.source} isFlashing={flashState.isFlashing()} step={state.type} percentage={state.percentage} position={state.position} failed={state.failed} speed={state.speed} eta={state.eta} /> ); } private renderSuccess() { return (
{ flashState.resetState(); this.setState({ current: 'main' }); }} />
); } public render() { return ( {this.state.current === 'main' ? this.renderMain() : this.renderSuccess()} ); } } export default MainPage;