diff --git a/Makefile b/Makefile index b313533a..b543539d 100644 --- a/Makefile +++ b/Makefile @@ -23,9 +23,7 @@ $(BUILD_DIRECTORY): $(BUILD_TEMPORARY_DIRECTORY): | $(BUILD_DIRECTORY) mkdir $@ -# See https://stackoverflow.com/a/13468229/1641422 SHELL := /bin/bash -PATH := $(shell pwd)/node_modules/.bin:$(PATH) # --------------------------------------------------------------------- # Operating system and architecture detection @@ -125,7 +123,7 @@ TARGETS = \ info \ lint \ lint-ts \ - lint-sass \ + lint-css \ lint-cpp \ lint-spell \ test-spectron \ @@ -140,15 +138,15 @@ TARGETS = \ electron-build webpack: - ./node_modules/.bin/webpack + npx webpack .PHONY: $(TARGETS) lint-ts: - balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts + npx balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts -lint-sass: - sass-lint -v lib/gui/app/scss/**/*.scss lib/gui/app/scss/*.scss +lint-css: + npx prettier --write lib/**/*.css lint-cpp: cpplint --recursive src @@ -160,18 +158,18 @@ lint-spell: --skip *.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: lint-ts lint-sass lint-cpp lint-spell +lint: lint-ts lint-css lint-cpp lint-spell MOCHA_OPTIONS=--recursive --reporter spec --require ts-node/register --require-main "tests/gui/allow-renderer-process-reuse.ts" test-spectron: - mocha $(MOCHA_OPTIONS) tests/spectron/runner.spec.ts + npx mocha $(MOCHA_OPTIONS) tests/spectron/runner.spec.ts test-gui: - electron-mocha $(MOCHA_OPTIONS) --full-trace --no-sandbox --renderer tests/gui/**/*.ts + npx electron-mocha $(MOCHA_OPTIONS) --full-trace --no-sandbox --renderer tests/gui/**/*.ts test-sdk: - electron-mocha $(MOCHA_OPTIONS) --full-trace --no-sandbox tests/shared/**/*.ts + npx electron-mocha $(MOCHA_OPTIONS) --full-trace --no-sandbox tests/shared/**/*.ts test: test-gui test-sdk test-spectron diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a186b1ad..6669b9b0 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -14,9 +14,7 @@ technologies used in Etcher that you should become familiar with: - [NodeJS][nodejs] - [Redux][redux] - [ImmutableJS][immutablejs] -- [Bootstrap][bootstrap] - [Sass][sass] -- [Flexbox Grid][flexbox-grid] - [Mocha][mocha] - [JSDoc][jsdoc] @@ -67,8 +65,6 @@ be documented instead! [nodejs]: https://nodejs.org [redux]: http://redux.js.org [immutablejs]: http://facebook.github.io/immutable-js/ -[bootstrap]: http://getbootstrap.com [sass]: http://sass-lang.com -[flexbox-grid]: http://flexboxgrid.com [mocha]: http://mochajs.org [jsdoc]: http://usejsdoc.org diff --git a/lib/gui/app/app.ts b/lib/gui/app/app.ts index 1119ae34..471c99ce 100644 --- a/lib/gui/app/app.ts +++ b/lib/gui/app/app.ts @@ -23,11 +23,13 @@ import * as ReactDOM from 'react-dom'; import { v4 as uuidV4 } from 'uuid'; import * as packageJSON from '../../../package.json'; +import { isDriveValid, isSourceDrive } from '../../shared/drive-constraints'; import * as EXIT_CODES from '../../shared/exit-codes'; import * as messages from '../../shared/messages'; import * as availableDrives from './models/available-drives'; import * as flashState from './models/flash-state'; import { init as ledsInit } from './models/leds'; +import { deselectImage, getImage, selectDrive } from './models/selection-state'; import * as settings from './models/settings'; import { Actions, observe, store } from './models/store'; import * as analytics from './modules/analytics'; @@ -247,9 +249,26 @@ async function addDrive(drive: Drive) { const drives = getDrives(); drives[preparedDrive.device] = preparedDrive; setDrives(drives); + if ( + (await settings.get('autoSelectAllDrives')) && + drive instanceof sdk.sourceDestination.BlockDevice && + // @ts-ignore BlockDevice.drive is private + isDriveValid(drive.drive, getImage()) + ) { + selectDrive(drive.device); + } } function removeDrive(drive: Drive) { + if ( + drive instanceof sdk.sourceDestination.BlockDevice && + // @ts-ignore BlockDevice.drive is private + isSourceDrive(drive.drive, getImage()) + ) { + // Deselect the image if it was on the drive that was removed. + // This will also deselect the image if the drive mountpoints change. + deselectImage(); + } const preparedDrive = prepareDrive(drive); const drives = getDrives(); delete drives[preparedDrive.device]; diff --git a/lib/gui/app/components/featured-project/featured-project.tsx b/lib/gui/app/components/featured-project/featured-project.tsx index 9aab2d2c..9ed36346 100644 --- a/lib/gui/app/components/featured-project/featured-project.tsx +++ b/lib/gui/app/components/featured-project/featured-project.tsx @@ -21,11 +21,14 @@ 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< @@ -34,23 +37,37 @@ export class FeaturedProject extends React.Component< > { constructor(props: FeaturedProjectProps) { super(props); - this.state = { endpoint: null }; + this.state = { + endpoint: null, + show: false, + }; } public async componentDidMount() { try { - const endpoint = + const url = new URL( (await settings.get('featuredProjectEndpoint')) || - 'https://assets.balena.io/etcher-featured/index.html'; - this.setState({ endpoint }); + '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 ? ( - + ) : null; } } diff --git a/lib/gui/app/components/finish/finish.tsx b/lib/gui/app/components/finish/finish.tsx index 7c4b1b51..6484461f 100644 --- a/lib/gui/app/components/finish/finish.tsx +++ b/lib/gui/app/components/finish/finish.tsx @@ -16,6 +16,7 @@ import * as _ from 'lodash'; import * as React from 'react'; +import { Flex } from 'rendition'; import { v4 as uuidV4 } from 'uuid'; import * as flashState from '../../models/flash-state'; @@ -56,50 +57,45 @@ function formattedErrors() { function FinishPage({ goToMain }: { goToMain: () => void }) { const results = flashState.getFlashResults().results || {}; return ( -
-
-
- + + + - { - restart(goToMain); - }} + { + restart(goToMain); + }} + /> + + + + + Thanks for using + + openExternal('https://balena.io/etcher?ref=etcher_offline_banner') + } /> -
- -
-
-
- Thanks for using - - openExternal( - 'https://balena.io/etcher?ref=etcher_offline_banner', - ) - } - > - - -
-
- made with - - by - - openExternal('https://balena.io?ref=etcher_success') - } - > - - -
-
-
-
-
+ + + made with + + by + openExternal('https://balena.io?ref=etcher_success')} + /> + + + ); } diff --git a/lib/gui/app/components/flash-another/flash-another.tsx b/lib/gui/app/components/flash-another/flash-another.tsx index 9157bdb1..5efc25b4 100644 --- a/lib/gui/app/components/flash-another/flash-another.tsx +++ b/lib/gui/app/components/flash-another/flash-another.tsx @@ -15,24 +15,17 @@ */ import * as React from 'react'; -import styled from 'styled-components'; import { BaseButton } from '../../styled-components'; -const FlashAnotherButton = styled(BaseButton)` - position: absolute; - right: 152px; - top: 60px; -`; - export interface FlashAnotherProps { onClick: () => void; } export const FlashAnother = (props: FlashAnotherProps) => { return ( - + Flash Another - + ); }; diff --git a/lib/gui/app/components/flash-results/flash-results.tsx b/lib/gui/app/components/flash-results/flash-results.tsx index 4c7000a5..aefff367 100644 --- a/lib/gui/app/components/flash-results/flash-results.tsx +++ b/lib/gui/app/components/flash-results/flash-results.tsx @@ -14,25 +14,15 @@ * limitations under the License. */ -import { faCheckCircle } from '@fortawesome/free-solid-svg-icons'; +import { faCheckCircle, faCircle } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as _ from 'lodash'; import outdent from 'outdent'; import * as React from 'react'; import { Txt, Flex } from 'rendition'; -import styled from 'styled-components'; -import { left, position, space, top } from 'styled-system'; import { progress } from '../../../../shared/messages'; import { bytesToMegabytes } from '../../../../shared/units'; -import { Underline } from '../../styled-components'; - -const Div = styled.div` - ${position} - ${top} - ${left} - ${space} -`; export function FlashResults({ errors, @@ -58,7 +48,15 @@ export function FlashResults({ 1, ); return ( -
+ -
- {_.map(results.devices, (quantity, type) => { + + {Object.entries(results.devices).map(([type, quantity]) => { return quantity ? ( - -
- - {quantity} - - {progress[type](quantity)} - -
-
+ + {quantity} + {progress[type](quantity)} +
) : null; })} {!allDevicesFailed && ( )} -
-
+ + ); } diff --git a/lib/gui/app/components/progress-button/progress-button.tsx b/lib/gui/app/components/progress-button/progress-button.tsx index 62fcff92..d9466ed3 100644 --- a/lib/gui/app/components/progress-button/progress-button.tsx +++ b/lib/gui/app/components/progress-button/progress-button.tsx @@ -84,7 +84,9 @@ export class ProgressButton extends React.PureComponent { return ( <> { warning={this.props.warning} onClick={this.props.callback} disabled={this.props.disabled} + style={{ + marginTop: 30, + }} > Flash! diff --git a/lib/gui/app/components/reduced-flashing-infos/reduced-flashing-infos.tsx b/lib/gui/app/components/reduced-flashing-infos/reduced-flashing-infos.tsx index 35d655c8..527f45fc 100644 --- a/lib/gui/app/components/reduced-flashing-infos/reduced-flashing-infos.tsx +++ b/lib/gui/app/components/reduced-flashing-infos/reduced-flashing-infos.tsx @@ -15,51 +15,20 @@ */ import * as React from 'react'; -import { default as styled } from 'styled-components'; -import { color } from 'styled-system'; - -import { SVGIcon } from '../svg-icon/svg-icon'; +import { Flex, Txt } from 'rendition'; import DriveSvg from '../../../assets/drive.svg'; import ImageSvg from '../../../assets/image.svg'; - -const Div = styled.div` - position: absolute; - top: 45px; - left: 545px; - - > span.step-name { - justify-content: flex-start; - - > span { - margin-left: 10px; - } - - > span:nth-child(2) { - font-weight: 500; - } - - > span:nth-child(3) { - font-weight: 400; - font-style: italic; - } - } - - .disabled { - opacity: 0.4; - } -`; - -const Span = styled.span` - ${color} -`; +import { SVGIcon } from '../svg-icon/svg-icon'; +import { middleEllipsis } from '../../utils/middle-ellipsis'; interface ReducedFlashingInfosProps { imageLogo: string; imageName: string; imageSize: string; driveTitle: string; - shouldShow: boolean; + driveLabel: string; + style?: React.CSSProperties; } export class ReducedFlashingInfos extends React.Component< @@ -71,24 +40,36 @@ export class ReducedFlashingInfos extends React.Component< } public render() { - return this.props.shouldShow ? ( -
- + return ( + + } + fallback={ImageSvg} + style={{ marginRight: '9px' }} /> - {this.props.imageName} - {this.props.imageSize} - + + {middleEllipsis(this.props.imageName, 16)} + + {this.props.imageSize} + - - - {this.props.driveTitle} - -
- ) : null; + + + + {middleEllipsis(this.props.driveTitle, 16)} + + +
+ ); } } diff --git a/lib/gui/app/components/safe-webview/safe-webview.tsx b/lib/gui/app/components/safe-webview/safe-webview.tsx index 234d7f23..961acc00 100644 --- a/lib/gui/app/components/safe-webview/safe-webview.tsx +++ b/lib/gui/app/components/safe-webview/safe-webview.tsx @@ -62,6 +62,7 @@ interface SafeWebviewProps { refreshNow?: boolean; // Webview lifecycle event onWebviewShow?: (isWebviewShowing: boolean) => void; + style?: React.CSSProperties; } interface SafeWebviewState { @@ -109,15 +110,18 @@ export class SafeWebview extends React.PureComponent< } public render() { + const { + style = { + flex: this.state.shouldShow ? undefined : '0 1', + width: this.state.shouldShow ? undefined : '0', + height: this.state.shouldShow ? undefined : '0', + }, + } = this.props; return ( ); } diff --git a/lib/gui/app/components/settings/settings.tsx b/lib/gui/app/components/settings/settings.tsx index 9b1bf1a2..e895cad0 100644 --- a/lib/gui/app/components/settings/settings.tsx +++ b/lib/gui/app/components/settings/settings.tsx @@ -19,45 +19,16 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as _ from 'lodash'; import * as os from 'os'; import * as React from 'react'; -import { Checkbox, Modal } from 'rendition'; +import { Checkbox, Flex, Txt } from 'rendition'; -import { version } from '../../../../../package.json'; +import { version, packageType } from '../../../../../package.json'; import * as settings from '../../models/settings'; import * as analytics from '../../modules/analytics'; import { open as openExternal } from '../../os/open-external/services/open-external'; +import { Modal } from '../../styled-components'; const platform = os.platform(); -interface WarningModalProps { - message: string; - confirmLabel: string; - cancel: () => void; - done: () => void; -} - -const WarningModal = ({ - message, - confirmLabel, - cancel, - done, -}: WarningModalProps) => { - return ( - - {message} - - ); -}; - interface Setting { name: string; label: string | JSX.Element; @@ -91,17 +62,11 @@ async function getSettingsList(): Promise { { name: 'updatesEnabled', label: 'Auto-updates enabled', + hide: _.includes(['rpm', 'deb'], packageType), }, ]; } -interface Warning { - setting: string; - settingValue: boolean; - description: string; - confirmLabel: string; -} - interface SettingsModalProps { toggleModal: (value: boolean) => void; } @@ -125,7 +90,6 @@ export function SettingsModal({ toggleModal }: SettingsModalProps) { } })(); }); - const [warning, setWarning] = React.useState(undefined); const toggleSetting = async ( setting: string, @@ -140,38 +104,27 @@ export function SettingsModal({ toggleModal }: SettingsModalProps) { dangerous, }); - if (value || options === undefined) { - await settings.set(setting, !value); - setCurrentSettings({ - ...currentSettings, - [setting]: !value, - }); - setWarning(undefined); - return; - } else { - // Show warning since it's a dangerous setting - setWarning({ - setting, - settingValue: value, - ...options, - }); - } + await settings.set(setting, !value); + setCurrentSettings({ + ...currentSettings, + [setting]: !value, + }); + return; }; return ( + Settings + + } done={() => toggleModal(false)} - style={{ - width: 780, - height: 420, - }} > -
+ {_.map(settingsList, (setting: Setting, i: number) => { return setting.hide ? null : ( -
+ toggleSetting(setting.name, setting.options)} /> -
+
); })} -
- - openExternal( - 'https://github.com/balena-io/etcher/blob/master/CHANGELOG.md', - ) - } - > - {version} - -
-
- - {warning === undefined ? null : ( - { - await settings.set(warning.setting, !warning.settingValue); - setCurrentSettings({ - ...currentSettings, - [warning.setting]: true, - }); - setWarning(undefined); + { - setWarning(undefined); - }} - /> - )} + onClick={() => + openExternal( + 'https://github.com/balena-io/etcher/blob/master/CHANGELOG.md', + ) + } + > + + {version} + +
); } diff --git a/lib/gui/app/components/source-selector/source-selector.tsx b/lib/gui/app/components/source-selector/source-selector.tsx index 0ec6b82d..4cd1c0d2 100644 --- a/lib/gui/app/components/source-selector/source-selector.tsx +++ b/lib/gui/app/components/source-selector/source-selector.tsx @@ -14,7 +14,11 @@ * limitations under the License. */ -import { faFile, faLink } from '@fortawesome/free-solid-svg-icons'; +import { + faFile, + faLink, + faExclamationTriangle, +} from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { sourceDestination } from 'etcher-sdk'; import { ipcRenderer, IpcRendererEvent } from 'electron'; @@ -22,7 +26,14 @@ import * as _ from 'lodash'; import { GPTPartition, MBRPartition } from 'partitioninfo'; import * as path from 'path'; import * as React from 'react'; -import { ButtonProps, Card as BaseCard, Input, Modal, Txt } from 'rendition'; +import { + ButtonProps, + Card as BaseCard, + Input, + Modal as SmallModal, + Txt, + Flex, +} from 'rendition'; import styled from 'styled-components'; import * as errors from '../../../../shared/errors'; @@ -38,8 +49,10 @@ import { replaceWindowsNetworkDriveLetter } from '../../os/windows-network-drive import { ChangeButton, DetailsText, + Modal, StepButton, StepNameButton, + ScrollableFlex, } from '../../styled-components'; import { colors } from '../../theme'; import { middleEllipsis } from '../../utils/middle-ellipsis'; @@ -49,19 +62,24 @@ import ImageSvg from '../../../assets/image.svg'; const recentUrlImagesKey = 'recentUrlImages'; -function normalizeRecentUrlImages(urls: any): string[] { +function normalizeRecentUrlImages(urls: any[]): URL[] { if (!Array.isArray(urls)) { urls = []; } - return _.chain(urls) - .filter(_.isString) - .reject(_.isEmpty) - .uniq() - .takeRight(5) - .value(); + urls = urls + .map((url) => { + try { + return new URL(url); + } catch (error) { + // Invalid URL, skip + } + }) + .filter((url) => url !== undefined); + urls = _.uniqBy(urls, (url) => url.href); + return urls.slice(urls.length - 5); } -function getRecentUrlImages(): string[] { +function getRecentUrlImages(): URL[] { let urls = []; try { urls = JSON.parse(localStorage.getItem(recentUrlImagesKey) || '[]'); @@ -71,11 +89,9 @@ function getRecentUrlImages(): string[] { return normalizeRecentUrlImages(urls); } -function setRecentUrlImages(urls: string[]) { - localStorage.setItem( - recentUrlImagesKey, - JSON.stringify(normalizeRecentUrlImages(urls)), - ); +function setRecentUrlImages(urls: URL[]) { + const normalized = normalizeRecentUrlImages(urls.map((url: URL) => url.href)); + localStorage.setItem(recentUrlImagesKey, JSON.stringify(normalized)); } const Card = styled(BaseCard)` @@ -103,37 +119,45 @@ function getState() { }; } -const URLSelector = ({ done }: { done: (imageURL: string) => void }) => { +const URLSelector = ({ + done, + cancel, +}: { + done: (imageURL: string) => void; + cancel: () => void; +}) => { const [imageURL, setImageURL] = React.useState(''); const [recentImages, setRecentImages]: [ - string[], - (value: React.SetStateAction) => void, + URL[], + (value: React.SetStateAction) => void, ] = React.useState([]); const [loading, setLoading] = React.useState(false); React.useEffect(() => { const fetchRecentUrlImages = async () => { - const recentUrlImages: string[] = await getRecentUrlImages(); + const recentUrlImages: URL[] = await getRecentUrlImages(); setRecentImages(recentUrlImages); }; fetchRecentUrlImages(); }, []); return ( { setLoading(true); - const sanitizedRecentUrls = normalizeRecentUrlImages([ - ...recentImages, + const urlStrings = recentImages.map((url: URL) => url.href); + const normalizedRecentUrls = normalizeRecentUrlImages([ + ...urlStrings, imageURL, ]); - setRecentUrlImages(sanitizedRecentUrls); + setRecentUrlImages(normalizedRecentUrls); await done(imageURL); }} > - - {!_.isEmpty(recentImages) && ( -
- Recent - ( - { - setImageURL(recent); - }} - > - - {_.last(_.split(recent, '/'))} - {recent} - - - ))} - /> -
+ + {recentImages.length > 0 && ( + + Recent + + ( + { + setImageURL(recent.href); + }} + style={{ + overflowWrap: 'break-word', + }} + > + {recent.pathname.split('/').pop()} - {recent.href} + + )) + .reverse()} + /> + + )}
); @@ -261,7 +290,7 @@ export class SourceSelector extends React.Component< private async onSelectImage(_event: IpcRendererEvent, imagePath: string) { const isURL = - _.startsWith(imagePath, 'https://') || _.startsWith(imagePath, 'http://'); + imagePath.startsWith('https://') || imagePath.startsWith('http://'); await this.selectImageByPath({ imagePath, SourceType: isURL ? sourceDestination.Http : sourceDestination.File, @@ -335,8 +364,8 @@ export class SourceSelector extends React.Component< }); } else { if ( - !_.startsWith(imagePath, 'https://') && - !_.startsWith(imagePath, 'http://') + !imagePath.startsWith('https://') && + !imagePath.startsWith('http://') ) { const invalidImageError = errors.createUserError({ title: 'Unsupported protocol', @@ -464,70 +493,67 @@ export class SourceSelector extends React.Component< return ( <> -
-
- } - /> -
+ -
- {hasImage ? ( - <> - - {middleEllipsis(imageName || imageBasename, 20)} - - {!flashing && ( - - Remove - - )} - - {shared.bytesToClosestUnit(imageSize)} - - - ) : ( - <> - , - }} - /> - , - }} - /> - - )} -
-
+ {hasImage ? ( + <> + + {middleEllipsis(imageName || imageBasename, 20)} + + {!flashing && ( + + Remove + + )} + {shared.bytesToClosestUnit(imageSize)} + + ) : ( + <> + , + }} + /> + , + }} + /> + + )} + {this.state.warning != null && ( - - {' '} + {' '} {this.state.warning.title} } @@ -544,11 +570,11 @@ export class SourceSelector extends React.Component< - + )} {showImageDetails && ( - { this.setState({ showImageDetails: false }); @@ -562,11 +588,16 @@ export class SourceSelector extends React.Component< Path: {imagePath} - + )} {showURLSelector && ( { + this.setState({ + showURLSelector: false, + }); + }} done={async (imageURL: string) => { // Avoid analytics and selection state changes // if no file was resolved from the dialog. diff --git a/lib/gui/app/components/svg-icon/svg-icon.tsx b/lib/gui/app/components/svg-icon/svg-icon.tsx index 077c5fd3..bcf2d777 100644 --- a/lib/gui/app/components/svg-icon/svg-icon.tsx +++ b/lib/gui/app/components/svg-icon/svg-icon.tsx @@ -39,13 +39,14 @@ function tryParseSVGContents(contents?: string): string | undefined { interface SVGIconProps { // List of embedded SVG contents to be tried in succession if any fails contents: string; - fallback: JSX.Element; + fallback: React.FunctionComponent>; // SVG image width unit width?: string; // SVG image height unit height?: string; // Should the element visually appear grayed out and disabled? disabled?: boolean; + style?: React.CSSProperties; } /** @@ -54,17 +55,19 @@ interface SVGIconProps { export class SVGIcon extends React.PureComponent { public render() { const svgData = tryParseSVGContents(this.props.contents); + const { width, height, style = {} } = this.props; + style.width = width || DEFAULT_SIZE; + style.height = height || DEFAULT_SIZE; if (svgData !== undefined) { - const width = this.props.width || DEFAULT_SIZE; - const height = this.props.height || DEFAULT_SIZE; return ( ); } - return this.props.fallback; + const { fallback: FallbackSVG } = this.props; + return ; } } diff --git a/lib/gui/app/components/target-selector/target-selector-button.tsx b/lib/gui/app/components/target-selector/target-selector-button.tsx index 4167075e..2d9e4315 100644 --- a/lib/gui/app/components/target-selector/target-selector-button.tsx +++ b/lib/gui/app/components/target-selector/target-selector-button.tsx @@ -15,10 +15,8 @@ */ import { Drive as DrivelistDrive } from 'drivelist'; -import * as _ from 'lodash'; import * as React from 'react'; -import { Txt } from 'rendition'; -import { default as styled } from 'styled-components'; +import { Txt, Flex, FlexProps } from 'rendition'; import { getDriveImageCompatibilityStatuses, @@ -33,10 +31,8 @@ import { StepNameButton, } from '../../styled-components'; import { middleEllipsis } from '../../utils/middle-ellipsis'; - -const TargetDetail = styled((props) => )` - float: ${({ float }) => float}; -`; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; interface TargetSelectorProps { targets: any[]; @@ -49,24 +45,26 @@ interface TargetSelectorProps { image: Image; } -function DriveCompatibilityWarning(props: { +function DriveCompatibilityWarning({ + drive, + image, + ...props +}: { drive: DrivelistDrive; image: Image; -}) { +} & FlexProps) { const compatibilityWarnings = getDriveImageCompatibilityStatuses( - props.drive, - props.image, + drive, + image, ); if (compatibilityWarnings.length === 0) { return null; } - const messages = _.map(compatibilityWarnings, 'message'); + const messages = compatibilityWarnings.map((warning) => warning.message); return ( - + + + ); } @@ -86,7 +84,11 @@ export function TargetSelector(props: TargetSelectorProps) { )} - + {bytesToClosestUnit(target.size)} @@ -104,21 +106,19 @@ export function TargetSelector(props: TargetSelectorProps) { } ${bytesToClosestUnit(target.size)}`} px={21} > - - - - {middleEllipsis(target.description, 14)} - - - {bytesToClosestUnit(target.size)} - - + + {middleEllipsis(target.description, 14)} + {bytesToClosestUnit(target.size)} , ); } return ( <> - + {targets.length} Targets {!props.flashing && ( diff --git a/lib/gui/app/components/target-selector/target-selector-modal.tsx b/lib/gui/app/components/target-selector/target-selector-modal.tsx index ccff228c..f4da1c64 100644 --- a/lib/gui/app/components/target-selector/target-selector-modal.tsx +++ b/lib/gui/app/components/target-selector/target-selector-modal.tsx @@ -50,7 +50,7 @@ import { import { store } from '../../models/store'; import { logEvent, logException } from '../../modules/analytics'; import { open as openExternal } from '../../os/open-external/services/open-external'; -import { Modal } from '../../styled-components'; +import { Modal, ScrollableFlex } from '../../styled-components'; import TargetSVGIcon from '../../../assets/tgt.svg'; @@ -83,19 +83,6 @@ function isDrivelistDrive( return typeof (drive as scanner.adapters.DrivelistDrive).size === 'number'; } -const ScrollableFlex = styled(Flex)` - overflow: auto; - - ::-webkit-scrollbar { - display: none; - } - - > div > div { - /* This is required for the sticky table header in TargetsTable */ - overflow-x: visible; - } -`; - const TargetsTable = styled(({ refFn, ...props }) => { return (
@@ -376,10 +363,6 @@ export class TargetSelectorModal extends React.Component< cancel={cancel} done={() => done(selectedList)} action={`Select (${selectedList.length})`} - style={{ - width: '780px', - height: '420px', - }} primaryButtonProps={{ primary: !hasStatus, warning: hasStatus, @@ -387,7 +370,7 @@ export class TargetSelectorModal extends React.Component< }} {...props} > - + {!hasAvailableDrives() ? ( Plug a target drive ) : ( - + ) => { if (t !== null) { diff --git a/lib/gui/app/scss/fonts/SourceSansPro-Regular.ttf b/lib/gui/app/css/fonts/SourceSansPro-Regular.ttf similarity index 100% rename from lib/gui/app/scss/fonts/SourceSansPro-Regular.ttf rename to lib/gui/app/css/fonts/SourceSansPro-Regular.ttf diff --git a/lib/gui/app/scss/fonts/SourceSansPro-SemiBold.ttf b/lib/gui/app/css/fonts/SourceSansPro-SemiBold.ttf similarity index 100% rename from lib/gui/app/scss/fonts/SourceSansPro-SemiBold.ttf rename to lib/gui/app/css/fonts/SourceSansPro-SemiBold.ttf diff --git a/lib/gui/app/scss/desktop.css b/lib/gui/app/css/main.css similarity index 62% rename from lib/gui/app/scss/desktop.css rename to lib/gui/app/css/main.css index e830430f..03ab634d 100644 --- a/lib/gui/app/scss/desktop.css +++ b/lib/gui/app/css/main.css @@ -14,41 +14,44 @@ * limitations under the License. */ -/* Prevent text selection */ -body { - -webkit-user-select: none; +@font-face { + font-family: "SourceSansPro"; + src: url("./fonts/SourceSansPro-Regular.ttf") format("truetype"); + font-weight: 500; + font-style: normal; + font-display: block; } - -/* Allow window to be dragged from anywhere */ -#app-header { - -webkit-app-region: drag; +@font-face { + font-family: "SourceSansPro"; + src: url("./fonts/SourceSansPro-SemiBold.ttf") format("truetype"); + font-weight: 600; + font-style: normal; + font-display: block; } -.modal-body { - -webkit-app-region: no-drag; -} - -button, -a, -input { - -webkit-app-region: no-drag; -} - -/* Prevent WebView bounce effect in OS X */ html, body { + margin: 0; + overflow: hidden; + + /* Prevent white flash when running application */ + background-color: #4d5057; + + /* Prevent WebView bounce effect in OS X */ height: 100%; width: 100%; } -html { - overflow: hidden; +/* Prevent text selection */ +body { + -webkit-user-select: none; + -webkit-overflow-scrolling: touch; } -body { - overflow: hidden; - -webkit-overflow-scrolling: touch; +/* Allow window to be dragged from header */ +#app-header { + -webkit-app-region: drag; } /* Prevent blue outline */ @@ -59,7 +62,6 @@ button:focus, outline: none !important; } -/* Titles don't have margins on desktop apps */ -h1, h2, h3, h4, h5, h6 { - margin: 0; +.disabled { + opacity: 0.4; } diff --git a/lib/gui/app/os/dialog.ts b/lib/gui/app/os/dialog.ts index aea6b821..ce906265 100644 --- a/lib/gui/app/os/dialog.ts +++ b/lib/gui/app/os/dialog.ts @@ -18,8 +18,21 @@ import * as electron from 'electron'; import * as _ from 'lodash'; import * as errors from '../../../shared/errors'; +import * as settings from '../../../gui/app/models/settings'; import { SUPPORTED_EXTENSIONS } from '../../../shared/supported-formats'; +async function mountSourceDrive() { + // sourceDrivePath is the name of the link in /dev/disk/by-path + const sourceDrivePath = await settings.get('automountOnFileSelect'); + if (sourceDrivePath) { + try { + await electron.ipcRenderer.invoke('mount-drive', sourceDrivePath); + } catch (error) { + // noop + } + } +} + /** * @summary Open an image selection dialog * @@ -27,6 +40,7 @@ import { SUPPORTED_EXTENSIONS } from '../../../shared/supported-formats'; * Notice that by image, we mean *.img/*.iso/*.zip/etc files. */ export async function selectImage(): Promise { + await mountSourceDrive(); const options: electron.OpenDialogOptions = { // This variable is set when running in GNU/Linux from // inside an AppImage, and represents the working directory diff --git a/lib/gui/app/pages/finish/styles/_finish.scss b/lib/gui/app/pages/finish/styles/_finish.scss deleted file mode 100644 index 34ce3c91..00000000 --- a/lib/gui/app/pages/finish/styles/_finish.scss +++ /dev/null @@ -1,120 +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. - */ - -.page-finish { - margin-top: 60px; -} - -.page-finish .title, -.page-finish .title h3 { - color: $palette-theme-dark-foreground; - font-weight: bold; -} - -.page-finish .center { - display: flex; - align-items: center; - justify-content: center; -} - -.page-finish .box > div > button { - margin-right: 20px; -} - -.page-finish webview { - width: 800px; - height: 300px; - position: absolute; - top: 80px; - left: 0; - z-index: 9001; -} - -.page-finish .fallback-banner { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - position: absolute; - bottom: 0; - color: white; - height: 320px; - width: 100vw; - left: 0; - - > * { - display: flex; - justify-content: center; - align-items: center; - } - - .caption { - display: flex; - font-weight: 500; - } - - .caption-big { - font-size: 28px; - font-weight: bold; - position: absolute; - top: 75px; - } - - .caption-small { - font-size: 12px; - } - - .fallback-footer { - font-size: 12px; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - position: absolute; - bottom: 0; - max-height: 21px; - margin-bottom: 17px; - } - - .section-footer { - position: absolute; - right: 0; - bottom: 0; - - .footer-right { - color: #7e8085; - font-size: 12px; - margin-right: 30px; - } - } -} - -.inline-flex { - display: inline-flex; -} - -.page-finish .tick { - /* hack(Shou): for some reason the height is stretched */ - height: 24px; - width: 24px; - border: none; - padding: 0; - margin: 0 15px 0 0; - justify-content: center; - align-items: center; - display: flex; - font-size: 16px; -} diff --git a/lib/gui/app/pages/main/DriveSelector.tsx b/lib/gui/app/pages/main/DriveSelector.tsx index 20c1a6bd..f89e4d98 100644 --- a/lib/gui/app/pages/main/DriveSelector.tsx +++ b/lib/gui/app/pages/main/DriveSelector.tsx @@ -16,8 +16,7 @@ import { scanner } from 'etcher-sdk'; import * as React from 'react'; -import styled from 'styled-components'; - +import { Flex } from 'rendition'; import { TargetSelector } from '../../components/target-selector/target-selector-button'; import { TargetSelectorModal } from '../../components/target-selector/target-selector-modal'; import { @@ -30,28 +29,9 @@ import { import * as settings from '../../models/settings'; import { observe } from '../../models/store'; import * as analytics from '../../modules/analytics'; - import DriveSvg from '../../../assets/drive.svg'; -const StepBorder = styled.div<{ - disabled: boolean; - left?: boolean; - right?: boolean; -}>` - height: 2px; - background-color: ${(props) => - props.disabled - ? props.theme.colors.dark.disabled.foreground - : props.theme.colors.dark.foreground}; - position: absolute; - width: 124px; - top: 19px; - - left: ${(props) => (props.left ? '-67px' : undefined)}; - right: ${(props) => (props.right ? '-67px' : undefined)}; -`; - -const getDriveListLabel = () => { +export const getDriveListLabel = () => { return getSelectedDrives() .map((drive: any) => { return `${drive.description} (${drive.displayName})`; @@ -100,17 +80,13 @@ export const selectAllTargets = ( }; interface DriveSelectorProps { - webviewShowing: boolean; disabled: boolean; - nextStepDisabled: boolean; hasDrive: boolean; flashing: boolean; } export const DriveSelector = ({ - webviewShowing, disabled, - nextStepDisabled, hasDrive, flashing, }: DriveSelectorProps) => { @@ -129,38 +105,31 @@ export const DriveSelector = ({ }); }, []); - const showStepConnectingLines = !webviewShowing || !flashing; - return ( -
- {showStepConnectingLines && ( - <> - - - - )} + + -
- -
- -
- { - setShowTargetSelectorModal(true); - }} - reselectDrive={() => { - analytics.logEvent('Reselect drive'); - setShowTargetSelectorModal(true); - }} - flashing={flashing} - targets={targets} - image={image} - /> -
+ { + setShowTargetSelectorModal(true); + }} + reselectDrive={() => { + analytics.logEvent('Reselect drive'); + setShowTargetSelectorModal(true); + }} + flashing={flashing} + targets={targets} + image={image} + /> {showTargetSelectorModal && ( )} -
+
); }; diff --git a/lib/gui/app/pages/main/Flash.tsx b/lib/gui/app/pages/main/Flash.tsx index 4eeac6af..7c46daca 100644 --- a/lib/gui/app/pages/main/Flash.tsx +++ b/lib/gui/app/pages/main/Flash.tsx @@ -34,6 +34,8 @@ import * as notification from '../../os/notification'; import { selectAllTargets } from './DriveSelector'; import FlashSvg from '../../../assets/flash.svg'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCircle } from '@fortawesome/free-solid-svg-icons'; const COMPLETED_PERCENTAGE = 100; const SPEED_PRECISION = 2; @@ -145,6 +147,8 @@ interface FlashStepProps { goToSuccess: () => void; source: SourceOptions; isFlashing: boolean; + isWebviewShowing: boolean; + style?: React.CSSProperties; // TODO: factorize step: 'decompressing' | 'flashing' | 'verifying'; percentage: number; @@ -234,62 +238,60 @@ export class FlashStep extends React.PureComponent< public render() { return ( <> -
-
- -
+ + -
- { - this.tryFlash(); - }} - /> - - {!_.isNil(this.props.speed) && - this.props.percentage !== COMPLETED_PERCENTAGE && ( - - {!_.isNil(this.props.speed) && ( - {this.props.speed.toFixed(SPEED_PRECISION)} MB/s - )} - {!_.isNil(this.props.eta) && ( - ETA: {formatSeconds(this.props.eta)} - )} - - )} - - {Boolean(this.props.failed) && ( -
-
- - - {this.props.failed} - - - {messages.progress.failed(this.props.failed)}{' '} - -
-
+ -
+ callback={() => { + this.tryFlash(); + }} + /> + + {!_.isNil(this.props.speed) && + this.props.percentage !== COMPLETED_PERCENTAGE && ( + + {!_.isNil(this.props.speed) && ( + {this.props.speed.toFixed(SPEED_PRECISION)} MB/s + )} + {!_.isNil(this.props.eta) && ( + ETA: {formatSeconds(this.props.eta)} + )} + + )} + + {Boolean(this.props.failed) && ( + + + {this.props.failed} + {messages.progress.failed(this.props.failed)} + + )} +
{this.state.warningMessages.length > 0 && ( ` + 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; @@ -86,6 +105,7 @@ interface MainPageStateFromStore { imageSize: number; imageName: string; driveTitle: string; + driveLabel: string; } interface MainPageState { @@ -122,6 +142,7 @@ export class MainPage extends React.Component< imageSize: selectionState.getImageSize(), imageName: getImageBasename(), driveTitle: getDrivesTitle(), + driveLabel: getDriveListLabel(), }; } @@ -136,17 +157,25 @@ export class MainPage extends React.Component< const shouldDriveStepBeDisabled = !this.state.hasImage; const shouldFlashStepBeDisabled = !this.state.hasImage || !this.state.hasDrive; + const notFlashingOrSplitView = + !this.state.isFlashing || !this.state.isWebviewShowing; return ( <> -
- - - + /> - )} - -
+ + {this.state.hideSettings ? null : ( { @@ -194,72 +221,100 @@ export class MainPage extends React.Component< )} -
+ {notFlashingOrSplitView && ( this.setState({ source }) } /> -
+ )} -
+ {notFlashingOrSplitView && ( + + + + )} + + {notFlashingOrSplitView && ( -
+ )} + + {notFlashingOrSplitView && ( + + + + )} {this.state.isFlashing && ( -
+ <> + + + { this.setState({ isWebviewShowing }); }} + style={{ + position: 'absolute', + right: 0, + bottom: 0, + width: '63.8vw', + height: '100vh', + }} /> -
+ )} -
- -
- -
- 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} - /> -
+ this.setState({ current: 'success' })} + shouldFlashStepBeDisabled={shouldFlashStepBeDisabled} + source={this.state.source} + isFlashing={this.state.isFlashing} + isWebviewShowing={this.state.isWebviewShowing} + step={state.type} + percentage={state.percentage} + position={state.position} + failed={state.failed} + speed={state.speed} + eta={state.eta} + style={{ zIndex: 1 }} + />
); @@ -267,15 +322,23 @@ export class MainPage extends React.Component< private renderSuccess() { return ( -
+ { flashState.resetState(); this.setState({ current: 'main' }); }} /> - -
+ + ); } diff --git a/lib/gui/app/pages/main/styles/_main.scss b/lib/gui/app/pages/main/styles/_main.scss deleted file mode 100644 index a8e2d9ff..00000000 --- a/lib/gui/app/pages/main/styles/_main.scss +++ /dev/null @@ -1,89 +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. - */ - -.disabled { - opacity: $disabled-opacity; -} - -.page-main { - flex: 1; - align-self: center; - margin: 20px; -} - -.page-main > .col-xs { - height: 165px; -} - -.page-main .relative { - position: relative; -} - -.page-main .glyphicon { - vertical-align: text-top; -} - -.page-main .step-name { - display: flex; - justify-content: center; - align-items: center; - height: 39px; - width: 100%; - font-weight: bold; - color: $palette-theme-primary-foreground; -} - -.target-status-wrap { - display: flex; - position: absolute; - top: 62px; - flex-direction: column; - margin: 8px 28px; - align-items: flex-start; -} - -.target-status-line { - display: flex; - align-items: baseline; - - > .target-status-dot { - width: 12px; - height: 12px; - border-radius: 50%; - margin-right: 10px; - } - - &.target-status-successful > .target-status-dot { - background-color: $palette-theme-success-background; - } - &.target-status-failed > .target-status-dot { - background-color: $palette-theme-danger-background; - } - - > .target-status-quantity { - color: white; - font-weight: bold; - } - - > .target-status-message { - color: gray; - margin-left: 10px; - } -} - -.space-vertical-large { - position: relative; -} diff --git a/lib/gui/app/scss/main.scss b/lib/gui/app/scss/main.scss deleted file mode 100644 index ee934aa3..00000000 --- a/lib/gui/app/scss/main.scss +++ /dev/null @@ -1,109 +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. - */ - -$icon-font-path: "../../../../node_modules/bootstrap-sass/assets/fonts/bootstrap/"; -$font-size-base: 16px; -$cursor-disabled: initial; -$link-hover-decoration: none; -$btn-min-width: 170px; -$link-color: #ddd; -$disabled-opacity: 0.2; - -@import "../../../../node_modules/flexboxgrid/dist/flexboxgrid.css"; -@import "../../../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap"; -@import "./modules/theme"; -@import "./modules/space"; -@import "../pages/main/styles/main"; -@import "../pages/finish/styles/finish"; -@import "./desktop"; - -@font-face { - font-family: "Source Sans Pro"; - src: url("./fonts/SourceSansPro-Regular.ttf") format("truetype"); - font-weight: 500; - font-style: normal; - font-display: block; -} - -@font-face { - font-family: "Source Sans Pro"; - src: url("./fonts/SourceSansPro-SemiBold.ttf") format("truetype"); - font-weight: 600; - font-style: normal; - font-display: block; -} - -// Prevent white flash when running application -html { - background-color: $palette-theme-dark-background; -} - -body { - background-color: $palette-theme-dark-background; - letter-spacing: 0.1px; - display: flex; - flex-direction: column; - font-family: "SourceSansPro"; - - > header { - flex: 0 0 auto; - } - - > main { - flex: 1; - display: flex; - } - - > footer { - flex: 0 0 auto; - } -} - -.section-loader { - webview { - flex: 0 1; - height: 0; - width: 0; - } - - &.isFinish webview { - flex: initial; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 320px; - } -} - -.featured-project { - webview { - flex: 0 1; - height: 0; - width: 0; - } - - &.fp-visible webview { - width: 480px; - height: 360px; - position: absolute; - z-index: 1; - left: 30px; - top: 45px; - border-radius: 7px; - overflow: hidden; - } -} diff --git a/lib/gui/app/scss/modules/_space.scss b/lib/gui/app/scss/modules/_space.scss deleted file mode 100644 index c4151951..00000000 --- a/lib/gui/app/scss/modules/_space.scss +++ /dev/null @@ -1,55 +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. - */ - -$spacing-large: 30px; -$spacing-medium: 15px; -$spacing-small: 10px; -$spacing-tiny: 5px; - -.space-medium { - margin: $spacing-medium; -} - -.space-vertical-medium { - margin-top: $spacing-medium; - margin-bottom: $spacing-medium; -} - -.space-vertical-small { - margin-top: $spacing-small; - margin-bottom: $spacing-small; -} - -.space-top-large { - margin-top: $spacing-large; -} - -.space-vertical-large { - margin-top: $spacing-large; - margin-bottom: $spacing-large; -} - -.space-bottom-medium { - margin-bottom: $spacing-medium; -} - -.space-bottom-large { - margin-bottom: $spacing-large; -} - -.space-right-tiny { - margin-right: $spacing-tiny; -} diff --git a/lib/gui/app/scss/modules/_theme.scss b/lib/gui/app/scss/modules/_theme.scss deleted file mode 100644 index 1ce922b3..00000000 --- a/lib/gui/app/scss/modules/_theme.scss +++ /dev/null @@ -1,37 +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. - */ - -$palette-theme-dark-foreground: #fff; -$palette-theme-dark-background: #4d5057; -$palette-theme-light-foreground: #666; -$palette-theme-light-background: #fff; -$palette-theme-dark-soft-foreground: #ddd; -$palette-theme-dark-soft-background: #64686a; -$palette-theme-light-soft-foreground: #b3b3b3; -$palette-theme-dark-disabled-background: #3a3c41; -$palette-theme-dark-disabled-foreground: #787c7f; -$palette-theme-light-disabled-background: #d5d5d5; -$palette-theme-light-disabled-foreground: #787c7f; -$palette-theme-default-background: #ececec; -$palette-theme-default-foreground: #b3b3b3; -$palette-theme-primary-background: #2297de; -$palette-theme-primary-foreground: #fff; -$palette-theme-warning-background: #ff912f; -$palette-theme-warning-foreground: #fff; -$palette-theme-danger-background: #d9534f; -$palette-theme-danger-foreground: #fff; -$palette-theme-success-background: #5fb835; -$palette-theme-success-foreground: #fff; diff --git a/lib/gui/app/styled-components.tsx b/lib/gui/app/styled-components.tsx index f2260398..19ba5ea7 100644 --- a/lib/gui/app/styled-components.tsx +++ b/lib/gui/app/styled-components.tsx @@ -21,14 +21,29 @@ import { Modal as ModalBase, Provider, Txt, + Flex, + FlexProps, + Theme as renditionTheme, } from 'rendition'; import styled from 'styled-components'; import { space } from 'styled-system'; import { colors, theme } from './theme'; +const defaultTheme = { + ...renditionTheme, + ...theme, + layer: { + extend: () => ` + > div:first-child { + background-color: transparent; + } + `, + }, +}; + export const ThemedProvider = (props: any) => ( - + ); export const BaseButton = styled(Button)` @@ -54,7 +69,6 @@ export const StepButton = styled((props: ButtonProps) => ( ))` color: #ffffff; - margin: auto; `; export const ChangeButton = styled(Button)` @@ -99,38 +113,65 @@ export const Footer = styled(Txt)` font-size: 10px; `; -export const Underline = styled(Txt.span)` - border-bottom: 1px dotted; - padding-bottom: 2px; -`; +export const DetailsText = (props: FlexProps) => ( + +); -export const DetailsText = styled(Txt.p)` - color: ${colors.dark.disabled.foreground}; - margin-bottom: 0; -`; - -export const Modal = styled((props) => { +export const Modal = styled(({ style, ...props }) => { return ( - ` + ${defaultTheme.layer.extend()} + + > div:last-child { + top: 0; + } + `, }, }} - {...props} - /> + > + + ); })` > div { - padding: 30px; + padding: 24px 30px; height: calc(100% - 80px); + ::-webkit-scrollbar { + display: none; + } + > h3 { margin: 0; } > div:last-child { + border-radius: 0 0 7px 7px; height: 80px; background-color: #fff; justify-content: center; @@ -142,3 +183,16 @@ export const Modal = styled((props) => { } } `; + +export const ScrollableFlex = styled(Flex)` + overflow: auto; + + ::-webkit-scrollbar { + display: none; + } + + > div > div { + /* This is required for the sticky table header in TargetsTable */ + overflow-x: visible; + } +`; diff --git a/lib/gui/app/theme.ts b/lib/gui/app/theme.ts index 46e744f9..20ab7c32 100644 --- a/lib/gui/app/theme.ts +++ b/lib/gui/app/theme.ts @@ -65,8 +65,22 @@ export const colors = { }, }; +const font = 'SourceSansPro'; + export const theme = { colors, + font, + global: { + font: { + family: font, + size: 16, + }, + text: { + medium: { + size: 16, + }, + }, + }, button: { border: { width: '0', @@ -79,6 +93,7 @@ export const theme = { && { width: 200px; height: 48px; + font-size: 16px; :disabled { background-color: ${colors.dark.disabled.background}; diff --git a/lib/shared/messages.ts b/lib/shared/messages.ts index ff32c937..6272b8ea 100644 --- a/lib/shared/messages.ts +++ b/lib/shared/messages.ts @@ -19,12 +19,12 @@ import { Dictionary } from 'lodash'; export const progress: Dictionary<(quantity: number) => string> = { successful: (quantity: number) => { const plural = quantity === 1 ? '' : 's'; - return `Successful device${plural}`; + return `Successful target${plural}`; }, failed: (quantity: number) => { const plural = quantity === 1 ? '' : 's'; - return `Failed device${plural}`; + return `Failed target${plural}`; }, }; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index c4404ace..3101f483 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -2630,9 +2630,9 @@ } }, "@babel/runtime-corejs2": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.10.2.tgz", - "integrity": "sha512-ZLwsFnNm3WpIARU1aLFtufjMHsmEnc8TjtrfAjmbgMbeoyR+LuQoyESoNdTfeDhL6IdY12SpeycXMgSgl8XGXA==", + "version": "7.10.3", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.10.3.tgz", + "integrity": "sha512-enKvnR/kKFbZFgXYo165wtSA5OeiTlgsnU4jV3vpKRhfWUJjLS6dfVcjIPeRcgJbgEgdgu0I+UyBWqu6c0GumQ==", "dev": true, "requires": { "core-js": "^2.6.5", @@ -2847,12 +2847,6 @@ "integrity": "sha512-gtis2/5yLdfI6n0ia0jH7NJs5i/Z/8M/ZbQL6jXQhCthEOe5Cr5NcQPhgTvFxNOtURE03/ZqUcEskdn2M+QaBg==", "dev": true }, - "@fortawesome/fontawesome-free-webfonts": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free-webfonts/-/fontawesome-free-webfonts-1.0.9.tgz", - "integrity": "sha512-nLgl6b6a+tXaoJJnSRw0hjN8cWM/Q5DhxKAwI9Xr0AiC43lQ2F98vQ1KLA6kw5OoYeAyisGGqmlwtBj0WqOI5Q==", - "dev": true - }, "@fortawesome/fontawesome-svg-core": { "version": "1.2.28", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.28.tgz", @@ -2943,20 +2937,6 @@ "acorn": "7.3.1", "acorn-jsx": "^5.2.0", "invariant": "2.2.4" - }, - "dependencies": { - "acorn": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", - "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true - } } }, "@react-google-maps/infobox": { @@ -3472,9 +3452,9 @@ "dev": true }, "@types/estree": { - "version": "0.0.44", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.44.tgz", - "integrity": "sha512-iaIVzr+w2ZJ5HkidlZ3EJM8VTZb2MJLCjw3V+505yVts0gRC4UMvjw0d1HPtGqI/HQC/KdsYtayfzl+AXY2R8g==", + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", + "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", "dev": true }, "@types/events": { @@ -3642,9 +3622,9 @@ } }, "@types/react-native": { - "version": "0.62.13", - "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.13.tgz", - "integrity": "sha512-hs4/tSABhcJx+J8pZhVoXHrOQD89WFmbs8QiDLNSA9zNrD46pityAuBWuwk1aMjPk9I3vC5ewkJroVRHgRIfdg==", + "version": "0.62.14", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.14.tgz", + "integrity": "sha512-ItBgiEQks2Mid6GsiLBx75grNH0glaKemTK9V7G+vSnvP+Zk3x1Wr+aTy4dJxRPPMg14DAJyYePLZwj2cigXbw==", "dev": true, "requires": { "@types/react": "*" @@ -4066,27 +4046,16 @@ "dev": true }, "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", "dev": true }, "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true }, "agent-base": { "version": "4.3.0", @@ -4842,12 +4811,6 @@ "dev": true, "optional": true }, - "bootstrap-sass": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/bootstrap-sass/-/bootstrap-sass-3.4.1.tgz", - "integrity": "sha512-p5rxsK/IyEDQm2CwiHxxUi0MZZtvVFbhWmyMOt4lLkA4bujDA1TGoKT0i1FKIWiugAdP+kK8T5KMDFIKQCLYIA==", - "dev": true - }, "boxen": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", @@ -5519,12 +5482,6 @@ "safe-buffer": "^5.0.1" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -5685,17 +5642,6 @@ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, "clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", @@ -5713,12 +5659,6 @@ } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, "coa": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", @@ -5737,9 +5677,9 @@ "dev": true }, "codemirror": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.54.0.tgz", - "integrity": "sha512-Pgf3surv4zvw+KaW3doUU7pGjF0BPU8/sj7eglWJjzni46U/DDW8pu3nZY0QgQKUcICDXRkq8jZmq0y6KhxM3Q==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.55.0.tgz", + "integrity": "sha512-TumikSANlwiGkdF/Blnu/rqovZ0Y3Jh8yy9TqrPbSM0xxSucq3RgnpVDQ+mD9q6JERJEIT2FMuF/fBGfkhIR/g==", "dev": true }, "codemirror-spell-checker": { @@ -6952,12 +6892,6 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, "deep-map-keys": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/deep-map-keys/-/deep-map-keys-1.2.0.tgz", @@ -7207,16 +7141,6 @@ } } }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -7358,9 +7282,9 @@ } }, "electron": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.4.tgz", - "integrity": "sha512-QzkeZNAiNB7KxcdoQKSoaiVT/GQdB4Vt0/ZZOuU8tIKABAsni2I7ztiAbUzxcsnQsqEBSfChuPuDQ5A4VbbzPg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.5.tgz", + "integrity": "sha512-bnL9H48LuQ250DML8xUscsKiuSu+xv5umXbpBXYJ0BfvYVmFfNbG3jCfhrsH7aP6UcQKVxOG1R/oQExd0EFneQ==", "dev": true, "requires": { "@electron/get": "^1.0.1", @@ -8282,20 +8206,6 @@ "es6-symbol": "^3.1.1" } }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -8311,31 +8221,6 @@ "es6-promise": "^4.0.3" } }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - }, - "dependencies": { - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - } - } - }, "es6-symbol": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", @@ -8376,119 +8261,6 @@ "integrity": "sha512-QGb9sFxBVpbzMggrKTX0ry1oiI4CSDAl9vIL702hzl1jGW8VZs7qfqTRX7WDOjoNDoEVGcEtu1ZOQgReSfT2kQ==", "dev": true }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dev": true, - "requires": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz", - "integrity": "sha1-5MyPoPAJ+4KaquI4VaKTYL4fbBE=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "concat-stream": "^1.4.6", - "debug": "^2.1.1", - "doctrine": "^1.2.2", - "es6-map": "^0.1.3", - "escope": "^3.6.0", - "espree": "^3.1.6", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^1.1.1", - "glob": "^7.0.3", - "globals": "^9.2.0", - "ignore": "^3.1.2", - "imurmurhash": "^0.1.4", - "inquirer": "^0.12.0", - "is-my-json-valid": "^2.10.0", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.5.1", - "json-stable-stringify": "^1.0.0", - "levn": "^0.3.0", - "lodash": "^4.0.0", - "mkdirp": "^0.5.0", - "optionator": "^0.8.1", - "path-is-absolute": "^1.0.0", - "path-is-inside": "^1.0.1", - "pluralize": "^1.2.1", - "progress": "^1.1.8", - "require-uncached": "^1.0.2", - "shelljs": "^0.6.0", - "strip-json-comments": "~1.0.1", - "table": "^3.7.8", - "text-table": "~0.2.0", - "user-home": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", - "dev": true - }, - "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -8499,16 +8271,6 @@ "estraverse": "^4.1.1" } }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -8537,9 +8299,9 @@ "dev": true }, "etcher-sdk": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.15.tgz", - "integrity": "sha512-PZ/OLbAmtQXQlla33FVwvyLL5rzpYG5gQLpPiz1zCzNDWykaVIM9lXQ8m0DxTp7/m11tM3lw1gT/IPCUKtKfdA==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.17.tgz", + "integrity": "sha512-cmsPI08f/uArgpWWvJLDKOYOLk99kUooQCKnbdWORwXvKCAnp7i2CAz2KMUDZ3csgsMx7a+JWFw+27/8NGr+Uw==", "dev": true, "requires": { "@ronomon/direct-io": "^3.0.1", @@ -8557,7 +8319,7 @@ "mountutils": "^1.3.18", "node-raspberrypi-usbboot": "^0.2.4", "outdent": "^0.7.0", - "partitioninfo": "^5.3.4", + "partitioninfo": "^5.3.5", "resin-image-fs": "^5.0.8", "rwmutex": "^1.0.0", "udif": "^0.17.0", @@ -8578,16 +8340,6 @@ } } }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "event-pubsub": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", @@ -8625,12 +8377,6 @@ "strip-eof": "^1.0.0" } }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true - }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -8901,12 +8647,6 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, "fastq": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", @@ -8989,16 +8729,6 @@ "bluebird": "^3.5.3" } }, - "file-entry-cache": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz", - "integrity": "sha1-RMYepgeuS+nBQC9B9EJwy/4zT/g=", - "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } - }, "file-loader": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz", @@ -9297,35 +9027,6 @@ "is-buffer": "~2.0.3" } }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flexboxgrid": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/flexboxgrid/-/flexboxgrid-6.3.1.tgz", - "integrity": "sha1-6ZiYr8B7cEdyK7galYpfuk1OIP0=", - "dev": true - }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", @@ -9413,15 +9114,6 @@ "readable-stream": "^2.0.0" } }, - "front-matter": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-2.1.2.tgz", - "integrity": "sha1-91mDufL0E75ljJPf172M5AePXNs=", - "dev": true, - "requires": { - "js-yaml": "^3.4.6" - } - }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -9498,24 +9190,6 @@ "globule": "^1.0.0" } }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dev": true, - "requires": { - "is-property": "^1.0.2" - } - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "^1.0.0" - } - }, "gensync": { "version": "1.0.0-beta.1", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", @@ -9721,23 +9395,6 @@ "minimatch": "~3.0.2" } }, - "gonzales-pe-sl": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/gonzales-pe-sl/-/gonzales-pe-sl-4.2.3.tgz", - "integrity": "sha1-aoaLw4BkXxQf7rBCxvl/zHG1n+Y=", - "dev": true, - "requires": { - "minimist": "1.1.x" - }, - "dependencies": { - "minimist": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", - "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=", - "dev": true - } - } - }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -9784,9 +9441,9 @@ } }, "gpt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gpt/-/gpt-2.0.2.tgz", - "integrity": "sha512-ZeXRFQLFaLhwRk9Xf1fQUqUG8112Nz7CvF8WOdtgW6iq3rB0EnCd0zkiEylYzUbqGhWe0joViRd4BR12JKtWwQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/gpt/-/gpt-2.0.4.tgz", + "integrity": "sha512-gCibB52dZAjDeyuAJE158FfVYpMa8poCBMYvNXCwDvZJ0+5D0YpP1hZ/KYtWpQyXu18ddoQoqj+FGnbyq2qhKw==", "dev": true, "requires": { "cyclic-32": "^1.1.0" @@ -9879,15 +9536,6 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -10387,15 +10035,6 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "inactivity-timer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/inactivity-timer/-/inactivity-timer-1.0.0.tgz", - "integrity": "sha512-kxWME4cNy0TKfy9wwJ2L3oCV1JDFQTPGtYdw3Zvpiv5GbZwfnCwfESJgM1MQaYcrzLYOziiU3YEAgWOafL7Kdw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -10436,95 +10075,6 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, - "inquirer": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "ansi-regex": "^2.0.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", - "cli-width": "^2.0.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "readline2": "^1.0.1", - "run-async": "^0.1.0", - "rx-lite": "^3.1.2", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "interpret": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", @@ -10729,25 +10279,6 @@ "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", "dev": true }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true - }, - "is-my-json-valid": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", - "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", - "dev": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, "is-npm": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", @@ -10793,12 +10324,6 @@ "isobject": "^3.0.1" } }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -10814,12 +10339,6 @@ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", "dev": true }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, "is-set": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", @@ -11026,15 +10545,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -11060,18 +10570,6 @@ "universalify": "^1.0.0" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -11105,12 +10603,6 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, - "known-css-properties": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.3.0.tgz", - "integrity": "sha512-QMQcnKAiQccfQTqtBh/qwquGZ2XK/DXND1jrcN9M8gMMy99Gwla7GQjndVUsEqIaRyP6bsFRuhwRj5poafBGJQ==", - "dev": true - }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -11165,16 +10657,6 @@ "leven": "^3.1.0" } }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -11521,12 +11003,6 @@ "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", "dev": true }, - "lodash.capitalize": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", - "dev": true - }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -11539,12 +11015,6 @@ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", "dev": true }, - "lodash.kebabcase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", - "dev": true - }, "log-symbols": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", @@ -11808,12 +11278,6 @@ "readable-stream": "^2.0.1" } }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", - "dev": true - }, "merge-deep": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", @@ -12692,12 +12156,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "mute-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", - "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", - "dev": true - }, "nan": { "version": "2.14.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", @@ -13388,20 +12846,6 @@ } } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, "ora": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", @@ -13891,12 +13335,6 @@ "xmldom": "0.1.x" } }, - "pluralize": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", - "dev": true - }, "polished": { "version": "3.6.5", "resolved": "https://registry.npmjs.org/polished/-/polished-3.6.5.tgz", @@ -13993,9 +13431,9 @@ "dev": true }, "prebuild-install": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.4.tgz", - "integrity": "sha512-AkKN+pf4fSEihjapLEEj8n85YIw/tN6BQqkhzbDc0RvEZGdkpJBGMUYx66AAMcPG2KzmPQS7Cm16an4HVBRRMA==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.5.tgz", + "integrity": "sha512-YmMO7dph9CYKi5IR/BzjOJlRzpxGGVo1EsLSUZ0mt/Mq0HWZIHOKHHcHdT69yG54C9m6i45GpItwRHpk0Py7Uw==", "dev": true, "requires": { "detect-libc": "^1.0.3", @@ -14015,12 +13453,6 @@ "which-pm-runs": "^1.0.0" } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -14301,9 +13733,9 @@ } }, "react-async-script": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.1.1.tgz", - "integrity": "sha512-pmgS3O7JcX4YtH/Xy//NXylpD5CNb5T4/zqlVUV3HvcuyOanatvuveYoxl3X30ZSq/+q/+mSXcNS8xDVQJpSeA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", "dev": true, "requires": { "hoist-non-react-statics": "^3.3.0", @@ -14400,9 +13832,9 @@ "dev": true }, "react-simplemde-editor": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/react-simplemde-editor/-/react-simplemde-editor-4.1.2.tgz", - "integrity": "sha512-0eEPhrOTRNNCxnuJMmUuPm/DHIijsm9H2aGrY9+nmMksccNHi7mfBM9ajoIzo9XzWZrXSvjBu+svzRdt48MjLw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/react-simplemde-editor/-/react-simplemde-editor-4.1.3.tgz", + "integrity": "sha512-MJ3SDYfYsNnEcmLzQCqPERDaarllwbxR06oyOQ+jJn0517HYIcQCfFoOIT4uewRY14g05n/Ux1Nka88Bocrdcg==", "dev": true, "requires": { "@types/codemirror": "^0.0.88", @@ -14447,17 +13879,6 @@ "picomatch": "^2.0.4" } }, - "readline2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "mute-stream": "0.0.5" - } - }, "recompose": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.26.0.tgz", @@ -14603,9 +14024,9 @@ "dev": true }, "rendition": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/rendition/-/rendition-15.2.1.tgz", - "integrity": "sha512-dwSiy43c3EEw+eZDz7qNNPQZ1zH7iTlAYd5AdHevmYwZdvnFNFQen0EdhAr9Z8o4ra6TYZpNJod4Vp9eZ1hufQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/rendition/-/rendition-15.2.4.tgz", + "integrity": "sha512-/AdQwNyBuHqbYDf7JTRvFNKnpWZQxEpOe8ac/hAAg9mOOjTt+kgV7SO7NjWKkl4IADic/OtWN7BpBsfAtuwrsw==", "dev": true, "requires": { "@fortawesome/fontawesome-svg-core": "^1.2.25", @@ -14755,39 +14176,6 @@ "integrity": "sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=", "dev": true }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - } - } - }, "resin-corvus": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/resin-corvus/-/resin-corvus-2.0.5.tgz", @@ -14953,21 +14341,6 @@ } } }, - "roboto-fontface": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", - "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==", - "dev": true - }, - "run-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dev": true, - "requires": { - "once": "^1.3.0" - } - }, "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", @@ -15077,96 +14450,6 @@ "xtend": "^4.0.1" } }, - "sass": { - "version": "1.26.5", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.5.tgz", - "integrity": "sha512-FG2swzaZUiX53YzZSjSakzvGtlds0lcbF+URuU9mxOv7WBh7NhXEVDa4kPKN4hN6fC2TkOTOKqiqp6d53N9X5Q==", - "dev": true, - "requires": { - "chokidar": ">=2.0.0 <4.0.0" - } - }, - "sass-lint": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sass-lint/-/sass-lint-1.13.1.tgz", - "integrity": "sha512-DSyah8/MyjzW2BWYmQWekYEKir44BpLqrCFsgs9iaWiVTcwZfwXHF586hh3D1n+/9ihUNMfd8iHAyb9KkGgs7Q==", - "dev": true, - "requires": { - "commander": "^2.8.1", - "eslint": "^2.7.0", - "front-matter": "2.1.2", - "fs-extra": "^3.0.1", - "glob": "^7.0.0", - "globule": "^1.0.0", - "gonzales-pe-sl": "^4.2.3", - "js-yaml": "^3.5.4", - "known-css-properties": "^0.3.0", - "lodash.capitalize": "^4.1.0", - "lodash.kebabcase": "^4.0.0", - "merge": "^1.2.0", - "path-is-absolute": "^1.0.0", - "util": "^0.10.3" - }, - "dependencies": { - "fs-extra": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", - "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^3.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - } - } - }, - "sass-loader": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", - "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "loader-utils": "^1.2.3", - "neo-async": "^2.6.1", - "schema-utils": "^2.6.1", - "semver": "^6.3.0" - }, - "dependencies": { - "schema-utils": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz", - "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==", - "dev": true, - "requires": { - "ajv": "^6.12.0", - "ajv-keywords": "^3.4.1" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -15321,15 +14604,6 @@ "safe-buffer": "^5.0.1" } }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -15351,12 +14625,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shelljs": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz", - "integrity": "sha1-7GIRvtGSBEIIj+D3Cyg3Iy7SyKg=", - "dev": true - }, "shortid": { "version": "2.2.15", "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.15.tgz", @@ -15600,9 +14868,9 @@ } }, "slugify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.0.tgz", - "integrity": "sha512-FtLNsMGBSRB/0JOE2A0fxlqjI6fJsgHGS13iTuVT28kViI4JjUiNqp/vyis0ZXYcMnpR3fzGNkv+6vRlI2GwdQ==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.4.tgz", + "integrity": "sha512-N2+9NJ8JzfRMh6PQLrBeDEnVDQZSytE/W4BTC4fNNPmO90Uu58uNwSlIJSs+lmPgWsaAF79WLhVPe5tuy7spjw==", "dev": true }, "snapdragon": { @@ -16256,102 +15524,6 @@ "integrity": "sha512-ckjrMCWWwg1J4d+B3xlTPLhgK6U/2qpW1TYzCLBSULKoLk2tFchis7nDEOmcbiLfpR/8GQK1Q2CrDNleF0USHA==", "dev": true }, - "table": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", - "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", - "dev": true, - "requires": { - "ajv": "^4.7.0", - "ajv-keywords": "^1.0.0", - "chalk": "^1.1.1", - "lodash": "^4.0.0", - "slice-ansi": "0.0.4", - "string-width": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, - "ajv-keywords": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -16483,12 +15655,6 @@ "worker-farm": "^1.7.0" } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -16797,15 +15963,6 @@ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "dev": true }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -16883,13 +16040,10 @@ } }, "uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", - "dev": true, - "requires": { - "commander": "~2.20.3" - } + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", + "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", + "dev": true }, "unbzip2-stream": { "version": "github:balena-io-modules/unbzip2-stream#4a54f56a25b58950f9e4277c56db2912d62242e7", @@ -17172,38 +16326,12 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "user-home": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", - "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0" - } - }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=", "dev": true }, - "util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -18207,12 +17335,6 @@ } } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -18310,15 +17432,6 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", @@ -18639,4 +17752,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 37ef3bd9..95bf4d5c 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,9 @@ "lint-staged": { "./**/*.{ts,tsx}": [ "make lint-ts" + ], + "./**/*.css": [ + "make lint-css" ] }, "author": "Balena Inc. ", @@ -44,8 +47,6 @@ ], "devDependencies": { "@balena/lint": "^5.0.4", - "@fortawesome/fontawesome-free-webfonts": "^1.0.9", - "@fortawesome/fontawesome-svg-core": "^1.2.25", "@fortawesome/free-brands-svg-icons": "^5.11.2", "@fortawesome/free-solid-svg-icons": "^5.11.2", "@fortawesome/react-fontawesome": "^0.1.7", @@ -66,24 +67,21 @@ "@types/tmp": "^0.2.0", "@types/webpack-node-externals": "^1.7.0", "bluebird": "^3.7.2", - "bootstrap-sass": "^3.3.6", "chai": "^4.2.0", "copy-webpack-plugin": "^6.0.1", "css-loader": "^3.5.3", "d3": "^4.13.0", "debug": "^4.2.0", - "electron": "9.0.4", + "electron": "9.0.5", "electron-builder": "^22.7.0", "electron-mocha": "^8.2.0", "electron-notarize": "^1.0.0", "electron-rebuild": "^1.11.0", "electron-updater": "^4.3.2", - "etcher-sdk": "^4.1.15", + "etcher-sdk": "^4.1.17", "file-loader": "^6.0.0", - "flexboxgrid": "^6.3.0", "husky": "^4.2.5", "immutable": "^3.8.1", - "inactivity-timer": "^1.0.0", "lint-staged": "^10.2.2", "lodash": "^4.17.10", "mini-css-extract-plugin": "^0.9.0", @@ -98,13 +96,9 @@ "react": "^16.8.5", "react-dom": "^16.8.5", "redux": "^4.0.5", - "rendition": "^15.2.1", + "rendition": "^15.2.4", "request": "^2.81.0", "resin-corvus": "^2.0.5", - "roboto-fontface": "^0.10.0", - "sass": "^1.26.5", - "sass-lint": "^1.12.1", - "sass-loader": "^8.0.2", "semver": "^7.3.2", "simple-progress-webpack-plugin": "^1.1.2", "sinon": "^9.0.2", diff --git a/webpack.config.ts b/webpack.config.ts index fc79acbd..eac976a1 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -309,22 +309,7 @@ const cssConfig = { rules: [ { test: /\.css$/i, - use: 'css-loader', - }, - { - test: /\.s[ac]ss$/i, - use: [ - MiniCssExtractPlugin.loader, - 'css-loader', - { - loader: 'sass-loader', - options: { - sassOptions: { - fiber: false, - }, - }, - }, - ], + use: [MiniCssExtractPlugin.loader, 'css-loader'], }, { test: /\.(woff|woff2|eot|ttf|otf|svg)$/, @@ -345,7 +330,7 @@ const cssConfig = { }), ], entry: { - index: path.join(__dirname, 'lib', 'gui', 'app', 'scss', 'main.scss'), + index: path.join(__dirname, 'lib', 'gui', 'app', 'css', 'main.css'), }, output: { path: path.join(__dirname, 'generated'),