firmware/restoreOfficialDialog: add new dialog

This commit is contained in:
David Lechner
2022-07-27 18:17:20 -05:00
parent bbd278b51e
commit 90b459d5db
14 changed files with 152 additions and 28 deletions
+5
View File
@@ -44,6 +44,11 @@ export const pybricksUsbDfuWindowsDriverInstallUrl =
export const pybricksUsbLinuxUdevRulesUrl =
'https://github.com/pybricks/support/discussions/688#discussioncomment-3239099';
export const pybricksBleFirmwareRestoreVideoUrl =
'https://pybricks.com/install/technic-boost-city/#restoring-the-original-firmware';
export const pybricksDfuRestoreUrl = 'https://dfu.pybricks.com';
/** Pybricks copyright statement. */
export const pybricksCopyright = 'Copyright (c) 2020-2022 The Pybricks Authors';
-21
View File
@@ -395,24 +395,3 @@ export const firmwareDidInstallPybricks = createAction(() => ({
export const firmwareDidFailToInstallPybricks = createAction(() => ({
type: 'firmware.action.didFailToInstallPybricks',
}));
/**
* Action that triggers the restore LEGO firmware saga.
*/
export const firmwareRestoreLego = createAction(() => ({
type: 'firmware.action.restoreLego',
}));
/**
* Action that indicates {@link firmwareRestoreLego} succeeded.
*/
export const firmwareDidRestoreLego = createAction(() => ({
type: 'firmware.action.didRestoreLego',
}));
/**
* Action that indicates {@link firmwareRestoreLego} failed.
*/
export const firmwareDidFailToRestoreLego = createAction(() => ({
type: 'firmware.action.didFailToRestoreLego',
}));
+3
View File
@@ -21,6 +21,9 @@ test('initial state', () => {
"isOpen": false,
},
"progress": null,
"restoreOfficialDialog": Object {
"isOpen": false,
},
}
`);
});
+7 -1
View File
@@ -4,6 +4,7 @@
import { Reducer, combineReducers } from 'redux';
import { didFailToFinish, didFinish, didProgress, didStart } from './actions';
import installPybricksDialog from './installPybricksDialog/reducers';
import restoreOfficialDialog from './restoreOfficialDialog/reducers';
const flashing: Reducer<boolean> = (state = false, action) => {
if (didStart.matches(action)) {
@@ -29,4 +30,9 @@ const progress: Reducer<number | null> = (state = null, action) => {
return state;
};
export default combineReducers({ installPybricksDialog, flashing, progress });
export default combineReducers({
installPybricksDialog,
restoreOfficialDialog,
flashing,
progress,
});
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { Classes, Dialog } from '@blueprintjs/core';
import classNames from 'classnames';
import React from 'react';
import { useDispatch } from 'react-redux';
import {
pybricksBleFirmwareRestoreVideoUrl,
pybricksDfuRestoreUrl,
} from '../../app/constants';
import { useSelector } from '../../reducers';
import ExternalLinkIcon from '../../utils/ExternalLinkIcon';
import { firmwareRestoreOfficialDialogHide } from './actions';
import { useI18n } from './i18n';
const RestoreOfficialDialog: React.VoidFunctionComponent = () => {
const { isOpen } = useSelector((s) => s.firmware.restoreOfficialDialog);
const dispatch = useDispatch();
const i18n = useI18n();
return (
<Dialog
isOpen={isOpen}
title={i18n.translate('title')}
onClose={() => dispatch(firmwareRestoreOfficialDialogHide())}
>
<div className={classNames(Classes.DIALOG_BODY, Classes.RUNNING_TEXT)}>
<h4>{i18n.translate('poweredUpHubs.title')}</h4>
<p>{i18n.translate('poweredUpHubs.message')}</p>
<p>
<a
href={pybricksBleFirmwareRestoreVideoUrl}
target="_blank"
rel="noreferrer"
>
{i18n.translate('poweredUpHubs.action')}
</a>
<ExternalLinkIcon />
</p>
<h4>{i18n.translate('spikeHubs.title')}</h4>
<p>{i18n.translate('spikeHubs.message')}</p>
<p>
<a href={pybricksDfuRestoreUrl} target="_blank" rel="noreferrer">
{i18n.translate('spikeHubs.action')}
</a>
<ExternalLinkIcon />
</p>
</div>
</Dialog>
);
};
export default RestoreOfficialDialog;
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
export {
show as firmwareRestoreOfficialDialogShow,
hide as firmwareRestoreOfficialDialogHide,
} from './redux';
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { useI18n as useShopifyI18n } from '@shopify/react-i18n';
import type { TypedI18n } from '../../i18n';
import type translations from './translations/en.json';
export function useI18n(): TypedI18n<typeof translations> {
// istanbul ignore next: babel-loader rewrites this line
const [i18n] = useShopifyI18n();
return i18n;
}
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import reducer from './redux';
export default reducer;
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { createSlice } from '@reduxjs/toolkit';
type State = {
isOpen: boolean;
};
const initialState: State = {
isOpen: false,
};
const slice = createSlice({
name: 'restoreOfficialDialog',
initialState,
reducers: {
show(state) {
state.isOpen = true;
},
hide(state) {
state.isOpen = false;
},
},
});
export const { show, hide } = slice.actions;
export default slice.reducer;
@@ -0,0 +1,13 @@
{
"title": "Restore official LEGO® Firmware",
"poweredUpHubs": {
"title": "Powered Up Hubs",
"message": "The official firmware can be restored on Powered Up hubs by putting the hub in bootloader mode and connecting to the hub using one of the official LEGO apps.",
"action": "Watch video."
},
"spikeHubs": {
"title": "SPIKE/MINDSTORMS Hubs",
"message": "The official LEGO software for these hubs does not have a way to restore the firmware on these hubs. So, we have provided a special site to do this for you.",
"action": "Pybricks DFU restore tool."
}
}
+8 -2
View File
@@ -136,8 +136,14 @@ a.#{bp.$ns}-button {
min-width: math.div(bp.$pt-grid-size, 2);
}
.#{bp.$ns}-running-text h4:first-child {
margin-top: 0;
.#{bp.$ns}-running-text {
*:first-child {
margin-top: 0;
}
*:last-child {
margin-bottom: 0;
}
}
// make scrollbars fit our style
+3 -2
View File
@@ -4,7 +4,8 @@
import { cleanup, getByLabelText, waitFor } from '@testing-library/react';
import React from 'react';
import { testRender } from '../../test';
import { firmwareInstallPybricks, firmwareRestoreLego } from '../firmware/actions';
import { firmwareInstallPybricks } from '../firmware/actions';
import { firmwareRestoreOfficialDialogShow } from '../firmware/restoreOfficialDialog/actions';
import Settings from './Settings';
afterEach(() => {
@@ -62,7 +63,7 @@ describe('firmware', () => {
});
await user.click(button);
expect(dispatch).toHaveBeenCalledWith(firmwareRestoreLego());
expect(dispatch).toHaveBeenCalledWith(firmwareRestoreOfficialDialogShow());
});
});
+5 -2
View File
@@ -21,8 +21,10 @@ import {
} from '../app/constants';
import { Button } from '../components/Button';
import HelpButton from '../components/HelpButton';
import { firmwareInstallPybricks, firmwareRestoreLego } from '../firmware/actions';
import { firmwareInstallPybricks } from '../firmware/actions';
import { InstallPybricksDialog } from '../firmware/installPybricksDialog/InstallPybricksDialog';
import RestoreOfficialDialog from '../firmware/restoreOfficialDialog/RestoreOfficialDialog';
import { firmwareRestoreOfficialDialogShow } from '../firmware/restoreOfficialDialog/actions';
import { pseudolocalize } from '../i18n';
import { useSelector } from '../reducers';
import ExternalLinkIcon from '../utils/ExternalLinkIcon';
@@ -108,8 +110,9 @@ const Settings: React.VoidFunctionComponent = () => {
minimal={true}
icon="download"
label={i18n.translate('firmware.flashLegoButton.label')}
onPress={() => dispatch(firmwareRestoreLego())}
onPress={() => dispatch(firmwareRestoreOfficialDialogShow())}
/>
<RestoreOfficialDialog />
</FormGroup>
<FormGroup label={i18n.translate('help.title')}>
<ButtonGroup minimal={true} vertical={true} alignText="left">