Incorporated review feedback and moved to QuickPickService

This commit is contained in:
Christian Weichel 2019-05-08 13:32:39 +02:00
parent be20365a6b
commit 43ab17fd34
8 changed files with 30 additions and 118 deletions

View File

@ -3,11 +3,13 @@ import { Command } from '@theia/core/lib/common/command';
export namespace ArduinoCommands {
export const VERIFY: Command = {
id: 'arduino-verify'
id: 'arduino-verify',
label: 'Verify Sketch'
}
export const UPLOAD: Command = {
id: 'arduino-upload'
id: 'arduino-upload',
label: 'Upload Sketch'
}
}

View File

@ -13,6 +13,7 @@ import { CoreService } from '../common/protocol/core-service';
import { WorkspaceServiceExt } from './workspace-service-ext';
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
import { ConfirmDialog } from '@theia/core/lib/browser';
import { QuickPickService } from '@theia/core/lib/common/quick-pick-service';
@injectable()
@ -33,6 +34,9 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
@inject(ToolOutputServiceClient)
protected readonly toolOutputServiceClient: ToolOutputServiceClient;
@inject(QuickPickService)
protected readonly quickPickService: QuickPickService;
@postConstruct()
protected async init(): Promise<void> {
// This is a hack. Otherwise, the backend services won't bind.
@ -56,7 +60,7 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
});
registry.registerItem({
id: ConnectedBoards.TOOLBAR_ID,
render: () => <ConnectedBoards boardsService={this.boardService}/>,
render: () => <ConnectedBoards boardsService={this.boardService} quickPickService={this.quickPickService} />,
isVisible: widget => this.isArduinoEditor(widget)
})
}

View File

@ -1,6 +1,7 @@
import * as React from 'react';
import { BoardsService, Board } from '../../common/protocol/boards-service';
import { SelectBoardDialog } from './select-board-dialog';
// import { SelectBoardDialog } from './select-board-dialog';
import { QuickPickService } from '@theia/core/lib/common/quick-pick-service';
export class ConnectedBoards extends React.Component<ConnectedBoards.Props, ConnectedBoards.State> {
static TOOLBAR_ID: 'connected-boards-toolbar';
@ -25,7 +26,9 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
}
return <div className={ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}>
<select disabled={!this.state.boards} onChange={this.onBoardSelect.bind(this)} value={this.state.selection}>
<select disabled={!this.state.boards}
onChange={this.onBoardSelect.bind(this)}
value={this.state.selection}>
<optgroup label="Attached boards">
{ content }
</optgroup>
@ -57,7 +60,7 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
if (selection === "select-other" || selection === "selected-other") {
let selectedBoard = this.state.otherBoard;
if (selection === "select-other" || !selectedBoard) {
selectedBoard = await new SelectBoardDialog(this.props.boardsService).open();
selectedBoard = await this.selectedInstalledBoard();
}
if (!selectedBoard) {
return;
@ -76,12 +79,27 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
this.setState({selection});
}
protected async selectedInstalledBoard(): Promise<Board | undefined> {
const {items} = await this.props.boardsService.search({});
const idx = new Map<string, Board>();
items.filter(pkg => !!pkg.installedVersion).forEach(pkg => pkg.boards.forEach(brd => idx.set(`${brd.name}`, brd) ));
const selection = await this.props.quickPickService.show(Array.from(idx.keys()));
if (!selection) {
return;
}
return idx.get(selection);
}
}
export namespace ConnectedBoards {
export interface Props {
readonly boardsService: BoardsService;
readonly quickPickService: QuickPickService;
}
export interface State {

View File

@ -1,103 +0,0 @@
import { AbstractDialog, ReactRenderer, Message } from "@theia/core/lib/browser";
import { Board, BoardsService } from "../../common/protocol/boards-service";
import * as React from 'react';
interface BoardGroup {
name: string
boards: Board[]
}
class DialogContentRenderer extends ReactRenderer {
protected availableBoards: BoardGroup[] = [ ];
protected searchTerm = "";
constructor(protected readonly boardsService: BoardsService, protected readonly onSelect: (b: Board) => void) {
super();
this.search();
}
doRender(): React.ReactNode {
return <React.Fragment>
<input type="text" placeholder="Search ..." onChange={this.onSearchChange.bind(this)} value={this.searchTerm} />
<select size={10} onChange={this.onChange.bind(this)}>
{ this.availableBoards.map((b, i) => (
<optgroup key={"pkg" + i} label={b.name}>
{ b.boards.map((brd, j) => <option key={j} value={`${i}::${j}`}>{brd.name}</option>) }
</optgroup>
)) }
</select>
</React.Fragment>;
}
protected onChange(evt: React.ChangeEvent<HTMLSelectElement>) {
const [grp, brd] = evt.target.value.split("::");
const grpidx = parseInt(grp, 10);
const brdidx = parseInt(brd, 10);
const board = this.availableBoards[grpidx].boards[brdidx];
this.onSelect(board);
}
protected onSearchChange(evt: React.ChangeEvent<HTMLInputElement>) {
this.searchTerm = evt.target.value;
this.search();
}
protected async search() {
const { items } = await this.boardsService.search({query: this.searchTerm });
this.availableBoards = items.map(pkg => {
const result: BoardGroup = {
name: pkg.name,
boards: pkg.boards.filter(b => b.name.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase()))
}
return result;
}).filter(grp => !!grp.boards).sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name === b.name) return 0;
return 1;
});
this.render();
}
}
export class SelectBoardDialog extends AbstractDialog<Board> {
protected result: Board;
protected readonly contentRenderer: DialogContentRenderer;
constructor(boardsService: BoardsService) {
super({ title: 'Select other board' });
this.contentNode.classList.add(SelectBoardDialog.Styles.DIALOG_CLASS);
this.contentRenderer = new DialogContentRenderer(boardsService, b => this.result = b);
this.contentRenderer.render();
this.contentNode.appendChild(this.contentRenderer.host);
this.appendCloseButton();
this.appendAcceptButton("Select");
}
get value(): Board {
return this.result;
}
onUpdateRequest(msg: Message) {
super.onUpdateRequest(msg);
this.contentRenderer.render();
}
dispose() {
this.contentRenderer.dispose();
super.dispose();
}
}
export namespace SelectBoardDialog {
export namespace Styles {
export const DIALOG_CLASS = "select-board-dialog";
export const SELECTOR_CLASS = "selector";
}
}

View File

@ -24,15 +24,6 @@ export class LibraryServiceImpl implements LibraryService {
const installedLibsIdx = new Map<string, InstalledLibrary>();
installedLibs.forEach(l => installedLibsIdx.set(l.getName(), l));
if (!options.query || options.query.length < 2) {
const items: Library[] = Array.from(installedLibsIdx.values()).map(lib => toLibrary({
name: lib.getName(),
installable: false,
installedVersion: lib.getInstalled()!.getVersion(),
}, lib.getInstalled()!));
return { items };
}
const req = new LibrarySearchReq();
req.setQuery(options.query || '');
req.setInstance(instance);