mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 01:23:52 +00:00
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pybricks/pybricks-code",
|
||||
"version": "1.0.0-beta.2",
|
||||
"version": "1.0.0-beta.3",
|
||||
"license": "MIT",
|
||||
"author": "The Pybricks Authors",
|
||||
"repository": {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { HubAction, HubMessageAction } from './hub';
|
||||
import { LicenseAction } from './license';
|
||||
import {
|
||||
BootloaderConnectionAction,
|
||||
BootloaderDidFailToRequestAction,
|
||||
BootloaderDidRequestAction,
|
||||
BootloaderRequestAction,
|
||||
BootloaderResponseAction,
|
||||
@@ -31,6 +32,7 @@ export type Action =
|
||||
| BleUartAction
|
||||
| BootloaderConnectionAction
|
||||
| BootloaderDidRequestAction
|
||||
| BootloaderDidFailToRequestAction
|
||||
| BootloaderRequestAction
|
||||
| BootloaderResponseAction
|
||||
| EditorAction
|
||||
|
||||
@@ -37,6 +37,10 @@ export enum BootloaderConnectionActionType {
|
||||
* Finished sending a message.
|
||||
*/
|
||||
DidSend = 'bootloader.action.connection.did.send',
|
||||
/**
|
||||
* Sending a message failed with error.
|
||||
*/
|
||||
DidFailToSend = 'bootloader.action.connection.did.failToSend',
|
||||
/**
|
||||
* The connection received a message.
|
||||
*/
|
||||
@@ -152,12 +156,18 @@ export function send(
|
||||
return { type: BootloaderConnectionActionType.Send, data, withResponse };
|
||||
}
|
||||
|
||||
export type BootloaderConnectionDidSendAction = Action<BootloaderConnectionActionType.DidSend> & {
|
||||
err?: Error;
|
||||
export type BootloaderConnectionDidSendAction = Action<BootloaderConnectionActionType.DidSend>;
|
||||
|
||||
export function didSend(): BootloaderConnectionDidSendAction {
|
||||
return { type: BootloaderConnectionActionType.DidSend };
|
||||
}
|
||||
|
||||
export type BootloaderConnectionDidFailToSendAction = Action<BootloaderConnectionActionType.DidFailToSend> & {
|
||||
err: Error;
|
||||
};
|
||||
|
||||
export function didSend(err?: Error): BootloaderConnectionDidSendAction {
|
||||
return { type: BootloaderConnectionActionType.DidSend, err };
|
||||
export function didFailToSend(err: Error): BootloaderConnectionDidFailToSendAction {
|
||||
return { type: BootloaderConnectionActionType.DidFailToSend, err };
|
||||
}
|
||||
|
||||
export type BootloaderConnectionDidReceiveAction = Action<BootloaderConnectionActionType.DidReceive> & {
|
||||
@@ -184,7 +194,7 @@ export type BootloaderConnectionAction =
|
||||
| BootloaderConnectionDidErrorAction
|
||||
| BootloaderConnectionSendAction
|
||||
| BootloaderConnectionDidSendAction
|
||||
| BootloaderConnectionDidSendAction
|
||||
| BootloaderConnectionDidFailToSendAction
|
||||
| BootloaderConnectionDidReceiveAction
|
||||
| BootloaderConnectionDidDisconnectAction;
|
||||
|
||||
@@ -355,26 +365,57 @@ export type BootloaderDidRequestType = 'bootloader.action.did.request';
|
||||
export const BootloaderDidRequestType = 'bootloader.action.did.request';
|
||||
|
||||
/**
|
||||
* Action that indicates a request was sent or failed to send.
|
||||
* Action that indicates a request was sent.
|
||||
*/
|
||||
export type BootloaderDidRequestAction = Action<BootloaderDidRequestType> & {
|
||||
/**
|
||||
* The unique identifier of the action.
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* The error on failure or undefined on success.
|
||||
*/
|
||||
err?: Error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an action that indicates a request was sent or failed to send.
|
||||
* Creates an action that indicates a request was sent.
|
||||
* @param id The unique identifier of the action.
|
||||
* @param err The error message on failure or undefined on success.
|
||||
*/
|
||||
export function didRequest(id: number, err?: Error): BootloaderDidRequestAction {
|
||||
return { type: BootloaderDidRequestType, id, err };
|
||||
export function didRequest(id: number): BootloaderDidRequestAction {
|
||||
return { type: BootloaderDidRequestType, id };
|
||||
}
|
||||
|
||||
/**
|
||||
* Action type for bootloader did fail to request action.
|
||||
*/
|
||||
export type BootloaderDidFailToRequestType = 'bootloader.action.did.failToRequest';
|
||||
|
||||
/**
|
||||
* Action type for bootloader did fail to request action.
|
||||
*/
|
||||
export const BootloaderDidFailToRequestType = 'bootloader.action.did.failToRequest';
|
||||
|
||||
/**
|
||||
* Action that indicates a request failed to send.
|
||||
*/
|
||||
export type BootloaderDidFailToRequestAction = Action<BootloaderDidFailToRequestType> & {
|
||||
/**
|
||||
* The unique identifier of the action.
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* The error.
|
||||
*/
|
||||
err: Error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an action that indicates a request failed to send.
|
||||
* @param id The unique identifier of the action.
|
||||
* @param err The error message.
|
||||
*/
|
||||
export function didFailToRequest(
|
||||
id: number,
|
||||
err: Error,
|
||||
): BootloaderDidFailToRequestAction {
|
||||
return { type: BootloaderDidFailToRequestType, id, err };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@ import { IAceEditor } from 'react-ace/lib/types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Action, Dispatch } from '../actions';
|
||||
import { setEditSession, storageChanged } from '../actions/editor';
|
||||
import { compile } from '../actions/mpy';
|
||||
import { RootState } from '../reducers';
|
||||
import { isMacOS } from '../utils/os';
|
||||
import { EditorStringId } from './editor-i18n';
|
||||
@@ -38,6 +39,7 @@ type StateProps = {
|
||||
type DispatchProps = {
|
||||
onSessionChanged: (session?: Ace.EditSession) => void;
|
||||
onProgramStorageChanged: (newValue: string) => void;
|
||||
onCheck: (script: string) => void;
|
||||
};
|
||||
|
||||
type EditorProps = StateProps & DispatchProps & WithI18nProps;
|
||||
@@ -76,7 +78,7 @@ class Editor extends React.Component<EditorProps> {
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const { darkMode, i18n, onSessionChanged } = this.props;
|
||||
const { darkMode, i18n, onSessionChanged, onCheck } = this.props;
|
||||
return (
|
||||
<div className="h-100">
|
||||
<ResizeSensor onResize={(): void => this.editor?.resize()}>
|
||||
@@ -97,12 +99,19 @@ class Editor extends React.Component<EditorProps> {
|
||||
enableSnippets: true,
|
||||
}}
|
||||
onLoad={(e): void => {
|
||||
// default binding is F2 which conflicts with 'check'
|
||||
e.commands.byName['toggleFoldWidget'].bindKey = {
|
||||
win: 'Shift-F2',
|
||||
mac: 'Shift-F2',
|
||||
};
|
||||
|
||||
config.loadModule(
|
||||
'ace/ext/menu_tools/get_editor_keyboard_shortcuts',
|
||||
(m) => {
|
||||
this.keyBindings = m.getEditorKeybordShortcuts(e);
|
||||
},
|
||||
);
|
||||
|
||||
config.loadModule('ace/ext/keybinding_menu', (m) =>
|
||||
m.init(e),
|
||||
);
|
||||
@@ -114,6 +123,12 @@ class Editor extends React.Component<EditorProps> {
|
||||
localStorage.setItem('program', v);
|
||||
}}
|
||||
commands={[
|
||||
{
|
||||
// command to check current program for errors
|
||||
name: 'check',
|
||||
bindKey: { win: 'F2', mac: 'F2' },
|
||||
exec: (editor) => onCheck(editor.getValue()),
|
||||
},
|
||||
{
|
||||
name: 'save',
|
||||
bindKey: { win: 'Ctrl-S', mac: 'Cmd-S' },
|
||||
@@ -158,6 +173,12 @@ class Editor extends React.Component<EditorProps> {
|
||||
icon="clipboard"
|
||||
label={isMacOS() ? 'Cmd-V' : 'Ctrl-V'}
|
||||
/>
|
||||
<MenuItem
|
||||
onClick={() => this.editor?.selectAll()}
|
||||
text={i18n.translate(EditorStringId.SelectAll)}
|
||||
icon="blank"
|
||||
label={isMacOS() ? 'Cmd-A' : 'Ctrl-A'}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
onClick={(): void => this.editor?.undo()}
|
||||
@@ -186,6 +207,9 @@ const mapStateToProps = (state: RootState): StateProps => ({
|
||||
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
|
||||
onSessionChanged: (s): Action => dispatch(setEditSession(s)),
|
||||
onProgramStorageChanged: (v): Action => dispatch(storageChanged(v)),
|
||||
// REVISIT: the options here might need to be changed - hopefully there is
|
||||
// one setting that works for all hub types for cases where we aren't connected.
|
||||
onCheck: (script) => dispatch(compile(script)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
||||
@@ -100,33 +100,38 @@ class OpenFileButton extends React.Component<Props> {
|
||||
position={Position.BOTTOM}
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
>
|
||||
<Button
|
||||
<div
|
||||
{...getRootProps()}
|
||||
intent={Intent.PRIMARY}
|
||||
disabled={this.props.enabled === false}
|
||||
className="no-box-shadow"
|
||||
style={
|
||||
this.props.enabled === false
|
||||
? { pointerEvents: 'none' }
|
||||
: undefined
|
||||
}
|
||||
// onClick={this.props.onClick}
|
||||
// breaks Dropzone when this.props.onClick is undefined
|
||||
// so we have to do it the long way
|
||||
{...(this.props.onClick
|
||||
? { onClick: this.props.onClick }
|
||||
: {})}
|
||||
tabIndex={-1}
|
||||
className="pb-open-file-button-root"
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
{this.props.showProgress ? (
|
||||
<Spinner
|
||||
value={this.props.progress}
|
||||
intent={Intent.PRIMARY}
|
||||
/>
|
||||
) : (
|
||||
<img src={this.props.icon} alt={this.props.id} />
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
disabled={this.props.enabled === false}
|
||||
className="no-box-shadow"
|
||||
style={
|
||||
this.props.enabled === false
|
||||
? { pointerEvents: 'none' }
|
||||
: undefined
|
||||
}
|
||||
// onClick={this.props.onClick}
|
||||
// breaks Dropzone when this.props.onClick is undefined
|
||||
// so we have to do it the long way
|
||||
{...(this.props.onClick
|
||||
? { onClick: this.props.onClick }
|
||||
: {})}
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
{this.props.showProgress ? (
|
||||
<Spinner
|
||||
value={this.props.progress}
|
||||
intent={Intent.PRIMARY}
|
||||
/>
|
||||
) : (
|
||||
<img src={this.props.icon} alt={this.props.id} />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Dropzone>
|
||||
|
||||
@@ -149,6 +149,11 @@ class Terminal extends React.Component<TerminalProps> {
|
||||
icon="clipboard"
|
||||
label={isMacOS() ? 'Cmd-V' : 'Ctrl-V'}
|
||||
/>
|
||||
<MenuItem
|
||||
onClick={() => this.xterm.selectAll()}
|
||||
text={i18n.translate(TerminalStringId.SelectAll)}
|
||||
icon="blank"
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
onClick={(): void => this.xterm.clear()}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"placeholder": "Write your program here...",
|
||||
"copy": "Copy",
|
||||
"paste": "Paste",
|
||||
"selectAll": "Select All",
|
||||
"undo": "Undo",
|
||||
"redo": "Redo"
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export enum EditorStringId {
|
||||
Placeholder = 'editor.placeholder',
|
||||
Copy = 'editor.copy',
|
||||
Paste = 'editor.paste',
|
||||
SelectAll = 'editor.selectAll',
|
||||
Undo = 'editor.undo',
|
||||
Redo = 'editor.redo',
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
@@ -10,19 +10,20 @@
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
enable-background="new 0 0 20 20"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="settings.svg"
|
||||
width="50"
|
||||
height="50"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
|
||||
id="metadata41"><rdf:RDF><cc:Work
|
||||
id="metadata12"><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></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs39" /><sodipodi:namedview
|
||||
id="defs10" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
@@ -31,101 +32,30 @@
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2089"
|
||||
inkscape:window-height="1160"
|
||||
id="namedview37"
|
||||
inkscape:window-width="1480"
|
||||
inkscape:window-height="1046"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:zoom="15.418475"
|
||||
inkscape:cx="21.7408"
|
||||
inkscape:cy="28.83975"
|
||||
inkscape:zoom="11.8"
|
||||
inkscape:cx="24.88532"
|
||||
inkscape:cy="16.779661"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Capa_1" />
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<g
|
||||
id="cog_2_"
|
||||
transform="matrix(2.25,0,0,2.25,2.5,2.5)"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<g
|
||||
id="g4"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,4.9999835,4.9999835)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
<path
|
||||
d="m 20.701,281.901 32.1,0.2 c 4.8,24.7 14.3,48.7 28.7,70.5 l -22.8,22.6 c -8.2,8.1 -8.2,21.2 -0.2,29.4 l 24.6,24.9 c 8.1,8.2 21.2,8.2 29.4,0.2 l 22.8,-22.6 c 21.6,14.6 45.5,24.5 70.2,29.5 l -0.2,32.1 c -0.1,11.5 9.2,20.8 20.7,20.9 l 35,0.2 c 11.5,0.1 20.8,-9.2 20.9,-20.7 l 0.2,-32.1 c 24.7,-4.8 48.7,-14.3 70.5,-28.7 l 22.6,22.8 c 8.1,8.2 21.2,8.2 29.4,0.2 l 24.9,-24.6 c 8.2,-8.1 8.2,-21.2 0.2,-29.4 l -22.6,-22.8 c 14.6,-21.6 24.5,-45.5 29.5,-70.2 l 32.1,0.2 c 11.5,0.1 20.8,-9.2 20.9,-20.7 l 0.2,-35 c 0.1,-11.5 -9.2,-20.8 -20.7,-20.9 l -32.1,-0.2 c -4.8,-24.7 -14.3,-48.7 -28.7,-70.5 l 22.8,-22.6 c 8.2,-8.1 8.2,-21.2 0.2,-29.4 l -24.6,-24.9 c -8.1,-8.2 -21.2,-8.2 -29.4,-0.2 l -22.8,22.6 c -21.6,-14.6 -45.5,-24.5 -70.2,-29.5 l 0.2,-32.1 c 0.1,-11.5 -9.2,-20.8 -20.7,-20.9 l -35,-0.2 c -11.5,-0.1 -20.8,9.2 -20.9,20.7 l -0.3,32.1 c -24.8,4.8 -48.8,14.3 -70.5,28.7 l -22.6,-22.8 c -8.1,-8.2 -21.2,-8.2 -29.4,-0.2 l -24.8,24.6 c -8.2,8.1 -8.2,21.2 -0.2,29.4 l 22.6,22.8 c -14.6,21.6 -24.5,45.5 -29.5,70.2 l -32.1,-0.2 c -11.5,-0.1 -20.8,9.2 -20.9,20.7 l -0.2,35 c -0.1,11.4 9.2,20.8 20.7,20.9 z m 158.6,-103.3 c 36.6,-36.2 95.5,-35.9 131.7,0.7 36.2,36.6 35.9,95.5 -0.7,131.7 -36.6,36.2 -95.5,35.9 -131.7,-0.7 -36.2,-36.6 -35.9,-95.5 0.7,-131.7 z"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
d="M 19,8 H 16.69 C 16.55,7.54 16.36,7.11 16.13,6.7 L 17.83,5 c 0.39,-0.39 0.39,-1.02 0,-1.41 L 16.42,2.18 c -0.39,-0.39 -1.02,-0.39 -1.41,0 l -1.7,1.7 C 12.9,3.66 12.47,3.47 12.01,3.33 V 1 c 0,-0.55 -0.45,-1 -1,-1 H 9 C 8.45,0 8,0.45 8,1 V 3.33 C 7.52,3.47 7.06,3.67 6.63,3.91 L 5,2.28 C 4.63,1.91 4.02,1.91 3.64,2.28 L 2.28,3.64 C 1.91,4.02 1.91,4.63 2.28,5 L 3.9,6.62 C 3.66,7.06 3.46,7.51 3.31,8 H 1 C 0.45,8 0,8.45 0,9 v 2 c 0,0.55 0.45,1 1,1 h 2.31 c 0.14,0.46 0.33,0.89 0.56,1.3 L 2.17,15 c -0.39,0.39 -0.39,1.02 0,1.41 l 1.41,1.41 c 0.39,0.39 1.02,0.39 1.41,0 l 1.7,-1.7 c 0.41,0.22 0.84,0.41 1.3,0.55 V 19 c 0,0.55 0.45,1 1,1 h 2 c 0.55,0 1,-0.45 1,-1 v -2.33 c 0.48,-0.14 0.94,-0.35 1.37,-0.59 L 15,17.72 c 0.37,0.37 0.98,0.37 1.36,0 l 1.36,-1.36 c 0.37,-0.37 0.37,-0.98 0,-1.36 L 16.1,13.38 C 16.34,12.95 16.55,12.49 16.7,12 H 19 c 0.55,0 1,-0.45 1,-1 V 9 C 20,8.45 19.55,8 19,8 Z m -9,6 C 7.79,14 6,12.21 6,10 6,7.79 7.79,6 10,6 c 2.21,0 4,1.79 4,4 0,2.21 -1.79,4 -4,4 z"
|
||||
id="path2"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964" />
|
||||
</g>
|
||||
<g
|
||||
id="g6"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g8"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g10"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g12"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g14"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g16"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g18"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g20"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g22"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g24"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g26"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g28"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g30"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g32"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
</g>
|
||||
<g
|
||||
id="g34"
|
||||
transform="matrix(0.08166572,0,0,0.08166572,224.90098,-214.90102)"
|
||||
style="fill:#ffffff;fill-opacity:0.90707964">
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;fill:#ffffff;fill-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -2,6 +2,7 @@
|
||||
"terminal": {
|
||||
"copy": "Copy",
|
||||
"paste": "Paste",
|
||||
"selectAll": "Select All",
|
||||
"clear": "Clear"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
export enum TerminalStringId {
|
||||
Copy = 'terminal.copy',
|
||||
Paste = 'terminal.paste',
|
||||
SelectAll = 'terminal.selectAll',
|
||||
Clear = 'terminal.clear',
|
||||
}
|
||||
|
||||
+5
-1
@@ -40,7 +40,11 @@ body {
|
||||
|
||||
// global style tweaks
|
||||
|
||||
.#{$ns}-dialog {
|
||||
.#{$ns}-toast {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.#{$ns}-button {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
didConnect,
|
||||
didDisconnect,
|
||||
didFailToConnect,
|
||||
didFailToRequest,
|
||||
didRequest,
|
||||
disconnect,
|
||||
eraseRequest,
|
||||
@@ -329,7 +330,7 @@ describe('flashFirmware', () => {
|
||||
// On city hub, we can end up in this situation. BLE writeValueWithResponse()
|
||||
// doesn't return until erasing is done, so there is a long window for
|
||||
// this to happen.
|
||||
saga.put(didRequest(0, new Error('failed due to disconnect')));
|
||||
saga.put(didFailToRequest(0, new Error('failed due to disconnect')));
|
||||
|
||||
await saga.end();
|
||||
});
|
||||
@@ -387,7 +388,7 @@ describe('flashFirmware', () => {
|
||||
expect(action).toEqual(infoRequest(0));
|
||||
|
||||
const testError = new Error('test');
|
||||
saga.put(didRequest(0, testError));
|
||||
saga.put(didFailToRequest(0, testError));
|
||||
|
||||
// should get a failure to start
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ import {
|
||||
BootloaderChecksumResponseAction,
|
||||
BootloaderConnectionAction,
|
||||
BootloaderConnectionActionType,
|
||||
BootloaderDidFailToRequestAction,
|
||||
BootloaderDidFailToRequestType,
|
||||
BootloaderDidRequestAction,
|
||||
BootloaderDidRequestType,
|
||||
BootloaderEraseResponseAction,
|
||||
@@ -85,15 +87,25 @@ function* disconnectAndCancel(): SagaGenerator<void> {
|
||||
}
|
||||
|
||||
function* waitForDidRequest(id: number): SagaGenerator<BootloaderDidRequestAction> {
|
||||
const request = yield* take<BootloaderDidRequestAction>(
|
||||
(a: Action) => a.type === BootloaderDidRequestType && a.id === id,
|
||||
);
|
||||
if (request.err) {
|
||||
yield* put(didFailToFinish(FailToFinishReasonType.BleError, request.err));
|
||||
const { requested, failedToRequest } = yield* race({
|
||||
requested: take<BootloaderDidRequestAction>(
|
||||
(a: Action) => a.type === BootloaderDidRequestType && a.id === id,
|
||||
),
|
||||
failedToRequest: take<BootloaderDidFailToRequestAction>(
|
||||
(a: Action) => a.type === BootloaderDidFailToRequestType && a.id === id,
|
||||
),
|
||||
});
|
||||
|
||||
if (failedToRequest) {
|
||||
yield* put(
|
||||
didFailToFinish(FailToFinishReasonType.BleError, failedToRequest.err),
|
||||
);
|
||||
yield* disconnectAndCancel();
|
||||
}
|
||||
|
||||
return request;
|
||||
defined(requested);
|
||||
|
||||
return requested;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
didConnect,
|
||||
didDisconnect,
|
||||
didFailToConnect,
|
||||
didFailToSend,
|
||||
didReceive,
|
||||
didSend,
|
||||
} from '../actions/lwp3-bootloader';
|
||||
@@ -34,7 +35,7 @@ function* write(
|
||||
}
|
||||
yield* put(didSend());
|
||||
} catch (err) {
|
||||
yield* put(didSend(err));
|
||||
yield* put(didFailToSend(err));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,16 +3,25 @@
|
||||
// File: sagas/lwp3-bootloader-protocol.ts
|
||||
// Handles LEGO Wireless Protocol v3 Bootloader protocol.
|
||||
|
||||
import { actionChannel, fork, put, take, takeEvery } from 'typed-redux-saga/macro';
|
||||
import {
|
||||
actionChannel,
|
||||
fork,
|
||||
put,
|
||||
race,
|
||||
take,
|
||||
takeEvery,
|
||||
} from 'typed-redux-saga/macro';
|
||||
import { Action } from '../actions';
|
||||
import {
|
||||
BootloaderConnectionActionType,
|
||||
BootloaderConnectionDidFailToSendAction,
|
||||
BootloaderConnectionDidReceiveAction,
|
||||
BootloaderConnectionDidSendAction,
|
||||
BootloaderRequestAction,
|
||||
BootloaderRequestActionType,
|
||||
checksumResponse,
|
||||
didError,
|
||||
didFailToRequest,
|
||||
didRequest,
|
||||
eraseResponse,
|
||||
errorResponse,
|
||||
@@ -104,10 +113,20 @@ function* encodeRequest(): Generator {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sent = yield* take<BootloaderConnectionDidSendAction>(
|
||||
BootloaderConnectionActionType.DidSend,
|
||||
);
|
||||
yield* put(didRequest(action.id, sent.err));
|
||||
const { failedToSend } = yield* race({
|
||||
sent: take<BootloaderConnectionDidSendAction>(
|
||||
BootloaderConnectionActionType.DidSend,
|
||||
),
|
||||
failedToSend: take<BootloaderConnectionDidFailToSendAction>(
|
||||
BootloaderConnectionActionType.DidFailToSend,
|
||||
),
|
||||
});
|
||||
|
||||
if (failedToSend) {
|
||||
yield* put(didFailToRequest(action.id, failedToSend.err));
|
||||
} else {
|
||||
yield* put(didRequest(action.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user