reorganize src/ directory

Makes for much less scrolling/jumping around.

https://redux.js.org/style-guide/style-guide#structure-files-as-feature-folders-or-ducks
This commit is contained in:
David Lechner
2021-02-01 10:26:05 -06:00
parent b30c31f8b7
commit 6f204a65f6
122 changed files with 389 additions and 779 deletions
@@ -7,18 +7,18 @@ import { AnchorButton, Button, Classes, Dialog } from '@blueprintjs/core';
import { WithI18nProps, withI18n } from '@shopify/react-i18n';
import React from 'react';
import { connect } from 'react-redux';
import { closeAboutDialog, openLicenseDialog } from '../actions/app';
import { RootState } from '../reducers';
import { closeAboutDialog, openLicenseDialog } from '../app/actions';
import {
appName,
legoDisclaimer,
pybricksCopyright,
pybricksWebsiteUrl,
} from '../settings/ui';
import ExternalLinkIcon from './ExternalLinkIcon';
import LicenseDialog from './LicenseDialog';
import { AboutStringId } from './about-i18n';
import en from './about-i18n.en.json';
} from '../app/constants';
import LicenseDialog from '../licenses/LicenseDialog';
import { RootState } from '../reducers';
import ExternalLinkIcon from '../utils/ExternalLinkIcon';
import { AboutStringId } from './i18n';
import en from './i18n.en.json';
import './about.scss';
@@ -2,8 +2,8 @@
// Copyright (c) 2021 The Pybricks Authors
import { lookup } from '../../test';
import { AboutStringId } from './about-i18n';
import en from './about-i18n.en.json';
import { AboutStringId } from './i18n';
import en from './i18n.en.json';
describe('Ensure .json file has matches for AboutStringId', () => {
test.each(Object.values(AboutStringId))('%s', (id) => {
+13 -13
View File
@@ -2,25 +2,25 @@
// Copyright (c) 2020 The Pybricks Authors
import { Dispatch as ReduxDispatch } from 'redux';
import { AppAction } from './app';
import { BLEAction, BLEConnectAction } from './ble';
import { BleUartAction } from './ble-uart';
import { EditorAction } from './editor';
import { FlashFirmwareAction } from './flash-firmware';
import { HubAction, HubMessageAction } from './hub';
import { LicenseAction } from './license';
import { AppAction } from './app/actions';
import { BleUartAction } from './ble-uart/actions';
import { BLEAction, BLEConnectAction } from './ble/actions';
import { EditorAction } from './editor/actions';
import { FlashFirmwareAction } from './firmware/actions';
import { HubAction, HubMessageAction } from './hub/actions';
import { LicenseAction } from './licenses/actions';
import {
BootloaderConnectionAction,
BootloaderDidFailToRequestAction,
BootloaderDidRequestAction,
BootloaderRequestAction,
BootloaderResponseAction,
} from './lwp3-bootloader';
import { MpyAction } from './mpy';
import { NotificationAction } from './notification';
import { ServiceWorkerAction } from './service-worker';
import { SettingsAction } from './settings';
import { TerminalDataAction } from './terminal';
} from './lwp3-bootloader/actions';
import { MpyAction } from './mpy/actions';
import { NotificationAction } from './notifications/actions';
import { ServiceWorkerAction } from './service-worker/actions';
import { SettingsAction } from './settings/actions';
import { TerminalDataAction } from './terminal/actions';
/**
* Common type for all actions.
+7 -7
View File
@@ -5,15 +5,15 @@ import { Classes } from '@blueprintjs/core';
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import SplitterLayout from 'react-splitter-layout';
import { toggleBoolean } from '../actions/settings';
import Editor from '../editor/Editor';
import { RootState } from '../reducers';
import { SettingId } from '../settings/user';
import SettingsDrawer from '../settings/SettingsDrawer';
import { toggleBoolean } from '../settings/actions';
import { SettingId } from '../settings/defaults';
import StatusBar from '../status-bar/StatusBar';
import Terminal from '../terminal/Terminal';
import Toolbar from '../toolbar/Toolbar';
import { isMacOS } from '../utils/os';
import Editor from './Editor';
import SettingsDrawer from './SettingsDrawer';
import StatusBar from './StatusBar';
import Terminal from './Terminal';
import Toolbar from './Toolbar';
import 'react-splitter-layout/lib/index.css';
import './app.scss';
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// File: actions/app.ts
//
// Actions for the app in general.
import { Action } from 'redux';
+3 -3
View File
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// File: reducers/app.ts
//
// Manages state the app in general.
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import { AppActionType } from '../actions/app';
import { ServiceWorkerActionType } from '../actions/service-worker';
import { ServiceWorkerActionType } from '../service-worker/actions';
import { BeforeInstallPromptEvent } from '../utils/dom';
import { AppActionType } from './actions';
export interface AppState {
readonly showSettings: boolean;
@@ -2,6 +2,7 @@
// Copyright (c) 2021 The Pybricks Authors
import { AsyncSaga, delay } from '../../test';
import { BeforeInstallPromptEvent } from '../utils/dom';
import {
checkForUpdate,
didBeforeInstallPrompt,
@@ -9,9 +10,8 @@ import {
didInstallPrompt,
installPrompt,
reload,
} from '../actions/app';
import { BeforeInstallPromptEvent } from '../utils/dom';
import app from './app';
} from './actions';
import app from './sagas';
test('monitorAppInstalled', async () => {
const saga = new AsyncSaga(app);
+2 -2
View File
@@ -3,6 +3,7 @@
import { eventChannel } from 'redux-saga';
import { call, fork, put, take, takeEvery } from 'typed-redux-saga/macro';
import { BeforeInstallPromptEvent } from '../utils/dom';
import {
AppActionType,
AppCheckForUpdatesAction,
@@ -12,8 +13,7 @@ import {
didCheckForUpdate,
didInstall,
didInstallPrompt,
} from '../actions/app';
import { BeforeInstallPromptEvent } from '../utils/dom';
} from './actions';
function* monitorAppInstalled(): Generator {
const chan = eventChannel<Event>((emit) => {
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: protocols/pybricks.ts
//
// Definitions related to the Pybricks Bluetooth low energy GATT service.
// Protocol details have not been defined yet.
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: protocols/nrf-uart.ts
//
// Definitions related to the nRF UART Bluetooth low energy GATT service.
//
// The Nordic Semiconductor nRF UART service is a defacto standard for providing
// serial communication using Bluetooth Low Energy.
// https://infocenter.nordicsemi.com/topic/sdk_nrf5_v16.0.0/ble_sdk_app_nus_eval.html
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: sagas/ble-uart.ts
//
// Manages connection to a Bluetooth Low Energy device with the Nordic (nRF) UART service.
import { END, eventChannel } from 'redux-saga';
@@ -12,6 +12,7 @@ import {
takeEvery,
takeMaybe,
} from 'typed-redux-saga/macro';
import { ServiceUUID as pybricksServiceUUID } from '../ble-pybricks/protocol';
import {
BLEActionType,
BleDeviceActionType as BLEDeviceActionType,
@@ -24,22 +25,21 @@ import {
didDisconnect,
didFailToConnect,
disconnect as disconnectAction,
} from '../actions/ble';
} from '../ble/actions';
import { BleConnectionState } from '../ble/reducers';
import { RootState } from '../reducers';
import {
BleUartActionType,
BleUartWriteAction,
didFailToWrite,
didWrite,
notify,
} from '../actions/ble-uart';
} from './actions';
import {
ServiceUUID as uartServiceUUID,
TxCharUUID as uartTxCharUUID,
RxCharUUID as urtRxCharUUID,
} from '../protocols/nrf-uart';
import { ServiceUUID as pybricksServiceUUID } from '../protocols/pybricks';
import { RootState } from '../reducers';
import { BleConnectionState } from '../reducers/ble';
} from './protocol';
function disconnect(
server: BluetoothRemoteGATTServer,
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: actions/ble.ts
//
// Actions for managing Bluetooth Low Energy connections.
import { Action } from 'redux';
+2 -2
View File
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: reducers/ble.ts
//
// Manages state for the Bluetooth Low Energy connection.
// This assumes that there is only one global connection to a single device.
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import { BleDeviceActionType } from '../actions/ble';
import { BleDeviceActionType } from './actions';
/**
* Describes the state of the BLE connection.
-55
View File
@@ -1,55 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
import { Button, Intent, Position, Tooltip } from '@blueprintjs/core';
import { WithI18nProps, withI18n } from '@shopify/react-i18n';
import React from 'react';
import { tooltipDelay } from '../settings/ui';
import { TooltipId } from './button-i18n';
import en from './button-i18n.en.json';
export interface LinkButtonProps {
/** A unique id for each instance. */
readonly id: string;
/** The URL to open. */
readonly url: string;
/** Tooltip text that appears when hovering over the button. */
readonly tooltip: TooltipId;
/** Icon shown on the button. */
readonly icon: string;
/** When true or undefined, the button is enabled. */
readonly enabled?: boolean;
}
type Props = LinkButtonProps & WithI18nProps;
class LinkButton extends React.Component<Props> {
render(): JSX.Element {
return (
<Tooltip
content={this.props.i18n.translate(this.props.tooltip)}
position={Position.BOTTOM}
hoverOpenDelay={tooltipDelay}
>
<Button
intent={Intent.PRIMARY}
disabled={this.props.enabled === false}
className="no-box-shadow"
style={
this.props.enabled === false
? { pointerEvents: 'none' }
: undefined
}
>
<a href={this.props.url} target="_blank" rel="noopener noreferrer">
<img src={this.props.icon} alt={this.props.id} />
</a>
</Button>
</Tooltip>
);
}
}
export default withI18n({ id: 'linkButton', fallback: en, translations: { en } })(
LinkButton,
);
-159
View File
@@ -1,159 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="50"
height="50"
viewBox="0 0 26.458333 26.458334"
version="1.1"
id="svg8"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="pybricks.svg"
inkscape:export-filename="button.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2">
<linearGradient
id="light-circle-fill"
osb:paint="solid"
gradientTransform="matrix(0.07840972,0,0,0.07840972,-20.351522,498.54009)">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5207" />
</linearGradient>
<linearGradient
id="icon-contents"
osb:paint="solid"
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
<stop
style="stop-color:#3880b7;stop-opacity:1;"
offset="0"
id="stop5179" />
</linearGradient>
<linearGradient
id="light-circle-edge"
osb:paint="solid"
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
<stop
style="stop-color:#b7b7b7;stop-opacity:1;"
offset="0"
id="stop5173" />
</linearGradient>
<linearGradient
id="dark-back"
osb:paint="solid"
gradientTransform="translate(1195.9167,-717.54999)">
<stop
style="stop-color:#333333;stop-opacity:1;"
offset="0"
id="stop1439" />
</linearGradient>
<linearGradient
id="dark-front"
osb:paint="solid"
gradientTransform="translate(4643.556,-4.2349475e-6)">
<stop
style="stop-color:#d4d4d4;stop-opacity:1;"
offset="0"
id="stop1389" />
</linearGradient>
<linearGradient
id="light-front"
osb:paint="solid"
gradientTransform="translate(-313.01005,-269.76128)">
<stop
style="stop-color:#4e4e4e;stop-opacity:1;"
offset="0"
id="stop1184" />
</linearGradient>
<linearGradient
id="light-back"
osb:paint="solid"
gradientTransform="translate(-78.252472)">
<stop
style="stop-color:#eeeeee;stop-opacity:1;"
offset="0"
id="stop1172" />
</linearGradient>
<linearGradient
id="light-circle-fill-7"
osb:paint="solid"
gradientTransform="matrix(1.4086066e-4,-8.1325943e-5,8.8105753e-5,1.5260364e-4,-260.60913,1176.7064)">
<stop
style="stop-color:#0088ce;stop-opacity:1;"
offset="0"
id="stop5207-5" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="20.226169"
inkscape:cy="25.148514"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1853"
inkscape:window-height="1145"
inkscape:window-x="67"
inkscape:window-y="27"
inkscape:window-maximized="1"
units="px"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0"
inkscape:snap-global="false"
showguides="true"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-270.54165)">
<path
style="fill:#fcfcfc;fill-opacity:1;stroke:none;stroke-width:0.18514594;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 1.9233968,276.12994 C 0.85786585,276.12994 0,276.98649 0,278.05127 v 0.0165 8.17314 2.39882 c 0,1.0648 0.85786585,1.92133 1.9233968,1.92133 h 3.3755047 c 1.065531,0 1.923397,-0.85653 1.923397,-1.92133 v -0.47646 H 19.236035 v 0.47646 c 0,1.0648 0.857866,1.92133 1.923397,1.92133 h 3.375504 c 1.065533,0 1.923397,-0.85653 1.923397,-1.92133 v -2.39882 -8.17314 -0.0165 c 0,-1.06478 -0.857864,-1.92133 -1.923397,-1.92133 h -3.375504 c -5.48261,0.0358 -11.132273,0.0125 -15.8605305,0 z m 0.4960938,2.41226 H 24.063647 v 4.66534 1.66812 3.28352 h -2.397786 v -2.39159 h -2.069124 v -0.89193 H 18.85363 v 0.89193 h -1.663981 v -0.89193 h -0.740007 v 0.89193 h -1.663981 v -0.89193 h -0.740006 v 0.89193 h -1.663981 v -0.89193 h -0.743108 v 0.89193 H 9.9745848 v -0.89193 H 9.2335451 v 0.89193 h -1.663981 v -0.89193 H 6.8864015 v 0.89193 H 4.817277 v 2.39159 H 2.4194906 v -2.39159 -0.89193 z"
id="rect1407"
inkscape:connector-curvature="0" />
<ellipse
ry="1.7064419"
rx="1.7076348"
cy="281.03445"
cx="8.4499493"
id="path1477"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.18514594;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
ry="1.7064419"
rx="1.7076348"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.18514594;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle1489"
cx="18.032797"
cy="281.03445" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

-164
View File
@@ -1,164 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="50"
height="50"
viewBox="0 0 26.458333 26.458334"
version="1.1"
id="svg8"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="support.svg"
inkscape:export-filename="button.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2">
<linearGradient
id="light-circle-fill"
osb:paint="solid"
gradientTransform="matrix(0.52916667,0,0,0.52916667,-5.9127106,167.15004)">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5207" />
</linearGradient>
<linearGradient
id="icon-contents"
osb:paint="solid"
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
<stop
style="stop-color:#3880b7;stop-opacity:1;"
offset="0"
id="stop5179" />
</linearGradient>
<linearGradient
id="light-circle-edge"
osb:paint="solid"
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
<stop
style="stop-color:#b7b7b7;stop-opacity:1;"
offset="0"
id="stop5173" />
</linearGradient>
<linearGradient
id="dark-back"
osb:paint="solid"
gradientTransform="translate(1195.9167,-717.54999)">
<stop
style="stop-color:#333333;stop-opacity:1;"
offset="0"
id="stop1439" />
</linearGradient>
<linearGradient
id="dark-front"
osb:paint="solid"
gradientTransform="translate(4643.556,-4.2349475e-6)">
<stop
style="stop-color:#d4d4d4;stop-opacity:1;"
offset="0"
id="stop1389" />
</linearGradient>
<linearGradient
id="light-front"
osb:paint="solid"
gradientTransform="translate(-313.01005,-269.76128)">
<stop
style="stop-color:#4e4e4e;stop-opacity:1;"
offset="0"
id="stop1184" />
</linearGradient>
<linearGradient
id="light-back"
osb:paint="solid"
gradientTransform="translate(-78.252472)">
<stop
style="stop-color:#eeeeee;stop-opacity:1;"
offset="0"
id="stop1172" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="28.310142"
inkscape:cy="27.553772"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1853"
inkscape:window-height="1145"
inkscape:window-x="67"
inkscape:window-y="27"
inkscape:window-maximized="1"
units="px"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0"
inkscape:snap-global="false"
showguides="false"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-270.54165)">
<path
sodipodi:nodetypes="sssscccsssssssssccccssss"
inkscape:connector-curvature="0"
id="path1050"
d="m 4.4548275,276.14161 c -1.959619,0 -3.56980798,1.61019 -3.56980798,3.56981 v 5.49225 c 0,1.95962 1.61018898,3.56981 3.56980798,3.56981 h 3.803465 l -0.829924,6.47299 10.2329705,-6.47299 h 4.090626 c 1.959619,0 3.570841,-1.61019 3.570841,-3.56981 v -5.49225 c 0,-1.95962 -1.611222,-3.56981 -3.570841,-3.56981 z m 0,2.11667 H 21.751965 c 0.823598,0 1.453141,0.62954 1.453141,1.45314 v 5.49225 c 0,0.8236 -0.629543,1.45314 -1.453141,1.45314 H 17.32068 l -7.4076185,4.79415 0.5884805,-4.79415 H 4.4548275 c -0.823598,0 -1.453141,-0.62954 -1.453141,-1.45314 v -5.49225 c 0,-0.8236 0.629543,-1.45314 1.453141,-1.45314 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
ry="0"
rx="0"
y="281.07489"
x="7.8086252"
height="2.1166668"
width="2.1166668"
id="rect1052"
style="fill:#fcfcfc;fill-opacity:1;stroke:none;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="fill:#fcfcfc;fill-opacity:1;stroke:none;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1054"
width="2.1166668"
height="2.1166668"
x="11.901399"
y="281.07489"
rx="0"
ry="0" />
<rect
ry="0"
rx="0"
y="281.07489"
x="15.994172"
height="2.1166668"
width="2.1166668"
id="rect1056"
style="fill:#fcfcfc;fill-opacity:1;stroke:none;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.7 KiB

-28
View File
@@ -1,28 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
// File: components/settings-i18n.ts
// Settings translation keys.
export enum SettingsStringId {
Title = 'settings.title',
AppearanceTitle = 'settings.appearance.title',
AppearanceDocumentationLabel = 'settings.appearance.documentation.label',
AppearanceDocumentationTooltip = 'settings.appearance.documentation.tooltip',
AppearanceDarkModeLabel = 'settings.appearance.dark-mode.label',
AppearanceDarkModeTooltip = 'settings.appearance.dark-mode.tooltip',
AppearanceZoomHelp = 'settings.appearance.zoom.help',
FirmwareTitle = 'settings.firmware.title',
FirmwareCurrentProgramLabel = 'settings.firmware.flash-current-program.label',
FirmwareCurrentProgramTooltip = 'settings.firmware.flash-current-program.tooltip',
HelpTitle = 'settings.help.title',
HelpProjectsLabel = 'settings.help.projects.label',
HelpSupportLabel = 'settings.help.support.label',
HelpChatLabel = 'settings.help.chat.label',
HelpBugsLabel = 'settings.help.bugs.label',
AppTitle = 'settings.app.title',
AppOfflineUseHelp = 'settings.app.offlineUseHelp',
AppInstallLabel = 'settings.app.install.label',
AppCheckForUpdateLabel = 'settings.app.checkForUpdate.label',
AppRestartLabel = 'settings.app.restart.label',
AppAboutLabel = 'settings.app.about.label',
}
@@ -14,14 +14,14 @@ import React from 'react';
import AceEditor from 'react-ace';
import { IAceEditor } from 'react-ace/lib/types';
import { connect } from 'react-redux';
import { setEditSession, storageChanged } from '../actions/editor';
import { compile } from '../actions/mpy';
import { toggleBoolean } from '../actions/settings';
import { compile } from '../mpy/actions';
import { RootState } from '../reducers';
import { SettingId } from '../settings/user';
import { toggleBoolean } from '../settings/actions';
import { SettingId } from '../settings/defaults';
import { isMacOS } from '../utils/os';
import { EditorStringId } from './editor-i18n';
import en from './editor-i18n.en.json';
import { setEditSession, storageChanged } from './actions';
import { EditorStringId } from './i18n';
import en from './i18n.en.json';
import 'ace-builds/src-noconflict/mode-python';
import 'ace-builds/src-noconflict/theme-tomorrow_night_eighties';
@@ -30,7 +30,7 @@ import 'ace-builds/src-noconflict/ext-searchbox';
import 'ace-builds/src-noconflict/ext-keybinding_menu';
import 'ace-builds/src-noconflict/ext-language_tools';
import './editor-snippets';
import './snippets';
import './editor.scss';
type StateProps = {
@@ -2,12 +2,12 @@
// Copyright (c) 2020 The Pybricks Authors
import { connect } from 'react-redux';
import * as editor from '../actions/editor';
import * as notification from '../actions/notification';
import * as notification from '../notifications/actions';
import { RootState } from '../reducers';
import OpenFileButton, { OpenFileButtonProps } from './OpenFileButton';
import { TooltipId } from './button-i18n';
import openIcon from './images/open.svg';
import OpenFileButton, { OpenFileButtonProps } from '../toolbar/OpenFileButton';
import { TooltipId } from '../toolbar/i18n';
import * as editor from './actions';
import openIcon from './open.svg';
type StateProps = Pick<OpenFileButtonProps, 'enabled'>;
type DispatchProps = Pick<OpenFileButtonProps, 'onFile' | 'onReject'>;
@@ -2,11 +2,11 @@
// Copyright (c) 2020 The Pybricks Authors
import { connect } from 'react-redux';
import * as editor from '../actions/editor';
import * as editor from '../editor/actions';
import { RootState } from '../reducers';
import ActionButton, { ActionButtonProps } from './ActionButton';
import { TooltipId } from './button-i18n';
import downloadIcon from './images/download.svg';
import ActionButton, { ActionButtonProps } from '../toolbar/ActionButton';
import { TooltipId } from '../toolbar/i18n';
import downloadIcon from './save.svg';
type StateProps = Pick<ActionButtonProps, 'enabled'>;
type DispatchProps = Pick<ActionButtonProps, 'onAction'>;

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -25,7 +25,7 @@
.pb-beta .ace_scroller::after {
content: '';
background: url('./images/beta.svg');
background: url('./beta.svg');
opacity: 1;
top: 0;
left: 0;
@@ -2,8 +2,8 @@
// Copyright (c) 2020 The Pybricks Authors
import { lookup } from '../../test';
import { EditorStringId } from './editor-i18n';
import en from './editor-i18n.en.json';
import { EditorStringId } from './i18n';
import en from './i18n.en.json';
describe('Ensure .json file has matches for EditorStringId', () => {
test.each(Object.values(EditorStringId))('%s', (id) => {
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: components/editor-i18n.ts
//
// Editor translation keys.
export enum EditorStringId {

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

@@ -4,7 +4,7 @@
import { Ace } from 'ace-builds';
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import { EditorActionType } from '../actions/editor';
import { EditorActionType } from './actions';
const current: Reducer<Ace.EditSession | null, Action> = (state = null, action) => {
switch (action.type) {
@@ -4,8 +4,8 @@
import { Ace } from 'ace-builds';
import { mock } from 'jest-mock-extended';
import { AsyncSaga } from '../../test';
import { open, reloadProgram, saveAs } from '../actions/editor';
import editor from './editor';
import { open, reloadProgram, saveAs } from './actions';
import editor from './sagas';
jest.mock('ace-builds');
jest.mock('file-saver');
+2 -2
View File
@@ -3,13 +3,13 @@
import FileSaver from 'file-saver';
import { select, takeEvery } from 'typed-redux-saga/macro';
import { RootState } from '../reducers';
import {
EditorActionType,
EditorOpenAction,
EditorReloadProgramAction,
EditorSaveAsAction,
} from '../actions/editor';
import { RootState } from '../reducers';
} from './actions';
const decoder = new TextDecoder();

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

@@ -2,18 +2,18 @@
// Copyright (c) 2020 The Pybricks Authors
import { AsyncSaga } from '../../test';
import { didFailToWrite } from '../ble-uart/actions';
import {
BleDeviceFailToConnectReasonType,
didFailToConnect as bleDidFailToConnect,
} from '../actions/ble';
import { didFailToWrite } from '../actions/ble-uart';
import { didFailToFetchList } from '../actions/license';
} from '../ble/actions';
import { didFailToFetchList } from '../licenses/actions';
import {
BootloaderConnectionFailureReason,
didError,
didFailToConnect,
} from '../actions/lwp3-bootloader';
import errorLog from './error-log';
} from '../lwp3-bootloader/actions';
import errorLog from './sagas';
test('bleDeviceDidFailToConnect', async () => {
const saga = new AsyncSaga(errorLog);
@@ -2,19 +2,22 @@
// Copyright (c) 2020 The Pybricks Authors
import { takeEvery } from 'typed-redux-saga/macro';
import { BleUartActionType, BleUartDidFailToWriteAction } from '../ble-uart/actions';
import {
BleDeviceActionType,
BleDeviceDidFailToConnectAction,
BleDeviceFailToConnectReasonType,
} from '../actions/ble';
import { BleUartActionType, BleUartDidFailToWriteAction } from '../actions/ble-uart';
import { LicenseActionType, LicenseDidFailToFetchListAction } from '../actions/license';
} from '../ble/actions';
import {
LicenseActionType,
LicenseDidFailToFetchListAction,
} from '../licenses/actions';
import {
BootloaderConnectionActionType,
BootloaderConnectionDidErrorAction,
BootloaderConnectionDidFailToConnectAction,
BootloaderConnectionFailureReason,
} from '../actions/lwp3-bootloader';
} from '../lwp3-bootloader/actions';
function bleDeviceDidFailToConnect(action: BleDeviceDidFailToConnectAction): void {
if (action.reason === BleDeviceFailToConnectReasonType.Unknown) {
@@ -2,13 +2,13 @@
// Copyright (c) 2020-2021 The Pybricks Authors
import { connect } from 'react-redux';
import { flashFirmware } from '../actions/flash-firmware';
import * as notification from '../actions/notification';
import { BootloaderConnectionState } from '../lwp3-bootloader/reducers';
import * as notification from '../notifications/actions';
import { RootState } from '../reducers';
import { BootloaderConnectionState } from '../reducers/bootloader';
import OpenFileButton, { OpenFileButtonProps } from './OpenFileButton';
import { TooltipId } from './button-i18n';
import firmwareIcon from './images/firmware.svg';
import OpenFileButton, { OpenFileButtonProps } from '../toolbar/OpenFileButton';
import { TooltipId } from '../toolbar/i18n';
import { flashFirmware } from './actions';
import firmwareIcon from './firmware.svg';
type StateProps = Pick<
OpenFileButtonProps,

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

@@ -3,7 +3,7 @@
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import { FlashFirmwareActionType } from '../actions/flash-firmware';
import { FlashFirmwareActionType } from './actions';
export interface FirmwareState {
/** The firmware is being erased/flashed right now. */
@@ -8,16 +8,6 @@ import {
} from '@pybricks/firmware';
import JSZip from 'jszip';
import { AsyncSaga } from '../../test';
import {
FailToFinishReasonType,
HubError,
MetadataProblem,
didFailToFinish,
didFinish,
didProgress,
didStart,
flashFirmware as flashFirmwareAction,
} from '../actions/flash-firmware';
import {
BootloaderConnectionFailureReason,
BootloaderProgramRequestAction,
@@ -40,12 +30,22 @@ import {
programRequest,
programResponse,
rebootRequest,
} from '../actions/lwp3-bootloader';
import { didCompile, didFailToCompile } from '../actions/mpy';
import { Command, HubType, Result } from '../protocols/lwp3-bootloader';
import { BootloaderConnectionState } from '../reducers/bootloader';
} from '../lwp3-bootloader/actions';
import { Command, HubType, Result } from '../lwp3-bootloader/protocol';
import { BootloaderConnectionState } from '../lwp3-bootloader/reducers';
import { didCompile, didFailToCompile } from '../mpy/actions';
import { createCountFunc } from '../utils/iter';
import flashFirmware from './flash-firmware';
import {
FailToFinishReasonType,
HubError,
MetadataProblem,
didFailToFinish,
didFinish,
didProgress,
didStart,
flashFirmware as flashFirmwareAction,
} from './actions';
import flashFirmware from './sagas';
afterEach(() => {
jest.restoreAllMocks();
@@ -19,17 +19,6 @@ import {
takeEvery,
} from 'typed-redux-saga/macro';
import { Action } from '../actions';
import {
FailToFinishReasonType,
FlashFirmwareActionType,
FlashFirmwareFlashAction,
HubError,
MetadataProblem,
didFailToFinish,
didFinish,
didProgress,
didStart,
} from '../actions/flash-firmware';
import {
BootloaderChecksumResponseAction,
BootloaderConnectionAction,
@@ -53,18 +42,29 @@ import {
initRequest,
programRequest,
rebootRequest,
} from '../actions/lwp3-bootloader';
} from '../lwp3-bootloader/actions';
import { MaxProgramFlashSize, Result } from '../lwp3-bootloader/protocol';
import { BootloaderConnectionState } from '../lwp3-bootloader/reducers';
import {
MpyActionType,
MpyDidCompileAction,
MpyDidFailToCompileAction,
compile,
} from '../actions/mpy';
import { MaxProgramFlashSize, Result } from '../protocols/lwp3-bootloader';
} from '../mpy/actions';
import { RootState } from '../reducers';
import { BootloaderConnectionState } from '../reducers/bootloader';
import { defined, maybe } from '../utils';
import { fmod, sumComplement32 } from '../utils/math';
import {
FailToFinishReasonType,
FlashFirmwareActionType,
FlashFirmwareFlashAction,
HubError,
MetadataProblem,
didFailToFinish,
didFinish,
didProgress,
didStart,
} from './actions';
const firmwareZipMap = new Map<HubType, string>([
[HubType.CityHub, cityHubZip],
@@ -2,14 +2,14 @@
// Copyright (c) 2020 The Pybricks Authors
import { connect } from 'react-redux';
import { toggleBluetooth } from '../actions/ble';
import { toggleBluetooth } from '../ble/actions';
import { BleConnectionState } from '../ble/reducers';
import { BootloaderConnectionState } from '../lwp3-bootloader/reducers';
import { RootState } from '../reducers';
import { BleConnectionState } from '../reducers/ble';
import { BootloaderConnectionState } from '../reducers/bootloader';
import ActionButton, { ActionButtonProps } from './ActionButton';
import { TooltipId } from './button-i18n';
import btConnectedIcon from './images/bt-connected.svg';
import btDisconnectedIcon from './images/bt-disconnected.svg';
import ActionButton, { ActionButtonProps } from '../toolbar/ActionButton';
import { TooltipId } from '../toolbar/i18n';
import btConnectedIcon from './bt-connected.svg';
import btDisconnectedIcon from './bt-disconnected.svg';
type StateProps = Pick<ActionButtonProps, 'tooltip' | 'icon' | 'enabled'>;
type DispatchProps = Pick<ActionButtonProps, 'onAction'>;
@@ -2,12 +2,12 @@
// Copyright (c) 2020 The Pybricks Authors
import { connect } from 'react-redux';
import { repl } from '../actions/hub';
import { RootState } from '../reducers';
import { HubRuntimeState } from '../reducers/hub';
import ActionButton, { ActionButtonProps } from './ActionButton';
import { TooltipId } from './button-i18n';
import replIcon from './images/repl.svg';
import ActionButton, { ActionButtonProps } from '../toolbar/ActionButton';
import { TooltipId } from '../toolbar/i18n';
import { repl } from './actions';
import { HubRuntimeState } from './reducers';
import replIcon from './repl.svg';
type StateProps = Pick<ActionButtonProps, 'enabled'>;
type DispatchProps = Pick<ActionButtonProps, 'onAction'>;
@@ -2,12 +2,12 @@
// Copyright (c) 2020 The Pybricks Authors
import { connect } from 'react-redux';
import { downloadAndRun } from '../actions/hub';
import { RootState } from '../reducers';
import { HubRuntimeState } from '../reducers/hub';
import ActionButton, { ActionButtonProps } from './ActionButton';
import { TooltipId } from './button-i18n';
import runIcon from './images/run.svg';
import ActionButton, { ActionButtonProps } from '../toolbar/ActionButton';
import { TooltipId } from '../toolbar/i18n';
import { downloadAndRun } from './actions';
import { HubRuntimeState } from './reducers';
import runIcon from './run.svg';
type StateProps = Pick<ActionButtonProps, 'enabled'>;
type DispatchProps = Pick<ActionButtonProps, 'onAction'>;
@@ -2,12 +2,12 @@
// Copyright (c) 2020 The Pybricks Authors
import { connect } from 'react-redux';
import { stop } from '../actions/hub';
import { RootState } from '../reducers';
import { HubRuntimeState } from '../reducers/hub';
import ActionButton, { ActionButtonProps } from './ActionButton';
import { TooltipId } from './button-i18n';
import stopIcon from './images/stop.svg';
import ActionButton, { ActionButtonProps } from '../toolbar/ActionButton';
import { TooltipId } from '../toolbar/i18n';
import { stop } from './actions';
import { HubRuntimeState } from './reducers';
import stopIcon from './stop.svg';
type StateProps = Pick<ActionButtonProps, 'enabled'>;
type DispatchProps = Pick<ActionButtonProps, 'onAction'>;

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

+2 -2
View File
@@ -3,8 +3,8 @@
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import { BleDeviceActionType } from '../actions/ble';
import { HubMessageActionType, HubRuntimeStatusType } from '../actions/hub';
import { BleDeviceActionType } from '../ble/actions';
import { HubMessageActionType, HubRuntimeStatusType } from './actions';
/**
* Describes the state of the MicroPython runtime on the hub.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

@@ -4,7 +4,9 @@
import { Ace } from 'ace-builds';
import { mock } from 'jest-mock-extended';
import { AsyncSaga } from '../../test';
import { BleUartActionType, BleUartWriteAction, didWrite } from '../actions/ble-uart';
import { BleUartActionType, BleUartWriteAction, didWrite } from '../ble-uart/actions';
import { MpyActionType, didCompile } from '../mpy/actions';
import { createCountFunc } from '../utils/iter';
import {
HubMessageActionType,
HubRuntimeStatusMessageAction,
@@ -13,10 +15,8 @@ import {
downloadAndRun,
repl,
stop,
} from '../actions/hub';
import { MpyActionType, didCompile } from '../actions/mpy';
import { createCountFunc } from '../utils/iter';
import hub from './hub';
} from './actions';
import hub from './sagas';
jest.mock('ace-builds');
+13 -13
View File
@@ -12,13 +12,23 @@ import {
takeEvery,
} from 'typed-redux-saga/macro';
import { Action } from '../actions';
import { BleDeviceActionType } from '../actions/ble';
import {
BleUartActionType,
BleUartDidFailToWriteAction,
BleUartDidWriteAction,
write,
} from '../actions/ble-uart';
} from '../ble-uart/actions';
import { SafeTxCharLength } from '../ble-uart/protocol';
import { BleDeviceActionType } from '../ble/actions';
import {
MpyActionType,
MpyDidCompileAction,
MpyDidFailToCompileAction,
compile,
} from '../mpy/actions';
import { RootState } from '../reducers';
import { defined } from '../utils';
import { xor8 } from '../utils/math';
import {
HubActionType,
HubChecksumMessageAction,
@@ -28,17 +38,7 @@ import {
HubRuntimeStatusType,
HubStopAction,
updateStatus,
} from '../actions/hub';
import {
MpyActionType,
MpyDidCompileAction,
MpyDidFailToCompileAction,
compile,
} from '../actions/mpy';
import { SafeTxCharLength } from '../protocols/nrf-uart';
import { RootState } from '../reducers';
import { defined } from '../utils';
import { xor8 } from '../utils/math';
} from './actions';
const downloadChunkSize = 100;

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

+17
View File
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
import { I18nManager } from '@shopify/react-i18n';
// TODO: add locale setting and use browser preferred language as default
/** The global i18n manager. */
export const i18nManager = new I18nManager({
locale: 'en',
onError: (err): void => console.error(err),
});
/** Enables or disables pseudolocalization for development. */
export function pseudolocalize(pseudolocalize: boolean): void {
i18nManager.update({ ...i18nManager.details, pseudolocalize });
}
+4 -4
View File
@@ -10,14 +10,14 @@ import { applyMiddleware, createStore } from 'redux';
import { createLogger } from 'redux-logger';
import createSagaMiddleware from 'redux-saga';
import './index.scss';
import { didSucceed, didUpdate } from './actions/service-worker';
import App from './components/App';
import * as I18nToaster from './components/I18nToaster';
import App from './app/App';
import { i18nManager } from './i18n';
import * as I18nToaster from './notifications/I18nToaster';
import rootReducer from './reducers';
import reportWebVitals from './reportWebVitals';
import rootSaga from './sagas';
import { didSucceed, didUpdate } from './service-worker/actions';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import { i18nManager } from './settings/i18n';
import { createCountFunc } from './utils/iter';
const toaster = I18nToaster.create(i18nManager);
@@ -15,13 +15,13 @@ import {
import { WithI18nProps, withI18n } from '@shopify/react-i18n';
import React from 'react';
import { connect } from 'react-redux';
import { closeLicenseDialog } from '../actions/app';
import { select } from '../actions/license';
import { closeLicenseDialog } from '../app/actions';
import { appName } from '../app/constants';
import { RootState } from '../reducers';
import { LicenseInfo, LicenseList } from '../reducers/license';
import { appName } from '../settings/ui';
import { LicenseStringId } from './license-i18n';
import en from './license-i18n.en.json';
import { select } from './actions';
import { LicenseStringId } from './i18n';
import en from './i18n.en.json';
import { LicenseInfo, LicenseList } from './reducers';
import './license.scss';
@@ -2,7 +2,7 @@
// Copyright (c) 2021 The Pybricks Authors
import { Action } from 'redux';
import { LicenseInfo, LicenseList } from '../reducers/license';
import { LicenseInfo, LicenseList } from './reducers';
export enum LicenseActionType {
DidFetchList = 'license.action.didFetchList',
@@ -2,8 +2,8 @@
// Copyright (c) 2021 The Pybricks Authors
import { lookup } from '../../test';
import { LicenseStringId } from './license-i18n';
import en from './license-i18n.en.json';
import { LicenseStringId } from './i18n';
import en from './i18n.en.json';
describe('Ensure .json file has matches for LicenseStringId', () => {
test.each(Object.values(LicenseStringId))('%s', (id) => {
@@ -3,7 +3,7 @@
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import { LicenseActionType } from '../actions/license';
import { LicenseActionType } from './actions';
export interface LicenseInfo {
readonly name: string;
@@ -4,10 +4,10 @@
// Tests for license sagas.
import { AsyncSaga, delay } from '../../test';
import { openLicenseDialog } from '../actions/app';
import { didFailToFetchList, didFetchList } from '../actions/license';
import { LicenseList } from '../reducers/license';
import license from './license';
import { openLicenseDialog } from '../app/actions';
import { didFailToFetchList, didFetchList } from './actions';
import { LicenseList } from './reducers';
import license from './sagas';
afterAll(() => {
jest.restoreAllMocks();
@@ -2,9 +2,9 @@
// Copyright (c) 2021 The Pybricks Authors
import { call, put, select, takeEvery } from 'typed-redux-saga/macro';
import { AppActionType } from '../actions/app';
import { didFailToFetchList, didFetchList } from '../actions/license';
import { AppActionType } from '../app/actions';
import { RootState } from '../reducers';
import { didFailToFetchList, didFetchList } from './actions';
function* fetchLicenses(): Generator {
const licenses = yield* select((s: RootState) => s.license.list);
@@ -2,12 +2,7 @@
// Copyright (c) 2020-2021 The Pybricks Authors
import { Action } from 'redux';
import {
Command,
HubType,
ProtectionLevel,
Result,
} from '../protocols/lwp3-bootloader';
import { Command, HubType, ProtectionLevel, Result } from './protocol';
/**
* Bootloader BLE connection actions.
@@ -3,10 +3,7 @@
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import {
BootloaderConnectionActionType,
BootloaderRequestActionType,
} from '../actions/lwp3-bootloader';
import { BootloaderConnectionActionType, BootloaderRequestActionType } from './actions';
/**
* Describes the state of the bootloader connection.
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// File: sagas/lwp3-bootloader-ble.ts
//
// Handles Bluetooth Low Energy connection to LEGO Wireless Protocol v3 Bootloader service.
import { END, eventChannel } from 'redux-saga';
@@ -16,8 +16,8 @@ import {
didFailToSend,
didReceive,
didSend,
} from '../actions/lwp3-bootloader';
import { CharacteristicUUID, ServiceUUID } from '../protocols/lwp3-bootloader';
} from './actions';
import { CharacteristicUUID, ServiceUUID } from './protocol';
function* handleNotify(data: DataView): Generator {
yield* put(didReceive(data));
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// File: sagas/lwp3-bootloader-protocol.test.ts
import { AsyncSaga } from '../../test';
import { createCountFunc } from '../utils/iter';
import {
BootloaderRequestActionType,
checksumRequest,
@@ -25,16 +25,9 @@ import {
send,
stateRequest,
stateResponse,
} from '../actions/lwp3-bootloader';
import {
Command,
HubType,
ProtectionLevel,
ProtocolError,
Result,
} from '../protocols/lwp3-bootloader';
import { createCountFunc } from '../utils/iter';
import bootloader from './lwp3-bootloader-protocol';
} from './actions';
import { Command, HubType, ProtectionLevel, ProtocolError, Result } from './protocol';
import bootloader from './sagas';
describe('message encoder', () => {
test.each([
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: sagas/lwp3-bootloader-protocol.ts
//
// Handles LEGO Wireless Protocol v3 Bootloader protocol.
import {
@@ -12,6 +12,7 @@ import {
takeEvery,
} from 'typed-redux-saga/macro';
import { Action } from '../actions';
import { hex } from '../utils';
import {
BootloaderConnectionActionType,
BootloaderConnectionDidFailToSendAction,
@@ -30,7 +31,7 @@ import {
programResponse,
send,
stateResponse,
} from '../actions/lwp3-bootloader';
} from './actions';
import {
Command,
ErrorBytecode,
@@ -51,8 +52,7 @@ import {
parseGetInfoResponse,
parseInitLoaderResponse,
parseProgramFlashResponse,
} from '../protocols/lwp3-bootloader';
import { hex } from '../utils';
} from './protocol';
/**
* Converts a request action into bytecodes and creates a new action to send
@@ -7,8 +7,8 @@ import {
MpyDidCompileAction,
MpyDidFailToCompileAction,
compile,
} from '../actions/mpy';
import mpy from './mpy';
} from './actions';
import mpy from './sagas';
enum MpyFeatureFlags {
MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = 1 << 0,
+1 -1
View File
@@ -9,7 +9,7 @@ import {
MpyCompileAction,
didCompile,
didFailToCompile,
} from '../actions/mpy';
} from './actions';
/**
* Compiles a script to .mpy and dispatches either didCompile on success or
@@ -5,8 +5,8 @@
import { Replacements, useI18n } from '@shopify/react-i18n';
import React from 'react';
import { MessageId } from './notification-i18n';
import en from './notification-i18n.en.json';
import { MessageId } from './i18n';
import en from './i18n.en.json';
type OwnProps = {
messageId: MessageId;
@@ -6,8 +6,8 @@
import { AnchorButton, Button, ButtonGroup, Intent } from '@blueprintjs/core';
import { useI18n } from '@shopify/react-i18n';
import React from 'react';
import { MessageId } from './notification-i18n';
import en from './notification-i18n.en.json';
import { MessageId } from './i18n';
import en from './i18n.en.json';
type OwnProps = {
messageId: MessageId;
@@ -2,8 +2,8 @@
// Copyright (c) 2020 The Pybricks Authors
import { lookup } from '../../test';
import { MessageId } from './notification-i18n';
import en from './notification-i18n.en.json';
import { MessageId } from './i18n';
import en from './i18n.en.json';
describe('Ensure .json file has matches for MessageIds', () => {
test.each(Object.values(MessageId))('%s', (id) => {
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: components/notification-i18n.ts
//
// Notification translation keys.
export enum MessageId {
@@ -5,27 +5,27 @@ import { IToaster } from '@blueprintjs/core';
import { FirmwareReaderError, FirmwareReaderErrorCode } from '@pybricks/firmware';
import { AsyncSaga } from '../../test';
import { Action } from '../actions';
import { didCheckForUpdate } from '../actions/app';
import { didCheckForUpdate } from '../app/actions';
import {
BleDeviceFailToConnectReasonType,
didFailToConnect as bleDidFailToConnect,
} from '../actions/ble';
import { storageChanged } from '../actions/editor';
} from '../ble/actions';
import { storageChanged } from '../editor/actions';
import {
FailToFinishReasonType,
HubError,
MetadataProblem,
didFailToFinish,
} from '../actions/flash-firmware';
} from '../firmware/actions';
import {
BootloaderConnectionFailureReason,
didFailToConnect as bootloaderDidFailToConnect,
} from '../actions/lwp3-bootloader';
import { didCompile, didFailToCompile } from '../actions/mpy';
import { add } from '../actions/notification';
import { didSucceed, didUpdate } from '../actions/service-worker';
import { MessageId } from '../components/notification-i18n';
import notification from './notification';
} from '../lwp3-bootloader/actions';
import { didCompile, didFailToCompile } from '../mpy/actions';
import { didSucceed, didUpdate } from '../service-worker/actions';
import { add } from './actions';
import { MessageId } from './i18n';
import notification from './sagas';
test.each([
bleDidFailToConnect({ reason: BleDeviceFailToConnectReasonType.NoWebBluetooth }),
@@ -14,33 +14,33 @@ import { Replacements } from '@shopify/react-i18n';
import React from 'react';
import { channel } from 'redux-saga';
import { delay, getContext, put, take, takeEvery } from 'typed-redux-saga/macro';
import { AppActionType, AppDidCheckForUpdateAction, reload } from '../actions/app';
import { AppActionType, AppDidCheckForUpdateAction, reload } from '../app/actions';
import { appName } from '../app/constants';
import {
BleDeviceActionType,
BleDeviceDidFailToConnectAction,
BleDeviceFailToConnectReasonType,
} from '../actions/ble';
import { EditorActionType, reloadProgram } from '../actions/editor';
} from '../ble/actions';
import { EditorActionType, reloadProgram } from '../editor/actions';
import {
FailToFinishReasonType,
FlashFirmwareActionType,
FlashFirmwareDidFailToFinishAction,
} from '../actions/flash-firmware';
} from '../firmware/actions';
import {
BootloaderConnectionActionType,
BootloaderConnectionDidFailToConnectAction,
BootloaderConnectionFailureReason,
} from '../actions/lwp3-bootloader';
import { MpyActionType, MpyDidFailToCompileAction } from '../actions/mpy';
import { NotificationActionType, NotificationAddAction } from '../actions/notification';
} from '../lwp3-bootloader/actions';
import { MpyActionType, MpyDidFailToCompileAction } from '../mpy/actions';
import {
ServiceWorkerAction,
ServiceWorkerActionType,
} from '../actions/service-worker';
import Notification from '../components/Notification';
import UnexpectedErrorNotification from '../components/UnexpectedErrorNotification';
import { MessageId } from '../components/notification-i18n';
import { appName } from '../settings/ui';
} from '../service-worker/actions';
import Notification from './Notification';
import UnexpectedErrorNotification from './UnexpectedErrorNotification';
import { NotificationActionType, NotificationAddAction } from './actions';
import { MessageId } from './i18n';
type NotificationContext = {
toaster: IToaster;
+10 -10
View File
@@ -2,15 +2,15 @@
// Copyright (c) 2020-2021 The Pybricks Authors
import { combineReducers } from 'redux';
import app, { AppState } from './app';
import ble, { BleState } from './ble';
import bootloader, { BootloaderState } from './bootloader';
import editor, { EditorState } from './editor';
import firmware, { FirmwareState } from './firmware';
import hub, { HubState } from './hub';
import license, { LicenseState } from './license';
import settings, { SettingsState } from './settings';
import terminal, { TerminalState } from './terminal';
import app, { AppState } from './app/reducers';
import ble, { BleState } from './ble/reducers';
import editor, { EditorState } from './editor/reducers';
import firmware, { FirmwareState } from './firmware/reducers';
import hub, { HubState } from './hub/reducers';
import licenses, { LicenseState } from './licenses/reducers';
import bootloader, { BootloaderState } from './lwp3-bootloader/reducers';
import settings, { SettingsState } from './settings/reducers';
import terminal, { TerminalState } from './terminal/reducers';
/**
* Root state for redux store.
@@ -34,7 +34,7 @@ export default combineReducers({
editor,
firmware,
hub,
license,
licenses,
settings,
terminal,
});
+38
View File
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
import { all, put } from 'typed-redux-saga/macro';
import { didStart } from './app/actions';
import app from './app/sagas';
import bleUart from './ble-uart/sagas';
import editor from './editor/sagas';
import errorLog from './error-log/sagas';
import flashFirmware from './firmware/sagas';
import hub from './hub/sagas';
import licenses from './licenses/sagas';
import lwp3BootloaderProtocol from './lwp3-bootloader/sagas';
import lwp3BootloaderBle from './lwp3-bootloader/sagas-ble';
import mpy from './mpy/sagas';
import notifications from './notifications/sagas';
import settings from './settings/sagas';
import terminal from './terminal/sagas';
/* istanbul ignore next */
export default function* (): Generator {
yield* all([
app(),
bleUart(),
lwp3BootloaderBle(),
lwp3BootloaderProtocol(),
editor(),
errorLog(),
flashFirmware(),
hub(),
licenses(),
mpy(),
notifications(),
settings(),
terminal(),
put(didStart()),
]);
}
-38
View File
@@ -1,38 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
import { all, put } from 'typed-redux-saga/macro';
import { didStart } from '../actions/app';
import app from './app';
import bleUart from './ble-uart';
import editor from './editor';
import errorLog from './error-log';
import flashFirmware from './flash-firmware';
import hub from './hub';
import license from './license';
import lwp3BootloaderBle from './lwp3-bootloader-ble';
import lwp3BootloaderProtocol from './lwp3-bootloader-protocol';
import mpy from './mpy';
import notification from './notification';
import settings from './settings';
import terminal from './terminal';
/* istanbul ignore next */
export default function* (): Generator {
yield* all([
app(),
bleUart(),
lwp3BootloaderBle(),
lwp3BootloaderProtocol(),
editor(),
errorLog(),
flashFirmware(),
hub(),
license(),
mpy(),
notification(),
settings(),
terminal(),
put(didStart()),
]);
}
@@ -2,10 +2,10 @@
// Copyright (c) 2021 The Pybricks Authors
import { connect } from 'react-redux';
import { openSettings as openSettings } from '../actions/app';
import ActionButton, { ActionButtonProps } from './ActionButton';
import { TooltipId } from './button-i18n';
import settingsIcon from './images/settings.svg';
import { openSettings as openSettings } from '../app/actions';
import ActionButton, { ActionButtonProps } from '../toolbar/ActionButton';
import { TooltipId } from '../toolbar/i18n';
import settingsIcon from './settings.svg';
type StateProps = undefined;
type DispatchProps = Pick<ActionButtonProps, 'onAction'>;
@@ -18,30 +18,30 @@ import {
import { WithI18nProps, withI18n } from '@shopify/react-i18n';
import React from 'react';
import { connect } from 'react-redux';
import AboutDialog from '../about/AboutDialog';
import {
checkForUpdate,
closeSettings,
installPrompt,
openAboutDialog,
reload,
} from '../actions/app';
import { setBoolean, toggleBoolean } from '../actions/settings';
import { RootState } from '../reducers';
import { pseudolocalize } from '../settings/i18n';
} from '../app/actions';
import {
pybricksBugReportsUrl,
pybricksGitterUrl,
pybricksProjectsUrl,
pybricksSupportUrl,
tooltipDelay,
} from '../settings/ui';
import { SettingId } from '../settings/user';
} from '../app/constants';
import { pseudolocalize } from '../i18n';
import { RootState } from '../reducers';
import ExternalLinkIcon from '../utils/ExternalLinkIcon';
import { BeforeInstallPromptEvent } from '../utils/dom';
import { isMacOS } from '../utils/os';
import AboutDialog from './AboutDialog';
import ExternalLinkIcon from './ExternalLinkIcon';
import { SettingsStringId } from './settings-i18n';
import en from './settings-i18n.en.json';
import { setBoolean, toggleBoolean } from './actions';
import { SettingId } from './defaults';
import { SettingsStringId } from './i18n';
import en from './i18n.en.json';
type StateProps = {
open: boolean;
@@ -2,7 +2,7 @@
// Copyright (c) 2021 The Pybricks Authors
import { Action } from 'redux';
import { SettingId } from '../settings/user';
import { SettingId } from './defaults';
/** Actions related to settings. */
export enum SettingsActionType {
@@ -2,8 +2,8 @@
// Copyright (c) 2021 The Pybricks Authors
import { lookup } from '../../test';
import { SettingsStringId } from './settings-i18n';
import en from './settings-i18n.en.json';
import { SettingsStringId } from './i18n';
import en from './i18n.en.json';
describe('Ensure .json file has matches for SettingsStringIds', () => {
test.each(Object.values(SettingsStringId))('%s', (id) => {
+25 -14
View File
@@ -1,17 +1,28 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// Copyright (c) 2021 The Pybricks Authors
//
// Settings translation keys.
import { I18nManager } from '@shopify/react-i18n';
// TODO: add locale setting and use browser preferred language as default
/** The global i18n manager. */
export const i18nManager = new I18nManager({
locale: 'en',
onError: (err): void => console.error(err),
});
/** Enables or disables pseudolocalization for development. */
export function pseudolocalize(pseudolocalize: boolean): void {
i18nManager.update({ ...i18nManager.details, pseudolocalize });
export enum SettingsStringId {
Title = 'settings.title',
AppearanceTitle = 'settings.appearance.title',
AppearanceDocumentationLabel = 'settings.appearance.documentation.label',
AppearanceDocumentationTooltip = 'settings.appearance.documentation.tooltip',
AppearanceDarkModeLabel = 'settings.appearance.dark-mode.label',
AppearanceDarkModeTooltip = 'settings.appearance.dark-mode.tooltip',
AppearanceZoomHelp = 'settings.appearance.zoom.help',
FirmwareTitle = 'settings.firmware.title',
FirmwareCurrentProgramLabel = 'settings.firmware.flash-current-program.label',
FirmwareCurrentProgramTooltip = 'settings.firmware.flash-current-program.tooltip',
HelpTitle = 'settings.help.title',
HelpProjectsLabel = 'settings.help.projects.label',
HelpSupportLabel = 'settings.help.support.label',
HelpChatLabel = 'settings.help.chat.label',
HelpBugsLabel = 'settings.help.bugs.label',
AppTitle = 'settings.app.title',
AppOfflineUseHelp = 'settings.app.offlineUseHelp',
AppInstallLabel = 'settings.app.install.label',
AppCheckForUpdateLabel = 'settings.app.checkForUpdate.label',
AppRestartLabel = 'settings.app.restart.label',
AppAboutLabel = 'settings.app.about.label',
}
@@ -3,8 +3,8 @@
import { Reducer, combineReducers } from 'redux';
import { Action } from '../actions';
import { SettingsActionType } from '../actions/settings';
import { SettingId, getDefaultBooleanValue } from '../settings/user';
import { SettingsActionType } from './actions';
import { SettingId, getDefaultBooleanValue } from './defaults';
export interface SettingsState {
readonly darkMode: boolean;

Some files were not shown because too many files have changed in this diff Show More