fix: expand boards if available on detected port

moved the board inference logic from UI to  model

Closes #2175

Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
Akos Kitta 2023-08-19 12:36:43 +02:00 committed by Akos Kitta
parent 5a76be306a
commit db01efead3
5 changed files with 166 additions and 52 deletions

View File

@ -1,10 +1,7 @@
import { nls } from '@theia/core/lib/common/nls'; import { nls } from '@theia/core/lib/common/nls';
import React from '@theia/core/shared/react'; import React from '@theia/core/shared/react';
import Tippy from '@tippyjs/react'; import Tippy from '@tippyjs/react';
import { import type { BoardList } from '../../../common/protocol/board-list';
BoardList,
isInferredBoardListItem,
} from '../../../common/protocol/board-list';
import { import {
boardIdentifierEquals, boardIdentifierEquals,
portIdentifierEquals, portIdentifierEquals,
@ -50,9 +47,7 @@ export const CertificateUploaderComponent = ({
if (!selectedItem) { if (!selectedItem) {
return; return;
} }
const board = isInferredBoardListItem(selectedItem) const board = selectedItem.board;
? selectedItem.inferredBoard
: selectedItem.board;
if (!board.fqbn) { if (!board.fqbn) {
return; return;
} }
@ -76,13 +71,9 @@ export const CertificateUploaderComponent = ({
if (!item) { if (!item) {
return; return;
} }
const board = isInferredBoardListItem(item) const board = item.board;
? item.inferredBoard
: item.board;
const selectedBoard = isInferredBoardListItem(selectedItem)
? selectedItem.inferredBoard
: selectedItem?.board;
const port = item.port; const port = item.port;
const selectedBoard = selectedItem?.board;
const selectedPort = selectedItem?.port; const selectedPort = selectedItem?.port;
if ( if (

View File

@ -1,14 +1,12 @@
import { nls } from '@theia/core/lib/common'; import { nls } from '@theia/core/lib/common';
import React from '@theia/core/shared/react'; import React from '@theia/core/shared/react';
import { import type {
BoardList, BoardList,
BoardListItemWithBoard, BoardListItemWithBoard,
InferredBoardListItem,
isInferredBoardListItem,
} from '../../../common/protocol/board-list'; } from '../../../common/protocol/board-list';
import { ArduinoSelect } from '../../widgets/arduino-select'; import { ArduinoSelect } from '../../widgets/arduino-select';
export type BoardOptionValue = BoardListItemWithBoard | InferredBoardListItem; export type BoardOptionValue = BoardListItemWithBoard;
type BoardOption = { value: BoardOptionValue | undefined; label: string }; type BoardOption = { value: BoardOptionValue | undefined; label: string };
export const SelectBoardComponent = ({ export const SelectBoardComponent = ({
@ -46,9 +44,7 @@ export const SelectBoardComponent = ({
'Select a board...' 'Select a board...'
); );
const updatableBoards = boardList.boards.filter((item) => { const updatableBoards = boardList.boards.filter((item) => {
const fqbn = ( const fqbn = item.board.fqbn;
isInferredBoardListItem(item) ? item.inferredBoard : item.board
).fqbn;
return fqbn && updatableFqbns.includes(fqbn); return fqbn && updatableFqbns.includes(fqbn);
}); });
let selBoard = -1; let selBoard = -1;
@ -57,15 +53,12 @@ export const SelectBoardComponent = ({
if (selectedItem === item) { if (selectedItem === item) {
selBoard = i; selBoard = i;
} }
const board = isInferredBoardListItem(item)
? item.inferredBoard
: item.board;
return { return {
label: nls.localize( label: nls.localize(
'arduino/certificate/boardAtPort', 'arduino/certificate/boardAtPort',
'{0} at {1}', '{0} at {1}',
board.name, item.board.name,
item.port?.address ?? '' item.port.address ?? ''
), ),
value: item, value: item,
}; };
@ -100,10 +93,7 @@ export const SelectBoardComponent = ({
label: nls.localize( label: nls.localize(
'arduino/certificate/boardAtPort', 'arduino/certificate/boardAtPort',
'{0} at {1}', '{0} at {1}',
(isInferredBoardListItem(selectedItem) selectedItem.board.name,
? selectedItem.inferredBoard
: selectedItem.board
).name,
selectedItem.port.address ?? '' selectedItem.port.address ?? ''
), ),
}) || }) ||

View File

@ -9,10 +9,9 @@ import {
ArduinoFirmwareUploader, ArduinoFirmwareUploader,
FirmwareInfo, FirmwareInfo,
} from '../../../common/protocol/arduino-firmware-uploader'; } from '../../../common/protocol/arduino-firmware-uploader';
import { import type {
BoardList, BoardList,
BoardListItemWithBoard, BoardListItemWithBoard,
isInferredBoardListItem,
} from '../../../common/protocol/board-list'; } from '../../../common/protocol/board-list';
import { ArduinoSelect } from '../../widgets/arduino-select'; import { ArduinoSelect } from '../../widgets/arduino-select';
import { SelectBoardComponent } from '../certificate-uploader/select-board-components'; import { SelectBoardComponent } from '../certificate-uploader/select-board-components';
@ -63,9 +62,7 @@ export const FirmwareUploaderComponent = ({
} }
// fetch the firmwares for the selected board // fetch the firmwares for the selected board
const board = isInferredBoardListItem(selectedItem) const board = selectedItem.board;
? selectedItem.inferredBoard
: selectedItem.board;
const firmwaresForFqbn = await firmwareUploader.availableFirmwares( const firmwaresForFqbn = await firmwareUploader.availableFirmwares(
board.fqbn || '' board.fqbn || ''
); );
@ -89,11 +86,14 @@ export const FirmwareUploaderComponent = ({
(firmware) => firmware.firmware_version === selectedFirmware?.value (firmware) => firmware.firmware_version === selectedFirmware?.value
); );
const selectedBoard = selectedItem?.board;
const selectedPort = selectedItem?.port;
try { try {
const installStatus = const installStatus =
!!firmwareToFlash && firmwareToFlash &&
!!selectedItem?.board && selectedBoard &&
(await flashFirmware(firmwareToFlash, selectedItem?.port)); selectedPort &&
(await flashFirmware(firmwareToFlash, selectedPort));
setInstallFeedback((installStatus && 'ok') || 'fail'); setInstallFeedback((installStatus && 'ok') || 'fail');
} catch { } catch {
@ -106,13 +106,9 @@ export const FirmwareUploaderComponent = ({
if (!item) { if (!item) {
return; return;
} }
const board = isInferredBoardListItem(item) const board = item.board;
? item.inferredBoard
: item.board;
const selectedBoard = isInferredBoardListItem(selectedItem)
? selectedItem.inferredBoard
: selectedItem?.board;
const port = item.port; const port = item.port;
const selectedBoard = selectedItem?.board;
const selectedPort = selectedItem?.port; const selectedPort = selectedItem?.port;
if ( if (

View File

@ -362,9 +362,12 @@ export interface BoardList {
readonly selectedIndex: number; readonly selectedIndex: number;
/** /**
* Contains all boards recognized from the detected port, and an optional unrecognized one that is derived from the detected port and the `initParam#selectedBoard`. * Contains all the following board+port pairs:
* - one discovered board on a detected board (`1`),
* - manually selected or overridden board for a detected port (`1`),
* - multiple discovered boards on detected port (`1..*`)
*/ */
readonly boards: readonly (BoardListItemWithBoard | InferredBoardListItem)[]; readonly boards: readonly BoardListItemWithBoard[];
/** /**
* If `predicate` is not defined, no ports are filtered. * If `predicate` is not defined, no ports are filtered.
@ -511,17 +514,27 @@ function collectPorts(
function collectBoards( function collectBoards(
items: readonly BoardListItem[] items: readonly BoardListItem[]
): readonly (BoardListItemWithBoard | InferredBoardListItem)[] { ): readonly BoardListItemWithBoard[] {
const boards: (BoardListItemWithBoard | InferredBoardListItem)[] = []; const result: BoardListItemWithBoard[] = [];
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const boards: BoardListItemWithBoard[] = [];
const item = items[i]; const item = items[i];
if (isInferredBoardListItem(item)) { const { port } = item;
boards.push(item); const board = getInferredBoardOrBoard(item);
} else if (item.board?.fqbn) { if (board) {
boards.push(<Required<BoardListItem>>item); boards.push({ board, port });
} }
if (isMultiBoardsBoardListItem(item)) {
for (const otherBoard of item.boards) {
if (!boardIdentifierEquals(board, otherBoard)) {
boards.push({ board: otherBoard, port });
}
}
}
boards.sort(boardListItemComparator);
result.push(...boards);
} }
return boards; return result;
} }
function findSelectedIndex( function findSelectedIndex(

View File

@ -328,6 +328,130 @@ describe('board-list', () => {
expect(items[0].labels.boardLabel).to.be.equal(Unknown); expect(items[0].labels.boardLabel).to.be.equal(Unknown);
}); });
describe('boards', () => {
it('should include discovered boards on detected ports', () => {
const { boards } = createBoardList({
...detectedPort(unoSerialPort, uno),
...detectedPort(mkr1000SerialPort, mkr1000),
...detectedPort(undiscoveredSerialPort),
});
expect(boards).to.deep.equal([
{
port: mkr1000SerialPort,
board: mkr1000,
},
{
port: unoSerialPort,
board: uno,
},
]);
});
it('should include manually selected boards on detected ports', () => {
const { boards } = createBoardList({
...detectedPort(unoSerialPort, uno),
...detectedPort(undiscoveredSerialPort, uno),
...detectedPort(undiscoveredUsbToUARTSerialPort),
});
expect(boards).to.deep.equal([
{
port: unoSerialPort,
board: uno,
},
{
port: undiscoveredSerialPort,
board: uno,
},
]);
});
it('should include manually overridden boards on detected ports', () => {
const { boards } = createBoardList(
{
...detectedPort(unoSerialPort, uno),
...detectedPort(mkr1000SerialPort, mkr1000),
},
emptyBoardsConfig(),
{
...history(unoSerialPort, mkr1000),
}
);
expect(boards).to.deep.equal([
{
port: mkr1000SerialPort,
board: mkr1000,
},
{
port: unoSerialPort,
board: mkr1000,
},
]);
});
it('should include all boards discovered on a port', () => {
const { boards } = createBoardList({
...detectedPort(
nanoEsp32SerialPort,
arduinoNanoEsp32,
esp32NanoEsp32
),
...detectedPort(
nanoEsp32DetectsMultipleEsp32BoardsSerialPort,
esp32S3DevModule,
esp32S3Box
),
});
expect(boards).to.deep.equal([
{
port: nanoEsp32SerialPort,
board: arduinoNanoEsp32,
},
{
port: nanoEsp32SerialPort,
board: esp32NanoEsp32,
},
{
port: nanoEsp32DetectsMultipleEsp32BoardsSerialPort,
board: esp32S3Box,
},
{
port: nanoEsp32DetectsMultipleEsp32BoardsSerialPort,
board: esp32S3DevModule,
},
]);
});
it('should include all boards discovered on a port (handle manual select)', () => {
const { boards } = createBoardList(
{
...detectedPort(
nanoEsp32SerialPort,
arduinoNanoEsp32,
esp32NanoEsp32
),
},
emptyBoardsConfig(),
{
...history(nanoEsp32SerialPort, esp32S3DevModule),
}
);
expect(boards).to.deep.equal([
{
port: nanoEsp32SerialPort,
board: arduinoNanoEsp32,
},
{
port: nanoEsp32SerialPort,
board: esp32NanoEsp32,
},
{
port: nanoEsp32SerialPort,
board: esp32S3DevModule,
},
]);
});
});
describe('defaultAction', () => { describe('defaultAction', () => {
it("'select' should be the default action for identifier boards", () => { it("'select' should be the default action for identifier boards", () => {
const { items } = createBoardList({ const { items } = createBoardList({