[ATL-1533] Firmware&Certificate Uploader (#469)

Co-authored-by: Alberto Iannaccone <a.iannaccone@arduino.cc>
This commit is contained in:
Francesco Stasi
2021-08-25 10:36:51 +02:00
committed by GitHub
parent 6233e1fa98
commit 302fb7b6af
37 changed files with 20276 additions and 19 deletions

View File

@@ -0,0 +1,204 @@
import * as React from 'react';
import {
ArduinoFirmwareUploader,
FirmwareInfo,
} from '../../../common/protocol/arduino-firmware-uploader';
import { AvailableBoard } from '../../boards/boards-service-provider';
import { ArduinoSelect } from '../../widgets/arduino-select';
import { SelectBoardComponent } from '../certificate-uploader/select-board-components';
type FirmwareOption = { value: string; label: string };
export const FirmwareUploaderComponent = ({
availableBoards,
firmwareUploader,
updatableFqbns,
flashFirmware,
isOpen,
}: {
availableBoards: AvailableBoard[];
firmwareUploader: ArduinoFirmwareUploader;
updatableFqbns: string[];
flashFirmware: (firmware: FirmwareInfo, port: string) => Promise<any>;
isOpen: any;
}): React.ReactElement => {
// boolean states for buttons
const [firmwaresFetching, setFirmwaresFetching] = React.useState(false);
const [installFeedback, setInstallFeedback] = React.useState<
'ok' | 'fail' | 'installing' | null
>(null);
const [selectedBoard, setSelectedBoard] =
React.useState<AvailableBoard | null>(null);
const [availableFirmwares, setAvailableFirmwares] = React.useState<
FirmwareInfo[]
>([]);
React.useEffect(() => {
setAvailableFirmwares([]);
}, [isOpen]);
const [selectedFirmware, setSelectedFirmware] =
React.useState<FirmwareOption | null>(null);
const [firmwareOptions, setFirmwareOptions] = React.useState<
FirmwareOption[]
>([]);
const fetchFirmwares = React.useCallback(async () => {
setInstallFeedback(null);
setFirmwaresFetching(true);
if (!selectedBoard) {
return;
}
// fetch the firmwares for the selected board
const firmwaresForFqbn = await firmwareUploader.availableFirmwares(
selectedBoard.fqbn || ''
);
setAvailableFirmwares(firmwaresForFqbn);
const firmwaresOpts = firmwaresForFqbn.map((f) => ({
label: f.firmware_version,
value: f.firmware_version,
}));
setFirmwareOptions(firmwaresOpts);
if (firmwaresForFqbn.length > 0) setSelectedFirmware(firmwaresOpts[0]);
setFirmwaresFetching(false);
}, [firmwareUploader, selectedBoard]);
const installFirmware = React.useCallback(async () => {
setInstallFeedback('installing');
const firmwareToFlash = availableFirmwares.find(
(firmware) => firmware.firmware_version === selectedFirmware?.value
);
try {
const installStatus =
!!firmwareToFlash &&
!!selectedBoard?.port &&
(await flashFirmware(firmwareToFlash, selectedBoard?.port.address));
setInstallFeedback((installStatus && 'ok') || 'fail');
} catch {
setInstallFeedback('fail');
}
}, [firmwareUploader, selectedBoard, selectedFirmware, availableFirmwares]);
const onBoardSelect = React.useCallback(
(board: AvailableBoard) => {
const newFqbn = (board && board.fqbn) || null;
const prevFqbn = (selectedBoard && selectedBoard.fqbn) || null;
if (newFqbn !== prevFqbn) {
setInstallFeedback(null);
setAvailableFirmwares([]);
setSelectedBoard(board);
}
},
[selectedBoard]
);
return (
<>
<div className="dialogSection">
<div className="dialogRow">
<label htmlFor="board-select">Select board</label>
</div>
<div className="dialogRow">
<div className="fl1">
<SelectBoardComponent
availableBoards={availableBoards}
updatableFqbns={updatableFqbns}
onBoardSelect={onBoardSelect}
selectedBoard={selectedBoard}
busy={installFeedback === 'installing'}
/>
</div>
<button
type="button"
className="theia-button secondary"
disabled={
selectedBoard === null ||
firmwaresFetching ||
installFeedback === 'installing'
}
onClick={fetchFirmwares}
>
Check Updates
</button>
</div>
</div>
{availableFirmwares.length > 0 && (
<>
<div className="dialogSection">
<div className="dialogRow">
<label htmlFor="firmware-select" className="fl1">
Select firmware version
</label>
<ArduinoSelect
id="firmware-select"
menuPosition="fixed"
isDisabled={
!selectedBoard ||
firmwaresFetching ||
installFeedback === 'installing'
}
options={firmwareOptions}
value={selectedFirmware}
tabSelectsValue={false}
onChange={(value) => {
if (value) {
setInstallFeedback(null);
setSelectedFirmware(value);
}
}}
/>
<button
type="button"
className="theia-button primary"
disabled={
selectedFirmware === null ||
firmwaresFetching ||
installFeedback === 'installing'
}
onClick={installFirmware}
>
Install
</button>
</div>
</div>
<div className="dialogSection">
{installFeedback === null && (
<div className="dialogRow warn">
<i className="fa fa-exclamation status-icon" />
Installation will overwrite the Sketch on the board.
</div>
)}
{installFeedback === 'installing' && (
<div className="dialogRow success">
<div className="spinner" />
Installing firmware.
</div>
)}
{installFeedback === 'ok' && (
<div className="dialogRow success">
<i className="fa fa-info status-icon" />
Firmware succesfully installed.
</div>
)}
{installFeedback === 'fail' && (
<div className="dialogRow warn">
<i className="fa fa-exclamation status-icon" />
Installation failed. Please try again.
</div>
)}
</div>
</>
)}
</>
);
};