From 76d0f5a464fbe9a132f729ec0aea406e00e0a649 Mon Sep 17 00:00:00 2001 From: jbicker Date: Fri, 26 Jul 2019 09:57:42 +0200 Subject: [PATCH 01/14] Implemented the Widget Re-introduced bottom panel tabs Signed-off-by: jbicker --- arduino-ide-extension/package.json | 2 + .../browser/arduino-frontend-contribution.tsx | 10 + .../src/browser/arduino-frontend-module.ts | 19 +- .../src/browser/monitor/monitor-connection.ts | 60 +++ .../src/browser/monitor/monitor-model.ts | 31 ++ .../monitor/monitor-view-contribution.tsx | 120 ++++++ .../src/browser/monitor/monitor-widget.tsx | 346 ++++++++++++++++++ .../src/browser/style/board-select-dialog.css | 1 + .../src/browser/style/index.css | 3 +- .../src/browser/style/serial-monitor.css | 86 +++++ .../style/silent-bottom-panel-tabs.css | 3 - .../src/common/protocol/monitor-service.ts | 1 + .../src/node/monitor/monitor-service-impl.ts | 11 +- yarn.lock | 219 ++++++++++- 14 files changed, 894 insertions(+), 18 deletions(-) create mode 100644 arduino-ide-extension/src/browser/monitor/monitor-connection.ts create mode 100644 arduino-ide-extension/src/browser/monitor/monitor-model.ts create mode 100644 arduino-ide-extension/src/browser/monitor/monitor-view-contribution.tsx create mode 100644 arduino-ide-extension/src/browser/monitor/monitor-widget.tsx create mode 100644 arduino-ide-extension/src/browser/style/serial-monitor.css delete mode 100644 arduino-ide-extension/src/browser/style/silent-bottom-panel-tabs.css diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 861026a0..73788a6d 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -23,7 +23,9 @@ "@theia/search-in-workspace": "next", "@types/ps-tree": "^1.1.0", "@types/which": "^1.3.1", + "@types/react-select": "^3.0.0", "css-element-queries": "^1.2.0", + "react-select": "^3.0.4", "p-queue": "^5.0.0", "ps-tree": "^1.2.0", "tree-kill": "^1.2.1", diff --git a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx index 9a778948..2568f287 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx +++ b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx @@ -47,6 +47,7 @@ import { BoardsToolBarItem } from './boards/boards-toolbar-item'; import { BoardsConfig } from './boards/boards-config'; import { MonitorService } from '../common/protocol/monitor-service'; import { ConfigService } from '../common/protocol/config-service'; +import { MonitorConnection } from './monitor/monitor-connection'; export namespace ArduinoMenus { export const SKETCH = [...MAIN_MENU_BAR, '3_sketch']; @@ -143,6 +144,8 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C @inject(ConfigService) protected readonly configService: ConfigService; + @inject(MonitorConnection) + protected readonly monitorConnection: MonitorConnection; protected boardsToolbarItem: BoardsToolBarItem | null; protected wsSketchCount: number = 0; @@ -244,6 +247,9 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C return; } + const connectionConfig = this.monitorConnection.connectionConfig; + await this.monitorConnection.disconnect(); + try { const { boardsConfig } = this.boardsServiceClient; if (!boardsConfig || !boardsConfig.selectedBoard) { @@ -256,6 +262,10 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C await this.coreService.upload({ uri: uri.toString(), board: boardsConfig.selectedBoard, port: selectedPort }); } catch (e) { await this.messageService.error(e.toString()); + } finally { + if (connectionConfig) { + await this.monitorConnection.connect(connectionConfig); + } } } }); diff --git a/arduino-ide-extension/src/browser/arduino-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-frontend-module.ts index 4e74e2c9..645c96d0 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-frontend-module.ts @@ -57,12 +57,12 @@ import { BoardItemRenderer } from './boards/boards-item-renderer'; import { MonitorServiceClientImpl } from './monitor/monitor-service-client-impl'; import { MonitorServicePath, MonitorService, MonitorServiceClient } from '../common/protocol/monitor-service'; import { ConfigService, ConfigServicePath } from '../common/protocol/config-service'; +import { MonitorWidget } from './monitor/monitor-widget'; +import { MonitorViewContribution } from './monitor/monitor-view-contribution'; +import { MonitorConnection } from './monitor/monitor-connection'; +import { MonitorModel } from './monitor/monitor-model'; const ElementQueries = require('css-element-queries/src/ElementQueries'); -if (!ARDUINO_PRO_MODE) { - require('../../src/browser/style/silent-bottom-panel-tabs.css'); -} - export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind) => { ElementQueries.listen(); ElementQueries.init(); @@ -155,12 +155,23 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un return workspaceServiceExt; }); + // Serial Monitor + bind(MonitorModel).toSelf().inSingletonScope(); + bind(MonitorWidget).toSelf(); + bindViewContribution(bind, MonitorViewContribution); + bind(TabBarToolbarContribution).toService(MonitorViewContribution); + bind(WidgetFactory).toDynamicValue(context => ({ + id: MonitorWidget.ID, + createWidget: () => context.container.get(MonitorWidget) + })); // Frontend binding for the monitor service. bind(MonitorService).toDynamicValue(context => { const connection = context.container.get(WebSocketConnectionProvider); const client = context.container.get(MonitorServiceClientImpl); return connection.createProxy(MonitorServicePath, client); }).inSingletonScope(); + // MonitorConnection + bind(MonitorConnection).toSelf().inSingletonScope(); // Monitor service client to receive and delegate notifications from the backend. bind(MonitorServiceClientImpl).toSelf().inSingletonScope(); bind(MonitorServiceClient).toDynamicValue(context => { diff --git a/arduino-ide-extension/src/browser/monitor/monitor-connection.ts b/arduino-ide-extension/src/browser/monitor/monitor-connection.ts new file mode 100644 index 00000000..ba0ec3eb --- /dev/null +++ b/arduino-ide-extension/src/browser/monitor/monitor-connection.ts @@ -0,0 +1,60 @@ +import { injectable, inject } from "inversify"; +import { MonitorService, ConnectionConfig } from "../../common/protocol/monitor-service"; +import { Emitter, Event } from "@theia/core"; + +@injectable() +export class MonitorConnection { + + @inject(MonitorService) + protected readonly monitorService: MonitorService; + + protected _connectionId: string | undefined; + + protected _connectionConfig: ConnectionConfig; + + protected readonly onConnectionChangedEmitter = new Emitter(); + readonly onConnectionChanged: Event = this.onConnectionChangedEmitter.event; + + get connectionId(): string | undefined { + return this._connectionId; + } + + set connectionId(cid: string | undefined) { + this._connectionId = cid; + } + + get connectionConfig(): ConnectionConfig { + return this._connectionConfig; + } + + async connect(config: ConnectionConfig): Promise { + if (this._connectionId) { + await this.disconnect(); + } + const { connectionId } = await this.monitorService.connect(config); + this._connectionId = connectionId; + this._connectionConfig = config; + + this.onConnectionChangedEmitter.fire(this._connectionId); + + return connectionId; + } + + async disconnect(): Promise { + let result = true; + const connections = await this.monitorService.getConnectionIds(); + if (this._connectionId && connections.findIndex(id => id === this._connectionId) >= 0) { + console.log('>>> Disposing existing monitor connection before establishing a new one...'); + result = await this.monitorService.disconnect(this._connectionId); + if (!result) { + // TODO: better!!! + console.error(`Could not close connection: ${this._connectionId}. Check the backend logs.`); + } else { + console.log(`<<< Disposed ${this._connectionId} connection.`); + this._connectionId = undefined; + } + this.onConnectionChangedEmitter.fire(this._connectionId); + } + return result; + } +} \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/monitor/monitor-model.ts b/arduino-ide-extension/src/browser/monitor/monitor-model.ts new file mode 100644 index 00000000..960d6301 --- /dev/null +++ b/arduino-ide-extension/src/browser/monitor/monitor-model.ts @@ -0,0 +1,31 @@ +import { injectable } from "inversify"; +import { Emitter } from "@theia/core"; + +@injectable() +export class MonitorModel { + + protected readonly onChangeEmitter = new Emitter(); + + readonly onChange = this.onChangeEmitter.event; + + protected _autoscroll: boolean = true; + protected _timestamp: boolean = false; + + get autoscroll(): boolean { + return this._autoscroll; + } + + get timestamp(): boolean { + return this._timestamp; + } + + toggleAutoscroll(): void { + this._autoscroll = !this._autoscroll; + this.onChangeEmitter.fire(undefined); + } + + toggleTimestamp(): void { + this._timestamp = !this._timestamp; + this.onChangeEmitter.fire(undefined); + } +} \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/monitor/monitor-view-contribution.tsx b/arduino-ide-extension/src/browser/monitor/monitor-view-contribution.tsx new file mode 100644 index 00000000..b4bc7dc7 --- /dev/null +++ b/arduino-ide-extension/src/browser/monitor/monitor-view-contribution.tsx @@ -0,0 +1,120 @@ +import * as React from 'react'; +import { injectable, inject } from "inversify"; +import { AbstractViewContribution } from "@theia/core/lib/browser"; +import { MonitorWidget } from "./monitor-widget"; +import { MenuModelRegistry, Command, CommandRegistry } from "@theia/core"; +import { ArduinoMenus } from "../arduino-frontend-contribution"; +import { TabBarToolbarContribution, TabBarToolbarRegistry } from "@theia/core/lib/browser/shell/tab-bar-toolbar"; +import { MonitorModel } from './monitor-model'; + +export namespace SerialMonitor { + export namespace Commands { + export const AUTOSCROLL: Command = { + id: 'serial-monitor-autoscroll', + label: 'Autoscroll' + } + export const TIMESTAMP: Command = { + id: 'serial-monitor-timestamp', + label: 'Timestamp' + } + export const CLEAR_OUTPUT: Command = { + id: 'serial-monitor-clear-output', + label: 'Clear Output', + iconClass: 'clear-all' + } + } +} + +@injectable() +export class MonitorViewContribution extends AbstractViewContribution implements TabBarToolbarContribution { + + static readonly OPEN_SERIAL_MONITOR = MonitorWidget.ID + ':toggle'; + + @inject(MonitorModel) protected readonly model: MonitorModel; + + constructor() { + super({ + widgetId: MonitorWidget.ID, + widgetName: 'Serial Monitor', + defaultWidgetOptions: { + area: 'bottom' + }, + toggleCommandId: MonitorViewContribution.OPEN_SERIAL_MONITOR, + toggleKeybinding: 'ctrl+shift+m' + }) + } + + registerMenus(menus: MenuModelRegistry): void { + if (this.toggleCommand) { + menus.registerMenuAction(ArduinoMenus.TOOLS, { + commandId: this.toggleCommand.id, + label: 'Serial Monitor' + }); + } + } + + async registerToolbarItems(registry: TabBarToolbarRegistry) { + registry.registerItem({ + id: 'monitor-autoscroll', + tooltip: 'Toggle Autoscroll', + render: () => this.renderAutoScrollButton(), + isVisible: widget => widget instanceof MonitorWidget, + onDidChange: this.model.onChange + }); + registry.registerItem({ + id: 'monitor-timestamp', + tooltip: 'Toggle Timestamp', + render: () => this.renderTimestampButton(), + isVisible: widget => widget instanceof MonitorWidget, + onDidChange: this.model.onChange + }); + registry.registerItem({ + id: SerialMonitor.Commands.CLEAR_OUTPUT.id, + command: SerialMonitor.Commands.CLEAR_OUTPUT.id, + tooltip: 'Clear Output' + }); + } + + registerCommands(commands: CommandRegistry): void { + super.registerCommands(commands); + commands.registerCommand(SerialMonitor.Commands.CLEAR_OUTPUT, { + isEnabled: widget => widget instanceof MonitorWidget, + isVisible: widget => widget instanceof MonitorWidget, + execute: widget => { + if (widget instanceof MonitorWidget) { + widget.clear(); + } + } + }); + } + + protected renderAutoScrollButton(): React.ReactNode { + + return +
+
; + } + + protected readonly toggleAutoScroll = () => this.doToggleAutoScroll(); + protected async doToggleAutoScroll() { + this.model.toggleAutoscroll(); + } + + protected renderTimestampButton(): React.ReactNode { + + return +
+
; + } + + protected readonly toggleTimestamp = () => this.doToggleTimestamp(); + protected async doToggleTimestamp() { + this.model.toggleTimestamp(); + } +} \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx new file mode 100644 index 00000000..f8e83815 --- /dev/null +++ b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx @@ -0,0 +1,346 @@ +import { ReactWidget, Message } from "@theia/core/lib/browser"; +import { postConstruct, injectable, inject } from "inversify"; +import * as React from 'react'; +import Select, { components } from 'react-select'; +import { Styles } from "react-select/src/styles"; +import { ThemeConfig } from "react-select/src/theme"; +import { OptionsType } from "react-select/src/types"; +import { MonitorServiceClientImpl } from "./monitor-service-client-impl"; +import { MessageService } from "@theia/core"; +import { ConnectionConfig, MonitorService } from "../../common/protocol/monitor-service"; +import { MonitorConnection } from "./monitor-connection"; +import { BoardsServiceClientImpl } from "../boards/boards-service-client-impl"; +import { AttachedSerialBoard, BoardsService, Board } from "../../common/protocol/boards-service"; +import { BoardsConfig } from "../boards/boards-config"; +import { MonitorModel } from "./monitor-model"; + +export namespace SerialMonitorSendField { + export interface Props { + onSend: (text: string) => void + } + + export interface State { + value: string; + } +} + +export class SerialMonitorSendField extends React.Component { + constructor(props: SerialMonitorSendField.Props) { + super(props); + this.state = { value: '' }; + + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + + render() { + return +
+ + +
+
+ } + + protected handleChange(event: React.ChangeEvent) { + this.setState({ value: event.target.value }); + } + + protected handleSubmit(event: React.FormEvent) { + this.props.onSend(this.state.value); + event.preventDefault(); + } +} + +export namespace SerialMonitorOutput { + export interface Props { + lines: string[]; + model: MonitorModel; + } +} + +export class SerialMonitorOutput extends React.Component { + protected theEnd: HTMLDivElement | null; + + render() { + let result = ''; + + const style: React.CSSProperties = { + whiteSpace: 'pre', + fontFamily: 'monospace', + }; + + for (let text of this.props.lines) { + result += text; + } + if (result.length === 0) { + result = ''; + } + return +
{result}
+
{ this.theEnd = el; }}> +
+
; + } + + protected scrollToBottom() { + if (this.theEnd) { + this.theEnd.scrollIntoView(); + } + } + + componentDidMount() { + if (this.props.model.autoscroll) { + this.scrollToBottom(); + } + } + + componentDidUpdate() { + if (this.props.model.autoscroll) { + this.scrollToBottom(); + } + } +} + +export interface SelectOption { + label: string; + value: string | number; +} + +@injectable() +export class MonitorWidget extends ReactWidget { + + static readonly ID = 'serial-monitor'; + + protected lines: string[]; + protected tempData: string; + protected _baudRate: number; + protected _lineEnding: string; + + constructor( + @inject(MonitorServiceClientImpl) protected readonly serviceClient: MonitorServiceClientImpl, + @inject(MonitorConnection) protected readonly connection: MonitorConnection, + @inject(MonitorService) protected readonly monitorService: MonitorService, + @inject(BoardsServiceClientImpl) protected readonly boardsServiceClient: BoardsServiceClientImpl, + @inject(MessageService) protected readonly messageService: MessageService, + @inject(BoardsService) protected readonly boardsService: BoardsService, + @inject(MonitorModel) protected readonly model: MonitorModel + ) { + super(); + + this.id = MonitorWidget.ID; + this.title.label = 'Serial Monitor'; + + this.lines = []; + this.tempData = ''; + this._lineEnding = '\n'; + + this.toDisposeOnDetach.push(serviceClient.onRead(({ data, connectionId }) => { + this.tempData += data; + if (this.tempData.endsWith('\n')) { + if (this.model.timestamp) { + const nu = new Date(); + this.tempData = `${nu.getHours()}:${nu.getMinutes()}:${nu.getSeconds()}.${nu.getMilliseconds()} -> ` + this.tempData; + } + this.lines.push(this.tempData); + this.tempData = ''; + this.update(); + } + })); + + // TODO onError + } + + @postConstruct() + protected init(): void { + this.update(); + } + + clear(): void { + this.lines = []; + this.update(); + } + + get baudRate(): number | undefined { + return this._baudRate; + } + + protected onAfterAttach(msg: Message) { + super.onAfterAttach(msg); + this.clear(); + this.connect(); + this.toDisposeOnDetach.push(this.boardsServiceClient.onBoardsChanged(async states => { + const currentConnectionConfig = this.connection.connectionConfig; + const connectedBoard = states.newState.boards + .filter(AttachedSerialBoard.is) + .find(board => { + const potentiallyConnected = currentConnectionConfig && currentConnectionConfig.board; + if (AttachedSerialBoard.is(potentiallyConnected)) { + return Board.equals(board, potentiallyConnected) && board.port === potentiallyConnected.port; + } + return false; + }); + if (!connectedBoard) { + this.close(); + } + })); + + this.toDisposeOnDetach.push(this.connection.onConnectionChanged(() => { + this.clear(); + })); + } + + protected onBeforeDetach(msg: Message) { + super.onBeforeDetach(msg); + this.connection.disconnect(); + } + + protected async connect() { + const config = await this.getConnectionConfig(); + if (config) { + this.connection.connect(config); + } + } + + protected async getConnectionConfig(): Promise { + const baudRate = this.baudRate; + const { boardsConfig } = this.boardsServiceClient; + const { selectedBoard, selectedPort } = boardsConfig; + if (!selectedBoard) { + this.messageService.warn('No boards selected.'); + return; + } + const { name } = selectedBoard; + if (!selectedPort) { + this.messageService.warn(`No ports selected for board: '${name}'.`); + return; + } + const attachedBoards = await this.boardsService.getAttachedBoards(); + const connectedBoard = attachedBoards.boards.filter(AttachedSerialBoard.is).find(board => BoardsConfig.Config.sameAs(boardsConfig, board)); + if (!connectedBoard) { + this.messageService.warn(`The selected '${name}' board is not connected on ${selectedPort}.`); + return; + } + + return { + baudRate, + board: selectedBoard, + port: selectedPort + } + } + + protected getLineEndings(): OptionsType { + return [ + { + label: 'No Line Ending', + value: '' + }, + { + label: 'Newline', + value: '\n' + }, + { + label: 'Carriage Return', + value: '\r' + }, + { + label: 'Both NL & CR', + value: '\r\n' + } + ] + } + + protected getBaudRates(): OptionsType { + const baudRates = [300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]; + return baudRates.map(baudRate => ({ label: baudRate + ' baud', value: baudRate })) + } + + protected render(): React.ReactNode { + const le = this.getLineEndings(); + const br = this.getBaudRates(); + return +
+
+
+ +
+
+ {this.renderSelectField('arduino-serial-monitor-line-endings', le, le[1], this.onChangeLineEnding)} + {this.renderSelectField('arduino-serial-monitor-baud-rates', br, br[4], this.onChangeBaudRate)} +
+
+
+ +
+
+
; + } + + protected readonly onSend = (value: string) => this.doSend(value); + protected async doSend(value: string) { + const { connectionId } = this.connection; + if (connectionId) { + this.monitorService.send(connectionId, value + this._lineEnding); + } + } + + protected readonly onChangeLineEnding = (le: SelectOption) => { + this._lineEnding = typeof le.value === 'string' ? le.value : '\n'; + } + + protected readonly onChangeBaudRate = (br: SelectOption) => { + this._baudRate = typeof br.value === 'number' ? br.value : 9600; + } + + protected renderSelectField(id: string, options: OptionsType, defaultVal: SelectOption, onChange: (v: SelectOption) => void): React.ReactNode { + const height = 25; + const selectStyles: Styles = { + control: (provided, state) => ({ + ...provided, + width: 200 + }), + dropdownIndicator: (p, s) => ({ + ...p, + padding: 0 + }), + indicatorSeparator: (p, s) => ({ + display: 'none' + }), + indicatorsContainer: (p, s) => ({ + padding: '0 5px' + }), + menu: (p, s) => ({ + ...p, + marginTop: 0 + }) + }; + const theme: ThemeConfig = theme => ({ + ...theme, + borderRadius: 0, + spacing: { + controlHeight: height, + baseUnit: 2, + menuGutter: 4 + } + }); + const DropdownIndicator = ( + props: React.Props + ) => { + return ( + + ); + }; + return + this.inputField = ref} + type='text' id='serial-monitor-send' + autoComplete='off' + value={this.state.value} + onChange={this.handleChange} /> diff --git a/arduino-ide-extension/src/browser/toolbar/arduino-toolbar.tsx b/arduino-ide-extension/src/browser/toolbar/arduino-toolbar.tsx index 31b7f113..2c6fd93e 100644 --- a/arduino-ide-extension/src/browser/toolbar/arduino-toolbar.tsx +++ b/arduino-ide-extension/src/browser/toolbar/arduino-toolbar.tsx @@ -47,7 +47,7 @@ export class ArduinoToolbarComponent extends React.Component{this.state.tooltip}; const items = [ - + {[...this.props.items].map(item => TabBarToolbarItem.is(item) ? this.renderItem(item) : item.render())} ] @@ -103,6 +103,7 @@ export class ArduinoToolbar extends ReactWidget { protected render(): React.ReactNode { return Date: Tue, 20 Aug 2019 10:41:17 +0200 Subject: [PATCH 12/14] Fixed wrong toppanel layout in electron Signed-off-by: jbicker --- arduino-ide-extension/src/browser/style/main.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arduino-ide-extension/src/browser/style/main.css b/arduino-ide-extension/src/browser/style/main.css index 134a2857..64b777eb 100644 --- a/arduino-ide-extension/src/browser/style/main.css +++ b/arduino-ide-extension/src/browser/style/main.css @@ -69,6 +69,7 @@ #arduino-toolbar-container { display: flex; + width: 100%; } .p-TabBar-toolbar.theia-arduino-toolbar { @@ -82,6 +83,7 @@ #theia-top-panel .p-TabBar-toolbar.theia-arduino-toolbar.left { min-width: 398px; + justify-content: flex-end; } .arduino-tool-item.item.connected-boards { From 2046c0bdee4ac8f596a48d943499d7142ff277ad Mon Sep 17 00:00:00 2001 From: jbicker Date: Tue, 20 Aug 2019 13:30:40 +0200 Subject: [PATCH 13/14] Continue monitoring with last connection if respective board is reconnected Signed-off-by: jbicker --- .../src/browser/monitor/monitor-widget.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx index 02838eea..eb39641f 100644 --- a/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx +++ b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx @@ -131,6 +131,8 @@ export class MonitorWidget extends ReactWidget implements StatefulWidget { protected widgetHeight: number; + protected continuePreviousConnection: boolean; + constructor( @inject(MonitorServiceClientImpl) protected readonly serviceClient: MonitorServiceClientImpl, @inject(MonitorConnection) protected readonly connection: MonitorConnection, @@ -204,13 +206,18 @@ export class MonitorWidget extends ReactWidget implements StatefulWidget { } return false; }); - if (!connectedBoard) { - this.close(); + if (connectedBoard && currentConnectionConfig) { + this.continuePreviousConnection = true; + this.connection.connect(currentConnectionConfig); } })); this.toDisposeOnDetach.push(this.connection.onConnectionChanged(() => { - this.clear(); + if (!this.continuePreviousConnection) { + this.clear(); + } else { + this.continuePreviousConnection = false; + } })); } From 79731304c16c9d2c8efb0887a2197587519201b1 Mon Sep 17 00:00:00 2001 From: jbicker Date: Tue, 20 Aug 2019 14:32:42 +0200 Subject: [PATCH 14/14] Reestablish monitor connection after reloading the window, reconnect after selecting another board Signed-off-by: jbicker --- .../src/browser/monitor/monitor-widget.tsx | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx index eb39641f..84425bff 100644 --- a/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx +++ b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx @@ -195,22 +195,29 @@ export class MonitorWidget extends ReactWidget implements StatefulWidget { super.onAfterAttach(msg); this.clear(); this.connect(); - this.toDisposeOnDetach.push(this.boardsServiceClient.onBoardsChanged(async states => { - const currentConnectionConfig = this.connection.connectionConfig; - const connectedBoard = states.newState.boards - .filter(AttachedSerialBoard.is) - .find(board => { - const potentiallyConnected = currentConnectionConfig && currentConnectionConfig.board; - if (AttachedSerialBoard.is(potentiallyConnected)) { - return Board.equals(board, potentiallyConnected) && board.port === potentiallyConnected.port; - } - return false; - }); - if (connectedBoard && currentConnectionConfig) { - this.continuePreviousConnection = true; - this.connection.connect(currentConnectionConfig); - } - })); + this.toDisposeOnDetach.push( + this.boardsServiceClient.onBoardsChanged(async states => { + const currentConnectionConfig = this.connection.connectionConfig; + const connectedBoard = states.newState.boards + .filter(AttachedSerialBoard.is) + .find(board => { + const potentiallyConnected = currentConnectionConfig && currentConnectionConfig.board; + if (AttachedSerialBoard.is(potentiallyConnected)) { + return Board.equals(board, potentiallyConnected) && board.port === potentiallyConnected.port; + } + return false; + }); + if (connectedBoard && currentConnectionConfig) { + this.continuePreviousConnection = true; + this.connection.connect(currentConnectionConfig); + } + }) + ); + this.toDisposeOnDetach.push( + this.boardsServiceClient.onBoardsConfigChanged(async boardConfig => { + this.connect(); + }) + ) this.toDisposeOnDetach.push(this.connection.onConnectionChanged(() => { if (!this.continuePreviousConnection) { @@ -255,7 +262,6 @@ export class MonitorWidget extends ReactWidget implements StatefulWidget { const attachedBoards = await this.boardsService.getAttachedBoards(); const connectedBoard = attachedBoards.boards.filter(AttachedSerialBoard.is).find(board => BoardsConfig.Config.sameAs(boardsConfig, board)); if (!connectedBoard) { - this.messageService.warn(`The selected '${name}' board is not connected on ${selectedPort}.`); return; }