mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-13 04:09:27 +00:00
ATL-374: Refactored the Output services.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { ArduinoDaemonClient } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoDaemonClientImpl implements ArduinoDaemonClient {
|
||||
|
||||
@inject(ILogger)
|
||||
protected readonly logger: ILogger;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
protected readonly onStartedEmitter = new Emitter<void>();
|
||||
protected readonly onStoppedEmitter = new Emitter<void>();
|
||||
protected _isRunning = false;
|
||||
|
||||
notifyStopped(): void {
|
||||
if (this._isRunning) {
|
||||
this._isRunning = false;
|
||||
this.onStoppedEmitter.fire();
|
||||
this.info('The CLI daemon process has stopped.');
|
||||
}
|
||||
}
|
||||
|
||||
notifyStarted(): void {
|
||||
if (!this._isRunning) {
|
||||
this._isRunning = true;
|
||||
this.onStartedEmitter.fire();
|
||||
this.info('The CLI daemon process has started.');
|
||||
}
|
||||
}
|
||||
|
||||
get onDaemonStarted(): Event<void> {
|
||||
return this.onStartedEmitter.event;
|
||||
}
|
||||
|
||||
get onDaemonStopped(): Event<void> {
|
||||
return this.onStoppedEmitter.event;
|
||||
}
|
||||
|
||||
get isRunning(): boolean {
|
||||
return this._isRunning;
|
||||
}
|
||||
|
||||
protected info(message: string): void {
|
||||
this.messageService.info(message, { timeout: 3000 });
|
||||
this.logger.info(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import { TerminalMenus } from '@theia/terminal/lib/browser/terminal-frontend-con
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import * as React from 'react';
|
||||
import { MainMenuManager } from '../common/main-menu-manager';
|
||||
import { BoardsService, BoardsServiceClient, CoreService, Port, SketchesService, ToolOutputServiceClient, ExecutableService } from '../common/protocol';
|
||||
import { BoardsService, CoreService, Port, SketchesService, ExecutableService } from '../common/protocol';
|
||||
import { ArduinoDaemon } from '../common/protocol/arduino-daemon';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
import { FileSystemExt } from '../common/protocol/filesystem-ext';
|
||||
@@ -32,7 +32,7 @@ import { ArduinoCommands } from './arduino-commands';
|
||||
import { BoardsConfig } from './boards/boards-config';
|
||||
import { BoardsConfigDialog } from './boards/boards-config-dialog';
|
||||
import { BoardsDataStore } from './boards/boards-data-store';
|
||||
import { BoardsServiceClientImpl } from './boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards/boards-service-provider';
|
||||
import { BoardsToolBarItem } from './boards/boards-toolbar-item';
|
||||
import { EditorMode } from './editor-mode';
|
||||
import { ArduinoMenus } from './menu/arduino-menus';
|
||||
@@ -44,6 +44,9 @@ import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted
|
||||
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
||||
|
||||
const debounce = require('lodash.debounce');
|
||||
import { OutputService } from '../common/protocol/output-service';
|
||||
import { NotificationCenter } from './notification-center';
|
||||
import { Settings } from './contributions/settings';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFrontendContribution implements FrontendApplicationContribution,
|
||||
@@ -61,15 +64,8 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
@inject(CoreService)
|
||||
protected readonly coreService: CoreService;
|
||||
|
||||
@inject(ToolOutputServiceClient)
|
||||
protected readonly toolOutputServiceClient: ToolOutputServiceClient;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
|
||||
// Unused but do not remove it. It's required by DI, otherwise `init` method is not called.
|
||||
@inject(BoardsServiceClient)
|
||||
protected readonly boardsServiceClient: BoardsServiceClient;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(SelectionService)
|
||||
protected readonly selectionService: SelectionService;
|
||||
@@ -151,6 +147,13 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
|
||||
@inject(ExecutableService)
|
||||
protected executableService: ExecutableService;
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected invalidConfigPopup: Promise<void | 'No' | 'Yes' | undefined> | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
@@ -198,6 +201,21 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
}
|
||||
}
|
||||
});
|
||||
this.notificationCenter.onConfigChanged(({ config }) => {
|
||||
if (config) {
|
||||
this.invalidConfigPopup = undefined;
|
||||
} else {
|
||||
if (!this.invalidConfigPopup) {
|
||||
this.invalidConfigPopup = this.messageService.error(`Your CLI configuration is invalid. Do you want to correct it now?`, 'No', 'Yes')
|
||||
.then(answer => {
|
||||
if (answer === 'Yes') {
|
||||
this.commandRegistry.executeCommand(Settings.Commands.OPEN_CLI_CONFIG.id)
|
||||
}
|
||||
this.invalidConfigPopup = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected startLanguageServer = debounce((fqbn: string, name: string | undefined) => this.doStartLanguageServer(fqbn, name));
|
||||
|
||||
@@ -8,17 +8,14 @@ import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging/w
|
||||
import { FrontendApplicationContribution, FrontendApplication as TheiaFrontendApplication } from '@theia/core/lib/browser/frontend-application'
|
||||
import { LibraryListWidget } from './library/library-list-widget';
|
||||
import { ArduinoFrontendContribution } from './arduino-frontend-contribution';
|
||||
import { LibraryServiceServer, LibraryServiceServerPath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service';
|
||||
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath } from '../common/protocol/boards-service';
|
||||
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
|
||||
import { SketchesServiceClientImpl } from '../common/protocol/sketches-service-client-impl';
|
||||
import { CoreService, CoreServicePath, CoreServiceClient } from '../common/protocol/core-service';
|
||||
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
||||
import { BoardsListWidget } from './boards/boards-list-widget';
|
||||
import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution';
|
||||
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
|
||||
import { ToolOutputService } from '../common/protocol/tool-output-service';
|
||||
import { ToolOutputServiceClientImpl } from './tool-output/client-service-impl';
|
||||
import { BoardsServiceClientImpl } from './boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards/boards-service-provider';
|
||||
import { WorkspaceService as TheiaWorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { WorkspaceService } from './theia/workspace/workspace-service';
|
||||
import { OutlineViewContribution as TheiaOutlineViewContribution } from '@theia/outline-view/lib/browser/outline-view-contribution';
|
||||
@@ -50,7 +47,7 @@ import { SearchInWorkspaceFrontendContribution } from './theia/search-in-workspa
|
||||
import { LibraryListWidgetFrontendContribution } from './library/library-widget-frontend-contribution';
|
||||
import { MonitorServiceClientImpl } from './monitor/monitor-service-client-impl';
|
||||
import { MonitorServicePath, MonitorService, MonitorServiceClient } from '../common/protocol/monitor-service';
|
||||
import { ConfigService, ConfigServicePath, ConfigServiceClient } from '../common/protocol/config-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';
|
||||
@@ -67,8 +64,7 @@ import { EditorMode } from './editor-mode';
|
||||
import { ListItemRenderer } from './widgets/component-list/list-item-renderer';
|
||||
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
|
||||
import { MonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service';
|
||||
import { ArduinoDaemonClientImpl } from './arduino-daemon-client-impl';
|
||||
import { ArduinoDaemonClient, ArduinoDaemonPath, ArduinoDaemon } from '../common/protocol/arduino-daemon';
|
||||
import { ArduinoDaemonPath, ArduinoDaemon } from '../common/protocol/arduino-daemon';
|
||||
import { EditorManager as TheiaEditorManager } from '@theia/editor/lib/browser';
|
||||
import { EditorManager } from './theia/editor/editor-manager';
|
||||
import { FrontendConnectionStatusService, ApplicationConnectionStatusContribution } from './theia/core/connection-status-service';
|
||||
@@ -76,8 +72,6 @@ import {
|
||||
FrontendConnectionStatusService as TheiaFrontendConnectionStatusService,
|
||||
ApplicationConnectionStatusContribution as TheiaApplicationConnectionStatusContribution
|
||||
} from '@theia/core/lib/browser/connection-status-service';
|
||||
import { ConfigServiceClientImpl } from './config-service-client-impl';
|
||||
import { CoreServiceClientImpl } from './core-service-client-impl';
|
||||
import { BoardsDataMenuUpdater } from './boards/boards-data-menu-updater';
|
||||
import { BoardsDataStore } from './boards/boards-data-store';
|
||||
import { ILogger } from '@theia/core';
|
||||
@@ -116,7 +110,6 @@ import { OutputWidget } from './theia/output/output-widget';
|
||||
import { BurnBootloader } from './contributions/burn-bootloader';
|
||||
import { ExamplesServicePath, ExamplesService } from '../common/protocol/examples-service';
|
||||
import { BuiltInExamples, LibraryExamples } from './contributions/examples';
|
||||
import { LibraryServiceProvider } from './library/library-service-provider';
|
||||
import { IncludeLibrary } from './contributions/include-library';
|
||||
import { OutputChannelManager as TheiaOutputChannelManager } from '@theia/output/lib/common/output-channel';
|
||||
import { OutputChannelManager } from './theia/output/output-channel';
|
||||
@@ -124,6 +117,10 @@ import { OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl, Ou
|
||||
import { ExecutableService, ExecutableServicePath } from '../common/protocol';
|
||||
import { MonacoTextModelService as TheiaMonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
||||
import { MonacoTextModelService } from './theia/monaco/monaco-text-model-service';
|
||||
import { OutputServiceImpl } from './output-service-impl';
|
||||
import { OutputServicePath, OutputService } from '../common/protocol/output-service';
|
||||
import { NotificationCenter } from './notification-center';
|
||||
import { NotificationServicePath, NotificationServiceServer } from '../common/protocol';
|
||||
|
||||
const ElementQueries = require('css-element-queries/src/ElementQueries');
|
||||
|
||||
@@ -153,8 +150,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ListItemRenderer).toSelf().inSingletonScope();
|
||||
|
||||
// Library service
|
||||
bind(LibraryServiceProvider).toSelf().inSingletonScope();
|
||||
bind(LibraryServiceServer).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServiceServerPath)).inSingletonScope();
|
||||
bind(LibraryService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServicePath)).inSingletonScope();
|
||||
|
||||
// Library list widget
|
||||
bind(LibraryListWidget).toSelf();
|
||||
@@ -170,34 +166,13 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(SketchesServiceClientImpl).toSelf().inSingletonScope();
|
||||
|
||||
// Config service
|
||||
bind(ConfigService).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(ConfigServiceClientImpl);
|
||||
return connection.createProxy(ConfigServicePath, client);
|
||||
}).inSingletonScope();
|
||||
bind(ConfigServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(ConfigServiceClient).toDynamicValue(context => {
|
||||
const client = context.container.get(ConfigServiceClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, ConfigServicePath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(ConfigService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ConfigServicePath)).inSingletonScope();
|
||||
|
||||
// Boards service
|
||||
bind(BoardsService).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(BoardsServiceClientImpl);
|
||||
return connection.createProxy(BoardsServicePath, client);
|
||||
}).inSingletonScope();
|
||||
bind(BoardsService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, BoardsServicePath)).inSingletonScope();
|
||||
// Boards service client to receive and delegate notifications from the backend.
|
||||
bind(BoardsServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(FrontendApplicationContribution).toService(BoardsServiceClientImpl);
|
||||
bind(BoardsServiceClient).toDynamicValue(async context => {
|
||||
const client = context.container.get(BoardsServiceClientImpl);
|
||||
const service = context.container.get<BoardsService>(BoardsService);
|
||||
await client.init(service);
|
||||
WebSocketConnectionProvider.createProxy(context.container, BoardsServicePath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(BoardsServiceProvider).toSelf().inSingletonScope();
|
||||
bind(FrontendApplicationContribution).toService(BoardsServiceProvider);
|
||||
|
||||
// To be able to track, and update the menu based on the core settings (aka. board details) of the currently selected board.
|
||||
bind(FrontendApplicationContribution).to(BoardsDataMenuUpdater).inSingletonScope();
|
||||
@@ -230,26 +205,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
})
|
||||
|
||||
// Core service
|
||||
bind(CoreService).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(CoreServiceClientImpl);
|
||||
return connection.createProxy(CoreServicePath, client);
|
||||
}).inSingletonScope();
|
||||
// Core service client to receive and delegate notifications when the index or the library index has been updated.
|
||||
bind(CoreServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(CoreServiceClient).toDynamicValue(context => {
|
||||
const client = context.container.get(CoreServiceClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, CoreServicePath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
|
||||
// Tool output service client
|
||||
bind(ToolOutputServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(ToolOutputServiceClient).toDynamicValue(context => {
|
||||
const client = context.container.get(ToolOutputServiceClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, ToolOutputService.SERVICE_PATH, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(CoreService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, CoreServicePath)).inSingletonScope();
|
||||
|
||||
// Serial monitor
|
||||
bind(MonitorModel).toSelf().inSingletonScope();
|
||||
@@ -341,18 +297,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ShellLayoutRestorer).toSelf().inSingletonScope();
|
||||
rebind(TheiaShellLayoutRestorer).toService(ShellLayoutRestorer);
|
||||
|
||||
// Arduino daemon client. Receives notifications from the backend if the CLI daemon process has been restarted.
|
||||
bind(ArduinoDaemon).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(ArduinoDaemonClientImpl);
|
||||
return connection.createProxy(ArduinoDaemonPath, client);
|
||||
}).inSingletonScope();
|
||||
bind(ArduinoDaemonClientImpl).toSelf().inSingletonScope();
|
||||
bind(ArduinoDaemonClient).toDynamicValue(context => {
|
||||
const client = context.container.get(ArduinoDaemonClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, ArduinoDaemonPath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(ArduinoDaemon).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ArduinoDaemonPath)).inSingletonScope();
|
||||
|
||||
// File-system extension
|
||||
bind(FileSystemExt).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, FileSystemExtPath)).inSingletonScope();
|
||||
@@ -379,4 +324,13 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
Contribution.configure(bind, BuiltInExamples);
|
||||
Contribution.configure(bind, LibraryExamples);
|
||||
Contribution.configure(bind, IncludeLibrary);
|
||||
|
||||
bind(OutputServiceImpl).toSelf().inSingletonScope().onActivation(({ container }, outputService) => {
|
||||
WebSocketConnectionProvider.createProxy(container, OutputServicePath, outputService);
|
||||
return outputService;
|
||||
});
|
||||
bind(OutputService).toService(OutputServiceImpl);
|
||||
|
||||
bind(NotificationCenter).toSelf().inSingletonScope();
|
||||
bind(NotificationServiceServer).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, NotificationServicePath)).inSingletonScope();
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import { BoardsService, Board } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsService, BoardsPackage } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { BoardsListWidgetFrontendContribution } from './boards-widget-frontend-contribution';
|
||||
import { InstallationProgressDialog } from '../widgets/progress-dialog';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
@@ -20,8 +20,8 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(BoardsListWidgetFrontendContribution)
|
||||
protected readonly boardsManagerFrontendContribution: BoardsListWidgetFrontendContribution;
|
||||
@@ -36,7 +36,7 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
|
||||
if (selectedBoard) {
|
||||
this.boardsService.search({}).then(packages => {
|
||||
const candidates = packages
|
||||
.filter(pkg => pkg.boards.some(board => Board.sameAs(board, selectedBoard)))
|
||||
.filter(pkg => BoardsPackage.contains(selectedBoard, pkg))
|
||||
.filter(({ installable, installedVersion }) => installable && !installedVersion);
|
||||
for (const candidate of candidates) {
|
||||
// tslint:disable-next-line:max-line-length
|
||||
|
||||
@@ -4,9 +4,8 @@ import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { ReactWidget, Message } from '@theia/core/lib/browser';
|
||||
import { BoardsService } from '../../common/protocol/boards-service';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { CoreServiceClientImpl } from '../core-service-client-impl';
|
||||
import { ArduinoDaemonClientImpl } from '../arduino-daemon-client-impl';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class BoardsConfigDialogWidget extends ReactWidget {
|
||||
@@ -14,14 +13,11 @@ export class BoardsConfigDialogWidget extends ReactWidget {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(CoreServiceClientImpl)
|
||||
protected readonly coreServiceClient: CoreServiceClientImpl;
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected readonly onBoardConfigChangedEmitter = new Emitter<BoardsConfig.Config>();
|
||||
readonly onBoardConfigChanged = this.onBoardConfigChangedEmitter.event;
|
||||
@@ -44,10 +40,8 @@ export class BoardsConfigDialogWidget extends ReactWidget {
|
||||
protected render(): React.ReactNode {
|
||||
return <div className='selectBoardContainer'>
|
||||
<BoardsConfig
|
||||
boardsService={this.boardsService}
|
||||
boardsServiceClient={this.boardsServiceClient}
|
||||
coreServiceClient={this.coreServiceClient}
|
||||
daemonClient={this.daemonClient}
|
||||
boardsServiceProvider={this.boardsServiceClient}
|
||||
notificationCenter={this.notificationCenter}
|
||||
onConfigChange={this.fireConfigChanged}
|
||||
onFocusNodeSet={this.setFocusNode} />
|
||||
</div>;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AbstractDialog, DialogProps, Widget, DialogError } from '@theia/core/li
|
||||
import { BoardsService } from '../../common/protocol/boards-service';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { BoardsConfigDialogWidget } from './boards-config-dialog-widget';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class BoardsConfigDialogProps extends DialogProps {
|
||||
@@ -19,8 +19,8 @@ export class BoardsConfigDialog extends AbstractDialog<BoardsConfig.Config> {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected config: BoardsConfig.Config = {};
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { DisposableCollection } from '@theia/core';
|
||||
import { BoardsService, Board, Port, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { CoreServiceClientImpl } from '../core-service-client-impl';
|
||||
import { ArduinoDaemonClientImpl } from '../arduino-daemon-client-impl';
|
||||
import { notEmpty } from '@theia/core/lib/common/objects';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Board, Port, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
import { MaybePromise } from '@theia/core';
|
||||
|
||||
export namespace BoardsConfig {
|
||||
|
||||
@@ -13,10 +14,8 @@ export namespace BoardsConfig {
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
readonly boardsService: BoardsService;
|
||||
readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
readonly coreServiceClient: CoreServiceClientImpl;
|
||||
readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
readonly notificationCenter: NotificationCenter;
|
||||
readonly onConfigChange: (config: Config) => void;
|
||||
readonly onFocusNodeSet: (element: HTMLElement | undefined) => void;
|
||||
}
|
||||
@@ -70,7 +69,7 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
|
||||
constructor(props: BoardsConfig.Props) {
|
||||
super(props);
|
||||
|
||||
const { boardsConfig } = props.boardsServiceClient;
|
||||
const { boardsConfig } = props.boardsServiceProvider;
|
||||
this.state = {
|
||||
searchResults: [],
|
||||
knownPorts: [],
|
||||
@@ -82,18 +81,17 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
|
||||
|
||||
componentDidMount() {
|
||||
this.updateBoards();
|
||||
this.props.boardsService.getAvailablePorts().then(ports => this.updatePorts(ports));
|
||||
const { boardsServiceClient, coreServiceClient, daemonClient } = this.props;
|
||||
this.updatePorts(this.props.boardsServiceProvider.availableBoards.map(({ port }) => port).filter(notEmpty));
|
||||
this.toDispose.pushAll([
|
||||
boardsServiceClient.onAttachedBoardsChanged(event => this.updatePorts(event.newState.ports, AttachedBoardsChangeEvent.diff(event).detached.ports)),
|
||||
boardsServiceClient.onBoardsConfigChanged(({ selectedBoard, selectedPort }) => {
|
||||
this.props.notificationCenter.onAttachedBoardsChanged(event => this.updatePorts(event.newState.ports, AttachedBoardsChangeEvent.diff(event).detached.ports)),
|
||||
this.props.boardsServiceProvider.onBoardsConfigChanged(({ selectedBoard, selectedPort }) => {
|
||||
this.setState({ selectedBoard, selectedPort }, () => this.fireConfigChanged());
|
||||
}),
|
||||
boardsServiceClient.onBoardsPackageInstalled(() => this.updateBoards(this.state.query)),
|
||||
boardsServiceClient.onBoardsPackageUninstalled(() => this.updateBoards(this.state.query)),
|
||||
coreServiceClient.onIndexUpdated(() => this.updateBoards(this.state.query)),
|
||||
daemonClient.onDaemonStarted(() => this.updateBoards(this.state.query)),
|
||||
daemonClient.onDaemonStopped(() => this.setState({ searchResults: [] }))
|
||||
this.props.notificationCenter.onPlatformInstalled(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onPlatformUninstalled(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onIndexUpdated(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onDaemonStarted(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onDaemonStopped(() => this.setState({ searchResults: [] }))
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -127,14 +125,14 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
|
||||
}
|
||||
|
||||
protected queryBoards = (options: { query?: string } = {}): Promise<Array<Board & { packageName: string }>> => {
|
||||
return this.props.boardsServiceClient.searchBoards(options);
|
||||
return this.props.boardsServiceProvider.searchBoards(options);
|
||||
}
|
||||
|
||||
protected get availablePorts(): Promise<Port[]> {
|
||||
return this.props.boardsService.getAvailablePorts();
|
||||
protected get availablePorts(): MaybePromise<Port[]> {
|
||||
return this.props.boardsServiceProvider.availableBoards.map(({ port }) => port).filter(notEmpty);
|
||||
}
|
||||
|
||||
protected queryPorts = async (availablePorts: Promise<Port[]> = this.availablePorts) => {
|
||||
protected queryPorts = async (availablePorts: MaybePromise<Port[]> = this.availablePorts) => {
|
||||
const ports = await availablePorts;
|
||||
return { knownPorts: ports.sort(Port.compare) };
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { inject, injectable } from 'inversify';
|
||||
import { CommandRegistry } from '@theia/core/lib/common/command';
|
||||
import { MenuModelRegistry, MenuNode } from '@theia/core/lib/common/menu';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { Board, ConfigOption, Programmer } from '../../common/protocol';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
|
||||
import { BoardsDataStore } from './boards-data-store';
|
||||
@@ -25,8 +25,8 @@ export class BoardsDataMenuUpdater implements FrontendApplicationContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
protected readonly toDisposeOnBoardChange = new DisposableCollection();
|
||||
|
||||
@@ -5,8 +5,8 @@ import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser';
|
||||
import { notEmpty } from '../../common/utils';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsService, ConfigOption, Installable, BoardDetails, Programmer } from '../../common/protocol';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
@@ -18,8 +18,8 @@ export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
@inject(LocalStorageService)
|
||||
protected readonly storageService: LocalStorageService;
|
||||
@@ -27,7 +27,7 @@ export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
protected readonly onChangedEmitter = new Emitter<void>();
|
||||
|
||||
onStart(): void {
|
||||
this.boardsServiceClient.onBoardsPackageInstalled(async ({ item }) => {
|
||||
this.notificationCenter.onPlatformInstalled(async ({ item }) => {
|
||||
const { installedVersion: version } = item;
|
||||
if (!version) {
|
||||
return;
|
||||
@@ -76,7 +76,8 @@ export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
const key = this.getStorageKey(fqbn, version);
|
||||
let data = await this.storageService.getData<BoardsDataStore.Data | undefined>(key, undefined);
|
||||
if (data) {
|
||||
if (data.programmers !== undefined) { // to be backward compatible. We did not save the `programmers` into the `localStorage`.
|
||||
// If `configOptions` is empty we rather reload the data. See arduino/arduino-cli#954 and arduino/arduino-cli#955.
|
||||
if (data.configOptions.length && data.programmers !== undefined) { // to be backward compatible. We did not save the `programmers` into the `localStorage`.
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { BoardsPackage, BoardsService } from '../../common/protocol/boards-service';
|
||||
import { ListWidget } from '../widgets/component-list/list-widget';
|
||||
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
||||
@@ -24,4 +24,13 @@ export class BoardsListWidget extends ListWidget<BoardsPackage> {
|
||||
});
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
super.init();
|
||||
this.toDispose.pushAll([
|
||||
this.notificationCenter.onPlatformInstalled(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onPlatformUninstalled(() => this.refresh(undefined)),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,14 +10,12 @@ import {
|
||||
Board,
|
||||
BoardsService,
|
||||
BoardsPackage,
|
||||
InstalledEvent,
|
||||
UninstalledEvent,
|
||||
BoardsServiceClient,
|
||||
AttachedBoardsChangeEvent
|
||||
} from '../../common/protocol';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { naturalCompare } from '../../common/utils';
|
||||
import { compareAnything } from '../theia/monaco/comparers';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
interface BoardMatch {
|
||||
readonly board: Board & Readonly<{ packageName: string }>;
|
||||
@@ -25,7 +23,7 @@ interface BoardMatch {
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApplicationContribution {
|
||||
export class BoardsServiceProvider implements FrontendApplicationContribution {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
@@ -36,9 +34,12 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
@inject(StorageService)
|
||||
protected storageService: StorageService;
|
||||
|
||||
protected readonly onBoardsPackageInstalledEmitter = new Emitter<InstalledEvent<BoardsPackage>>();
|
||||
protected readonly onBoardsPackageUninstalledEmitter = new Emitter<UninstalledEvent<BoardsPackage>>();
|
||||
protected readonly onAttachedBoardsChangedEmitter = new Emitter<AttachedBoardsChangeEvent>();
|
||||
@inject(BoardsService)
|
||||
protected boardsService: BoardsService;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected notificationCenter: NotificationCenter;
|
||||
|
||||
protected readonly onBoardsConfigChangedEmitter = new Emitter<BoardsConfig.Config>();
|
||||
protected readonly onAvailableBoardsChangedEmitter = new Emitter<AvailableBoard[]>();
|
||||
|
||||
@@ -54,14 +55,7 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
protected _attachedBoards: Board[] = []; // This does not contain the `Unknown` boards. They're visible from the available ports only.
|
||||
protected _availablePorts: Port[] = [];
|
||||
protected _availableBoards: AvailableBoard[] = [];
|
||||
protected boardsService: BoardsService;
|
||||
|
||||
/**
|
||||
* Event when the state of the attached/detached boards has changed. For instance, the user have detached a physical board.
|
||||
*/
|
||||
readonly onAttachedBoardsChanged = this.onAttachedBoardsChangedEmitter.event;
|
||||
readonly onBoardsPackageInstalled = this.onBoardsPackageInstalledEmitter.event;
|
||||
readonly onBoardsPackageUninstalled = this.onBoardsPackageUninstalledEmitter.event;
|
||||
/**
|
||||
* Unlike `onAttachedBoardsChanged` this even fires when the user modifies the selected board in the IDE.\
|
||||
* This even also fires, when the boards package was not available for the currently selected board,
|
||||
@@ -72,33 +66,72 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
readonly onBoardsConfigChanged = this.onBoardsConfigChangedEmitter.event;
|
||||
readonly onAvailableBoardsChanged = this.onAvailableBoardsChangedEmitter.event;
|
||||
|
||||
async onStart(): Promise<void> {
|
||||
return this.loadState();
|
||||
}
|
||||
onStart(): void {
|
||||
this.notificationCenter.onAttachedBoardsChanged(this.notifyAttachedBoardsChanged.bind(this));
|
||||
this.notificationCenter.onPlatformInstalled(this.notifyPlatformInstalled.bind(this));
|
||||
this.notificationCenter.onPlatformUninstalled(this.notifyPlatformUninstalled.bind(this));
|
||||
|
||||
/**
|
||||
* When the FE connects to the BE, the BE stets the known boards and ports.\
|
||||
* This is a DI workaround for not being able to inject the service into the client.
|
||||
*/
|
||||
async init(boardsService: BoardsService): Promise<void> {
|
||||
this.boardsService = boardsService;
|
||||
const [attachedBoards, availablePorts] = await Promise.all([
|
||||
Promise.all([
|
||||
this.boardsService.getAttachedBoards(),
|
||||
this.boardsService.getAvailablePorts()
|
||||
]);
|
||||
this._attachedBoards = attachedBoards;
|
||||
this._availablePorts = availablePorts;
|
||||
this.reconcileAvailableBoards().then(() => this.tryReconnect());
|
||||
this.boardsService.getAvailablePorts(),
|
||||
this.loadState()
|
||||
]).then(([attachedBoards, availablePorts]) => {
|
||||
this._attachedBoards = attachedBoards;
|
||||
this._availablePorts = availablePorts;
|
||||
this.reconcileAvailableBoards().then(() => this.tryReconnect());
|
||||
});
|
||||
}
|
||||
|
||||
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
|
||||
this.logger.info('Attached boards and available ports changed: ', JSON.stringify(event));
|
||||
protected notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
|
||||
if (!AttachedBoardsChangeEvent.isEmpty(event)) {
|
||||
this.logger.info('Attached boards and available ports changed:');
|
||||
this.logger.info(AttachedBoardsChangeEvent.toString(event));
|
||||
this.logger.info(`------------------------------------------`);
|
||||
}
|
||||
this._attachedBoards = event.newState.boards;
|
||||
this.onAttachedBoardsChangedEmitter.fire(event);
|
||||
this._availablePorts = event.newState.ports;
|
||||
this.reconcileAvailableBoards().then(() => this.tryReconnect());
|
||||
}
|
||||
|
||||
protected notifyPlatformInstalled(event: { item: BoardsPackage }): void {
|
||||
this.logger.info('Boards package installed: ', JSON.stringify(event));
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
const { installedVersion, id } = event.item;
|
||||
if (selectedBoard) {
|
||||
const installedBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (installedBoard && (!selectedBoard.fqbn || selectedBoard.fqbn === installedBoard.fqbn)) {
|
||||
this.logger.info(`Board package ${id}[${installedVersion}] was installed. Updating the FQBN of the currently selected ${selectedBoard.name} board. [FQBN: ${installedBoard.fqbn}]`);
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: installedBoard
|
||||
};
|
||||
return;
|
||||
}
|
||||
// Trigger a board re-set. See: https://github.com/arduino/arduino-cli/issues/954
|
||||
// E.g: install `adafruit:avr`, then select `adafruit:avr:adafruit32u4` board, and finally install the required `arduino:avr`
|
||||
this.boardsConfig = this.boardsConfig;
|
||||
}
|
||||
}
|
||||
|
||||
protected notifyPlatformUninstalled(event: { item: BoardsPackage }): void {
|
||||
this.logger.info('Boards package uninstalled: ', JSON.stringify(event));
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
if (selectedBoard && selectedBoard.fqbn) {
|
||||
const uninstalledBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (uninstalledBoard && uninstalledBoard.fqbn === selectedBoard.fqbn) {
|
||||
this.logger.info(`Board package ${event.item.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`);
|
||||
const selectedBoardWithoutFqbn = {
|
||||
name: selectedBoard.name
|
||||
// No FQBN
|
||||
};
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: selectedBoardWithoutFqbn
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async tryReconnect(): Promise<boolean> {
|
||||
if (this.latestValidBoardsConfig && !this.canUploadTo(this.boardsConfig)) {
|
||||
for (const board of this.availableBoards.filter(({ state }) => state !== AvailableBoard.State.incomplete)) {
|
||||
@@ -127,43 +160,6 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
return false;
|
||||
}
|
||||
|
||||
notifyInstalled(event: InstalledEvent<BoardsPackage>): void {
|
||||
this.logger.info('Boards package installed: ', JSON.stringify(event));
|
||||
this.onBoardsPackageInstalledEmitter.fire(event);
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
const { installedVersion, id } = event.item;
|
||||
if (selectedBoard) {
|
||||
const installedBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (installedBoard && (!selectedBoard.fqbn || selectedBoard.fqbn === installedBoard.fqbn)) {
|
||||
this.logger.info(`Board package ${id}[${installedVersion}] was installed. Updating the FQBN of the currently selected ${selectedBoard.name} board. [FQBN: ${installedBoard.fqbn}]`);
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: installedBoard
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notifyUninstalled(event: UninstalledEvent<BoardsPackage>): void {
|
||||
this.logger.info('Boards package uninstalled: ', JSON.stringify(event));
|
||||
this.onBoardsPackageUninstalledEmitter.fire(event);
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
if (selectedBoard && selectedBoard.fqbn) {
|
||||
const uninstalledBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (uninstalledBoard && uninstalledBoard.fqbn === selectedBoard.fqbn) {
|
||||
this.logger.info(`Board package ${event.item.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`);
|
||||
const selectedBoardWithoutFqbn = {
|
||||
name: selectedBoard.name
|
||||
// No FQBN
|
||||
};
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: selectedBoardWithoutFqbn
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set boardsConfig(config: BoardsConfig.Config) {
|
||||
this.doSetBoardsConfig(config);
|
||||
this.saveState().finally(() => this.reconcileAvailableBoards().finally(() => this.onBoardsConfigChangedEmitter.fire(this._boardsConfig)));
|
||||
@@ -5,7 +5,7 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Port } from '../../common/protocol';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { ArduinoCommands } from '../arduino-commands';
|
||||
import { BoardsServiceClientImpl, AvailableBoard } from './boards-service-client-impl';
|
||||
import { BoardsServiceProvider, AvailableBoard } from './boards-service-provider';
|
||||
|
||||
export interface BoardsDropDownListCoords {
|
||||
readonly top: number;
|
||||
@@ -181,7 +181,7 @@ export class BoardsToolBarItem extends React.Component<BoardsToolBarItem.Props,
|
||||
export namespace BoardsToolBarItem {
|
||||
|
||||
export interface Props {
|
||||
readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
readonly boardsServiceClient: BoardsServiceProvider;
|
||||
readonly commands: CommandRegistry;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ import {
|
||||
} from '@theia/core/lib/browser/quick-open';
|
||||
import { naturalCompare } from '../../../common/utils';
|
||||
import { BoardsService, Port, Board, ConfigOption, ConfigValue } from '../../../common/protocol';
|
||||
import { CoreServiceClientImpl } from '../../core-service-client-impl';
|
||||
import { BoardsDataStore } from '../boards-data-store';
|
||||
import { BoardsServiceClientImpl, AvailableBoard } from '../boards-service-client-impl';
|
||||
import { BoardsServiceProvider, AvailableBoard } from '../boards-service-provider';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenModel, QuickOpenHandler, CommandContribution, KeybindingContribution, Command {
|
||||
@@ -38,14 +38,14 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(CoreServiceClientImpl)
|
||||
protected coreServiceClient: CoreServiceClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected notificationCenter: NotificationCenter;
|
||||
|
||||
protected isOpen: boolean = false;
|
||||
protected currentQuery: string = '';
|
||||
@@ -59,7 +59,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
// `init` name is used by the `QuickOpenHandler`.
|
||||
@postConstruct()
|
||||
protected postConstruct(): void {
|
||||
this.coreServiceClient.onIndexUpdated(() => this.update(this.availableBoards));
|
||||
this.notificationCenter.onIndexUpdated(() => this.update(this.availableBoards));
|
||||
this.boardsServiceClient.onAvailableBoardsChanged(availableBoards => this.update(availableBoards));
|
||||
this.update(this.boardsServiceClient.availableBoards);
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { CommandService } from '@theia/core/lib/common/command';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { ConfigServiceClient, Config } from '../common/protocol';
|
||||
import { Settings } from './contributions/settings';
|
||||
|
||||
@injectable()
|
||||
export class ConfigServiceClientImpl implements ConfigServiceClient {
|
||||
|
||||
@inject(CommandService)
|
||||
protected readonly commandService: CommandService;
|
||||
|
||||
@inject(ILogger)
|
||||
protected readonly logger: ILogger;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
protected readonly onConfigChangedEmitter = new Emitter<Config>();
|
||||
protected invalidConfigPopup: Promise<void | 'No' | 'Yes' | undefined> | undefined;
|
||||
|
||||
notifyConfigChanged(config: Config): void {
|
||||
this.invalidConfigPopup = undefined;
|
||||
this.info(`The CLI configuration has been successfully reloaded.`);
|
||||
this.onConfigChangedEmitter.fire(config);
|
||||
}
|
||||
|
||||
notifyInvalidConfig(): void {
|
||||
if (!this.invalidConfigPopup) {
|
||||
this.invalidConfigPopup = this.messageService.error(`Your CLI configuration is invalid. Do you want to correct it now?`, 'No', 'Yes')
|
||||
.then(answer => {
|
||||
if (answer === 'Yes') {
|
||||
this.commandService.executeCommand(Settings.Commands.OPEN_CLI_CONFIG.id)
|
||||
}
|
||||
this.invalidConfigPopup = undefined;
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
get onConfigChanged(): Event<Config> {
|
||||
return this.onConfigChangedEmitter.event;
|
||||
}
|
||||
|
||||
protected info(message: string): void {
|
||||
this.messageService.info(message, { timeout: 3000 });
|
||||
this.logger.info(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { MonitorConnection } from '../monitor/monitor-connection';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
@@ -19,8 +19,8 @@ export class BurnBootloader extends SketchContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
|
||||
@@ -5,10 +5,10 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa
|
||||
import { OpenSketch } from './open-sketch';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { LibraryServiceProvider } from '../library/library-service-provider';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { ExamplesService, ExampleContainer } from '../../common/protocol/examples-service';
|
||||
import { SketchContribution, CommandRegistry, MenuModelRegistry } from './contribution';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export abstract class Examples extends SketchContribution {
|
||||
@@ -25,8 +25,8 @@ export abstract class Examples extends SketchContribution {
|
||||
@inject(ExamplesService)
|
||||
protected readonly examplesService: ExamplesService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
|
||||
@@ -113,15 +113,15 @@ export class BuiltInExamples extends Examples {
|
||||
@injectable()
|
||||
export class LibraryExamples extends Examples {
|
||||
|
||||
@inject(LibraryServiceProvider)
|
||||
protected readonly libraryServiceProvider: LibraryServiceProvider;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
|
||||
onStart(): void {
|
||||
this.register(); // no `await`
|
||||
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.register());
|
||||
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.register());
|
||||
this.notificationCenter.onLibraryInstalled(() => this.register());
|
||||
this.notificationCenter.onLibraryUninstalled(() => this.register());
|
||||
}
|
||||
|
||||
protected handleBoardChanged(fqbn: string | undefined): void {
|
||||
|
||||
@@ -6,12 +6,12 @@ import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { MenuModelRegistry, MenuPath } from '@theia/core/lib/common/menu';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { LibraryPackage, LibraryLocation } from '../../common/protocol';
|
||||
import { LibraryPackage, LibraryLocation, LibraryService } from '../../common/protocol';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { LibraryListWidget } from '../library/library-list-widget';
|
||||
import { LibraryServiceProvider } from '../library/library-service-provider';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry } from './contribution';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class IncludeLibrary extends SketchContribution {
|
||||
@@ -28,11 +28,14 @@ export class IncludeLibrary extends SketchContribution {
|
||||
@inject(EditorManager)
|
||||
protected readonly editorManager: EditorManager;
|
||||
|
||||
@inject(LibraryServiceProvider)
|
||||
protected readonly libraryServiceProvider: LibraryServiceProvider;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(LibraryService)
|
||||
protected readonly libraryService: LibraryService;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
@@ -40,8 +43,8 @@ export class IncludeLibrary extends SketchContribution {
|
||||
onStart(): void {
|
||||
this.updateMenuActions();
|
||||
this.boardsServiceClient.onBoardsConfigChanged(() => this.updateMenuActions())
|
||||
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.updateMenuActions());
|
||||
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.updateMenuActions());
|
||||
this.notificationCenter.onLibraryInstalled(() => this.updateMenuActions());
|
||||
this.notificationCenter.onLibraryUninstalled(() => this.updateMenuActions());
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
@@ -62,7 +65,7 @@ export class IncludeLibrary extends SketchContribution {
|
||||
const fqbn = this.boardsServiceClient.boardsConfig.selectedBoard?.fqbn;
|
||||
// Do not show board specific examples, when no board is selected.
|
||||
if (fqbn) {
|
||||
libraries.push(...await this.libraryServiceProvider.list({ fqbn }));
|
||||
libraries.push(...await this.libraryService.list({ fqbn }));
|
||||
}
|
||||
|
||||
// `Include Library` submenu
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { MonitorConnection } from '../monitor/monitor-connection';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
@@ -20,8 +20,8 @@ export class UploadSketch extends SketchContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
@@ -16,8 +16,8 @@ export class VerifySketch extends SketchContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { LocalStorageService } from '@theia/core/lib/browser/storage-service';
|
||||
import { CoreServiceClient } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class CoreServiceClientImpl implements CoreServiceClient {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
|
||||
@inject(MessageService)
|
||||
protected messageService: MessageService;
|
||||
|
||||
@inject(LocalStorageService)
|
||||
protected storageService: LocalStorageService;
|
||||
|
||||
protected readonly onIndexUpdatedEmitter = new Emitter<void>();
|
||||
|
||||
notifyIndexUpdated(): void {
|
||||
this.info('Index has been updated.');
|
||||
this.onIndexUpdatedEmitter.fire();
|
||||
}
|
||||
|
||||
get onIndexUpdated(): Event<void> {
|
||||
return this.onIndexUpdatedEmitter.event;
|
||||
}
|
||||
|
||||
protected info(message: string): void {
|
||||
this.messageService.info(message, { timeout: 3000 });
|
||||
this.logger.info(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { LibraryPackage } from '../../common/protocol/library-service';
|
||||
import { injectable, postConstruct, inject } from 'inversify';
|
||||
import { LibraryPackage, LibraryService } from '../../common/protocol/library-service';
|
||||
import { ListWidget } from '../widgets/component-list/list-widget';
|
||||
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
||||
import { LibraryServiceProvider } from './library-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
||||
@@ -11,7 +10,7 @@ export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
||||
static WIDGET_LABEL = 'Library Manager';
|
||||
|
||||
constructor(
|
||||
@inject(LibraryServiceProvider) protected service: LibraryServiceProvider,
|
||||
@inject(LibraryService) protected service: LibraryService,
|
||||
@inject(ListItemRenderer) protected itemRenderer: ListItemRenderer<LibraryPackage>) {
|
||||
|
||||
super({
|
||||
@@ -25,4 +24,13 @@ export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
||||
});
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
super.init();
|
||||
this.toDispose.pushAll([
|
||||
this.notificationCenter.onLibraryInstalled(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onLibraryUninstalled(() => this.refresh(undefined)),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Searchable, InstalledEvent, UninstalledEvent } from '../../common/protocol';
|
||||
import { LibraryPackage, LibraryServiceServer, LibraryService } from '../../common/protocol/library-service';
|
||||
|
||||
@injectable()
|
||||
export class LibraryServiceProvider implements Required<LibraryService> {
|
||||
|
||||
@inject(LibraryServiceServer)
|
||||
protected readonly server: JsonRpcProxy<LibraryServiceServer>;
|
||||
|
||||
protected readonly onLibraryPackageInstalledEmitter = new Emitter<InstalledEvent<LibraryPackage>>();
|
||||
protected readonly onLibraryPackageUninstalledEmitter = new Emitter<UninstalledEvent<LibraryPackage>>();
|
||||
protected readonly toDispose = new DisposableCollection(
|
||||
this.onLibraryPackageInstalledEmitter,
|
||||
this.onLibraryPackageUninstalledEmitter
|
||||
);
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.server.setClient({
|
||||
notifyInstalled: event => this.onLibraryPackageInstalledEmitter.fire(event),
|
||||
notifyUninstalled: event => this.onLibraryPackageUninstalledEmitter.fire(event)
|
||||
});
|
||||
}
|
||||
|
||||
get onLibraryPackageInstalled(): Event<InstalledEvent<LibraryPackage>> {
|
||||
return this.onLibraryPackageInstalledEmitter.event;
|
||||
}
|
||||
|
||||
get onLibraryPackageUninstalled(): Event<InstalledEvent<LibraryPackage>> {
|
||||
return this.onLibraryPackageUninstalledEmitter.event;
|
||||
}
|
||||
|
||||
// #region remote library service API
|
||||
|
||||
async install(options: { item: LibraryPackage; version?: string | undefined; }): Promise<void> {
|
||||
return this.server.install(options);
|
||||
}
|
||||
|
||||
async list(options: LibraryService.List.Options): Promise<LibraryPackage[]> {
|
||||
return this.server.list(options);
|
||||
}
|
||||
|
||||
async uninstall(options: { item: LibraryPackage; }): Promise<void> {
|
||||
return this.server.uninstall(options);
|
||||
}
|
||||
|
||||
async search(options: Searchable.Options): Promise<LibraryPackage[]> {
|
||||
return this.server.search(options);
|
||||
}
|
||||
|
||||
// #endregion remote API
|
||||
|
||||
dispose(): void {
|
||||
this.toDispose.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,11 +4,12 @@ import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { MonitorService, MonitorConfig, MonitorError, Status, MonitorReadEvent } from '../../common/protocol/monitor-service';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { Port, Board, BoardsService, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||
import { MonitorServiceClientImpl } from './monitor-service-client-impl';
|
||||
import { BoardsConfig } from '../boards/boards-config';
|
||||
import { MonitorModel } from './monitor-model';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class MonitorConnection {
|
||||
@@ -25,8 +26,11 @@ export class MonitorConnection {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
@inject(MessageService)
|
||||
protected messageService: MessageService;
|
||||
@@ -110,11 +114,11 @@ export class MonitorConnection {
|
||||
}
|
||||
}
|
||||
});
|
||||
this.boardsServiceClient.onBoardsConfigChanged(this.handleBoardConfigChange.bind(this));
|
||||
this.boardsServiceClient.onAttachedBoardsChanged(event => {
|
||||
this.boardsServiceProvider.onBoardsConfigChanged(this.handleBoardConfigChange.bind(this));
|
||||
this.notificationCenter.onAttachedBoardsChanged(event => {
|
||||
if (this.autoConnect && this.connected) {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
if (this.boardsServiceClient.canUploadTo(boardsConfig, { silent: false })) {
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
if (this.boardsServiceProvider.canUploadTo(boardsConfig, { silent: false })) {
|
||||
const { attached } = AttachedBoardsChangeEvent.diff(event);
|
||||
if (attached.boards.some(board => !!board.port && BoardsConfig.Config.sameAs(boardsConfig, board))) {
|
||||
const { selectedBoard: board, selectedPort: port } = boardsConfig;
|
||||
@@ -128,7 +132,7 @@ export class MonitorConnection {
|
||||
// Handles the `baudRate` changes by reconnecting if required.
|
||||
this.monitorModel.onChange(({ property }) => {
|
||||
if (property === 'baudRate' && this.autoConnect && this.connected) {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
this.handleBoardConfigChange(boardsConfig);
|
||||
}
|
||||
});
|
||||
@@ -154,7 +158,7 @@ export class MonitorConnection {
|
||||
// We have to make sure the previous boards config has been restored.
|
||||
// Otherwise, we might start the auto-connection without configured boards.
|
||||
this.applicationState.reachedState('started_contributions').then(() => {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
this.handleBoardConfigChange(boardsConfig);
|
||||
});
|
||||
} else if (oldValue && !value) {
|
||||
@@ -227,7 +231,7 @@ export class MonitorConnection {
|
||||
|
||||
protected async handleBoardConfigChange(boardsConfig: BoardsConfig.Config): Promise<void> {
|
||||
if (this.autoConnect) {
|
||||
if (this.boardsServiceClient.canUploadTo(boardsConfig, { silent: false })) {
|
||||
if (this.boardsServiceProvider.canUploadTo(boardsConfig, { silent: false })) {
|
||||
// Instead of calling `getAttachedBoards` and filtering for `AttachedSerialBoard` we have to check the available ports.
|
||||
// The connected board might be unknown. See: https://github.com/arduino/arduino-pro-ide/issues/127#issuecomment-563251881
|
||||
this.boardsService.getAvailablePorts().then(ports => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { injectable, inject } from 'inversify';
|
||||
import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { MonitorConfig } from '../../common/protocol/monitor-service';
|
||||
import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class MonitorModel implements FrontendApplicationContribution {
|
||||
@@ -12,8 +12,8 @@ export class MonitorModel implements FrontendApplicationContribution {
|
||||
@inject(LocalStorageService)
|
||||
protected readonly localStorageService: LocalStorageService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected readonly onChangeEmitter: Emitter<MonitorModel.State.Change<keyof MonitorModel.State>>;
|
||||
protected _autoscroll: boolean;
|
||||
|
||||
92
arduino-ide-extension/src/browser/notification-center.ts
Normal file
92
arduino-ide-extension/src/browser/notification-center.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import { NotificationServiceClient, NotificationServiceServer } from '../common/protocol/notification-service';
|
||||
import { AttachedBoardsChangeEvent, BoardsPackage, LibraryPackage, Config } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class NotificationCenter implements NotificationServiceClient, FrontendApplicationContribution {
|
||||
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly server: JsonRpcProxy<NotificationServiceServer>;
|
||||
|
||||
protected readonly indexUpdatedEmitter = new Emitter<void>();
|
||||
protected readonly daemonStartedEmitter = new Emitter<void>();
|
||||
protected readonly daemonStoppedEmitter = new Emitter<void>();
|
||||
protected readonly configChangedEmitter = new Emitter<{ config: Config | undefined }>();
|
||||
protected readonly platformInstalledEmitter = new Emitter<{ item: BoardsPackage }>();
|
||||
protected readonly platformUninstalledEmitter = new Emitter<{ item: BoardsPackage }>();
|
||||
protected readonly libraryInstalledEmitter = new Emitter<{ item: LibraryPackage }>();
|
||||
protected readonly libraryUninstalledEmitter = new Emitter<{ item: LibraryPackage }>();
|
||||
protected readonly attachedBoardsChangedEmitter = new Emitter<AttachedBoardsChangeEvent>();
|
||||
|
||||
protected readonly toDispose = new DisposableCollection(
|
||||
this.indexUpdatedEmitter,
|
||||
this.daemonStartedEmitter,
|
||||
this.daemonStoppedEmitter,
|
||||
this.configChangedEmitter,
|
||||
this.platformInstalledEmitter,
|
||||
this.platformUninstalledEmitter,
|
||||
this.libraryInstalledEmitter,
|
||||
this.libraryUninstalledEmitter,
|
||||
this.attachedBoardsChangedEmitter
|
||||
);
|
||||
|
||||
readonly onIndexUpdated = this.indexUpdatedEmitter.event;
|
||||
readonly onDaemonStarted = this.daemonStartedEmitter.event;
|
||||
readonly onDaemonStopped = this.daemonStoppedEmitter.event;
|
||||
readonly onConfigChanged = this.configChangedEmitter.event;
|
||||
readonly onPlatformInstalled = this.platformInstalledEmitter.event;
|
||||
readonly onPlatformUninstalled = this.platformUninstalledEmitter.event;
|
||||
readonly onLibraryInstalled = this.libraryInstalledEmitter.event;
|
||||
readonly onLibraryUninstalled = this.libraryUninstalledEmitter.event;
|
||||
readonly onAttachedBoardsChanged = this.attachedBoardsChangedEmitter.event;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.server.setClient(this);
|
||||
}
|
||||
|
||||
onStop(): void {
|
||||
this.toDispose.dispose();
|
||||
}
|
||||
|
||||
notifyIndexUpdated(): void {
|
||||
this.indexUpdatedEmitter.fire();
|
||||
}
|
||||
|
||||
notifyDaemonStarted(): void {
|
||||
this.daemonStartedEmitter.fire();
|
||||
}
|
||||
|
||||
notifyDaemonStopped(): void {
|
||||
this.daemonStoppedEmitter.fire();
|
||||
}
|
||||
|
||||
notifyConfigChanged(event: { config: Config | undefined }): void {
|
||||
this.configChangedEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyPlatformInstalled(event: { item: BoardsPackage }): void {
|
||||
this.platformInstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyPlatformUninstalled(event: { item: BoardsPackage }): void {
|
||||
this.platformUninstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyLibraryInstalled(event: { item: LibraryPackage }): void {
|
||||
this.libraryInstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyLibraryUninstalled(event: { item: LibraryPackage }): void {
|
||||
this.libraryUninstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
|
||||
this.attachedBoardsChangedEmitter.fire(event);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { OutputContribution } from '@theia/output/lib/browser/output-contribution';
|
||||
import { OutputChannelManager, OutputChannelSeverity } from '@theia/output/lib/common/output-channel';
|
||||
import { ToolOutputServiceClient, ToolOutputMessage } from '../../common/protocol/tool-output-service';
|
||||
import { OutputService, OutputMessage } from '../common/protocol/output-service';
|
||||
|
||||
@injectable()
|
||||
export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
||||
export class OutputServiceImpl implements OutputService {
|
||||
|
||||
@inject(OutputContribution)
|
||||
protected outputContribution: OutputContribution;
|
||||
@@ -12,13 +12,12 @@ export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
||||
@inject(OutputChannelManager)
|
||||
protected outputChannelManager: OutputChannelManager;
|
||||
|
||||
onMessageReceived(message: ToolOutputMessage): void {
|
||||
const { tool, chunk } = message;
|
||||
const name = `Arduino: ${tool}`;
|
||||
const channel = this.outputChannelManager.getChannel(name);
|
||||
append(message: OutputMessage): void {
|
||||
const { name, chunk } = message;
|
||||
const channel = this.outputChannelManager.getChannel(`Arduino: ${name}`);
|
||||
// Zen-mode: we do not reveal the output for daemon messages.
|
||||
const show: Promise<any> = tool === 'daemon'
|
||||
// This will open and reveal the view but won't show it. You will see the toggle bottom panel on the status bar
|
||||
const show: Promise<any> = name === 'daemon'
|
||||
// This will open and reveal the view but won't show it. You will see the toggle bottom panel on the status bar.
|
||||
? this.outputContribution.openView({ activate: false, reveal: false })
|
||||
// This will open, reveal but do not activate the Output view.
|
||||
: Promise.resolve(channel.show({ preserveFocus: true }));
|
||||
@@ -26,7 +25,7 @@ export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
||||
show.then(() => channel.append(chunk, this.toOutputSeverity(message)));
|
||||
}
|
||||
|
||||
private toOutputSeverity(message: ToolOutputMessage): OutputChannelSeverity {
|
||||
protected toOutputSeverity(message: OutputMessage): OutputChannelSeverity {
|
||||
if (message.severity) {
|
||||
switch (message.severity) {
|
||||
case 'error': return OutputChannelSeverity.Error
|
||||
@@ -6,20 +6,30 @@ import {
|
||||
ApplicationConnectionStatusContribution as TheiaApplicationConnectionStatusContribution,
|
||||
ConnectionStatus
|
||||
} from '@theia/core/lib/browser/connection-status-service';
|
||||
import { ArduinoDaemonClientImpl } from '../../arduino-daemon-client-impl';
|
||||
import { ArduinoDaemon } from '../../../common/protocol';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class FrontendConnectionStatusService extends TheiaFrontendConnectionStatusService {
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(ArduinoDaemon)
|
||||
protected readonly daemon: ArduinoDaemon;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected isRunning = false;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
protected async init(): Promise<void> {
|
||||
this.schedulePing();
|
||||
try {
|
||||
this.isRunning = await this.daemon.isRunning();
|
||||
} catch { }
|
||||
this.notificationCenter.onDaemonStarted(() => this.isRunning = true);
|
||||
this.notificationCenter.onDaemonStopped(() => this.isRunning = false);
|
||||
this.wsConnectionProvider.onIncomingMessageActivity(() => {
|
||||
// natural activity
|
||||
this.updateStatus(this.daemonClient.isRunning);
|
||||
this.updateStatus(this.isRunning);
|
||||
this.schedulePing();
|
||||
});
|
||||
}
|
||||
@@ -29,22 +39,35 @@ export class FrontendConnectionStatusService extends TheiaFrontendConnectionStat
|
||||
@injectable()
|
||||
export class ApplicationConnectionStatusContribution extends TheiaApplicationConnectionStatusContribution {
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(ArduinoDaemon)
|
||||
protected readonly daemon: ArduinoDaemon;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected isRunning = false;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
try {
|
||||
this.isRunning = await this.daemon.isRunning();
|
||||
} catch { }
|
||||
this.notificationCenter.onDaemonStarted(() => this.isRunning = true);
|
||||
this.notificationCenter.onDaemonStopped(() => this.isRunning = false);
|
||||
}
|
||||
|
||||
protected onStateChange(state: ConnectionStatus): void {
|
||||
if (!this.daemonClient.isRunning && state === ConnectionStatus.ONLINE) {
|
||||
if (!this.isRunning && state === ConnectionStatus.ONLINE) {
|
||||
return;
|
||||
}
|
||||
super.onStateChange(state);
|
||||
}
|
||||
|
||||
protected handleOffline(): void {
|
||||
const { isRunning } = this.daemonClient;
|
||||
this.statusBar.setElement('connection-status', {
|
||||
alignment: StatusBarAlignment.LEFT,
|
||||
text: isRunning ? 'Offline' : '$(bolt) CLI Daemon Offline',
|
||||
tooltip: isRunning ? 'Cannot connect to the backend.' : 'Cannot connect to the CLI daemon.',
|
||||
text: this.isRunning ? 'Offline' : '$(bolt) CLI Daemon Offline',
|
||||
tooltip: this.isRunning ? 'Cannot connect to the backend.' : 'Cannot connect to the CLI daemon.',
|
||||
priority: 5000
|
||||
});
|
||||
this.toDisposeOnOnline.push(Disposable.create(() => this.statusBar.removeElement('connection-status')));
|
||||
|
||||
@@ -10,17 +10,13 @@ import { Searchable } from '../../../common/protocol/searchable';
|
||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||
import { FilterableListContainer } from './filterable-list-container';
|
||||
import { ListItemRenderer } from './list-item-renderer';
|
||||
import { CoreServiceClientImpl } from '../../core-service-client-impl';
|
||||
import { ArduinoDaemonClientImpl } from '../../arduino-daemon-client-impl';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
|
||||
@injectable()
|
||||
export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget {
|
||||
|
||||
@inject(CoreServiceClientImpl)
|
||||
protected readonly coreServiceClient: CoreServiceClientImpl;
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
/**
|
||||
* Do not touch or use it. It is for setting the focus on the `input` after the widget activation.
|
||||
@@ -49,9 +45,9 @@ export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget
|
||||
protected init(): void {
|
||||
this.update();
|
||||
this.toDispose.pushAll([
|
||||
this.coreServiceClient.onIndexUpdated(() => this.refresh(undefined)),
|
||||
this.daemonClient.onDaemonStarted(() => this.refresh(undefined)),
|
||||
this.daemonClient.onDaemonStopped(() => this.refresh(undefined))
|
||||
this.notificationCenter.onIndexUpdated(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onDaemonStarted(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onDaemonStopped(() => this.refresh(undefined))
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user