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
@@ -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) => {
|
||||
@@ -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.
|
||||
@@ -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,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';
|
||||
@@ -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);
|
||||
@@ -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,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';
|
||||
@@ -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.
|
||||
@@ -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,
|
||||
);
|
||||
@@ -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 |
@@ -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 |
@@ -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');
|
||||
@@ -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 |
@@ -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');
|
||||
|
||||
@@ -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 |
@@ -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 });
|
||||
}
|
||||
@@ -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,
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
});
|
||||
@@ -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()),
|
||||
]);
|
||||
}
|
||||
@@ -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) => {
|
||||
@@ -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;
|
||||