From a92bfccce85e8b9d8d51a9fafb348bff6fb0d9ab Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Tue, 25 Jul 2023 17:47:36 +0200 Subject: [PATCH] single-source port match logic --- .../boards/boards-config-component.tsx | 25 +++++++++++++------ .../browser/boards/boards-config-dialog.tsx | 16 ++++++++++-- .../src/common/protocol/board-list.ts | 12 ++++----- .../src/common/protocol/boards-service.ts | 19 ++++++++++++-- 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/arduino-ide-extension/src/browser/boards/boards-config-component.tsx b/arduino-ide-extension/src/browser/boards/boards-config-component.tsx index 8bc80197f..3a94e1712 100644 --- a/arduino-ide-extension/src/browser/boards/boards-config-component.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-config-component.tsx @@ -3,11 +3,13 @@ import { Event } from '@theia/core/lib/common/event'; import { FrontendApplicationState } from '@theia/core/lib/common/frontend-application-state'; import { nls } from '@theia/core/lib/common/nls'; import * as React from '@theia/core/shared/react'; -import { BoardList } from '../../common/protocol/board-list'; import { Board, BoardIdentifier, + BoardsConfig, BoardWithPackage, + DetectedPort, + findMatchingPortIndex, Port, PortIdentifier, } from '../../common/protocol/boards-service'; @@ -15,7 +17,10 @@ import { NotificationCenter } from '../notification-center'; namespace BoardsConfigComponent { export interface Props { - readonly boardList: BoardList; + /** + * This is not the real config, it's only living in the dialog. Users can change it without update and can cancel any modifications. + */ + readonly boardsConfig: BoardsConfig; readonly notificationCenter: NotificationCenter; readonly onFocusNodeSet: (element: HTMLElement | undefined) => void; readonly onFilteredTextDidChangeEvent: Event; @@ -25,6 +30,9 @@ namespace BoardsConfigComponent { readonly searchBoards: (query?: { query?: string; }) => Promise; + readonly ports: ( + predicate?: (port: DetectedPort) => boolean + ) => readonly DetectedPort[]; } export interface State { @@ -194,7 +202,7 @@ export class BoardsConfigComponent extends React.Component< } private renderBoards(): React.ReactNode { - const { boardList } = this.props; + const { boardsConfig } = this.props; const { searchResults, query } = this.state; // Board names are not unique per core https://github.com/arduino/arduino-pro-ide/issues/262#issuecomment-661019560 // It is tricky when the core is not yet installed, no FQBNs are available. @@ -202,7 +210,7 @@ export class BoardsConfigComponent extends React.Component< const toKey = ({ name, packageName, fqbn }: Board.Detailed) => !!fqbn ? `${name}-${packageName}-${fqbn}` : `${name}-${packageName}`; for (const board of Board.decorateBoards( - boardList.boardsConfig.selectedBoard, + boardsConfig.selectedBoard, searchResults )) { const key = toKey(board); @@ -255,9 +263,12 @@ export class BoardsConfigComponent extends React.Component< } private renderPorts(): React.ReactNode { - const { boardList } = this.props; const predicate = this.state.showAllPorts ? undefined : Port.isVisiblePort; - const detectedPorts = boardList.ports(predicate); + const detectedPorts = this.props.ports(predicate); + const matchingIndex = findMatchingPortIndex( + this.props.boardsConfig.selectedPort, + detectedPorts + ); return !detectedPorts.length ? (
{nls.localize('arduino/board/noPortsDiscovered', 'No ports discovered')} @@ -269,7 +280,7 @@ export class BoardsConfigComponent extends React.Component< key={`${Port.keyOf(detectedPort.port)}`} item={detectedPort.port} label={Port.toString(detectedPort.port)} - selected={index === detectedPorts.matchingIndex} + selected={index === matchingIndex} onClick={this.selectPort} /> ))} diff --git a/arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx b/arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx index 4cdd2c9a5..786fdad5d 100644 --- a/arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx @@ -15,6 +15,7 @@ import { BoardIdentifier, BoardsConfig, BoardWithPackage, + DetectedPort, emptyBoardsConfig, PortIdentifier, } from '../../common/protocol/boards-service'; @@ -43,9 +44,11 @@ export class BoardsConfigDialog extends ReactDialog { private readonly onFilterTextDidChangeEmitter: Emitter; private readonly onBoardSelected = (board: BoardIdentifier): void => { this._boardsConfig.selectedBoard = board; + this.update(); }; private readonly onPortSelected = (port: PortIdentifier): void => { this._boardsConfig.selectedPort = port; + this.update(); }; private readonly setFocusNode = (element: HTMLElement | undefined): void => { this.focusNode = element; @@ -55,6 +58,11 @@ export class BoardsConfigDialog extends ReactDialog { }): Promise => { return this.boardsServiceProvider.searchBoards(options); }; + private readonly ports = ( + predicate?: (port: DetectedPort) => boolean + ): readonly DetectedPort[] => { + return this.boardsServiceProvider.boardList.ports(predicate); + }; private _boardsConfig: BoardsConfig; private focusNode: HTMLElement | undefined; @@ -75,7 +83,10 @@ export class BoardsConfigDialog extends ReactDialog { @postConstruct() protected init(): void { - this.boardsServiceProvider.onBoardListDidChange(() => this.update()); // Do not add to `toDispose`! + this.boardsServiceProvider.onBoardListDidChange(() => { + this._boardsConfig = deepClone(this.boardsServiceProvider.boardsConfig); + this.update(); + }); // Do not add to `toDispose`! this._boardsConfig = deepClone(this.boardsServiceProvider.boardsConfig); } @@ -118,7 +129,7 @@ export class BoardsConfigDialog extends ReactDialog {
{ } onAppStateDidChange={this.notificationCenter.onAppStateDidChange} searchBoards={this.searchBoards} + ports={this.ports} />
diff --git a/arduino-ide-extension/src/common/protocol/board-list.ts b/arduino-ide-extension/src/common/protocol/board-list.ts index 38e195248..85c6e338a 100644 --- a/arduino-ide-extension/src/common/protocol/board-list.ts +++ b/arduino-ide-extension/src/common/protocol/board-list.ts @@ -7,6 +7,7 @@ import { DetectedPort, DetectedPorts, emptyBoardsConfig, + findMatchingPortIndex, isBoardIdentifier, isDefinedBoardsConfig, Port, @@ -227,13 +228,10 @@ export function createBoardList( } } const ports = _allPorts.filter(predicate); - let matchingIndex = -1; - if (boardsConfig.selectedPort) { - const selectedPortKey = Port.keyOf(boardsConfig.selectedPort); - matchingIndex = ports.findIndex( - (detectedPort) => Port.keyOf(detectedPort.port) === selectedPortKey - ); - } + const matchingIndex = findMatchingPortIndex( + boardsConfig.selectedPort, + ports + ); return Object.assign(ports, { matchingIndex }); }; diff --git a/arduino-ide-extension/src/common/protocol/boards-service.ts b/arduino-ide-extension/src/common/protocol/boards-service.ts index 37c55fc8c..18464ae77 100644 --- a/arduino-ide-extension/src/common/protocol/boards-service.ts +++ b/arduino-ide-extension/src/common/protocol/boards-service.ts @@ -19,6 +19,18 @@ export interface DetectedPort { readonly port: Port; readonly boards: Pick[]; } + +export function findMatchingPortIndex( + toFind: PortIdentifier | undefined, + ports: readonly DetectedPort[] | readonly Port[] +): number { + if (!toFind) { + return -1; + } + const toFindPortKey = Port.keyOf(toFind); + return ports.findIndex((port) => Port.keyOf(port) === toFindPortKey); +} + /** * The closest representation what the Arduino CLI detects with the `board list --watch` gRPC equivalent. * The keys are unique identifiers generated from the port object (via `Port#keyOf`). @@ -185,8 +197,11 @@ export namespace Port { /** * Key is the combination of address and protocol formatted like `'arduino+${protocol}://${address}'` used to uniquely identify a port. */ - export function keyOf({ protocol, address }: PortIdentifier): string { - return `arduino+${protocol}://${address}`; + export function keyOf(port: PortIdentifier | Port | DetectedPort): string { + if (isPortIdentifier(port)) { + return `arduino+${port.protocol}://${port.address}`; + } + return keyOf(port.port); } export function toString({ addressLabel, protocolLabel }: Port): string {