From 66f429c47864bccea98c3134bec7e4b5a4ecf44c Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 31 Jul 2019 11:49:26 +0200 Subject: [PATCH] workaround for non-unique names. Fine tuned the port unnselection when attached boards change. This should make sure we do not have to `await` for the attached boards from the backend. Signed-off-by: Akos Kitta --- .../src/browser/boards/boards-config.tsx | 70 +++++++++++++------ .../src/browser/style/board-select-dialog.css | 15 +++- .../src/common/protocol/boards-service.ts | 19 +++-- 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/arduino-ide-extension/src/browser/boards/boards-config.tsx b/arduino-ide-extension/src/browser/boards/boards-config.tsx index 61640d30..9509f46f 100644 --- a/arduino-ide-extension/src/browser/boards/boards-config.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-config.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { DisposableCollection } from '@theia/core'; -import { BoardsService, Board, AttachedSerialBoard } from '../../common/protocol/boards-service'; +import { BoardsService, Board, AttachedSerialBoard, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service'; import { BoardsServiceClientImpl } from './boards-service-client-impl'; export namespace BoardsConfig { @@ -18,7 +18,7 @@ export namespace BoardsConfig { } export interface State extends Config { - searchResults: Board[]; + searchResults: Array; knownPorts: string[]; } @@ -26,13 +26,15 @@ export namespace BoardsConfig { export abstract class Item extends React.Component<{ item: T, - name: string, + label: string, selected: boolean, onClick: (item: T) => void, - missing?: boolean }> { + missing?: boolean, + detail?: string +}> { render(): React.ReactNode { - const { selected, name, missing } = this.props; + const { selected, label, missing, detail } = this.props; const classNames = ['item']; if (selected) { classNames.push('selected'); @@ -40,9 +42,12 @@ export abstract class Item extends React.Component<{ if (missing === true) { classNames.push('missing') } - return
- {name} - {selected ? : ''} + return
+
+ {label} +
+ {!detail ? '' :
{detail}
} + {!selected ? '' :
}
; } @@ -72,7 +77,7 @@ export class BoardsConfig extends React.Component this.updatePorts(boards)); const { boardsServiceClient: client } = this.props; this.toDispose.pushAll([ - client.onBoardsChanged(event => this.updatePorts(event.newState.boards)), + client.onBoardsChanged(event => this.updatePorts(event.newState.boards, AttachedBoardsChangeEvent.diff(event).detached)), client.onBoardsConfigChanged(({ selectedBoard, selectedPort }) => { this.setState({ selectedBoard, selectedPort }, () => this.fireConfigChanged()); }) @@ -96,23 +101,24 @@ export class BoardsConfig extends React.Component this.setState({ searchResults })); } - protected updatePorts = (boards: Board[] = []) => { + protected updatePorts = (boards: Board[] = [], detachedBoards: Board[] = []) => { this.queryPorts(Promise.resolve({ boards })).then(({ knownPorts }) => { let { selectedPort } = this.state; - if (!!selectedPort && knownPorts.indexOf(selectedPort) === -1) { + const removedPorts = detachedBoards.filter(AttachedSerialBoard.is).map(({ port }) => port); + if (!!selectedPort && removedPorts.indexOf(selectedPort) === -1) { selectedPort = undefined; } this.setState({ knownPorts, selectedPort }, () => this.fireConfigChanged()); }); } - protected queryBoards = (options: { query?: string } = {}): Promise<{ searchResults: Board[] }> => { + protected queryBoards = (options: { query?: string } = {}): Promise<{ searchResults: Array }> => { const { boardsService } = this.props; const query = (options.query || '').toLocaleLowerCase(); - return new Promise<{ searchResults: Board[] }>(resolve => { + return new Promise<{ searchResults: Array }>(resolve => { boardsService.search(options) .then(({ items }) => items - .map(item => item.boards) + .map(item => item.boards.map(board => ({ ...board, packageName: item.name }))) .reduce((acc, curr) => acc.concat(curr), []) .filter(board => board.name.toLocaleLowerCase().indexOf(query) !== -1) .sort(Board.compare)) @@ -139,7 +145,7 @@ export class BoardsConfig extends React.Component this.fireConfigChanged()); } - protected selectBoard = (selectedBoard: Board | undefined) => { + protected selectBoard = (selectedBoard: Board & { packageName: string } | undefined) => { this.setState({ selectedBoard }, () => this.fireConfigChanged()); } @@ -166,18 +172,40 @@ export class BoardsConfig extends React.Component(); + for (const { name } of searchResults) { + const counter = distinctBoardNames.get(name) || 0; + distinctBoardNames.set(name, counter + 1); + } + + // Due to the non-unique board names, we have to check the package name as well. + const selected = (board: Board & { packageName: string }) => { + if (!!selectedBoard) { + if (Board.equals(board, selectedBoard)) { + if ('packageName' in selectedBoard) { + return board.packageName === (selectedBoard as any).packageName; + } + return true; + } + } + return false; + } + return
- {this.state.searchResults.map((board, index) => - key={`${board.name}-${index}`} + {this.state.searchResults.map(board => + key={`${board.name}-${board.packageName}`} item={board} - name={board.name} - selected={!!selectedBoard && Board.equals(board, selectedBoard)} + label={board.name} + detail={(distinctBoardNames.get(board.name) || 0) > 1 ? ` - ${board.packageName}` : undefined} + selected={selected(board)} onClick={this.selectBoard} missing={!Board.installed(board)} />)} @@ -197,7 +225,7 @@ export class BoardsConfig extends React.Component key={port} item={port} - name={port} + label={port} selected={this.state.selectedPort === port} onClick={this.selectPort} />)} diff --git a/arduino-ide-extension/src/browser/style/board-select-dialog.css b/arduino-ide-extension/src/browser/style/board-select-dialog.css index 58dea0c5..15a6c05d 100644 --- a/arduino-ide-extension/src/browser/style/board-select-dialog.css +++ b/arduino-ide-extension/src/browser/style/board-select-dialog.css @@ -83,7 +83,20 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i{ #select-board-dialog .selectBoardContainer .body .list .item { padding: 10px 5px 10px 10px; display: flex; - justify-content: space-between; + justify-content: end; +} + +#select-board-dialog .selectBoardContainer .body .list .item .selected-icon { + margin-left: auto; +} + +#select-board-dialog .selectBoardContainer .body .list .item .detail { + font-size: var(--theia-ui-font-size1); + color: var(--theia-disabled-color0); + width: 155px; /* used heuristics for the calculation */ + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; } #select-board-dialog .selectBoardContainer .body .list .item.missing { diff --git a/arduino-ide-extension/src/common/protocol/boards-service.ts b/arduino-ide-extension/src/common/protocol/boards-service.ts index edc2158a..e59a00b4 100644 --- a/arduino-ide-extension/src/common/protocol/boards-service.ts +++ b/arduino-ide-extension/src/common/protocol/boards-service.ts @@ -7,6 +7,21 @@ export interface AttachedBoardsChangeEvent { readonly oldState: Readonly<{ boards: Board[] }>; readonly newState: Readonly<{ boards: Board[] }>; } +export namespace AttachedBoardsChangeEvent { + + export function diff(event: AttachedBoardsChangeEvent): Readonly<{ attached: Board[], detached: Board[] }> { + const diff = (left: T[], right: T[]) => { + return left.filter(item => right.indexOf(item) === -1); + } + const { boards: newBoards } = event.newState; + const { boards: oldBoards } = event.oldState; + return { + detached: diff(oldBoards, newBoards), + attached: diff(newBoards, oldBoards) + }; + } + +} export interface BoardInstalledEvent { readonly pkg: Readonly; @@ -34,10 +49,6 @@ export interface Board { fqbn?: string } -export interface Port { - port?: string; -} - export namespace Board { export function is(board: any): board is Board {