Skip to content

Commit 66f429c

Browse files
Akos Kittajbicker
Akos Kitta
authored andcommitted
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 <kittaakos@typefox.io>
1 parent 0dc45da commit 66f429c

File tree

3 files changed

+78
-26
lines changed

3 files changed

+78
-26
lines changed

arduino-ide-extension/src/browser/boards/boards-config.tsx

+49-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { DisposableCollection } from '@theia/core';
3-
import { BoardsService, Board, AttachedSerialBoard } from '../../common/protocol/boards-service';
3+
import { BoardsService, Board, AttachedSerialBoard, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
44
import { BoardsServiceClientImpl } from './boards-service-client-impl';
55

66
export namespace BoardsConfig {
@@ -18,31 +18,36 @@ export namespace BoardsConfig {
1818
}
1919

2020
export interface State extends Config {
21-
searchResults: Board[];
21+
searchResults: Array<Board & { packageName: string }>;
2222
knownPorts: string[];
2323
}
2424

2525
}
2626

2727
export abstract class Item<T> extends React.Component<{
2828
item: T,
29-
name: string,
29+
label: string,
3030
selected: boolean,
3131
onClick: (item: T) => void,
32-
missing?: boolean }> {
32+
missing?: boolean,
33+
detail?: string
34+
}> {
3335

3436
render(): React.ReactNode {
35-
const { selected, name, missing } = this.props;
37+
const { selected, label, missing, detail } = this.props;
3638
const classNames = ['item'];
3739
if (selected) {
3840
classNames.push('selected');
3941
}
4042
if (missing === true) {
4143
classNames.push('missing')
4244
}
43-
return <div onClick={this.onClick} className={classNames.join(' ')}>
44-
{name}
45-
{selected ? <i className='fa fa-check'></i> : ''}
45+
return <div onClick={this.onClick} className={classNames.join(' ')} title={`${label}${!detail ? '' : detail}`}>
46+
<div className='label'>
47+
{label}
48+
</div>
49+
{!detail ? '' : <div className='detail'>{detail}</div>}
50+
{!selected ? '' : <div className='selected-icon'><i className='fa fa-check'/></div>}
4651
</div>;
4752
}
4853

@@ -72,7 +77,7 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
7277
this.props.boardsService.getAttachedBoards().then(({ boards }) => this.updatePorts(boards));
7378
const { boardsServiceClient: client } = this.props;
7479
this.toDispose.pushAll([
75-
client.onBoardsChanged(event => this.updatePorts(event.newState.boards)),
80+
client.onBoardsChanged(event => this.updatePorts(event.newState.boards, AttachedBoardsChangeEvent.diff(event).detached)),
7681
client.onBoardsConfigChanged(({ selectedBoard, selectedPort }) => {
7782
this.setState({ selectedBoard, selectedPort }, () => this.fireConfigChanged());
7883
})
@@ -96,23 +101,24 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
96101
this.queryBoards({ query }).then(({ searchResults }) => this.setState({ searchResults }));
97102
}
98103

99-
protected updatePorts = (boards: Board[] = []) => {
104+
protected updatePorts = (boards: Board[] = [], detachedBoards: Board[] = []) => {
100105
this.queryPorts(Promise.resolve({ boards })).then(({ knownPorts }) => {
101106
let { selectedPort } = this.state;
102-
if (!!selectedPort && knownPorts.indexOf(selectedPort) === -1) {
107+
const removedPorts = detachedBoards.filter(AttachedSerialBoard.is).map(({ port }) => port);
108+
if (!!selectedPort && removedPorts.indexOf(selectedPort) === -1) {
103109
selectedPort = undefined;
104110
}
105111
this.setState({ knownPorts, selectedPort }, () => this.fireConfigChanged());
106112
});
107113
}
108114

109-
protected queryBoards = (options: { query?: string } = {}): Promise<{ searchResults: Board[] }> => {
115+
protected queryBoards = (options: { query?: string } = {}): Promise<{ searchResults: Array<Board & { packageName: string }> }> => {
110116
const { boardsService } = this.props;
111117
const query = (options.query || '').toLocaleLowerCase();
112-
return new Promise<{ searchResults: Board[] }>(resolve => {
118+
return new Promise<{ searchResults: Array<Board & { packageName: string }> }>(resolve => {
113119
boardsService.search(options)
114120
.then(({ items }) => items
115-
.map(item => item.boards)
121+
.map(item => item.boards.map(board => ({ ...board, packageName: item.name })))
116122
.reduce((acc, curr) => acc.concat(curr), [])
117123
.filter(board => board.name.toLocaleLowerCase().indexOf(query) !== -1)
118124
.sort(Board.compare))
@@ -139,7 +145,7 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
139145
this.setState({ selectedPort }, () => this.fireConfigChanged());
140146
}
141147

142-
protected selectBoard = (selectedBoard: Board | undefined) => {
148+
protected selectBoard = (selectedBoard: Board & { packageName: string } | undefined) => {
143149
this.setState({ selectedBoard }, () => this.fireConfigChanged());
144150
}
145151

@@ -166,18 +172,40 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
166172
}
167173

168174
protected renderBoards(): React.ReactNode {
169-
const { selectedBoard } = this.state;
175+
const { selectedBoard, searchResults } = this.state;
176+
// Board names are not unique. We show the corresponding core name as a detail.
177+
// https://github.com/arduino/arduino-cli/pull/294#issuecomment-513764948
178+
const distinctBoardNames = new Map<string, number>();
179+
for (const { name } of searchResults) {
180+
const counter = distinctBoardNames.get(name) || 0;
181+
distinctBoardNames.set(name, counter + 1);
182+
}
183+
184+
// Due to the non-unique board names, we have to check the package name as well.
185+
const selected = (board: Board & { packageName: string }) => {
186+
if (!!selectedBoard) {
187+
if (Board.equals(board, selectedBoard)) {
188+
if ('packageName' in selectedBoard) {
189+
return board.packageName === (selectedBoard as any).packageName;
190+
}
191+
return true;
192+
}
193+
}
194+
return false;
195+
}
196+
170197
return <React.Fragment>
171198
<div className='search'>
172199
<input type='search' placeholder='SEARCH BOARD' onChange={this.updateBoards} ref={this.focusNodeSet} />
173200
<i className='fa fa-search'></i>
174201
</div>
175202
<div className='boards list'>
176-
{this.state.searchResults.map((board, index) => <Item<Board>
177-
key={`${board.name}-${index}`}
203+
{this.state.searchResults.map(board => <Item<Board & { packageName: string }>
204+
key={`${board.name}-${board.packageName}`}
178205
item={board}
179-
name={board.name}
180-
selected={!!selectedBoard && Board.equals(board, selectedBoard)}
206+
label={board.name}
207+
detail={(distinctBoardNames.get(board.name) || 0) > 1 ? ` - ${board.packageName}` : undefined}
208+
selected={selected(board)}
181209
onClick={this.selectBoard}
182210
missing={!Board.installed(board)}
183211
/>)}
@@ -197,7 +225,7 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
197225
{this.state.knownPorts.map(port => <Item<string>
198226
key={port}
199227
item={port}
200-
name={port}
228+
label={port}
201229
selected={this.state.selectedPort === port}
202230
onClick={this.selectPort}
203231
/>)}

arduino-ide-extension/src/browser/style/board-select-dialog.css

+14-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,20 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i{
8383
#select-board-dialog .selectBoardContainer .body .list .item {
8484
padding: 10px 5px 10px 10px;
8585
display: flex;
86-
justify-content: space-between;
86+
justify-content: end;
87+
}
88+
89+
#select-board-dialog .selectBoardContainer .body .list .item .selected-icon {
90+
margin-left: auto;
91+
}
92+
93+
#select-board-dialog .selectBoardContainer .body .list .item .detail {
94+
font-size: var(--theia-ui-font-size1);
95+
color: var(--theia-disabled-color0);
96+
width: 155px; /* used heuristics for the calculation */
97+
white-space: pre;
98+
overflow: hidden;
99+
text-overflow: ellipsis;
87100
}
88101

89102
#select-board-dialog .selectBoardContainer .body .list .item.missing {

arduino-ide-extension/src/common/protocol/boards-service.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ export interface AttachedBoardsChangeEvent {
77
readonly oldState: Readonly<{ boards: Board[] }>;
88
readonly newState: Readonly<{ boards: Board[] }>;
99
}
10+
export namespace AttachedBoardsChangeEvent {
11+
12+
export function diff(event: AttachedBoardsChangeEvent): Readonly<{ attached: Board[], detached: Board[] }> {
13+
const diff = <T>(left: T[], right: T[]) => {
14+
return left.filter(item => right.indexOf(item) === -1);
15+
}
16+
const { boards: newBoards } = event.newState;
17+
const { boards: oldBoards } = event.oldState;
18+
return {
19+
detached: diff(oldBoards, newBoards),
20+
attached: diff(newBoards, oldBoards)
21+
};
22+
}
23+
24+
}
1025

1126
export interface BoardInstalledEvent {
1227
readonly pkg: Readonly<BoardPackage>;
@@ -34,10 +49,6 @@ export interface Board {
3449
fqbn?: string
3550
}
3651

37-
export interface Port {
38-
port?: string;
39-
}
40-
4152
export namespace Board {
4253

4354
export function is(board: any): board is Board {

0 commit comments

Comments
 (0)