diff --git a/src/components/AboutDialog.tsx b/src/about/AboutDialog.tsx similarity index 90% rename from src/components/AboutDialog.tsx rename to src/about/AboutDialog.tsx index 7639d67a..56b1782f 100644 --- a/src/components/AboutDialog.tsx +++ b/src/about/AboutDialog.tsx @@ -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'; diff --git a/src/components/about.scss b/src/about/about.scss similarity index 100% rename from src/components/about.scss rename to src/about/about.scss diff --git a/src/components/about-i18n.en.json b/src/about/i18n.en.json similarity index 100% rename from src/components/about-i18n.en.json rename to src/about/i18n.en.json diff --git a/src/components/about-i18n.test.ts b/src/about/i18n.test.ts similarity index 77% rename from src/components/about-i18n.test.ts rename to src/about/i18n.test.ts index 3c94a2b1..5c7a14ea 100644 --- a/src/components/about-i18n.test.ts +++ b/src/about/i18n.test.ts @@ -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) => { diff --git a/src/components/about-i18n.ts b/src/about/i18n.ts similarity index 100% rename from src/components/about-i18n.ts rename to src/about/i18n.ts diff --git a/src/actions/index.ts b/src/actions.ts similarity index 56% rename from src/actions/index.ts rename to src/actions.ts index 698e8d22..d055a233 100644 --- a/src/actions/index.ts +++ b/src/actions.ts @@ -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. diff --git a/src/components/App.tsx b/src/app/App.tsx similarity index 95% rename from src/components/App.tsx rename to src/app/App.tsx index 7fcfe8c3..f27a286a 100644 --- a/src/components/App.tsx +++ b/src/app/App.tsx @@ -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'; diff --git a/src/actions/app.ts b/src/app/actions.ts similarity index 99% rename from src/actions/app.ts rename to src/app/actions.ts index cd09b533..bfbc2936 100644 --- a/src/actions/app.ts +++ b/src/app/actions.ts @@ -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'; diff --git a/src/components/app.scss b/src/app/app.scss similarity index 100% rename from src/components/app.scss rename to src/app/app.scss diff --git a/src/settings/ui.ts b/src/app/constants.ts similarity index 100% rename from src/settings/ui.ts rename to src/app/constants.ts diff --git a/src/reducers/app.ts b/src/app/reducers.ts similarity index 96% rename from src/reducers/app.ts rename to src/app/reducers.ts index 6872ab86..9853b550 100644 --- a/src/reducers/app.ts +++ b/src/app/reducers.ts @@ -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; diff --git a/src/sagas/app.test.ts b/src/app/sagas.test.ts similarity index 98% rename from src/sagas/app.test.ts rename to src/app/sagas.test.ts index 0bcfd496..2b0576e0 100644 --- a/src/sagas/app.test.ts +++ b/src/app/sagas.test.ts @@ -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); diff --git a/src/sagas/app.ts b/src/app/sagas.ts similarity index 99% rename from src/sagas/app.ts rename to src/app/sagas.ts index 85eac92d..8319a687 100644 --- a/src/sagas/app.ts +++ b/src/app/sagas.ts @@ -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((emit) => { diff --git a/src/protocols/pybricks.ts b/src/ble-pybricks/protocol.ts similarity index 90% rename from src/protocols/pybricks.ts rename to src/ble-pybricks/protocol.ts index 24dfce0f..49baab26 100644 --- a/src/protocols/pybricks.ts +++ b/src/ble-pybricks/protocol.ts @@ -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. diff --git a/src/actions/ble-uart.ts b/src/ble-uart/actions.ts similarity index 100% rename from src/actions/ble-uart.ts rename to src/ble-uart/actions.ts diff --git a/src/protocols/nrf-uart.ts b/src/ble-uart/protocol.ts similarity index 96% rename from src/protocols/nrf-uart.ts rename to src/ble-uart/protocol.ts index b8c9421e..a6a961f3 100644 --- a/src/protocols/nrf-uart.ts +++ b/src/ble-uart/protocol.ts @@ -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 diff --git a/src/sagas/ble-uart.ts b/src/ble-uart/sagas.ts similarity index 96% rename from src/sagas/ble-uart.ts rename to src/ble-uart/sagas.ts index 8b346520..207cf767 100644 --- a/src/sagas/ble-uart.ts +++ b/src/ble-uart/sagas.ts @@ -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, diff --git a/src/actions/ble.ts b/src/ble/actions.ts similarity index 99% rename from src/actions/ble.ts rename to src/ble/actions.ts index 19f4785d..ec52d7e5 100644 --- a/src/actions/ble.ts +++ b/src/ble/actions.ts @@ -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'; diff --git a/src/reducers/ble.ts b/src/ble/reducers.ts similarity index 95% rename from src/reducers/ble.ts rename to src/ble/reducers.ts index c229c55a..6bc91d07 100644 --- a/src/reducers/ble.ts +++ b/src/ble/reducers.ts @@ -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. diff --git a/src/components/LinkButton.tsx b/src/components/LinkButton.tsx deleted file mode 100644 index 4f8e8ac1..00000000 --- a/src/components/LinkButton.tsx +++ /dev/null @@ -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 { - render(): JSX.Element { - return ( - - - - ); - } -} - -export default withI18n({ id: 'linkButton', fallback: en, translations: { en } })( - LinkButton, -); diff --git a/src/components/images/pybricks.svg b/src/components/images/pybricks.svg deleted file mode 100644 index cf3ffcc2..00000000 --- a/src/components/images/pybricks.svg +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/src/components/images/support.svg b/src/components/images/support.svg deleted file mode 100644 index 76ce8d29..00000000 --- a/src/components/images/support.svg +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/src/components/settings-i18n.ts b/src/components/settings-i18n.ts deleted file mode 100644 index ba191e65..00000000 --- a/src/components/settings-i18n.ts +++ /dev/null @@ -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', -} diff --git a/src/components/Editor.tsx b/src/editor/Editor.tsx similarity index 96% rename from src/components/Editor.tsx rename to src/editor/Editor.tsx index d1d0b2fd..968c39d2 100644 --- a/src/components/Editor.tsx +++ b/src/editor/Editor.tsx @@ -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 = { diff --git a/src/components/OpenButton.tsx b/src/editor/OpenButton.tsx similarity index 79% rename from src/components/OpenButton.tsx rename to src/editor/OpenButton.tsx index 5b586281..e6a02140 100644 --- a/src/components/OpenButton.tsx +++ b/src/editor/OpenButton.tsx @@ -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; type DispatchProps = Pick; diff --git a/src/components/SaveAsButton.tsx b/src/editor/SaveAsButton.tsx similarity index 81% rename from src/components/SaveAsButton.tsx rename to src/editor/SaveAsButton.tsx index 12df0514..77c0dad1 100644 --- a/src/components/SaveAsButton.tsx +++ b/src/editor/SaveAsButton.tsx @@ -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; type DispatchProps = Pick; diff --git a/src/actions/editor.ts b/src/editor/actions.ts similarity index 100% rename from src/actions/editor.ts rename to src/editor/actions.ts diff --git a/src/components/images/beta.svg b/src/editor/beta.svg similarity index 100% rename from src/components/images/beta.svg rename to src/editor/beta.svg diff --git a/src/components/editor.scss b/src/editor/editor.scss similarity index 93% rename from src/components/editor.scss rename to src/editor/editor.scss index b501d877..910048bd 100644 --- a/src/components/editor.scss +++ b/src/editor/editor.scss @@ -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; diff --git a/src/components/editor-i18n.en.json b/src/editor/i18n.en.json similarity index 100% rename from src/components/editor-i18n.en.json rename to src/editor/i18n.en.json diff --git a/src/components/editor-i18n.test.ts b/src/editor/i18n.test.ts similarity index 77% rename from src/components/editor-i18n.test.ts rename to src/editor/i18n.test.ts index 9c30d6c6..e95107bf 100644 --- a/src/components/editor-i18n.test.ts +++ b/src/editor/i18n.test.ts @@ -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) => { diff --git a/src/components/editor-i18n.ts b/src/editor/i18n.ts similarity index 90% rename from src/components/editor-i18n.ts rename to src/editor/i18n.ts index 24faea36..7e6d044b 100644 --- a/src/components/editor-i18n.ts +++ b/src/editor/i18n.ts @@ -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 { diff --git a/src/components/images/open.svg b/src/editor/open.svg similarity index 100% rename from src/components/images/open.svg rename to src/editor/open.svg diff --git a/src/reducers/editor.ts b/src/editor/reducers.ts similarity index 91% rename from src/reducers/editor.ts rename to src/editor/reducers.ts index 593d9ebb..4f822032 100644 --- a/src/reducers/editor.ts +++ b/src/editor/reducers.ts @@ -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 = (state = null, action) => { switch (action.type) { diff --git a/src/sagas/editor.test.ts b/src/editor/sagas.test.ts similarity index 91% rename from src/sagas/editor.test.ts rename to src/editor/sagas.test.ts index c09aed41..3e26a5e0 100644 --- a/src/sagas/editor.test.ts +++ b/src/editor/sagas.test.ts @@ -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'); diff --git a/src/sagas/editor.ts b/src/editor/sagas.ts similarity index 98% rename from src/sagas/editor.ts rename to src/editor/sagas.ts index 7db2ec38..30cb5069 100644 --- a/src/sagas/editor.ts +++ b/src/editor/sagas.ts @@ -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(); diff --git a/src/components/images/download.svg b/src/editor/save.svg similarity index 100% rename from src/components/images/download.svg rename to src/editor/save.svg diff --git a/src/components/editor-snippets.ts b/src/editor/snippets.ts similarity index 100% rename from src/components/editor-snippets.ts rename to src/editor/snippets.ts diff --git a/src/sagas/error-log.test.ts b/src/error-log/sagas.test.ts similarity index 90% rename from src/sagas/error-log.test.ts rename to src/error-log/sagas.test.ts index 5bc961ea..a9b1b589 100644 --- a/src/sagas/error-log.test.ts +++ b/src/error-log/sagas.test.ts @@ -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); diff --git a/src/sagas/error-log.ts b/src/error-log/sagas.ts similarity index 90% rename from src/sagas/error-log.ts rename to src/error-log/sagas.ts index 79325d9f..259764be 100644 --- a/src/sagas/error-log.ts +++ b/src/error-log/sagas.ts @@ -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) { diff --git a/src/components/FlashButton.tsx b/src/firmware/FlashButton.tsx similarity index 79% rename from src/components/FlashButton.tsx rename to src/firmware/FlashButton.tsx index c8275972..cba488ad 100644 --- a/src/components/FlashButton.tsx +++ b/src/firmware/FlashButton.tsx @@ -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, diff --git a/src/actions/flash-firmware.ts b/src/firmware/actions.ts similarity index 100% rename from src/actions/flash-firmware.ts rename to src/firmware/actions.ts diff --git a/src/components/images/firmware.svg b/src/firmware/firmware.svg similarity index 100% rename from src/components/images/firmware.svg rename to src/firmware/firmware.svg diff --git a/src/reducers/firmware.ts b/src/firmware/reducers.ts similarity index 94% rename from src/reducers/firmware.ts rename to src/firmware/reducers.ts index fee94835..b96ca514 100644 --- a/src/reducers/firmware.ts +++ b/src/firmware/reducers.ts @@ -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. */ diff --git a/src/sagas/flash-firmware.test.ts b/src/firmware/sagas.test.ts similarity index 99% rename from src/sagas/flash-firmware.test.ts rename to src/firmware/sagas.test.ts index dcf9aa74..e6504e4d 100644 --- a/src/sagas/flash-firmware.test.ts +++ b/src/firmware/sagas.test.ts @@ -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(); diff --git a/src/sagas/flash-firmware.ts b/src/firmware/sagas.ts similarity index 98% rename from src/sagas/flash-firmware.ts rename to src/firmware/sagas.ts index 7d3234e7..a6e72b52 100644 --- a/src/sagas/flash-firmware.ts +++ b/src/firmware/sagas.ts @@ -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.CityHub, cityHubZip], diff --git a/src/components/BluetoothButton.tsx b/src/hub/BluetoothButton.tsx similarity index 71% rename from src/components/BluetoothButton.tsx rename to src/hub/BluetoothButton.tsx index 2ec44150..2f301f37 100644 --- a/src/components/BluetoothButton.tsx +++ b/src/hub/BluetoothButton.tsx @@ -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; type DispatchProps = Pick; diff --git a/src/components/ReplButton.tsx b/src/hub/ReplButton.tsx similarity index 79% rename from src/components/ReplButton.tsx rename to src/hub/ReplButton.tsx index e6230634..e98c46fe 100644 --- a/src/components/ReplButton.tsx +++ b/src/hub/ReplButton.tsx @@ -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; type DispatchProps = Pick; diff --git a/src/components/RunButton.tsx b/src/hub/RunButton.tsx similarity index 79% rename from src/components/RunButton.tsx rename to src/hub/RunButton.tsx index 77005fac..a26fbdfa 100644 --- a/src/components/RunButton.tsx +++ b/src/hub/RunButton.tsx @@ -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; type DispatchProps = Pick; diff --git a/src/components/StopButton.tsx b/src/hub/StopButton.tsx similarity index 78% rename from src/components/StopButton.tsx rename to src/hub/StopButton.tsx index f0917496..324ae89f 100644 --- a/src/components/StopButton.tsx +++ b/src/hub/StopButton.tsx @@ -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; type DispatchProps = Pick; diff --git a/src/actions/hub.ts b/src/hub/actions.ts similarity index 100% rename from src/actions/hub.ts rename to src/hub/actions.ts diff --git a/src/components/images/bt-connected.svg b/src/hub/bt-connected.svg similarity index 100% rename from src/components/images/bt-connected.svg rename to src/hub/bt-connected.svg diff --git a/src/components/images/bt-disconnected.svg b/src/hub/bt-disconnected.svg similarity index 100% rename from src/components/images/bt-disconnected.svg rename to src/hub/bt-disconnected.svg diff --git a/src/reducers/hub.ts b/src/hub/reducers.ts similarity index 94% rename from src/reducers/hub.ts rename to src/hub/reducers.ts index 89cea018..838902d5 100644 --- a/src/reducers/hub.ts +++ b/src/hub/reducers.ts @@ -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. diff --git a/src/components/images/repl.svg b/src/hub/repl.svg similarity index 100% rename from src/components/images/repl.svg rename to src/hub/repl.svg diff --git a/src/components/images/run.svg b/src/hub/run.svg similarity index 100% rename from src/components/images/run.svg rename to src/hub/run.svg diff --git a/src/sagas/hub.test.ts b/src/hub/sagas.test.ts similarity index 96% rename from src/sagas/hub.test.ts rename to src/hub/sagas.test.ts index 150b2054..7e2094fc 100644 --- a/src/sagas/hub.test.ts +++ b/src/hub/sagas.test.ts @@ -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'); diff --git a/src/sagas/hub.ts b/src/hub/sagas.ts similarity index 96% rename from src/sagas/hub.ts rename to src/hub/sagas.ts index c7578deb..c290bf68 100644 --- a/src/sagas/hub.ts +++ b/src/hub/sagas.ts @@ -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; diff --git a/src/components/images/stop.svg b/src/hub/stop.svg similarity index 100% rename from src/components/images/stop.svg rename to src/hub/stop.svg diff --git a/src/i18n.ts b/src/i18n.ts new file mode 100644 index 00000000..2731a64e --- /dev/null +++ b/src/i18n.ts @@ -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 }); +} diff --git a/src/index.tsx b/src/index.tsx index 94154f7f..8643e3f3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -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); diff --git a/src/components/LicenseDialog.tsx b/src/licenses/LicenseDialog.tsx similarity index 95% rename from src/components/LicenseDialog.tsx rename to src/licenses/LicenseDialog.tsx index 69d2b1af..7f879d1a 100644 --- a/src/components/LicenseDialog.tsx +++ b/src/licenses/LicenseDialog.tsx @@ -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'; diff --git a/src/actions/license.ts b/src/licenses/actions.ts similarity index 94% rename from src/actions/license.ts rename to src/licenses/actions.ts index 5a593a20..8732ef0e 100644 --- a/src/actions/license.ts +++ b/src/licenses/actions.ts @@ -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', diff --git a/src/components/license-i18n.en.json b/src/licenses/i18n.en.json similarity index 100% rename from src/components/license-i18n.en.json rename to src/licenses/i18n.en.json diff --git a/src/components/license-i18n.test.ts b/src/licenses/i18n.test.ts similarity index 76% rename from src/components/license-i18n.test.ts rename to src/licenses/i18n.test.ts index e4bc2625..a42e74d2 100644 --- a/src/components/license-i18n.test.ts +++ b/src/licenses/i18n.test.ts @@ -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) => { diff --git a/src/components/license-i18n.ts b/src/licenses/i18n.ts similarity index 100% rename from src/components/license-i18n.ts rename to src/licenses/i18n.ts diff --git a/src/components/license.scss b/src/licenses/license.scss similarity index 100% rename from src/components/license.scss rename to src/licenses/license.scss diff --git a/src/reducers/license.ts b/src/licenses/reducers.ts similarity index 94% rename from src/reducers/license.ts rename to src/licenses/reducers.ts index cae9e9cd..8b508c69 100644 --- a/src/reducers/license.ts +++ b/src/licenses/reducers.ts @@ -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; diff --git a/src/sagas/license.test.ts b/src/licenses/sagas.test.ts similarity index 89% rename from src/sagas/license.test.ts rename to src/licenses/sagas.test.ts index 95daafb1..c418a452 100644 --- a/src/sagas/license.test.ts +++ b/src/licenses/sagas.test.ts @@ -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(); diff --git a/src/sagas/license.ts b/src/licenses/sagas.ts similarity index 87% rename from src/sagas/license.ts rename to src/licenses/sagas.ts index cb672624..f36bab02 100644 --- a/src/sagas/license.ts +++ b/src/licenses/sagas.ts @@ -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); diff --git a/src/actions/lwp3-bootloader.ts b/src/lwp3-bootloader/actions.ts similarity index 99% rename from src/actions/lwp3-bootloader.ts rename to src/lwp3-bootloader/actions.ts index 9bf35a9f..6efa0d25 100644 --- a/src/actions/lwp3-bootloader.ts +++ b/src/lwp3-bootloader/actions.ts @@ -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. diff --git a/src/protocols/lwp3-bootloader.ts b/src/lwp3-bootloader/protocol.ts similarity index 100% rename from src/protocols/lwp3-bootloader.ts rename to src/lwp3-bootloader/protocol.ts diff --git a/src/reducers/bootloader.ts b/src/lwp3-bootloader/reducers.ts similarity index 93% rename from src/reducers/bootloader.ts rename to src/lwp3-bootloader/reducers.ts index b9aaefa8..2b20ead7 100644 --- a/src/reducers/bootloader.ts +++ b/src/lwp3-bootloader/reducers.ts @@ -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. diff --git a/src/sagas/lwp3-bootloader-ble.ts b/src/lwp3-bootloader/sagas-ble.ts similarity index 97% rename from src/sagas/lwp3-bootloader-ble.ts rename to src/lwp3-bootloader/sagas-ble.ts index 338064fb..f6f1d0e6 100644 --- a/src/sagas/lwp3-bootloader-ble.ts +++ b/src/lwp3-bootloader/sagas-ble.ts @@ -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)); diff --git a/src/sagas/lwp3-bootloader-protocol.test.ts b/src/lwp3-bootloader/sagas.test.ts similarity index 97% rename from src/sagas/lwp3-bootloader-protocol.test.ts rename to src/lwp3-bootloader/sagas.test.ts index 5805928f..e668df8c 100644 --- a/src/sagas/lwp3-bootloader-protocol.test.ts +++ b/src/lwp3-bootloader/sagas.test.ts @@ -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([ diff --git a/src/sagas/lwp3-bootloader-protocol.ts b/src/lwp3-bootloader/sagas.ts similarity index 98% rename from src/sagas/lwp3-bootloader-protocol.ts rename to src/lwp3-bootloader/sagas.ts index 55f5922b..8e08b929 100644 --- a/src/sagas/lwp3-bootloader-protocol.ts +++ b/src/lwp3-bootloader/sagas.ts @@ -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 diff --git a/src/actions/mpy.ts b/src/mpy/actions.ts similarity index 100% rename from src/actions/mpy.ts rename to src/mpy/actions.ts diff --git a/src/sagas/mpy.test.ts b/src/mpy/sagas.test.ts similarity index 96% rename from src/sagas/mpy.test.ts rename to src/mpy/sagas.test.ts index 1ca2232d..6a9fa18d 100644 --- a/src/sagas/mpy.test.ts +++ b/src/mpy/sagas.test.ts @@ -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, diff --git a/src/sagas/mpy.ts b/src/mpy/sagas.ts similarity index 97% rename from src/sagas/mpy.ts rename to src/mpy/sagas.ts index 0ef64485..ad36a3b9 100644 --- a/src/sagas/mpy.ts +++ b/src/mpy/sagas.ts @@ -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 diff --git a/src/components/I18nToaster.tsx b/src/notifications/I18nToaster.tsx similarity index 100% rename from src/components/I18nToaster.tsx rename to src/notifications/I18nToaster.tsx diff --git a/src/components/Notification.tsx b/src/notifications/Notification.tsx similarity index 86% rename from src/components/Notification.tsx rename to src/notifications/Notification.tsx index 3976044f..88ec7c6f 100644 --- a/src/components/Notification.tsx +++ b/src/notifications/Notification.tsx @@ -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; diff --git a/src/components/UnexpectedErrorNotification.tsx b/src/notifications/UnexpectedErrorNotification.tsx similarity index 94% rename from src/components/UnexpectedErrorNotification.tsx rename to src/notifications/UnexpectedErrorNotification.tsx index 8f9957ea..84f2d61e 100644 --- a/src/components/UnexpectedErrorNotification.tsx +++ b/src/notifications/UnexpectedErrorNotification.tsx @@ -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; diff --git a/src/actions/notification.ts b/src/notifications/actions.ts similarity index 100% rename from src/actions/notification.ts rename to src/notifications/actions.ts diff --git a/src/components/notification-i18n.en.json b/src/notifications/i18n.en.json similarity index 100% rename from src/components/notification-i18n.en.json rename to src/notifications/i18n.en.json diff --git a/src/components/notification-i18n.test.ts b/src/notifications/i18n.test.ts similarity index 75% rename from src/components/notification-i18n.test.ts rename to src/notifications/i18n.test.ts index 8f2d9729..4eea1a95 100644 --- a/src/components/notification-i18n.test.ts +++ b/src/notifications/i18n.test.ts @@ -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) => { diff --git a/src/components/notification-i18n.ts b/src/notifications/i18n.ts similarity index 97% rename from src/components/notification-i18n.ts rename to src/notifications/i18n.ts index 132562ea..361e915a 100644 --- a/src/components/notification-i18n.ts +++ b/src/notifications/i18n.ts @@ -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 { diff --git a/src/sagas/notification.test.ts b/src/notifications/sagas.test.ts similarity index 90% rename from src/sagas/notification.test.ts rename to src/notifications/sagas.test.ts index 0431e5f5..125bc967 100644 --- a/src/sagas/notification.test.ts +++ b/src/notifications/sagas.test.ts @@ -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 }), diff --git a/src/sagas/notification.ts b/src/notifications/sagas.ts similarity index 95% rename from src/sagas/notification.ts rename to src/notifications/sagas.ts index 96073b07..acfce26a 100644 --- a/src/sagas/notification.ts +++ b/src/notifications/sagas.ts @@ -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; diff --git a/src/reducers/index.ts b/src/reducers.ts similarity index 54% rename from src/reducers/index.ts rename to src/reducers.ts index 46aa9798..277a34b9 100644 --- a/src/reducers/index.ts +++ b/src/reducers.ts @@ -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, }); diff --git a/src/sagas.ts b/src/sagas.ts new file mode 100644 index 00000000..1f30f024 --- /dev/null +++ b/src/sagas.ts @@ -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()), + ]); +} diff --git a/src/sagas/index.ts b/src/sagas/index.ts deleted file mode 100644 index b79ecf12..00000000 --- a/src/sagas/index.ts +++ /dev/null @@ -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()), - ]); -} diff --git a/src/actions/service-worker.ts b/src/service-worker/actions.ts similarity index 100% rename from src/actions/service-worker.ts rename to src/service-worker/actions.ts diff --git a/src/components/SettingsButton.tsx b/src/settings/SettingsButton.tsx similarity index 74% rename from src/components/SettingsButton.tsx rename to src/settings/SettingsButton.tsx index e54680f8..f41b4cf8 100644 --- a/src/components/SettingsButton.tsx +++ b/src/settings/SettingsButton.tsx @@ -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; diff --git a/src/components/SettingsDrawer.tsx b/src/settings/SettingsDrawer.tsx similarity index 97% rename from src/components/SettingsDrawer.tsx rename to src/settings/SettingsDrawer.tsx index d5c61f60..557d5d64 100644 --- a/src/components/SettingsDrawer.tsx +++ b/src/settings/SettingsDrawer.tsx @@ -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; diff --git a/src/actions/settings.ts b/src/settings/actions.ts similarity index 98% rename from src/actions/settings.ts rename to src/settings/actions.ts index eb624360..2ea917bf 100644 --- a/src/actions/settings.ts +++ b/src/settings/actions.ts @@ -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 { diff --git a/src/settings/user.ts b/src/settings/defaults.ts similarity index 100% rename from src/settings/user.ts rename to src/settings/defaults.ts diff --git a/src/components/settings-i18n.en.json b/src/settings/i18n.en.json similarity index 100% rename from src/components/settings-i18n.en.json rename to src/settings/i18n.en.json diff --git a/src/components/settings-i18n.en.test.ts b/src/settings/i18n.en.test.ts similarity index 76% rename from src/components/settings-i18n.en.test.ts rename to src/settings/i18n.en.test.ts index 679896e4..89604446 100644 --- a/src/components/settings-i18n.en.test.ts +++ b/src/settings/i18n.en.test.ts @@ -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) => { diff --git a/src/settings/i18n.ts b/src/settings/i18n.ts index 2731a64e..9f8f0b84 100644 --- a/src/settings/i18n.ts +++ b/src/settings/i18n.ts @@ -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', } diff --git a/src/reducers/settings.ts b/src/settings/reducers.ts similarity index 92% rename from src/reducers/settings.ts rename to src/settings/reducers.ts index 6ae87bc5..1a575719 100644 --- a/src/reducers/settings.ts +++ b/src/settings/reducers.ts @@ -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; diff --git a/src/sagas/settings.test.ts b/src/settings/sagas.test.ts similarity index 98% rename from src/sagas/settings.test.ts rename to src/settings/sagas.test.ts index 00c1e623..4dae2884 100644 --- a/src/sagas/settings.test.ts +++ b/src/settings/sagas.test.ts @@ -1,18 +1,18 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2020-2021 The Pybricks Authors -// File: sagas/settings.test.ts +// // Tests for settings sagas. import { AsyncSaga } from '../../test'; -import { didStart } from '../actions/app'; +import { didStart } from '../app/actions'; import { didBooleanChange, didFailToSetBoolean, setBoolean, toggleBoolean, -} from '../actions/settings'; -import { SettingId } from '../settings/user'; -import settings from './settings'; +} from './actions'; +import { SettingId } from './defaults'; +import settings from './sagas'; afterAll(() => { jest.restoreAllMocks(); diff --git a/src/sagas/settings.ts b/src/settings/sagas.ts similarity index 96% rename from src/sagas/settings.ts rename to src/settings/sagas.ts index 394c9475..defd1e3a 100644 --- a/src/sagas/settings.ts +++ b/src/settings/sagas.ts @@ -7,7 +7,8 @@ import { EventChannel, eventChannel } from 'redux-saga'; import { call, fork, put, select, take, takeEvery } from 'typed-redux-saga/macro'; -import { AppActionType } from '../actions/app'; +import { AppActionType } from '../app/actions'; +import { RootState } from '../reducers'; import { SettingsActionType, SettingsSetBooleanAction, @@ -15,9 +16,8 @@ import { didBooleanChange, didFailToSetBoolean, setBoolean, -} from '../actions/settings'; -import { RootState } from '../reducers'; -import { SettingId, getDefaultBooleanValue } from '../settings/user'; +} from './actions'; +import { SettingId, getDefaultBooleanValue } from './defaults'; function stringToBoolean(value: string): boolean { return value.toLowerCase().match(/(true|yes|1)/) !== null; diff --git a/src/components/images/settings.svg b/src/settings/settings.svg similarity index 100% rename from src/components/images/settings.svg rename to src/settings/settings.svg diff --git a/src/components/StatusBar.tsx b/src/status-bar/StatusBar.tsx similarity index 100% rename from src/components/StatusBar.tsx rename to src/status-bar/StatusBar.tsx diff --git a/src/components/status-bar.scss b/src/status-bar/status-bar.scss similarity index 100% rename from src/components/status-bar.scss rename to src/status-bar/status-bar.scss diff --git a/src/components/Terminal.tsx b/src/terminal/Terminal.tsx similarity index 97% rename from src/components/Terminal.tsx rename to src/terminal/Terminal.tsx index b6dd1350..e66387c1 100644 --- a/src/components/Terminal.tsx +++ b/src/terminal/Terminal.tsx @@ -14,11 +14,11 @@ import { connect } from 'react-redux'; import { Observable, Unsubscribe } from 'redux'; import { Terminal as XTerm } from 'xterm'; import { FitAddon } from 'xterm-addon-fit'; -import { receiveData } from '../actions/terminal'; import { RootState } from '../reducers'; import { isMacOS } from '../utils/os'; -import { TerminalStringId } from './terminal-i18n'; -import en from './terminal-i18n.en.json'; +import { receiveData } from './actions'; +import { TerminalStringId } from './i18n'; +import en from './i18n.en.json'; import 'xterm/css/xterm.css'; diff --git a/src/actions/terminal.ts b/src/terminal/actions.ts similarity index 100% rename from src/actions/terminal.ts rename to src/terminal/actions.ts diff --git a/src/components/terminal-i18n.en.json b/src/terminal/i18n.en.json similarity index 100% rename from src/components/terminal-i18n.en.json rename to src/terminal/i18n.en.json diff --git a/src/components/terminal-i18n.test.ts b/src/terminal/i18n.test.ts similarity index 76% rename from src/components/terminal-i18n.test.ts rename to src/terminal/i18n.test.ts index 40fb478e..920f97b6 100644 --- a/src/components/terminal-i18n.test.ts +++ b/src/terminal/i18n.test.ts @@ -2,8 +2,8 @@ // Copyright (c) 2020 The Pybricks Authors import { lookup } from '../../test'; -import { TerminalStringId } from './terminal-i18n'; -import en from './terminal-i18n.en.json'; +import { TerminalStringId } from './i18n'; +import en from './i18n.en.json'; describe('Ensure .json file has matches for TerminalStringIds', () => { test.each(Object.values(TerminalStringId))('%s', (id) => { diff --git a/src/components/terminal-i18n.ts b/src/terminal/i18n.ts similarity index 87% rename from src/components/terminal-i18n.ts rename to src/terminal/i18n.ts index 774f98e4..330dd5d0 100644 --- a/src/components/terminal-i18n.ts +++ b/src/terminal/i18n.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2020 The Pybricks Authors -// File: components/terminal-i18n.ts +// // Terminal translation keys. export enum TerminalStringId { diff --git a/src/reducers/terminal.ts b/src/terminal/reducers.ts similarity index 91% rename from src/reducers/terminal.ts rename to src/terminal/reducers.ts index 2b2c4170..4c3b6cbf 100644 --- a/src/reducers/terminal.ts +++ b/src/terminal/reducers.ts @@ -4,7 +4,7 @@ import { Reducer } from 'react'; import { Observable, combineReducers } from 'redux'; import { Action } from '../actions'; -import { TerminalActionType } from '../actions/terminal'; +import { TerminalActionType } from './actions'; type DataSource = Observable | null; diff --git a/src/sagas/terminal.test.ts b/src/terminal/sagas.test.ts similarity index 98% rename from src/sagas/terminal.test.ts rename to src/terminal/sagas.test.ts index b1fbbaa2..b2dfb418 100644 --- a/src/sagas/terminal.test.ts +++ b/src/terminal/sagas.test.ts @@ -3,30 +3,30 @@ import { AsyncSaga, delay } from '../../test'; -import { didStart } from '../actions/app'; +import { didStart } from '../app/actions'; import { BleUartActionType, BleUartWriteAction, didFailToWrite, didWrite, notify, -} from '../actions/ble-uart'; +} from '../ble-uart/actions'; import { HubChecksumMessageAction, HubMessageActionType, HubRuntimeStatusMessageAction, HubRuntimeStatusType, -} from '../actions/hub'; +} from '../hub/actions'; +import { HubRuntimeState } from '../hub/reducers'; +import { createCountFunc } from '../utils/iter'; import { TerminalActionType, TerminalDataSendDataAction, TerminalSetDataSourceAction, receiveData, sendData, -} from '../actions/terminal'; -import { HubRuntimeState } from '../reducers/hub'; -import { createCountFunc } from '../utils/iter'; -import terminal from './terminal'; +} from './actions'; +import terminal from './sagas'; describe('Data receiver filters out hub status', () => { test('normal message - no status', async () => { diff --git a/src/sagas/terminal.ts b/src/terminal/sagas.ts similarity index 94% rename from src/sagas/terminal.ts rename to src/terminal/sagas.ts index 621392d5..6fbbe70c 100644 --- a/src/sagas/terminal.ts +++ b/src/terminal/sagas.ts @@ -14,19 +14,19 @@ import { } from 'typed-redux-saga/macro'; import PushStream from 'zen-push'; import { Action } from '../actions'; -import { AppActionType, AppDidStartAction } from '../actions/app'; -import { BleUartActionType, BleUartNotifyAction, write } from '../actions/ble-uart'; -import { HubRuntimeStatusType, checksum, updateStatus } from '../actions/hub'; +import { AppActionType, AppDidStartAction } from '../app/actions'; +import { BleUartActionType, BleUartNotifyAction, write } from '../ble-uart/actions'; +import { SafeTxCharLength } from '../ble-uart/protocol'; +import { HubRuntimeStatusType, checksum, updateStatus } from '../hub/actions'; +import { HubRuntimeState } from '../hub/reducers'; +import { RootState } from '../reducers'; +import { defined } from '../utils'; import { TerminalActionType, TerminalDataReceiveDataAction, sendData, setDataSource, -} from '../actions/terminal'; -import { SafeTxCharLength } from '../protocols/nrf-uart'; -import { RootState } from '../reducers'; -import { HubRuntimeState } from '../reducers/hub'; -import { defined } from '../utils'; +} from './actions'; const encoder = new TextEncoder(); const decoder = new TextDecoder(); diff --git a/src/components/ActionButton.tsx b/src/toolbar/ActionButton.tsx similarity index 95% rename from src/components/ActionButton.tsx rename to src/toolbar/ActionButton.tsx index 4b21ecde..f0cafcfa 100644 --- a/src/components/ActionButton.tsx +++ b/src/toolbar/ActionButton.tsx @@ -12,9 +12,9 @@ import { } 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'; +import { tooltipDelay } from '../app/constants'; +import { TooltipId } from './i18n'; +import en from './i18n.en.json'; export interface ActionButtonProps { /** A unique id for each instance. */ diff --git a/src/components/OpenFileButton.tsx b/src/toolbar/OpenFileButton.tsx similarity index 97% rename from src/components/OpenFileButton.tsx rename to src/toolbar/OpenFileButton.tsx index bf8ac93c..58e1cf51 100644 --- a/src/components/OpenFileButton.tsx +++ b/src/toolbar/OpenFileButton.tsx @@ -5,9 +5,9 @@ import { Button, Intent, Position, Spinner, Tooltip } from '@blueprintjs/core'; import { WithI18nProps, withI18n } from '@shopify/react-i18n'; import React from 'react'; import Dropzone, { FileRejection } from 'react-dropzone'; -import { tooltipDelay } from '../settings/ui'; -import { TooltipId } from './button-i18n'; -import en from './button-i18n.en.json'; +import { tooltipDelay } from '../app/constants'; +import { TooltipId } from './i18n'; +import en from './i18n.en.json'; export interface OpenFileButtonProps { /** A unique id for each instance. */ diff --git a/src/components/Toolbar.tsx b/src/toolbar/Toolbar.tsx similarity index 78% rename from src/components/Toolbar.tsx rename to src/toolbar/Toolbar.tsx index 5107bd8d..3bb6c007 100644 --- a/src/components/Toolbar.tsx +++ b/src/toolbar/Toolbar.tsx @@ -3,14 +3,14 @@ import { Alignment, ButtonGroup, Navbar } from '@blueprintjs/core'; import React from 'react'; -import BluetoothButton from './BluetoothButton'; -import FlashButton from './FlashButton'; -import OpenButton from './OpenButton'; -import ReplButton from './ReplButton'; -import RunButton from './RunButton'; -import SaveAsButton from './SaveAsButton'; -import SettingsButton from './SettingsButton'; -import StopButton from './StopButton'; +import OpenButton from '../editor/OpenButton'; +import SaveAsButton from '../editor/SaveAsButton'; +import FlashButton from '../firmware/FlashButton'; +import BluetoothButton from '../hub/BluetoothButton'; +import ReplButton from '../hub/ReplButton'; +import RunButton from '../hub/RunButton'; +import StopButton from '../hub/StopButton'; +import SettingsButton from '../settings/SettingsButton'; import './toolbar.scss'; diff --git a/src/components/button-i18n.en.json b/src/toolbar/i18n.en.json similarity index 100% rename from src/components/button-i18n.en.json rename to src/toolbar/i18n.en.json diff --git a/src/components/button-i18n.test.ts b/src/toolbar/i18n.test.ts similarity index 77% rename from src/components/button-i18n.test.ts rename to src/toolbar/i18n.test.ts index 74ee65ff..ef822cb2 100644 --- a/src/components/button-i18n.test.ts +++ b/src/toolbar/i18n.test.ts @@ -2,8 +2,8 @@ // Copyright (c) 2020 The Pybricks Authors import { lookup } from '../../test'; -import { TooltipId } from './button-i18n'; -import en from './button-i18n.en.json'; +import { TooltipId } from './i18n'; +import en from './i18n.en.json'; describe('Ensure .json file has matches for TooltipIds', () => { test.each(Object.values(TooltipId))('%s', (id) => { diff --git a/src/components/button-i18n.ts b/src/toolbar/i18n.ts similarity index 93% rename from src/components/button-i18n.ts rename to src/toolbar/i18n.ts index 2fafaadf..657adce1 100644 --- a/src/components/button-i18n.ts +++ b/src/toolbar/i18n.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2020-2021 The Pybricks Authors -// File: components/button-i18n.ts +// // Button translation keys. export enum TooltipId { diff --git a/src/components/toolbar.scss b/src/toolbar/toolbar.scss similarity index 100% rename from src/components/toolbar.scss rename to src/toolbar/toolbar.scss diff --git a/src/components/ExternalLinkIcon.tsx b/src/utils/ExternalLinkIcon.tsx similarity index 100% rename from src/components/ExternalLinkIcon.tsx rename to src/utils/ExternalLinkIcon.tsx diff --git a/src/components/external-link.scss b/src/utils/external-link.scss similarity index 100% rename from src/components/external-link.scss rename to src/utils/external-link.scss