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

View File

@ -1,6 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import { BoardsService, Board } from '../../common/protocol/boards-service'; 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> { export class ConnectedBoards extends React.Component<ConnectedBoards.Props, ConnectedBoards.State> {
static TOOLBAR_ID: 'connected-boards-toolbar'; 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}> 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"> <optgroup label="Attached boards">
{ content } { content }
</optgroup> </optgroup>
@ -57,7 +60,7 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
if (selection === "select-other" || selection === "selected-other") { if (selection === "select-other" || selection === "selected-other") {
let selectedBoard = this.state.otherBoard; let selectedBoard = this.state.otherBoard;
if (selection === "select-other" || !selectedBoard) { if (selection === "select-other" || !selectedBoard) {
selectedBoard = await new SelectBoardDialog(this.props.boardsService).open(); selectedBoard = await this.selectedInstalledBoard();
} }
if (!selectedBoard) { if (!selectedBoard) {
return; return;
@ -76,12 +79,27 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
this.setState({selection}); 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 namespace ConnectedBoards {
export interface Props { export interface Props {
readonly boardsService: BoardsService; readonly boardsService: BoardsService;
readonly quickPickService: QuickPickService;
} }
export interface State { 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>(); const installedLibsIdx = new Map<string, InstalledLibrary>();
installedLibs.forEach(l => installedLibsIdx.set(l.getName(), l)); 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(); const req = new LibrarySearchReq();
req.setQuery(options.query || ''); req.setQuery(options.query || '');
req.setInstance(instance); req.setInstance(instance);