Skip to content

Commit cb30f00

Browse files
authored
Merge pull request #1009 from pybricks/dlech
restore official firmware dialog
2 parents 8989247 + 90b459d commit cb30f00

File tree

21 files changed

+314
-144
lines changed

21 files changed

+314
-144
lines changed

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,24 @@
77
### Added
88
- Added better error message when no files to backup ([support#681]).
99
- Added multi-step firmware flashing dialog.
10-
- Added support for flashing firmware via USB DFU.
10+
- Added support for flashing firmware via USB DFU ([support#659]).
1111
- Added an interactive introductory tour of the app.
12+
- Added restore official LEGO firmware dialog.
13+
14+
### Changed
15+
- Updated dependencies.
16+
- Updated firmware to Pybricks v3.2.0b3:
17+
18+
### Fixed
19+
- Fix integral control not working properly.
20+
21+
### Changed
22+
- `Motor.run_time` no longer raises an exception for negative time values.
1223

1324
### Fixed
1425
- Fixed deleting files that are not open in the editor.
1526

27+
[support#659]: https://github.com/pybricks/support/issues/659
1628
[support#681]: https://github.com/pybricks/support/issues/681
1729

1830
## [2.0.0-beta.3] - 2022-07-06

src/alerts/UnexpectedErrorAlert.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
// Copyright (c) 2022 The Pybricks Authors
33

44
import './UnexpectedErrorAlert.scss';
5-
import { AnchorButton, Button, ButtonGroup, Collapse, Intent } from '@blueprintjs/core';
5+
import {
6+
AnchorButton,
7+
Button,
8+
ButtonGroup,
9+
Collapse,
10+
Intent,
11+
Pre,
12+
} from '@blueprintjs/core';
613
import React, { useState } from 'react';
714
import { useId } from 'react-aria';
815
import { CreateToast } from '../i18nToaster';
@@ -33,7 +40,7 @@ const UnexpectedErrorAlert: React.VoidFunctionComponent<UnexpectedErrorAlertProp
3340
<span id={labelId}>{i18n.translate('technicalInfo')}</span>
3441
</span>
3542
<Collapse isOpen={isExpanded}>
36-
<pre className="pb-alerts-stack-trace">{error.stack}</pre>
43+
<Pre className="pb-alerts-stack-trace">{error.stack}</Pre>
3744
</Collapse>
3845
<div>
3946
<ButtonGroup minimal={true} fill={true}>

src/app/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ export const pybricksUsbDfuWindowsDriverInstallUrl =
4444
export const pybricksUsbLinuxUdevRulesUrl =
4545
'https://github.com/pybricks/support/discussions/688#discussioncomment-3239099';
4646

47+
export const pybricksBleFirmwareRestoreVideoUrl =
48+
'https://pybricks.com/install/technic-boost-city/#restoring-the-original-firmware';
49+
50+
export const pybricksDfuRestoreUrl = 'https://dfu.pybricks.com';
51+
4752
/** Pybricks copyright statement. */
4853
export const pybricksCopyright = 'Copyright (c) 2020-2022 The Pybricks Authors';
4954

src/ble/alerts/NoWebBluetooth.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright (c) 2022 The Pybricks Authors
33

4-
import { Button, Intent } from '@blueprintjs/core';
4+
import { Button, Code, Intent } from '@blueprintjs/core';
55
import React from 'react';
66
import { CreateToast } from '../../i18nToaster';
77
import { isIOS, isLinux } from '../../utils/os';
@@ -19,9 +19,9 @@ const NoWebBluetooth: React.VoidFunctionComponent = () => {
1919
<>
2020
<p>{i18n.translate('noWebBluetooth.linux')}</p>
2121
<p>
22-
<code>
22+
<Code>
2323
chrome://flags/#enable-experimental-web-platform-features
24-
</code>
24+
</Code>
2525
<Button
2626
icon="duplicate"
2727
small={true}

src/explorer/fileNameFormGroup/FileNameFormGroup.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright (c) 2022 The Pybricks Authors
33

4-
import { Classes, FormGroup, InputGroup, Intent, Tag } from '@blueprintjs/core';
4+
import { Classes, Code, FormGroup, InputGroup, Intent, Tag } from '@blueprintjs/core';
55
import type { AriaButtonProps } from '@react-types/button';
66
import React, { useCallback, useRef } from 'react';
77
import { useButton } from 'react-aria';
@@ -108,19 +108,19 @@ const FileNameHelpText: React.VoidFunctionComponent<FileNameHelpTextProps> = ({
108108
return (
109109
<>
110110
{i18n.translate('helpText.hasInvalidFirstCharacter', {
111-
letters: <code className={Classes.CODE}>a…z</code>,
112-
underscore: <code className={Classes.CODE}>_</code>,
111+
letters: <Code className={Classes.CODE}>a…z</Code>,
112+
underscore: <Code className={Classes.CODE}>_</Code>,
113113
})}
114114
</>
115115
);
116116
case FileNameValidationResult.HasInvalidCharacters:
117117
return (
118118
<>
119119
{i18n.translate('helpText.hasInvalidCharacters', {
120-
letters: <code className={Classes.CODE}>a…z</code>,
121-
numbers: <code className={Classes.CODE}>0…9</code>,
122-
dash: <code className={Classes.CODE}>-</code>,
123-
underscore: <code className={Classes.CODE}>_</code>,
120+
letters: <Code className={Classes.CODE}>a…z</Code>,
121+
numbers: <Code className={Classes.CODE}>0…9</Code>,
122+
dash: <Code className={Classes.CODE}>-</Code>,
123+
underscore: <Code className={Classes.CODE}>_</Code>,
124124
})}{' '}
125125
<FixItButton onPress={handleHasInvalidCharacters} />
126126
</>

src/firmware/actions.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -395,24 +395,3 @@ export const firmwareDidInstallPybricks = createAction(() => ({
395395
export const firmwareDidFailToInstallPybricks = createAction(() => ({
396396
type: 'firmware.action.didFailToInstallPybricks',
397397
}));
398-
399-
/**
400-
* Action that triggers the restore LEGO firmware saga.
401-
*/
402-
export const firmwareRestoreLego = createAction(() => ({
403-
type: 'firmware.action.restoreLego',
404-
}));
405-
406-
/**
407-
* Action that indicates {@link firmwareRestoreLego} succeeded.
408-
*/
409-
export const firmwareDidRestoreLego = createAction(() => ({
410-
type: 'firmware.action.didRestoreLego',
411-
}));
412-
413-
/**
414-
* Action that indicates {@link firmwareRestoreLego} failed.
415-
*/
416-
export const firmwareDidFailToRestoreLego = createAction(() => ({
417-
type: 'firmware.action.didFailToRestoreLego',
418-
}));

src/firmware/installPybricksDialog/InstallPybricksDialog.tsx

Lines changed: 96 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Callout,
88
Checkbox,
99
Classes,
10+
Code,
1011
ControlGroup,
1112
DialogStep,
1213
FormGroup,
@@ -17,6 +18,7 @@ import {
1718
MenuItem,
1819
MultistepDialog,
1920
NonIdealState,
21+
Pre,
2022
Spinner,
2123
Switch,
2224
} from '@blueprintjs/core';
@@ -69,12 +71,12 @@ const SelectHubPanel: React.VoidFunctionComponent = () => {
6971
popoverClassName={Classes2.POPOVER2_CONTENT_SIZING}
7072
placement="right-end"
7173
content={
72-
<div>
73-
<h3>
74+
<div className={Classes.RUNNING_TEXT}>
75+
<h4>
7476
{i18n.translate(
7577
'selectHubPanel.notOnListButton.info.mindstorms.title',
7678
)}
77-
</h3>
79+
</h4>
7880
<ul>
7981
<li>
8082
{i18n.translate(
@@ -92,11 +94,11 @@ const SelectHubPanel: React.VoidFunctionComponent = () => {
9294
)}
9395
</li>
9496
</ul>
95-
<h3>
97+
<h4>
9698
{i18n.translate(
9799
'selectHubPanel.notOnListButton.info.poweredUp.title',
98100
)}
99-
</h3>
101+
</h4>
100102
<ul>
101103
<li>
102104
{i18n.translate(
@@ -154,28 +156,27 @@ const AcceptLicensePanel: React.VoidFunctionComponent<AcceptLicensePanelProps> =
154156

155157
return (
156158
<div className={dialogBody}>
157-
<div className="pb-firmware-installPybricksDialog-license">
158-
<div className="pb-firmware-installPybricksDialog-license-text">
159-
{data ? (
160-
<pre>{data.licenseText}</pre>
161-
) : (
162-
<NonIdealState
163-
icon={error ? 'error' : <Spinner />}
164-
description={
165-
error
166-
? i18n.translate('licensePanel.licenseText.error')
167-
: undefined
168-
}
169-
/>
170-
)}
171-
</div>
172-
<Checkbox
173-
label={i18n.translate('licensePanel.acceptCheckbox.label')}
174-
checked={licenseAccepted}
175-
onChange={(e) => onLicenseAcceptedChanged(e.currentTarget.checked)}
176-
disabled={!data}
177-
/>
159+
<div className="pb-firmware-installPybricksDialog-license-text">
160+
{data ? (
161+
<Pre>{data.licenseText}</Pre>
162+
) : (
163+
<NonIdealState
164+
icon={error ? 'error' : <Spinner />}
165+
description={
166+
error
167+
? i18n.translate('licensePanel.licenseText.error')
168+
: undefined
169+
}
170+
/>
171+
)}
178172
</div>
173+
<Checkbox
174+
className="pb-firmware-installPybricksDialog-license-checkbox"
175+
label={i18n.translate('licensePanel.acceptCheckbox.label')}
176+
checked={licenseAccepted}
177+
onChange={(e) => onLicenseAcceptedChanged(e.currentTarget.checked)}
178+
disabled={!data}
179+
/>
179180
</div>
180181
);
181182
};
@@ -248,7 +249,7 @@ const ConfigureOptionsPanel: React.VoidFunctionComponent<SelectOptionsPanelProps
248249
<Switch
249250
labelElement={i18n.translate(
250251
'optionsPanel.customMain.include.label',
251-
{ main: <code>main.py</code> },
252+
{ main: <Code>main.py</Code> },
252253
)}
253254
checked={includeProgram}
254255
onChange={(e) =>
@@ -349,82 +350,84 @@ const BootloaderModePanel: React.VoidFunctionComponent<BootloaderModePanelProps>
349350
return (
350351
<div className={dialogBody}>
351352
{hubHasUSB(hubType) && isLinux() && (
352-
<p>
353-
<Callout intent={Intent.WARNING} icon="warning-sign">
354-
{i18n.translate('bootloaderPanel.warning.linux')}{' '}
355-
<a
356-
href={pybricksUsbLinuxUdevRulesUrl}
357-
target="_blank"
358-
rel="noreferrer"
359-
>
360-
{i18n.translate('bootloaderPanel.warning.learnMore')}
361-
</a>
362-
<ExternalLinkIcon />
363-
</Callout>
364-
</p>
353+
<Callout intent={Intent.WARNING} icon="warning-sign">
354+
{i18n.translate('bootloaderPanel.warning.linux')}{' '}
355+
<a
356+
href={pybricksUsbLinuxUdevRulesUrl}
357+
target="_blank"
358+
rel="noreferrer"
359+
>
360+
{i18n.translate('bootloaderPanel.warning.learnMore')}
361+
</a>
362+
<ExternalLinkIcon />
363+
</Callout>
365364
)}
366365
{hubHasUSB(hubType) && isWindows() && (
367-
<p>
368-
<Callout intent={Intent.WARNING} icon="warning-sign">
369-
{i18n.translate('bootloaderPanel.warning.windows')}{' '}
370-
<a
371-
href={pybricksUsbDfuWindowsDriverInstallUrl}
372-
target="_blank"
373-
rel="noreferrer"
374-
>
375-
{i18n.translate('bootloaderPanel.warning.learnMore')}
376-
</a>
377-
<ExternalLinkIcon />
378-
</Callout>
379-
</p>
366+
<Callout intent={Intent.WARNING} icon="warning-sign">
367+
{i18n.translate('bootloaderPanel.warning.windows')}{' '}
368+
<a
369+
href={pybricksUsbDfuWindowsDriverInstallUrl}
370+
target="_blank"
371+
rel="noreferrer"
372+
>
373+
{i18n.translate('bootloaderPanel.warning.learnMore')}
374+
</a>
375+
<ExternalLinkIcon />
376+
</Callout>
380377
)}
381378

382-
<p>{i18n.translate('bootloaderPanel.instruction1')}</p>
383-
<ol>
384-
{hubHasUSB(hubType) && (
385-
<li>{i18n.translate('bootloaderPanel.step.disconnectUsb')}</li>
386-
)}
387-
388-
<li>{i18n.translate('bootloaderPanel.step.powerOff')}</li>
379+
<div className={Classes.RUNNING_TEXT}>
380+
<p>{i18n.translate('bootloaderPanel.instruction1')}</p>
381+
<ol>
382+
{hubHasUSB(hubType) && (
383+
<li>{i18n.translate('bootloaderPanel.step.disconnectUsb')}</li>
384+
)}
389385

390-
{/* City hub has power issues and requires disconnecting motors/sensors */}
391-
{hubType === Hub.City && (
392-
<li>{i18n.translate('bootloaderPanel.step.disconnectIo')}</li>
393-
)}
386+
<li>{i18n.translate('bootloaderPanel.step.powerOff')}</li>
394387

395-
<li>{i18n.translate('bootloaderPanel.step.holdButton', { button })}</li>
388+
{/* City hub has power issues and requires disconnecting motors/sensors */}
389+
{hubType === Hub.City && (
390+
<li>{i18n.translate('bootloaderPanel.step.disconnectIo')}</li>
391+
)}
396392

397-
{hubHasUSB(hubType) && (
398-
<li>{i18n.translate('bootloaderPanel.step.connectUsb')}</li>
399-
)}
393+
<li>
394+
{i18n.translate('bootloaderPanel.step.holdButton', { button })}
395+
</li>
400396

401-
<li>
402-
{i18n.translate('bootloaderPanel.step.waitForLight', {
403-
button,
404-
light,
405-
lightPattern,
406-
})}
407-
</li>
397+
{hubHasUSB(hubType) && (
398+
<li>{i18n.translate('bootloaderPanel.step.connectUsb')}</li>
399+
)}
408400

409-
<li>
410-
{i18n.translate(
411-
/* hubs with USB will keep the power on, but other hubs won't */
412-
hubHasUSB(hubType)
413-
? 'bootloaderPanel.step.releaseButton'
414-
: 'bootloaderPanel.step.keepHolding',
415-
{
401+
<li>
402+
{i18n.translate('bootloaderPanel.step.waitForLight', {
416403
button,
417-
},
418-
)}
419-
</li>
420-
</ol>
421-
<p>
422-
{i18n.translate('bootloaderPanel.instruction2', {
423-
flashFirmware: (
424-
<strong>{i18n.translate('flashFirmwareButton.label')}</strong>
425-
),
426-
})}
427-
</p>
404+
light,
405+
lightPattern,
406+
})}
407+
</li>
408+
409+
<li>
410+
{i18n.translate(
411+
/* hubs with USB will keep the power on, but other hubs won't */
412+
hubHasUSB(hubType)
413+
? 'bootloaderPanel.step.releaseButton'
414+
: 'bootloaderPanel.step.keepHolding',
415+
{
416+
button,
417+
},
418+
)}
419+
</li>
420+
</ol>
421+
<p>
422+
{i18n.translate('bootloaderPanel.instruction2', {
423+
flashFirmware: (
424+
<strong>
425+
{i18n.translate('flashFirmwareButton.label')}
426+
</strong>
427+
),
428+
})}
429+
</p>
430+
</div>
428431
</div>
429432
);
430433
};

0 commit comments

Comments
 (0)