@@ -3,13 +3,13 @@ import * as ReactDOM from '@theia/core/shared/react-dom';
33import { CommandRegistry } from '@theia/core/lib/common/command' ;
44import { DisposableCollection } from '@theia/core/lib/common/disposable' ;
55import { Port } from '../../common/protocol' ;
6- import { BoardsConfig } from './boards-config' ;
76import { ArduinoCommands } from '../arduino-commands' ;
87import {
98 BoardsServiceProvider ,
109 AvailableBoard ,
1110} from './boards-service-provider' ;
1211import { nls } from '@theia/core/lib/common' ;
12+ import classNames from 'classnames' ;
1313
1414export interface BoardsDropDownListCoords {
1515 readonly top : number ;
@@ -28,10 +28,12 @@ export namespace BoardsDropDown {
2828
2929export class BoardsDropDown extends React . Component < BoardsDropDown . Props > {
3030 protected dropdownElement : HTMLElement ;
31+ private listRef : React . RefObject < HTMLDivElement > ;
3132
3233 constructor ( props : BoardsDropDown . Props ) {
3334 super ( props ) ;
3435
36+ this . listRef = React . createRef ( ) ;
3537 let list = document . getElementById ( 'boards-dropdown-container' ) ;
3638 if ( ! list ) {
3739 list = document . createElement ( 'div' ) ;
@@ -41,6 +43,12 @@ export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
4143 }
4244 }
4345
46+ override componentDidUpdate ( prevProps : BoardsDropDown . Props ) : void {
47+ if ( prevProps . coords === 'hidden' && this . listRef . current ) {
48+ this . listRef . current . focus ( ) ;
49+ }
50+ }
51+
4452 override render ( ) : React . ReactNode {
4553 return ReactDOM . createPortal ( this . renderNode ( ) , this . dropdownElement ) ;
4654 }
@@ -61,21 +69,22 @@ export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
6169 position : 'absolute' ,
6270 ...coords ,
6371 } }
72+ ref = { this . listRef }
73+ tabIndex = { 0 }
6474 >
65- { items
66- . map ( ( { name, port, selected, onClick } ) => ( {
67- label : nls . localize (
68- 'arduino/board/boardListItem' ,
69- '{0} at {1}' ,
70- name ,
71- Port . toString ( port )
72- ) ,
73- selected,
74- onClick,
75- } ) )
76- . map ( this . renderItem ) }
75+ < div className = "arduino-boards-dropdown-list--items-container" >
76+ { items
77+ . map ( ( { name, port, selected, onClick } ) => ( {
78+ boardLabel : name ,
79+ port,
80+ selected,
81+ onClick,
82+ } ) )
83+ . map ( this . renderItem ) }
84+ </ div >
7785 < div
7886 key = { footerLabel }
87+ tabIndex = { 0 }
7988 className = "arduino-boards-dropdown-item arduino-board-dropdown-footer"
8089 onClick = { ( ) => this . props . openBoardsConfig ( ) }
8190 >
@@ -86,22 +95,49 @@ export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
8695 }
8796
8897 protected renderItem ( {
89- label,
98+ boardLabel,
99+ port,
90100 selected,
91101 onClick,
92102 } : {
93- label : string ;
103+ boardLabel : string ;
104+ port : Port ;
94105 selected ?: boolean ;
95106 onClick : ( ) => void ;
96107 } ) : React . ReactNode {
108+ const protocolIcon = iconNameFromProtocol ( port . protocol ) ;
109+ const onKeyUp = ( e : React . KeyboardEvent ) => {
110+ if ( e . key === 'Enter' ) {
111+ onClick ( ) ;
112+ }
113+ } ;
114+
97115 return (
98116 < div
99- key = { label }
100- className = { `arduino-boards-dropdown-item ${ selected ? 'selected' : '' } ` }
117+ key = { `board-item--${ boardLabel } -${ port . address } ` }
118+ className = { classNames ( 'arduino-boards-dropdown-item' , {
119+ 'arduino-boards-dropdown-item--selected' : selected ,
120+ } ) }
101121 onClick = { onClick }
122+ onKeyUp = { onKeyUp }
123+ tabIndex = { 0 }
102124 >
103- < div > { label } </ div >
104- { selected ? < span className = "fa fa-check" /> : '' }
125+ < div
126+ className = { classNames (
127+ 'arduino-boards-dropdown-item--protocol' ,
128+ 'fa' ,
129+ protocolIcon
130+ ) }
131+ />
132+ < div className = "arduino-boards-dropdown-item--label" >
133+ < div className = "arduino-boards-dropdown-item--board-label" >
134+ { boardLabel }
135+ </ div >
136+ < div className = "arduino-boards-dropdown-item--port-label" >
137+ { port . address }
138+ </ div >
139+ </ div >
140+ { selected ? < div className = "fa fa-check" /> : '' }
105141 </ div >
106142 ) ;
107143 }
@@ -163,36 +199,43 @@ export class BoardsToolBarItem extends React.Component<
163199
164200 override render ( ) : React . ReactNode {
165201 const { coords, availableBoards } = this . state ;
166- const boardsConfig = this . props . boardsServiceClient . boardsConfig ;
167- const title = BoardsConfig . Config . toString ( boardsConfig , {
168- default : nls . localize (
169- 'arduino/common/noBoardSelected' ,
170- 'No board selected'
171- ) ,
172- } ) ;
173- const decorator = ( ( ) => {
174- const selectedBoard = availableBoards . find ( ( { selected } ) => selected ) ;
175- if ( ! selectedBoard || ! selectedBoard . port ) {
176- return 'fa fa-times notAttached' ;
177- }
178- if ( selectedBoard . state === AvailableBoard . State . guessed ) {
179- return 'fa fa-exclamation-triangle guessed' ;
180- }
181- return '' ;
182- } ) ( ) ;
202+ const selectedBoard = availableBoards . find ( ( { selected } ) => selected ) ;
203+
204+ const boardLabel =
205+ selectedBoard ?. name ||
206+ nls . localize ( 'arduino/board/selectBoard' , 'Select Board' ) ;
207+ const selectedPortLabel = portLabel ( selectedBoard ?. port ?. address ) ;
208+
209+ const isConnected = Boolean (
210+ selectedBoard && AvailableBoard . hasPort ( selectedBoard )
211+ ) ;
212+ const protocolIcon = isConnected
213+ ? iconNameFromProtocol ( selectedBoard ?. port ?. protocol || '' )
214+ : null ;
215+ const procolIconClassNames = classNames (
216+ 'arduino-boards-toolbar-item--protocol' ,
217+ 'fa' ,
218+ protocolIcon
219+ ) ;
183220
184221 return (
185222 < React . Fragment >
186- < div className = "arduino-boards-toolbar-item-container" >
187- < div className = "arduino-boards-toolbar-item" title = { title } >
188- < div className = "inner-container" onClick = { this . show } >
189- < span className = { decorator } />
190- < div className = "label noWrapInfo" >
191- < div className = "noWrapInfo noselect" > { title } </ div >
192- </ div >
193- < span className = "fa fa-caret-down caret" />
194- </ div >
223+ < div
224+ className = "arduino-boards-toolbar-item-container"
225+ title = { selectedPortLabel }
226+ onClick = { this . show }
227+ >
228+ { protocolIcon && < div className = { procolIconClassNames } /> }
229+ < div
230+ className = { classNames (
231+ 'arduino-boards-toolbar-item--label' ,
232+ 'noWrapInfo noselect' ,
233+ { 'arduino-boards-toolbar-item--label-connected' : isConnected }
234+ ) }
235+ >
236+ { boardLabel }
195237 </ div >
238+ < div className = "fa fa-caret-down caret" />
196239 </ div >
197240 < BoardsDropDown
198241 coords = { coords }
@@ -212,6 +255,7 @@ export class BoardsToolBarItem extends React.Component<
212255 selectedPort : board . port ,
213256 } ;
214257 }
258+ this . setState ( { coords : 'hidden' } ) ;
215259 } ,
216260 } ) ) }
217261 openBoardsConfig = { this . openDialog }
@@ -222,7 +266,6 @@ export class BoardsToolBarItem extends React.Component<
222266
223267 protected openDialog = ( ) => {
224268 this . props . commands . executeCommand ( ArduinoCommands . OPEN_BOARDS_DIALOG . id ) ;
225- this . setState ( { coords : 'hidden' } ) ;
226269 } ;
227270}
228271export namespace BoardsToolBarItem {
@@ -236,3 +279,26 @@ export namespace BoardsToolBarItem {
236279 coords : BoardsDropDownListCoords | 'hidden' ;
237280 }
238281}
282+
283+ function iconNameFromProtocol ( protocol : string ) : string {
284+ switch ( protocol ) {
285+ case 'serial' :
286+ return 'fa-arduino-technology-usb' ;
287+ case 'network' :
288+ return 'fa-arduino-technology-connection' ;
289+ /*
290+ Bluetooth ports are not listed yet from the CLI;
291+ Not sure about the naming ('bluetooth'); make sure it's correct before uncommenting the following lines
292+ */
293+ // case 'bluetooth':
294+ // return 'fa-arduino-technology-bluetooth';
295+ default :
296+ return 'fa-arduino-technology-3dimensionscube' ;
297+ }
298+ }
299+
300+ function portLabel ( portName ?: string ) : string {
301+ return portName
302+ ? nls . localize ( 'arduino/board/portLabel' , 'Port: {0}' , portName )
303+ : nls . localize ( 'arduino/board/disconnected' , 'Disconnected' ) ;
304+ }
0 commit comments