firmware: add select picker for selecting custom main.py

This commit is contained in:
David Lechner
2022-07-20 14:25:40 -05:00
parent 85deb42f76
commit af8a31d50c
10 changed files with 150 additions and 41 deletions
@@ -13,12 +13,14 @@ import {
Icon,
InputGroup,
Intent,
MenuItem,
MultistepDialog,
NonIdealState,
Spinner,
Switch,
} from '@blueprintjs/core';
import { Classes as Classes2, Popover2 } from '@blueprintjs/popover2';
import { Select2 } from '@blueprintjs/select';
import classNames from 'classnames';
import React, { useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
@@ -31,6 +33,8 @@ import {
hubHasUSB,
} from '../../components/hubPicker';
import { HubPicker } from '../../components/hubPicker/HubPicker';
import { FileMetadata } from '../../fileStorage';
import { useFileStorageMetadata } from '../../fileStorage/hooks';
import { useSelector } from '../../reducers';
import {
firmwareInstallPybricksDialogAccept,
@@ -176,19 +180,24 @@ type SelectOptionsPanelProps = {
hubType: Hub;
hubName: string;
includeProgram: boolean;
selectedIncludeFile: FileMetadata | undefined;
onChangeHubName(hubName: string): void;
onChangeIncludeProgram(includeProgram: boolean): void;
onChangeSelectedIncludeFile(selectedIncludeFile: FileMetadata | undefined): void;
};
const ConfigureOptionsPanel: React.VoidFunctionComponent<SelectOptionsPanelProps> = ({
hubType,
hubName,
includeProgram,
selectedIncludeFile,
onChangeHubName,
onChangeIncludeProgram,
onChangeSelectedIncludeFile,
}) => {
const i18n = useI18n();
const isHubNameValid = validateHubName(hubName);
const files = useFileStorageMetadata();
return (
<div className={dialogBody}>
@@ -198,7 +207,6 @@ const ConfigureOptionsPanel: React.VoidFunctionComponent<SelectOptionsPanelProps
>
<ControlGroup>
<InputGroup
id="hub-name-input"
value={hubName}
onChange={(e) => onChangeHubName(e.currentTarget.value)}
onMouseOver={(e) => e.preventDefault()}
@@ -234,8 +242,9 @@ const ConfigureOptionsPanel: React.VoidFunctionComponent<SelectOptionsPanelProps
)) || (
<ControlGroup>
<Switch
label={i18n.translate(
I18nId.OptionsPanelCustomMainIncludeCurrentProgramLabel,
labelElement={i18n.translate(
I18nId.OptionsPanelCustomMainIncludeLabel,
{ main: <code>main.py</code> },
)}
checked={includeProgram}
onChange={(e) =>
@@ -244,12 +253,54 @@ const ConfigureOptionsPanel: React.VoidFunctionComponent<SelectOptionsPanelProps
)
}
/>
<Select2
items={files || []}
itemRenderer={(
item,
{ handleClick, handleFocus, modifiers },
) => (
<MenuItem
roleStructure="listoption"
active={modifiers.active}
disabled={modifiers.disabled}
text={item.path}
key={item.uuid}
onClick={handleClick}
onFocus={handleFocus}
/>
)}
noResults={
<MenuItem
roleStructure="listoption"
disabled={true}
text={i18n.translate(
I18nId.OptionsPanelCustomMainIncludeNoFiles,
)}
/>
}
filterable={false}
popoverProps={{ minimal: true }}
disabled={!includeProgram}
onItemSelect={onChangeSelectedIncludeFile}
>
<Button
icon="double-caret-vertical"
text={
selectedIncludeFile?.path ??
i18n.translate(
I18nId.OptionsPanelCustomMainIncludeNoSelection,
)
}
disabled={!includeProgram}
/>
</Select2>
<HelpButton
helpForLabel={i18n.translate(
I18nId.OptionsPanelCustomMainIncludeCurrentProgramLabel,
I18nId.OptionsPanelCustomMainIncludeLabel,
{ main: 'main.py' },
)}
content={i18n.translate(
I18nId.OptionsPanelCustomMainIncludeCurrentProgramHelp,
I18nId.OptionsPanelCustomMainIncludeHelp,
{
appName,
},
@@ -355,6 +406,7 @@ export const InstallPybricksDialog: React.VoidFunctionComponent = () => {
const [hubType, setHubType] = useState(defaultHubType);
const [hubName, setHubName] = useState('');
const [includeProgram, setIncludeProgram] = useState(false);
const [selectedIncludeFile, setSelectedIncludeFile] = useState<FileMetadata>();
const [licenseAccepted, setLicenseAccepted] = useState(false);
const { data } = useFirmware(hubType);
const i18n = useI18n();
@@ -370,7 +422,7 @@ export const InstallPybricksDialog: React.VoidFunctionComponent = () => {
dispatch(
firmwareInstallPybricksDialogAccept(
data?.firmwareZip ?? new ArrayBuffer(0),
undefined,
selectedIncludeFile?.path,
hubName,
),
),
@@ -406,8 +458,10 @@ export const InstallPybricksDialog: React.VoidFunctionComponent = () => {
hubType={hubType}
hubName={hubName}
includeProgram={includeProgram}
selectedIncludeFile={selectedIncludeFile}
onChangeHubName={setHubName}
onChangeIncludeProgram={setIncludeProgram}
onChangeSelectedIncludeFile={setSelectedIncludeFile}
/>
}
backButtonProps={{ text: i18n.translate(I18nId.BackButtonLabel) }}
@@ -8,7 +8,12 @@ export const firmwareInstallPybricksDialogShow = createAction(() => ({
type: 'firmware.installPybricksDialog.action.show',
}));
/** Actions that indicates the user accepted the install Pybricks firmware dialog. */
/**
* Action that indicates the user accepted the install Pybricks firmware dialog.
* @param firmwareZip The firmware.zip raw data.
* @param customProgram Optional path of custom program to include when flashing firmware.
* @param hubName The hub name to use when flashing firmware.
*/
export const firmwareInstallPybricksDialogAccept = createAction(
(firmwareZip: ArrayBuffer, customProgram: string | undefined, hubName: string) => ({
type: 'firmware.installPybricksDialog.action.accept',
+4 -2
View File
@@ -36,8 +36,10 @@ export enum I18nId {
OptionsPanelCustomMainLabel = 'optionsPanel.customMain.label',
OptionsPanelCustomMainLabelInfo = 'optionsPanel.customMain.labelInfo',
OptionsPanelCustomMainNotApplicableMessage = 'optionsPanel.customMain.notApplicable.message',
OptionsPanelCustomMainIncludeCurrentProgramLabel = 'optionsPanel.customMain.includeCurrentProgram.label',
OptionsPanelCustomMainIncludeCurrentProgramHelp = 'optionsPanel.customMain.includeCurrentProgram.help',
OptionsPanelCustomMainIncludeLabel = 'optionsPanel.customMain.include.label',
OptionsPanelCustomMainIncludeNoSelection = 'optionsPanel.customMain.include.noSelection',
OptionsPanelCustomMainIncludeNoFiles = 'optionsPanel.customMain.include.noFiles',
OptionsPanelCustomMainIncludeHelp = 'optionsPanel.customMain.include.help',
BootloaderPanelTitle = 'bootloaderPanel.title',
BootloaderPanelInstruction1 = 'bootloaderPanel.instruction1',
BootloaderPanelButtonBluetooth = 'bootloaderPanel.button.bluetooth',
@@ -40,13 +40,15 @@
"error": "The name is too long."
},
"customMain": {
"label": "Custom program",
"label": "Include custom program",
"labelInfo": "(optional)",
"notApplicable": {
"message": "This hub has external flash memory so including a custom program when flashing firmware is not needed."
},
"includeCurrentProgram": {
"label": "Include current program",
"include": {
"label": "Include selected program as {main}",
"noSelection": "(no selection)",
"noFiles": "(no files)",
"help": "Enable to include your program when flashing the firmware or disable to use the default program. Flashing your program along with the firmware will allow you to run your program without being connected to {appName}"
}
}