diff --git a/src/app/App.tsx b/src/app/App.tsx index 6a3b9fb5..48eab1d8 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -3,7 +3,6 @@ import { Classes } from '@blueprintjs/core'; import React, { useEffect, useState } from 'react'; -import { useDispatch } from 'react-redux'; import SplitterLayout from 'react-splitter-layout'; import { useLocalStorage, useTernaryDarkMode } from 'usehooks-ts'; import Editor, { EditorType } from '../editor/Editor'; @@ -13,7 +12,6 @@ import StatusBar from '../status-bar/StatusBar'; import Terminal from '../terminal/Terminal'; import Toolbar from '../toolbar/Toolbar'; import { isMacOS } from '../utils/os'; -import { appEditor } from './actions'; import 'react-splitter-layout/lib/index.css'; import './app.scss'; @@ -132,7 +130,6 @@ const App: React.VoidFunctionComponent = ({ onEditorChanged }) => { const { isDarkMode } = useTernaryDarkMode(); const { isSettingShowDocsEnabled } = useSettingIsShowDocsEnabled(); const [isDragging, setIsDragging] = useState(false); - const dispatch = useDispatch(); const [docsSplit, setDocsSplit] = useLocalStorage('app-docs-split', 30); const [terminalSplit, setTerminalSplit] = useLocalStorage('app-terminal-split', 30); @@ -177,7 +174,6 @@ const App: React.VoidFunctionComponent = ({ onEditorChanged }) => { > { - dispatch(appEditor(editor !== null)); if (onEditorChanged) { onEditorChanged(editor); } diff --git a/src/app/actions.ts b/src/app/actions.ts index 312ca0a6..2be6281d 100644 --- a/src/app/actions.ts +++ b/src/app/actions.ts @@ -48,9 +48,3 @@ export const didInstall = createAction(() => ({ export const didStart = createAction(() => ({ type: 'app.action.didStart', })); - -/** Temporary action for transitioning editor context. Do no use in new code. */ -export const appEditor = createAction((hasEditor: boolean) => ({ - type: 'app.action.editor', - hasEditor, -})); diff --git a/src/app/reducers.test.ts b/src/app/reducers.test.ts index f6bc4577..603a333a 100644 --- a/src/app/reducers.test.ts +++ b/src/app/reducers.test.ts @@ -22,7 +22,6 @@ test('initial state', () => { expect(reducers(undefined, {} as AnyAction)).toMatchInlineSnapshot(` Object { "checkingForUpdate": false, - "hasEditor": false, "hasUnresolvedInstallPrompt": false, "isServiceWorkerRegistered": false, "promptingInstall": false, diff --git a/src/app/reducers.ts b/src/app/reducers.ts index f8d385ce..7b450fb4 100644 --- a/src/app/reducers.ts +++ b/src/app/reducers.ts @@ -13,7 +13,6 @@ import { appDidCheckForUpdate, appDidReceiveBeforeInstallPrompt, appDidResolveInstallPrompt, - appEditor, appShowInstallPrompt, didInstall, } from './actions'; @@ -92,15 +91,6 @@ const readyForOfflineUse: Reducer = (state = false, action) => { return state; }; -/** Temporary reducer for transitioning editor context. Do no use in new code. */ -const hasEditor: Reducer = (state = false, action) => { - if (appEditor.matches(action)) { - return action.hasEditor; - } - - return state; -}; - export default combineReducers({ isServiceWorkerRegistered, checkingForUpdate, @@ -108,5 +98,4 @@ export default combineReducers({ hasUnresolvedInstallPrompt, promptingInstall, readyForOfflineUse, - hasEditor, }); diff --git a/src/editor/actions.ts b/src/editor/actions.ts new file mode 100644 index 00000000..382458ee --- /dev/null +++ b/src/editor/actions.ts @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2022 The Pybricks Authors + +import { createAction } from '../actions'; + +/** Action that indicates that a code editor was created. */ +export const editorDidCreate = createAction(() => ({ + type: 'editor.action.didCreate', +})); diff --git a/src/editor/reducers.ts b/src/editor/reducers.ts new file mode 100644 index 00000000..7a711942 --- /dev/null +++ b/src/editor/reducers.ts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2022 The Pybricks Authors + +import { Reducer, combineReducers } from 'redux'; +import { editorDidCreate } from './actions'; + +/** Indicates that the code editor is ready for use. */ +const isReady: Reducer = (state = false, action) => { + if (editorDidCreate.matches(action)) { + return true; + } + + return state; +}; + +export default combineReducers({ isReady }); diff --git a/src/editor/sagas.ts b/src/editor/sagas.ts index ba2596ad..620e58dc 100644 --- a/src/editor/sagas.ts +++ b/src/editor/sagas.ts @@ -11,6 +11,7 @@ import { fileStorageReadFile, } from '../fileStorage/actions'; import { RootState } from '../reducers'; +import { editorDidCreate } from './actions'; function* handleDidCreateEditor(editor: monaco.editor.ICodeEditor): Generator { // first, we need to be sure that file storage is ready @@ -42,6 +43,8 @@ function* handleDidCreateEditor(editor: monaco.editor.ICodeEditor): Generator { } // TODO: subscribe to actions that act on the editor + + yield* put(editorDidCreate()); } function* monitorEditors(): Generator { diff --git a/src/reducers.ts b/src/reducers.ts index 4af658a8..899d5014 100644 --- a/src/reducers.ts +++ b/src/reducers.ts @@ -5,6 +5,7 @@ import { TypedUseSelectorHook, useSelector as useReduxSelector } from 'react-red import { Reducer, combineReducers } from 'redux'; import app from './app/reducers'; import ble from './ble/reducers'; +import editor from './editor/reducers'; import explorer from './explorer/reducers'; import fileStorage from './fileStorage/reducers'; import firmware from './firmware/reducers'; @@ -18,6 +19,7 @@ export const rootReducer = combineReducers({ app, bootloader, ble, + editor, explorer, fileStorage, firmware, diff --git a/src/toolbar/buttons/run/RunButton.test.tsx b/src/toolbar/buttons/run/RunButton.test.tsx index 3b6b8ff6..150afc59 100644 --- a/src/toolbar/buttons/run/RunButton.test.tsx +++ b/src/toolbar/buttons/run/RunButton.test.tsx @@ -14,7 +14,7 @@ afterEach(() => { it('should dispatch action when clicked', () => { const [button, dispatch] = testRender(, { - app: { hasEditor: true }, + editor: { isReady: true }, hub: { runtime: HubRuntimeState.Idle }, }); diff --git a/src/toolbar/buttons/run/RunButton.tsx b/src/toolbar/buttons/run/RunButton.tsx index 7bde736f..f0d11c6f 100644 --- a/src/toolbar/buttons/run/RunButton.tsx +++ b/src/toolbar/buttons/run/RunButton.tsx @@ -1,6 +1,3 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors - // SPDX-License-Identifier: MIT // Copyright (c) 2020-2022 The Pybricks Authors @@ -17,7 +14,7 @@ import icon from './icon.svg'; const RunButton: React.VFC = () => { const downloadProgress = useSelector((s) => s.hub.downloadProgress); const runtime = useSelector((s) => s.hub.runtime); - const hasEditor = useSelector((s) => s.app.hasEditor); + const isEditorReady = useSelector((s) => s.editor.isReady); const keyboardShortcut = 'F5'; // istanbul ignore next: babel-loader rewrites this line @@ -36,7 +33,7 @@ const RunButton: React.VFC = () => { : i18n.translate(I18nId.TooltipAction, { key: keyboardShortcut }) } icon={icon} - enabled={hasEditor && runtime === HubRuntimeState.Idle} + enabled={isEditorReady && runtime === HubRuntimeState.Idle} showProgress={runtime === HubRuntimeState.Loading} progress={downloadProgress === null ? undefined : downloadProgress} onAction={() => dispatch(downloadAndRun())}