mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-24 11:46:32 +00:00
Merge pull request #31 from bcmi-labs/open-boards-dialog
PROEDITOR-9: Open boards dialog
This commit is contained in:
commit
35086ca1a1
@ -40,4 +40,12 @@ export namespace ArduinoCommands {
|
||||
label: "Refresh attached boards"
|
||||
}
|
||||
|
||||
export const SELECT_BOARD: Command = {
|
||||
id: "arduino-select-board"
|
||||
}
|
||||
|
||||
export const OPEN_BOARDS_DIALOG: Command = {
|
||||
id: "arduino-open-boards-dialog"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,16 +4,21 @@ import { CommonMenus } from "@theia/core/lib/browser";
|
||||
import { ArduinoCommands } from "./arduino-commands";
|
||||
import { SketchesService, Sketch } from "../common/protocol/sketches-service";
|
||||
import { AWorkspaceService } from "./arduino-workspace-service";
|
||||
import { BoardsService } from "../common/protocol/boards-service";
|
||||
|
||||
export namespace ArduinoOpenSketchContextMenu {
|
||||
export const PATH: MenuPath = ['arduino-open-sketch-context-menu'];
|
||||
export const OPEN_GROUP: MenuPath = [...PATH, '1_open'];
|
||||
export const WS_SKETCHES_GROUP: MenuPath = [...PATH, '2_sketches'];
|
||||
export const EXAMPLE_SKETCHES_GROUP: MenuPath = [...PATH, '3_examples'];
|
||||
export namespace ArduinoToolbarContextMenu {
|
||||
export const OPEN_SKETCH_PATH: MenuPath = ['arduino-open-sketch-context-menu'];
|
||||
export const OPEN_GROUP: MenuPath = [...OPEN_SKETCH_PATH, '1_open'];
|
||||
export const WS_SKETCHES_GROUP: MenuPath = [...OPEN_SKETCH_PATH, '2_sketches'];
|
||||
export const EXAMPLE_SKETCHES_GROUP: MenuPath = [...OPEN_SKETCH_PATH, '3_examples'];
|
||||
|
||||
export const SELECT_BOARDS_PATH: MenuPath = ['arduino-select-boards-context-menu'];
|
||||
export const CONNECTED_GROUP: MenuPath = [...SELECT_BOARDS_PATH, '1_connected'];
|
||||
export const OPEN_BOARDS_DIALOG_GROUP: MenuPath = [...SELECT_BOARDS_PATH, '2_open_boards_dialog'];
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFileMenuContribution implements MenuContribution {
|
||||
export class ArduinoToolbarMenuContribution implements MenuContribution {
|
||||
|
||||
@inject(CommandRegistry)
|
||||
protected readonly commands: CommandRegistry;
|
||||
@ -21,6 +26,9 @@ export class ArduinoFileMenuContribution implements MenuContribution {
|
||||
@inject(SketchesService)
|
||||
protected readonly sketches: SketchesService;
|
||||
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
constructor(
|
||||
@inject(AWorkspaceService) protected readonly workspaceService: AWorkspaceService,
|
||||
@inject(MenuModelRegistry) protected readonly menuRegistry: MenuModelRegistry) {
|
||||
@ -31,21 +39,19 @@ export class ArduinoFileMenuContribution implements MenuContribution {
|
||||
})
|
||||
}
|
||||
|
||||
protected registerSketchesInMenu(registry: MenuModelRegistry) {
|
||||
this.getWorkspaceSketches().then(sketches => {
|
||||
sketches.forEach(sketch => {
|
||||
const command: Command = {
|
||||
id: 'openSketch' + sketch.name
|
||||
}
|
||||
this.commands.registerCommand(command, {
|
||||
execute: () => this.commands.executeCommand(ArduinoCommands.OPEN_SKETCH.id, sketch)
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ArduinoOpenSketchContextMenu.WS_SKETCHES_GROUP, {
|
||||
commandId: command.id,
|
||||
label: sketch.name
|
||||
});
|
||||
})
|
||||
protected async registerSketchesInMenu(registry: MenuModelRegistry) {
|
||||
const sketches = await this.getWorkspaceSketches();
|
||||
sketches.forEach(sketch => {
|
||||
const command: Command = {
|
||||
id: 'openSketch' + sketch.name
|
||||
}
|
||||
this.commands.registerCommand(command, {
|
||||
execute: () => this.commands.executeCommand(ArduinoCommands.OPEN_SKETCH.id, sketch)
|
||||
});
|
||||
registry.registerMenuAction(ArduinoToolbarContextMenu.WS_SKETCHES_GROUP, {
|
||||
commandId: command.id,
|
||||
label: sketch.name
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@ -57,11 +63,16 @@ export class ArduinoFileMenuContribution implements MenuContribution {
|
||||
registerMenus(registry: MenuModelRegistry) {
|
||||
registry.registerMenuAction([...CommonMenus.FILE, '0_new_sletch'], {
|
||||
commandId: ArduinoCommands.NEW_SKETCH.id
|
||||
})
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ArduinoOpenSketchContextMenu.OPEN_GROUP, {
|
||||
registry.registerMenuAction(ArduinoToolbarContextMenu.OPEN_GROUP, {
|
||||
commandId: ArduinoCommands.OPEN_FILE_NAVIGATOR.id,
|
||||
label: 'Open...'
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ArduinoToolbarContextMenu.OPEN_BOARDS_DIALOG_GROUP, {
|
||||
commandId: ArduinoCommands.OPEN_BOARDS_DIALOG.id,
|
||||
label: 'Select Other Board & Port'
|
||||
});
|
||||
}
|
||||
}
|
@ -3,9 +3,9 @@ import { injectable, inject, postConstruct } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { EditorWidget } from '@theia/editor/lib/browser/editor-widget';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { CommandContribution, CommandRegistry } from '@theia/core/lib/common/command';
|
||||
import { CommandContribution, CommandRegistry, Command } from '@theia/core/lib/common/command';
|
||||
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { BoardsService } from '../common/protocol/boards-service';
|
||||
import { BoardsService, Board, AttachedSerialBoard } from '../common/protocol/boards-service';
|
||||
import { ArduinoCommands } from './arduino-commands';
|
||||
import { ConnectedBoards } from './components/connected-boards';
|
||||
import { CoreService } from '../common/protocol/core-service';
|
||||
@ -15,7 +15,7 @@ import { QuickPickService } from '@theia/core/lib/common/quick-pick-service';
|
||||
import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution';
|
||||
import { BoardsNotificationService } from './boards-notification-service';
|
||||
import { WorkspaceRootUriAwareCommandHandler, WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands';
|
||||
import { SelectionService } from '@theia/core';
|
||||
import { SelectionService, MenuModelRegistry } from '@theia/core';
|
||||
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { SketchFactory } from './sketch-factory';
|
||||
import { ArduinoToolbar } from './toolbar/arduino-toolbar';
|
||||
@ -23,10 +23,12 @@ import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { ContextMenuRenderer, OpenerService, Widget } from '@theia/core/lib/browser';
|
||||
import { OpenFileDialogProps, FileDialogService } from '@theia/filesystem/lib/browser/file-dialog';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
||||
import { ArduinoOpenSketchContextMenu } from './arduino-file-menu';
|
||||
import { ArduinoToolbarContextMenu } from './arduino-file-menu';
|
||||
import { Sketch, SketchesService } from '../common/protocol/sketches-service';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution'
|
||||
import { BoardsToolBarItem } from './boards/boards-toolbar-item';
|
||||
import { SelectBoardDialog } from './boards/select-board-dialog';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFrontendContribution implements TabBarToolbarContribution, CommandContribution {
|
||||
@ -85,10 +87,58 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
|
||||
@inject(SketchesService)
|
||||
protected readonly sketches: SketchesService;
|
||||
|
||||
@inject(SelectBoardDialog)
|
||||
protected readonly selectBoardsDialog: SelectBoardDialog;
|
||||
|
||||
@inject(MenuModelRegistry)
|
||||
protected readonly menuRegistry: MenuModelRegistry;
|
||||
|
||||
@inject(CommandRegistry)
|
||||
protected readonly commands: CommandRegistry;
|
||||
|
||||
protected boardsToolbarItem: BoardsToolBarItem | null;
|
||||
protected attachedBoards: Board[];
|
||||
protected selectedBoard: Board;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
// This is a hack. Otherwise, the backend services won't bind.
|
||||
await this.workspaceServiceExt.roots();
|
||||
const { boards } = await this.boardService.getAttachedBoards();
|
||||
this.attachedBoards = boards;
|
||||
this.registerConnectedBoardsInMenu(this.menuRegistry);
|
||||
}
|
||||
|
||||
protected async registerConnectedBoardsInMenu(registry: MenuModelRegistry) {
|
||||
this.attachedBoards.forEach(board => {
|
||||
const port = this.getPort(board);
|
||||
const command: Command = {
|
||||
id: 'selectBoard' + port
|
||||
}
|
||||
this.commands.registerCommand(command, {
|
||||
execute: () => this.commands.executeCommand(ArduinoCommands.SELECT_BOARD.id, board),
|
||||
isToggled: () => this.isSelectedBoard(board)
|
||||
});
|
||||
registry.registerMenuAction(ArduinoToolbarContextMenu.CONNECTED_GROUP, {
|
||||
commandId: command.id,
|
||||
label: board.name + ' at ' + port
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected isSelectedBoard(board: Board): boolean {
|
||||
return AttachedSerialBoard.is(board) &&
|
||||
this.selectedBoard &&
|
||||
AttachedSerialBoard.is(this.selectedBoard) &&
|
||||
board.port === this.selectedBoard.port &&
|
||||
board.fqbn === this.selectedBoard.fqbn;
|
||||
}
|
||||
|
||||
protected getPort(board: Board): string {
|
||||
if (AttachedSerialBoard.is(board)) {
|
||||
return board.port;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
||||
@ -118,15 +168,11 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
|
||||
});
|
||||
registry.registerItem({
|
||||
id: ConnectedBoards.TOOLBAR_ID,
|
||||
// render: () => <BoardsToolBarItem
|
||||
// onNoBoardsInstalled={this.onNoBoardsInstalled.bind(this)}
|
||||
// onUnknownBoard={this.onUnknownBoard.bind(this)} />,
|
||||
render: () => <ConnectedBoards
|
||||
boardsService={this.boardService}
|
||||
render: () => <BoardsToolBarItem
|
||||
ref={ref => this.boardsToolbarItem = ref}
|
||||
contextMenuRenderer={this.contextMenuRenderer}
|
||||
boardsNotificationService={this.boardsNotificationService}
|
||||
quickPickService={this.quickPickService}
|
||||
onNoBoardsInstalled={this.onNoBoardsInstalled.bind(this)}
|
||||
onUnknownBoard={this.onUnknownBoard.bind(this)} />,
|
||||
boardService={this.boardService} />,
|
||||
isVisible: widget => this.isArduinoToolbar(widget)
|
||||
})
|
||||
}
|
||||
@ -180,7 +226,7 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
|
||||
execute: async (widget: Widget, event: React.MouseEvent<HTMLElement>) => {
|
||||
const el = (event.target as HTMLElement).parentElement;
|
||||
if (el) {
|
||||
this.contextMenuRenderer.render(ArduinoOpenSketchContextMenu.PATH, {
|
||||
this.contextMenuRenderer.render(ArduinoToolbarContextMenu.OPEN_SKETCH_PATH, {
|
||||
x: el.getBoundingClientRect().left,
|
||||
y: el.getBoundingClientRect().top + el.offsetHeight
|
||||
});
|
||||
@ -221,7 +267,30 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
|
||||
registry.registerCommand(ArduinoCommands.REFRESH_BOARDS, {
|
||||
isEnabled: () => true,
|
||||
execute: () => this.boardsNotificationService.notifyBoardsInstalled()
|
||||
});
|
||||
registry.registerCommand(ArduinoCommands.SELECT_BOARD, {
|
||||
isEnabled: () => true,
|
||||
execute: async (board: Board) => {
|
||||
this.selectBoard(board);
|
||||
}
|
||||
})
|
||||
registry.registerCommand(ArduinoCommands.OPEN_BOARDS_DIALOG, {
|
||||
isEnabled: () => true,
|
||||
execute: async () => {
|
||||
const boardAndPort = await this.selectBoardsDialog.open();
|
||||
if (boardAndPort && boardAndPort.board) {
|
||||
this.selectBoard(boardAndPort.board);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected async selectBoard(board: Board) {
|
||||
await this.boardService.selectBoard(board)
|
||||
if (this.boardsToolbarItem) {
|
||||
this.boardsToolbarItem.setSelectedBoard(board);
|
||||
}
|
||||
this.selectedBoard = board;
|
||||
}
|
||||
|
||||
protected async openSketchFilesInNewWindow(uri: string) {
|
||||
@ -278,24 +347,24 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
|
||||
return widget;
|
||||
}
|
||||
|
||||
private async onNoBoardsInstalled() {
|
||||
const action = await this.messageService.info("You have no boards installed. Use the boards mangager to install one.", "Open Boards Manager");
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
// private async onNoBoardsInstalled() {
|
||||
// const action = await this.messageService.info("You have no boards installed. Use the boards mangager to install one.", "Open Boards Manager");
|
||||
// if (!action) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
this.boardsListWidgetFrontendContribution.openView({ reveal: true });
|
||||
}
|
||||
// this.boardsListWidgetFrontendContribution.openView({ reveal: true });
|
||||
// }
|
||||
|
||||
private async onUnknownBoard() {
|
||||
const action = await this.messageService.warn("There's a board connected for which you need to install software." +
|
||||
" If this were not a PoC we would offer you the right package now.", "Open Boards Manager");
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
// private async onUnknownBoard() {
|
||||
// const action = await this.messageService.warn("There's a board connected for which you need to install software." +
|
||||
// " If this were not a PoC we would offer you the right package now.", "Open Boards Manager");
|
||||
// if (!action) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
this.boardsListWidgetFrontendContribution.openView({ reveal: true });
|
||||
}
|
||||
// this.boardsListWidgetFrontendContribution.openView({ reveal: true });
|
||||
// }
|
||||
|
||||
private isArduinoToolbar(maybeToolbarWidget: any): boolean {
|
||||
if (maybeToolbarWidget instanceof ArduinoToolbar) {
|
||||
|
@ -27,7 +27,7 @@ import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service
|
||||
import { AWorkspaceService } from './arduino-workspace-service';
|
||||
import { ThemeService } from '@theia/core/lib/browser/theming';
|
||||
import { ArduinoTheme } from './arduino-theme';
|
||||
import { ArduinoFileMenuContribution } from './arduino-file-menu';
|
||||
import { ArduinoToolbarMenuContribution } from './arduino-file-menu';
|
||||
import { MenuContribution } from '@theia/core';
|
||||
import { SketchFactory } from './sketch-factory';
|
||||
import { OutlineViewContribution } from '@theia/outline-view/lib/browser/outline-view-contribution';
|
||||
@ -48,6 +48,8 @@ import { CustomApplicationShell } from './customization/custom-application-shell
|
||||
import { CustomFrontendApplication } from './customization/custom-frontend-application';
|
||||
import { EditorWidgetFactory } from '@theia/editor/lib/browser/editor-widget-factory';
|
||||
import { CustomEditorWidgetFactory } from './customization/custom-editor-widget-factory';
|
||||
import { SelectBoardDialog, SelectBoardDialogProps } from './boards/select-board-dialog';
|
||||
import { SelectBoardDialogWidget } from './boards/select-board-dialog-widget';
|
||||
|
||||
export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind) => {
|
||||
// Commands and toolbar items
|
||||
@ -55,7 +57,7 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un
|
||||
bind(CommandContribution).toService(ArduinoFrontendContribution);
|
||||
bind(TabBarToolbarContribution).toService(ArduinoFrontendContribution);
|
||||
bind(FrontendApplicationContribution).toService(ArduinoFrontendContribution);
|
||||
bind(MenuContribution).to(ArduinoFileMenuContribution).inSingletonScope();
|
||||
bind(MenuContribution).to(ArduinoToolbarMenuContribution).inSingletonScope();
|
||||
|
||||
bind(ArduinoToolbarContribution).toSelf().inSingletonScope();
|
||||
bind(FrontendApplicationContribution).toService(ArduinoToolbarContribution);
|
||||
@ -94,6 +96,13 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un
|
||||
}));
|
||||
bind(FrontendApplicationContribution).toService(BoardsListWidgetFrontendContribution);
|
||||
|
||||
// Board select dialog
|
||||
bind(SelectBoardDialogWidget).toSelf().inSingletonScope();
|
||||
bind(SelectBoardDialog).toSelf().inSingletonScope();
|
||||
bind(SelectBoardDialogProps).toConstantValue({
|
||||
title: 'Select Board'
|
||||
})
|
||||
|
||||
// Core service
|
||||
bind(CoreService)
|
||||
.toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, CoreServicePath))
|
||||
|
@ -0,0 +1,80 @@
|
||||
import * as React from 'react';
|
||||
import { BoardsService, Board } from '../../common/protocol/boards-service';
|
||||
import { ContextMenuRenderer } from '@theia/core/lib/browser';
|
||||
import { ArduinoToolbarContextMenu } from '../arduino-file-menu';
|
||||
import { BoardsNotificationService } from '../boards-notification-service';
|
||||
|
||||
export namespace BoardsToolBarItem {
|
||||
export interface Props {
|
||||
readonly contextMenuRenderer: ContextMenuRenderer;
|
||||
readonly boardsNotificationService: BoardsNotificationService;
|
||||
readonly boardService: BoardsService;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
selectedBoard?: Board;
|
||||
selectedIsAttached: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export class BoardsToolBarItem extends React.Component<BoardsToolBarItem.Props, BoardsToolBarItem.State> {
|
||||
|
||||
protected attachedBoards: Board[];
|
||||
|
||||
constructor(props: BoardsToolBarItem.Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
selectedBoard: undefined,
|
||||
selectedIsAttached: true
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setAttachedBoards();
|
||||
}
|
||||
|
||||
protected async setAttachedBoards() {
|
||||
const { boards } = await this.props.boardService.getAttachedBoards();
|
||||
this.attachedBoards = boards;
|
||||
if (this.attachedBoards.length) {
|
||||
await this.props.boardService.selectBoard(this.attachedBoards[0]);
|
||||
this.setSelectedBoard(this.attachedBoards[0]);
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedBoard(board: Board) {
|
||||
if (this.attachedBoards && this.attachedBoards.length) {
|
||||
this.setState({ selectedIsAttached: !!this.attachedBoards.find(attachedBoard => attachedBoard.name === board.name) });
|
||||
}
|
||||
this.setState({ selectedBoard: board });
|
||||
}
|
||||
|
||||
protected readonly doShowSelectBoardsMenu = (event: React.MouseEvent<HTMLElement>) => this.showSelectBoardsMenu(event);
|
||||
protected showSelectBoardsMenu(event: React.MouseEvent<HTMLElement>) {
|
||||
const el = (event.target as HTMLElement).parentElement;
|
||||
if (el) {
|
||||
this.props.contextMenuRenderer.render({
|
||||
menuPath: ArduinoToolbarContextMenu.SELECT_BOARDS_PATH,
|
||||
anchor: {
|
||||
x: el.getBoundingClientRect().left,
|
||||
y: el.getBoundingClientRect().top + el.offsetHeight
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <React.Fragment>
|
||||
<div className='arduino-boards-toolbar-item-container' onClick={this.doShowSelectBoardsMenu}>
|
||||
<div className='arduino-boards-toolbar-item'>
|
||||
<div className='inner-container'>
|
||||
<span className={!this.state.selectedBoard || !this.state.selectedIsAttached ? 'fa fa-times notAttached' : ''}></span>
|
||||
<div className='label'>{this.state.selectedBoard ? this.state.selectedBoard.name : 'no board selected'}</div>
|
||||
<span className='fa fa-caret-down'></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>;
|
||||
}
|
||||
}
|
@ -0,0 +1,305 @@
|
||||
import * as React from 'react';
|
||||
import { ReactWidget } from '@theia/core/lib/browser';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { BoardsService, Board, BoardPackage, AttachedSerialBoard } from '../../common/protocol/boards-service';
|
||||
import { BoardsNotificationService } from '../boards-notification-service';
|
||||
import { Emitter, Event } from '@theia/core';
|
||||
|
||||
export interface BoardAndPortSelection {
|
||||
board?: Board;
|
||||
port?: string;
|
||||
}
|
||||
|
||||
export namespace BoardAndPortSelectableItem {
|
||||
export interface Props {
|
||||
item: BoardAndPortSelection,
|
||||
selected: boolean,
|
||||
onSelect: (selection: BoardAndPortSelection) => void
|
||||
}
|
||||
}
|
||||
|
||||
export class BoardAndPortSelectableItem extends React.Component<BoardAndPortSelectableItem.Props> {
|
||||
|
||||
render(): React.ReactNode {
|
||||
if (this.props.item.board || this.props.item.port) {
|
||||
return <div onClick={this.select} className={`item ${this.props.selected ? 'selected' : ''}`}>
|
||||
{this.props.item.board ? this.props.item.board.name : this.props.item.port}
|
||||
{this.props.selected ? <i className='fa fa-check'></i> : ''}
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
protected readonly select = (() => {
|
||||
this.props.onSelect({ board: this.props.item.board, port: this.props.item.port })
|
||||
}).bind(this);
|
||||
}
|
||||
|
||||
export namespace BoardAndPortSelectionList {
|
||||
export interface Props {
|
||||
type: 'boards' | 'ports';
|
||||
list: BoardAndPortSelection[];
|
||||
onSelect: (selection: BoardAndPortSelection) => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
selection: BoardAndPortSelection
|
||||
}
|
||||
}
|
||||
|
||||
export class BoardAndPortSelectionList extends React.Component<BoardAndPortSelectionList.Props, BoardAndPortSelectionList.State> {
|
||||
|
||||
constructor(props: BoardAndPortSelectionList.Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
selection: {}
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.setState({ selection: {} });
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <div className={`${this.props.type} list`}>
|
||||
{this.props.list.map(item => <BoardAndPortSelectableItem
|
||||
key={item.board ? item.board.name : item.port}
|
||||
onSelect={this.doSelect}
|
||||
item={item}
|
||||
selected={this.isSelectedItem(item)}
|
||||
/>)}
|
||||
</div>
|
||||
}
|
||||
|
||||
protected readonly doSelect = (boardAndPortSelection: BoardAndPortSelection) => {
|
||||
this.setState({ selection: boardAndPortSelection });
|
||||
this.props.onSelect(boardAndPortSelection);
|
||||
}
|
||||
|
||||
protected readonly isSelectedItem = ((item: BoardAndPortSelection) => {
|
||||
if (this.state.selection.board) {
|
||||
return (this.state.selection.board === item.board);
|
||||
} else if (this.state.selection.port) {
|
||||
return (this.state.selection.port === item.port);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
protected readonly isSelectedPort = ((port: string) => {
|
||||
return (this.state.selection.port && this.state.selection.port === port) || false;
|
||||
});
|
||||
}
|
||||
|
||||
export namespace BoardAndPortSelectionComponent {
|
||||
export interface Props {
|
||||
boardsService: BoardsService;
|
||||
onSelect: (selection: BoardAndPortSelection) => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
boards: Board[];
|
||||
ports: string[];
|
||||
selection: BoardAndPortSelection;
|
||||
}
|
||||
}
|
||||
|
||||
export class BoardAndPortSelectionComponent extends React.Component<BoardAndPortSelectionComponent.Props, BoardAndPortSelectionComponent.State> {
|
||||
|
||||
protected allBoards: Board[] = [];
|
||||
protected boardListComponent: BoardAndPortSelectionList | null;
|
||||
protected portListComponent: BoardAndPortSelectionList | null;
|
||||
|
||||
constructor(props: BoardAndPortSelectionComponent.Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
boards: [],
|
||||
ports: [],
|
||||
selection: {}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.searchAvailableBoards();
|
||||
this.setPorts();
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
if (this.boardListComponent) {
|
||||
this.boardListComponent.reset();
|
||||
}
|
||||
if (this.portListComponent) {
|
||||
this.portListComponent.reset();
|
||||
}
|
||||
this.setState({ selection: {} });
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <React.Fragment>
|
||||
<div className='body'>
|
||||
<div className='left container'>
|
||||
<div className='content'>
|
||||
<div className='title'>
|
||||
BOARDS
|
||||
</div>
|
||||
<div className='search'>
|
||||
<input type='search' placeholder='SEARCH BOARD' onChange={this.doFilter} />
|
||||
<i className='fa fa-search'></i>
|
||||
</div>
|
||||
<BoardAndPortSelectionList
|
||||
ref={ref => { this.boardListComponent = ref }}
|
||||
type='boards'
|
||||
onSelect={this.doSelect}
|
||||
list={this.state.boards.map<BoardAndPortSelection>(board => ({ board }))} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='right container'>
|
||||
<div className='content'>
|
||||
<div className='title'>
|
||||
PORTS
|
||||
</div>
|
||||
{
|
||||
this.state.ports.length ?
|
||||
<BoardAndPortSelectionList
|
||||
ref={ref => { this.portListComponent = ref }}
|
||||
type='ports'
|
||||
onSelect={this.doSelect}
|
||||
list={this.state.ports.map<BoardAndPortSelection>(port => ({ port }))} /> : 'loading ports...'
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
protected sort(items: Board[]): Board[] {
|
||||
return items.sort((a, b) => {
|
||||
if (a.name < b.name) {
|
||||
return -1;
|
||||
} else if (a.name === b.name) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected readonly doSelect = (boardAndPortSelection: BoardAndPortSelection) => {
|
||||
const selection = this.state.selection;
|
||||
if (boardAndPortSelection.board) {
|
||||
selection.board = boardAndPortSelection.board;
|
||||
}
|
||||
if (boardAndPortSelection.port) {
|
||||
selection.port = boardAndPortSelection.port;
|
||||
}
|
||||
this.setState({ selection });
|
||||
this.props.onSelect(this.state.selection);
|
||||
}
|
||||
|
||||
protected readonly doFilter = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const boards = this.allBoards.filter(board => board.name.toLowerCase().indexOf(event.target.value.toLowerCase()) >= 0);
|
||||
this.setState({ boards })
|
||||
}
|
||||
|
||||
protected async searchAvailableBoards() {
|
||||
const boardPkg = await this.props.boardsService.search({});
|
||||
const boards = [].concat.apply([], boardPkg.items.map<Board[]>(item => item.boards)) as Board[];
|
||||
this.allBoards = this.sort(boards);
|
||||
this.setState({ boards: this.allBoards });
|
||||
}
|
||||
|
||||
protected async setPorts() {
|
||||
const ports: string[] = [];
|
||||
const { boards } = await this.props.boardsService.getAttachedBoards();
|
||||
boards.forEach(board => {
|
||||
if (AttachedSerialBoard.is(board)) {
|
||||
ports.push(board.port);
|
||||
}
|
||||
});
|
||||
this.setState({ ports });
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class SelectBoardDialogWidget extends ReactWidget {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
@inject(BoardsNotificationService)
|
||||
protected readonly boardsNotificationService: BoardsNotificationService;
|
||||
|
||||
protected readonly onChangedEmitter = new Emitter<BoardAndPortSelection>();
|
||||
protected boardAndPortSelectionComponent: BoardAndPortSelectionComponent | null;
|
||||
protected attachedBoards: Promise<{ boards: Board[] }>;
|
||||
|
||||
boardAndPort: BoardAndPortSelection = {};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.id = 'select-board-dialog';
|
||||
|
||||
this.toDispose.push(this.onChangedEmitter);
|
||||
}
|
||||
|
||||
get onChanged(): Event<BoardAndPortSelection> {
|
||||
return this.onChangedEmitter.event;
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
if (this.boardAndPortSelectionComponent) {
|
||||
this.boardAndPortSelectionComponent.reset();
|
||||
}
|
||||
this.boardAndPort = {};
|
||||
}
|
||||
|
||||
setAttachedBoards(attachedBoards: Promise<{ boards: Board[] }>): void {
|
||||
this.attachedBoards = attachedBoards;
|
||||
}
|
||||
|
||||
protected fireChanged(boardAndPort: BoardAndPortSelection): void {
|
||||
this.onChangedEmitter.fire(boardAndPort);
|
||||
}
|
||||
|
||||
protected render(): React.ReactNode {
|
||||
let content: React.ReactNode;
|
||||
|
||||
const boardsServiceDelegate = this.boardsService;
|
||||
const attachedBoards = this.attachedBoards;
|
||||
const boardsService: BoardsService = {
|
||||
getAttachedBoards: () => attachedBoards,
|
||||
selectBoard: (board: Board) => boardsServiceDelegate.selectBoard(board),
|
||||
getSelectBoard: () => boardsServiceDelegate.getSelectBoard(),
|
||||
search: (options: { query?: string }) => boardsServiceDelegate.search(options),
|
||||
install: async (item: BoardPackage) => {
|
||||
await boardsServiceDelegate.install(item);
|
||||
this.boardsNotificationService.notifyBoardsInstalled();
|
||||
}
|
||||
}
|
||||
|
||||
content = <React.Fragment>
|
||||
<div className='selectBoardContainer'>
|
||||
<div className='head'>
|
||||
<div className='title'>
|
||||
Select Other Board & Port
|
||||
</div>
|
||||
<div className='text'>
|
||||
<p>Select both a BOARD and a PORT if you want to upload a sketch.</p>
|
||||
<p>If you only select a BOARD you will be able just to compile,</p>
|
||||
<p>but not to upload your sketch.</p>
|
||||
</div>
|
||||
</div>
|
||||
<BoardAndPortSelectionComponent
|
||||
ref={ref => this.boardAndPortSelectionComponent = ref}
|
||||
boardsService={boardsService}
|
||||
onSelect={this.onSelect} />
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
protected readonly onSelect = (selection: BoardAndPortSelection) => { this.doOnSelect(selection) };
|
||||
protected doOnSelect(selection: BoardAndPortSelection) {
|
||||
this.boardAndPort = selection;
|
||||
this.fireChanged(this.boardAndPort);
|
||||
}
|
||||
}
|
111
arduino-ide-extension/src/browser/boards/select-board-dialog.ts
Normal file
111
arduino-ide-extension/src/browser/boards/select-board-dialog.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { AbstractDialog, DialogProps, Widget, Panel, DialogError } from '@theia/core/lib/browser';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { SelectBoardDialogWidget, BoardAndPortSelection } from './select-board-dialog-widget';
|
||||
import { Message } from '@phosphor/messaging';
|
||||
import { Disposable } from '@theia/core';
|
||||
import { Board, BoardsService, AttachedSerialBoard } from '../../common/protocol/boards-service';
|
||||
|
||||
@injectable()
|
||||
export class SelectBoardDialogProps extends DialogProps {
|
||||
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class SelectBoardDialog extends AbstractDialog<BoardAndPortSelection> {
|
||||
|
||||
protected readonly dialogPanel: Panel;
|
||||
protected attachedBoards: Board[];
|
||||
|
||||
constructor(
|
||||
@inject(SelectBoardDialogProps) protected readonly props: SelectBoardDialogProps,
|
||||
@inject(SelectBoardDialogWidget) protected readonly widget: SelectBoardDialogWidget,
|
||||
@inject(BoardsService) protected readonly boardService: BoardsService
|
||||
) {
|
||||
super({ title: props.title });
|
||||
|
||||
this.dialogPanel = new Panel();
|
||||
this.dialogPanel.addWidget(this.widget);
|
||||
|
||||
this.toDispose.push(this.widget.onChanged(() => this.update()));
|
||||
this.toDispose.push(this.dialogPanel);
|
||||
|
||||
this.attachedBoards = [];
|
||||
this.init();
|
||||
|
||||
this.appendCloseButton('CANCEL');
|
||||
this.appendAcceptButton('OK');
|
||||
}
|
||||
|
||||
protected init() {
|
||||
const boards = this.boardService.getAttachedBoards();
|
||||
boards.then(b => this.attachedBoards = b.boards);
|
||||
this.widget.setAttachedBoards(boards);
|
||||
}
|
||||
|
||||
protected onAfterAttach(msg: Message): void {
|
||||
Widget.attach(this.dialogPanel, this.contentNode);
|
||||
|
||||
this.toDisposeOnDetach.push(Disposable.create(() => {
|
||||
Widget.detach(this.dialogPanel);
|
||||
}))
|
||||
|
||||
super.onAfterAttach(msg);
|
||||
this.update();
|
||||
}
|
||||
|
||||
protected onUpdateRequest(msg: Message) {
|
||||
super.onUpdateRequest(msg);
|
||||
this.widget.update();
|
||||
}
|
||||
|
||||
protected onActivateRequest(msg: Message): void {
|
||||
this.widget.activate();
|
||||
}
|
||||
|
||||
protected handleEnter(event: KeyboardEvent): boolean | void {
|
||||
if (event.target instanceof HTMLTextAreaElement) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected isValid(value: BoardAndPortSelection): DialogError {
|
||||
if (!value.board) {
|
||||
if (value.port) {
|
||||
return 'Please pick the Board connected to the Port you have selected';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
get value(): BoardAndPortSelection {
|
||||
const boardAndPortSelection = this.widget.boardAndPort;
|
||||
if (this.attachedBoards.length) {
|
||||
boardAndPortSelection.board = this.attachedBoards.find(b => {
|
||||
const isAttachedBoard = !!boardAndPortSelection.board &&
|
||||
b.name === boardAndPortSelection.board.name &&
|
||||
b.fqbn === boardAndPortSelection.board.fqbn;
|
||||
if (boardAndPortSelection.port) {
|
||||
return isAttachedBoard &&
|
||||
AttachedSerialBoard.is(b) &&
|
||||
b.port === boardAndPortSelection.port;
|
||||
} else {
|
||||
return isAttachedBoard;
|
||||
}
|
||||
|
||||
})
|
||||
|| boardAndPortSelection.board;
|
||||
}
|
||||
return boardAndPortSelection;
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.widget.reset();
|
||||
super.close();
|
||||
}
|
||||
|
||||
onAfterDetach(msg: Message) {
|
||||
this.widget.reset();
|
||||
super.onAfterDetach(msg);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { Board } from '../../common/protocol/boards-service';
|
||||
|
||||
export namespace BoardsToolBarItem {
|
||||
export interface Props {
|
||||
readonly onNoBoardsInstalled: () => void;
|
||||
readonly onUnknownBoard: (board: Board) => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
showOpenButton: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export class BoardsToolBarItem extends React.Component<BoardsToolBarItem.Props, BoardsToolBarItem.State> {
|
||||
|
||||
constructor(props: BoardsToolBarItem.Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showOpenButton: false
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
|
||||
return <React.Fragment>
|
||||
<div className='arduino-boards-toolbar-item-container' onClick={() => this.setState({ showOpenButton: !this.state.showOpenButton })}>
|
||||
<div className='arduino-boards-toolbar-item'>
|
||||
<div className='inner-container'>
|
||||
<div className='label'>Hallo</div>
|
||||
{this.state.showOpenButton ? <div className='arduino-open-boards-button'> OPEN BOARDS DIALOG </div> : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>;
|
||||
}
|
||||
}
|
@ -29,14 +29,14 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
|
||||
content = [ <option key="loading" value="0">{label}</option> ];
|
||||
}
|
||||
|
||||
return <div className={`${ARDUINO_TOOLBAR_ITEM_CLASS} item ${ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}`}>
|
||||
<select disabled={!this.state.boards}
|
||||
return <div key='arduino-connected-boards' className={`${ARDUINO_TOOLBAR_ITEM_CLASS} item ${ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}`}>
|
||||
<select key='arduino-connected-boards-select' disabled={!this.state.boards}
|
||||
onChange={this.onBoardSelect.bind(this)}
|
||||
value={this.state.selection}>
|
||||
<optgroup label="Attached boards">
|
||||
<optgroup key='arduino-connected-boards-select-opt-group' label="Attached boards">
|
||||
{ content }
|
||||
</optgroup>
|
||||
<optgroup label="_________">
|
||||
<optgroup label="_________" key='arduino-connected-boards-select-opt-group2'>
|
||||
{ !!this.state.otherBoard && <option value="selected-other" key="selected-other">{this.state.otherBoard.name} (not attached)</option> }
|
||||
<option value="select-other" key="select-other">Select other Board</option>
|
||||
</optgroup>
|
||||
|
@ -86,7 +86,7 @@ is not optimized for dense, information rich UIs.
|
||||
--theia-brand-color3: var(--md-blue-100);
|
||||
/* Secondary Brand colors */
|
||||
--theia-secondary-brand-color0: var(--md-grey-700);
|
||||
--theia-secondary-brand-color1: var(--md-grey-500);
|
||||
--theia-secondary-brand-color1: #b5c8c9;
|
||||
--theia-secondary-brand-color2: var(--md-grey-300);
|
||||
--theia-secondary-brand-color3: var(--md-grey-100);
|
||||
/* Accent colors (dark to bright): Use these to create contrast to layout colors. */
|
||||
@ -147,7 +147,7 @@ is not optimized for dense, information rich UIs.
|
||||
/* Menu */
|
||||
--theia-menu-color0: var(--theia-layout-color3);
|
||||
--theia-menu-color1: var(--theia-layout-color0);
|
||||
--theia-menu-color2: var(--theia-layout-color3);
|
||||
--theia-menu-color2: #dae3e3;
|
||||
/* Statusbar */
|
||||
--theia-statusbar-color: var(--theia-arduino-light);
|
||||
--theia-statusBar-font-color: var(--theia-inverse-ui-font-color0);
|
||||
@ -157,7 +157,7 @@ is not optimized for dense, information rich UIs.
|
||||
--theia-ui-button-color-hover: var(--theia-arduino-light1);
|
||||
--theia-ui-button-font-color: var(--theia-inverse-ui-font-color0);
|
||||
--theia-ui-button-color-secondary: var(--theia-secondary-brand-color1);
|
||||
--theia-ui-button-color-secondary-hover: var(--theia-secondary-brand-color0);
|
||||
--theia-ui-button-color-secondary-hover: var(--theia-menu-color2);
|
||||
--theia-ui-button-font-color-secondary: var(--theia-inverse-ui-font-color0);
|
||||
--theia-ui-button-color-disabled: var(--theia-accent-color3);
|
||||
--theia-ui-button-font-color-disabled: var(--theia-ui-font-color2);
|
||||
@ -169,8 +169,8 @@ is not optimized for dense, information rich UIs.
|
||||
/* Dialogs */
|
||||
--theia-ui-dialog-header-color: var(--theia-arduino-light);
|
||||
--theia-ui-dialog-header-font-color: var(--theia-inverse-ui-font-color0);
|
||||
--theia-ui-dialog-color: var(--theia-layout-color0);
|
||||
--theia-ui-dialog-font-color: var(--theia-ui-font-color1);
|
||||
--theia-ui-dialog-color: rgb(236, 241, 241);
|
||||
--theia-ui-dialog-font-color: black;
|
||||
/* Variables */
|
||||
--theia-variable-name-color: #9B46B0;
|
||||
--theia-variable-value-color: rgba(108, 108, 108, 0.8);
|
||||
|
152
arduino-ide-extension/src/browser/style/board-select-dialog.css
Normal file
152
arduino-ide-extension/src/browser/style/board-select-dialog.css
Normal file
@ -0,0 +1,152 @@
|
||||
div#select-board-dialog {
|
||||
margin: 5px 20px 50px 20px;
|
||||
}
|
||||
|
||||
div#select-board-dialog .selectBoardContainer .body {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div#select-board-dialog .selectBoardContainer .head {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
div#select-board-dialog .selectBoardContainer .head .title {
|
||||
font-weight: 400;
|
||||
letter-spacing: .02em;
|
||||
font-size: 1.2em;
|
||||
color: #00979d;
|
||||
margin: 17px 0;
|
||||
}
|
||||
|
||||
div#select-board-dialog .selectBoardContainer .head .text {
|
||||
margin-bottom: 21px;
|
||||
}
|
||||
|
||||
div#select-board-dialog .selectBoardContainer .body .list .item.selected {
|
||||
background: var(--theia-ui-button-color-secondary-hover);
|
||||
}
|
||||
|
||||
div#select-board-dialog .selectBoardContainer .body .list .item.selected i{
|
||||
color: var(--theia-arduino-light);
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .search input,
|
||||
#select-board-dialog .selectBoardContainer .body .boards.list,
|
||||
#select-board-dialog .selectBoardContainer .body .search,
|
||||
#select-board-dialog .selectBoardContainer .body .ports.list {
|
||||
background: white;
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .search input {
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 37px;
|
||||
padding: 10px 8px;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
display: flex;
|
||||
color: var(--theia-content-font-color0);
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .search input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .left.container .content {
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .right.container .content {
|
||||
margin: 0 0 0 5px;
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .container .content .title{
|
||||
color: #7f8c8d;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .list .item {
|
||||
padding: 10px 5px 10px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
#select-board-dialog .selectBoardContainer .body .list .item:hover {
|
||||
background: var(--theia-ui-button-color-secondary-hover);
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .list {
|
||||
max-height: 265px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .search {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.p-Widget.dialogOverlay .dialogBlock {
|
||||
width: 740px;
|
||||
}
|
||||
|
||||
button.theia-button {
|
||||
height: 31px;
|
||||
}
|
||||
|
||||
button.theia-button.secondary {
|
||||
background-color: #b5c8c9;
|
||||
color: #000;
|
||||
box-shadow: 0 4px #95a5a6;
|
||||
}
|
||||
|
||||
button.theia-button.main {
|
||||
color: #fff;
|
||||
background-color: #00979c;
|
||||
box-shadow: 0 4px #005c5f;
|
||||
}
|
||||
|
||||
.dialogControl {
|
||||
margin: 0 20px 30px 0;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item-container {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item-container .arduino-boards-toolbar-item .inner-container {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item-container .arduino-boards-toolbar-item .inner-container .notAttached {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
color: red;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item .label {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item {
|
||||
background: white;
|
||||
height: 18px;
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
@import './list-widget.css';
|
||||
@import './select-board-dialog.css';
|
||||
@import './main.css';
|
||||
@import './board-select-dialog.css';
|
||||
@import './main.css';
|
||||
|
@ -53,24 +53,10 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item .label {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.arduino-open-boards-button {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item {
|
||||
background: white;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.arduino-tool-item.item.connected-boards select {
|
||||
line-height: var(--theia-content-line-height);
|
||||
|
@ -1,13 +0,0 @@
|
||||
|
||||
.select-board-dialog {
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.select-board-dialog input {
|
||||
width: calc(100% - 8px);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.select-board-dialog select {
|
||||
width: 100%;
|
||||
}
|
@ -4,8 +4,8 @@ export const BoardsServicePath = '/services/boards-service';
|
||||
export const BoardsService = Symbol('BoardsService');
|
||||
export interface BoardsService {
|
||||
getAttachedBoards(): Promise<{ boards: Board[] }>;
|
||||
selectBoard(board: Board): Promise<void>;
|
||||
getSelectBoard(): Promise<Board | undefined>;
|
||||
selectBoard(board: Board | AttachedSerialBoard | AttachedNetworkBoard): Promise<void>;
|
||||
getSelectBoard(): Promise<Board | AttachedSerialBoard | AttachedNetworkBoard | undefined>;
|
||||
|
||||
search(options: { query?: string }): Promise<{ items: BoardPackage[] }>;
|
||||
install(item: BoardPackage): Promise<void>;
|
||||
@ -23,31 +23,29 @@ export interface Board {
|
||||
|
||||
export interface AttachedSerialBoard extends Board {
|
||||
port: string;
|
||||
serialNumber: string;
|
||||
productID: string;
|
||||
vendorID: string;
|
||||
type: 'serial';
|
||||
serialNumber?: string;
|
||||
productID?: string;
|
||||
vendorID?: string;
|
||||
}
|
||||
|
||||
export namespace AttachedSerialBoard {
|
||||
export function is(b: Board): b is AttachedSerialBoard {
|
||||
return 'port' in b
|
||||
&& 'serialNumber' in b
|
||||
&& 'productID' in b
|
||||
&& 'vendorID' in b;
|
||||
return 'type' in b && (b as Board & { type: any }).type === 'serial' &&
|
||||
'port' in b && !!(b as Board & { port: any }).port && typeof (b as Board & { port: any }).port === 'string';
|
||||
}
|
||||
}
|
||||
|
||||
export interface AttachedNetworkBoard extends Board {
|
||||
info: string;
|
||||
address: string;
|
||||
info?: string;
|
||||
address?: string;
|
||||
port: number;
|
||||
type: 'network';
|
||||
}
|
||||
|
||||
export namespace AttachedNetworkBoard {
|
||||
export function is(b: Board): b is AttachedNetworkBoard {
|
||||
return 'name' in b
|
||||
&& 'info' in b
|
||||
&& 'address' in b
|
||||
&& 'port' in b;
|
||||
return 'type' in b && (b as Board & { type: any }).type === 'network' &&
|
||||
'port' in b && !!(b as Board & { port: any }).port && typeof (b as Board & { port: any }).port === 'number';
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
name: b.getName() || "unknown",
|
||||
fqbn: b.getFqbn(),
|
||||
port: b.getPort(),
|
||||
type: 'serial',
|
||||
serialNumber: b.getSerialnumber(),
|
||||
productID: b.getProductid(),
|
||||
vendorID: b.getVendorid()
|
||||
@ -41,6 +42,7 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
address: b.getAddress(),
|
||||
info: b.getInfo(),
|
||||
port: b.getPort(),
|
||||
type: 'network'
|
||||
});
|
||||
|
||||
return { boards: serialBoards.concat(networkBoards) };
|
||||
|
Loading…
x
Reference in New Issue
Block a user