diff --git a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx index 9d337ac1..bb926a04 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx +++ b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx @@ -36,7 +36,7 @@ import { ColorContribution } from '@theia/core/lib/browser/color-application-con import { ColorRegistry } from '@theia/core/lib/browser/color-registry'; import { ArduinoDaemon } from '../common/protocol/arduino-daemon'; import { ConfigService } from '../common/protocol/config-service'; -import { BoardsConfigStore } from './boards/boards-config-store'; +import { BoardsDataStore } from './boards/boards-data-store'; import { MainMenuManager } from '../common/main-menu-manager'; import { FileSystemExt } from '../common/protocol/filesystem-ext'; import { ArduinoMenus } from './menu/arduino-menus'; @@ -130,8 +130,8 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut @inject(ConfigService) protected readonly configService: ConfigService; - @inject(BoardsConfigStore) - protected readonly boardsConfigStore: BoardsConfigStore; + @inject(BoardsDataStore) + protected readonly boardsDataStore: BoardsDataStore; @inject(MainMenuManager) protected readonly mainMenuManager: MainMenuManager; diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 42daed28..d7e3f1aa 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -82,8 +82,8 @@ import { } from '@theia/core/lib/browser/connection-status-service'; import { ConfigServiceClientImpl } from './config-service-client-impl'; import { CoreServiceClientImpl } from './core-service-client-impl'; -import { BoardsDetailsMenuUpdater } from './boards/boards-details-menu-updater'; -import { BoardsConfigStore } from './boards/boards-config-store'; +import { BoardsDataMenuUpdater } from './boards/boards-details-menu-updater'; +import { BoardsDataStore } from './boards/boards-data-store'; import { ILogger } from '@theia/core'; import { FileSystemExt, FileSystemExtPath } from '../common/protocol/filesystem-ext'; import { WorkspaceFrontendContribution as TheiaWorkspaceFrontendContribution, FileMenuContribution as TheiaFileMenuContribution } from '@theia/workspace/lib/browser'; @@ -183,9 +183,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { }).inSingletonScope(); // 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(BoardsDetailsMenuUpdater).inSingletonScope(); - bind(BoardsConfigStore).toSelf().inSingletonScope(); - bind(FrontendApplicationContribution).toService(BoardsConfigStore); + bind(FrontendApplicationContribution).to(BoardsDataMenuUpdater).inSingletonScope(); + bind(BoardsDataStore).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(BoardsDataStore); // Logger for the Arduino daemon bind(ILogger).toDynamicValue(ctx => { const parentLogger = ctx.container.get(ILogger); diff --git a/arduino-ide-extension/src/browser/boards/boards-config-store.ts b/arduino-ide-extension/src/browser/boards/boards-data-store.ts similarity index 64% rename from arduino-ide-extension/src/browser/boards/boards-config-store.ts rename to arduino-ide-extension/src/browser/boards/boards-data-store.ts index 8967174c..8ef40676 100644 --- a/arduino-ide-extension/src/browser/boards/boards-config-store.ts +++ b/arduino-ide-extension/src/browser/boards/boards-data-store.ts @@ -1,14 +1,15 @@ import { injectable, inject, named } from 'inversify'; import { ILogger } from '@theia/core/lib/common/logger'; +import { deepClone } from '@theia/core/lib/common/objects'; import { MaybePromise } from '@theia/core/lib/common/types'; import { Event, Emitter } from '@theia/core/lib/common/event'; -import { deepClone, notEmpty } from '@theia/core/lib/common/objects'; import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser'; -import { BoardsService, ConfigOption, Installable, BoardDetails } from '../../common/protocol'; +import { notEmpty } from '../../common/utils'; import { BoardsServiceClientImpl } from './boards-service-client-impl'; +import { BoardsService, ConfigOption, Installable, BoardDetails, Programmer } from '../../common/protocol'; @injectable() -export class BoardsConfigStore implements FrontendApplicationContribution { +export class BoardsDataStore implements FrontendApplicationContribution { @inject(ILogger) @named('store') @@ -60,39 +61,59 @@ export class BoardsConfigStore implements FrontendApplicationContribution { fqbn: string, boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { - const configOptions = await this.getConfig(fqbn, boardsPackageVersion); + const { configOptions } = await this.getData(fqbn, boardsPackageVersion); return ConfigOption.decorate(fqbn, configOptions); } - async getConfig( + async getData( fqbn: string, - boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { + boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { const version = await boardsPackageVersion; if (!version) { - return []; + return BoardsDataStore.Data.EMPTY; } const key = this.getStorageKey(fqbn, version); - let configOptions = await this.storageService.getData(key, undefined); - if (configOptions) { - return configOptions; + let data = await this.storageService.getData(key, undefined); + if (data) { + if (data.programmers !== undefined) { // to be backward compatible. We did not save the `programmers` into the `localStorage`. + return data; + } } - const details = await this.getBoardDetailsSafe(fqbn); - if (!details) { - return []; + const boardDetails = await this.getBoardDetailsSafe(fqbn); + if (!boardDetails) { + return BoardsDataStore.Data.EMPTY; } - configOptions = details.configOptions; - await this.storageService.setData(key, configOptions); - return configOptions; + data = { configOptions: boardDetails.configOptions, programmers: boardDetails.programmers }; + await this.storageService.setData(key, data); + return data; } - async setSelected( + async selectProgrammer( + { fqbn, programmer }: { fqbn: string, programmer: Programmer }, + boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { + + const { configOptions, programmers } = deepClone(await this.getData(fqbn, boardsPackageVersion)); + if (!programmers.find(p => Programmer.equals(programmer, p))) { + return false; + } + + const version = await boardsPackageVersion; + if (!version) { + return false; + } + await this.setData({ fqbn, data: { configOptions, programmers }, version }); + this.fireChanged(); + return true; + } + + async selectConfigOption( { fqbn, option, selectedValue }: { fqbn: string, option: string, selectedValue: string }, boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { - const configOptions = deepClone(await this.getConfig(fqbn, boardsPackageVersion)); + const { configOptions, programmers } = deepClone(await this.getData(fqbn, boardsPackageVersion)); const configOption = configOptions.find(c => c.option === option); if (!configOption) { return false; @@ -113,16 +134,16 @@ export class BoardsConfigStore implements FrontendApplicationContribution { if (!version) { return false; } - await this.setConfig({ fqbn, configOptions, version }); + await this.setData({ fqbn, data: { configOptions, programmers }, version }); this.fireChanged(); return true; } - protected async setConfig( - { fqbn, configOptions, version }: { fqbn: string, configOptions: ConfigOption[], version: Installable.Version }): Promise { + protected async setData( + { fqbn, data, version }: { fqbn: string, data: BoardsDataStore.Data, version: Installable.Version }): Promise { const key = this.getStorageKey(fqbn, version); - return this.storageService.setData(key, configOptions); + return this.storageService.setData(key, data); } protected getStorageKey(fqbn: string, version: Installable.Version): string { @@ -159,3 +180,16 @@ export class BoardsConfigStore implements FrontendApplicationContribution { } } + +export namespace BoardsDataStore { + export interface Data { + readonly configOptions: ConfigOption[]; + readonly programmers: Programmer[]; + } + export namespace Data { + export const EMPTY: Data = { + configOptions: [], + programmers: [] + }; + } +} diff --git a/arduino-ide-extension/src/browser/boards/boards-details-menu-updater.ts b/arduino-ide-extension/src/browser/boards/boards-details-menu-updater.ts index e7f1688d..8a135703 100644 --- a/arduino-ide-extension/src/browser/boards/boards-details-menu-updater.ts +++ b/arduino-ide-extension/src/browser/boards/boards-details-menu-updater.ts @@ -5,12 +5,12 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa import { BoardsServiceClientImpl } from './boards-service-client-impl'; import { Board, ConfigOption } from '../../common/protocol'; import { FrontendApplicationContribution } from '@theia/core/lib/browser'; -import { BoardsConfigStore } from './boards-config-store'; +import { BoardsDataStore } from './boards-data-store'; import { MainMenuManager } from '../../common/main-menu-manager'; import { ArduinoMenus } from '../menu/arduino-menus'; @injectable() -export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution { +export class BoardsDataMenuUpdater implements FrontendApplicationContribution { @inject(CommandRegistry) protected readonly commandRegistry: CommandRegistry; @@ -21,8 +21,8 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution @inject(MainMenuManager) protected readonly mainMenuManager: MainMenuManager; - @inject(BoardsConfigStore) - protected readonly boardsConfigStore: BoardsConfigStore; + @inject(BoardsDataStore) + protected readonly boardsDataStore: BoardsDataStore; @inject(BoardsServiceClientImpl) protected readonly boardsServiceClient: BoardsServiceClientImpl; @@ -30,7 +30,7 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution protected readonly toDisposeOnBoardChange = new DisposableCollection(); onStart(): void { - this.boardsConfigStore.onChanged(() => this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard)); + this.boardsDataStore.onChanged(() => this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard)); this.boardsServiceClient.onBoardsConfigChanged(({ selectedBoard }) => this.updateMenuActions(selectedBoard)); this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard); } @@ -41,8 +41,8 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution this.mainMenuManager.update(); const { fqbn } = selectedBoard; if (fqbn) { - const configOptions = await this.boardsConfigStore.getConfig(fqbn); - const boardsConfigMenuPath = [...ArduinoMenus.TOOLS, 'z_boardsConfig']; // `z_` is for ordering. + const { configOptions, programmers } = await this.boardsDataStore.getData(fqbn); + const boardsConfigMenuPath = [...ArduinoMenus.TOOLS, 'z01_boardsConfig']; // `z_` is for ordering. for (const { label, option, values } of configOptions.sort(ConfigOption.LABEL_COMPARATOR)) { const menuPath = [...boardsConfigMenuPath, `${option}`]; const commands = new Map() @@ -51,7 +51,7 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution const command = { id }; const selectedValue = value.value; const handler = { - execute: () => this.boardsConfigStore.setSelected({ fqbn, option, selectedValue }), + execute: () => this.boardsDataStore.selectConfigOption({ fqbn, option, selectedValue }), isToggled: () => value.selected }; commands.set(id, Object.assign(this.commandRegistry.registerCommand(command, handler), { label: value.label })); @@ -67,6 +67,18 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution }) ]); } + const programmersMenuPath = [...ArduinoMenus.TOOLS, 'z02_programmers']; + for (const programmer of programmers) { + const { id, name } = programmer; + const menuPath = [...programmersMenuPath, `${name}`]; + const command = { id: `${fqbn}-programmer--${id}` }; + const handler = { execute: () => this.boardsDataStore.selectProgrammer({ fqbn, programmer }) }; + this.menuRegistry.registerMenuAction(menuPath, { commandId: command.id, label: name }); + this.toDisposeOnBoardChange.pushAll([ + this.commandRegistry.registerCommand(command, handler), + Disposable.create(() => this.menuRegistry.unregisterMenuAction(command, menuPath)) + ]); + } this.mainMenuManager.update(); } } diff --git a/arduino-ide-extension/src/browser/boards/quick-open/boards-quick-open-service.ts b/arduino-ide-extension/src/browser/boards/quick-open/boards-quick-open-service.ts index 6f9f6b74..45c76041 100644 --- a/arduino-ide-extension/src/browser/boards/quick-open/boards-quick-open-service.ts +++ b/arduino-ide-extension/src/browser/boards/quick-open/boards-quick-open-service.ts @@ -17,7 +17,7 @@ import { import { naturalCompare } from '../../../common/utils'; import { BoardsService, Port, Board, ConfigOption, ConfigValue } from '../../../common/protocol'; import { CoreServiceClientImpl } from '../../core-service-client-impl'; -import { BoardsConfigStore } from '../boards-config-store'; +import { BoardsDataStore } from '../boards-data-store'; import { BoardsServiceClientImpl, AvailableBoard } from '../boards-service-client-impl'; @injectable() @@ -41,8 +41,8 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM @inject(BoardsServiceClientImpl) protected readonly boardsServiceClient: BoardsServiceClientImpl; - @inject(BoardsConfigStore) - protected readonly configStore: BoardsConfigStore; + @inject(BoardsDataStore) + protected readonly boardsDataStore: BoardsDataStore; @inject(CoreServiceClientImpl) protected coreServiceClient: CoreServiceClientImpl; @@ -52,7 +52,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM // Attached boards plus the user's config. protected availableBoards: AvailableBoard[] = []; // Only for the `selected` one from the `availableBoards`. Note: the `port` of the `selected` is optional. - protected boardConfigs: ConfigOption[] = []; + protected data: BoardsDataStore.Data = BoardsDataStore.Data.EMPTY; protected allBoards: Board.Detailed[] = [] protected selectedBoard?: (AvailableBoard & { port: Port }); @@ -86,7 +86,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM placeholder += 'No board selected.'; } placeholder += 'Type to filter boards'; - if (this.boardConfigs.length) { + if (this.data.configOptions.length) { placeholder += ' or use the ↓↑ keys to adjust the board settings...'; } else { placeholder += '...'; @@ -129,7 +129,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM // Show the config only if the `input` is empty. if (!lookFor.trim().length) { - toAccept.push(...this.boardConfigs.map((config, i) => { + toAccept.push(...this.data.configOptions.map((config, i) => { let group: QuickOpenGroupItemOptions | undefined = undefined; if (i === 0) { group = { groupLabel: 'Board Settings', showBorder: true }; @@ -157,14 +157,14 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM protected async update(availableBoards: AvailableBoard[]): Promise { // `selectedBoard` is not an attached board, we need to show the board settings for it (TODO: clarify!) const selectedBoard = availableBoards.filter(AvailableBoard.hasPort).find(({ selected }) => selected); - const [configs, boards] = await Promise.all([ - selectedBoard && selectedBoard.fqbn ? this.configStore.getConfig(selectedBoard.fqbn) : Promise.resolve([]), + const [data, boards] = await Promise.all([ + selectedBoard && selectedBoard.fqbn ? this.boardsDataStore.getData(selectedBoard.fqbn) : Promise.resolve(BoardsDataStore.Data.EMPTY), this.boardsService.allBoards({}) ]); this.allBoards = Board.decorateBoards(selectedBoard, boards) .filter(board => !availableBoards.some(availableBoard => Board.sameAs(availableBoard, board))); this.availableBoards = availableBoards; - this.boardConfigs = configs; + this.data = data; this.selectedBoard = selectedBoard; if (this.isOpen) { @@ -280,7 +280,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM return; } const { fqbn } = this.selectedBoard; - this.configStore.setSelected({ + this.boardsDataStore.selectConfigOption({ fqbn, option: config.option, selectedValue: value.value diff --git a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts index 8ce87723..5012338f 100644 --- a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts @@ -1,7 +1,7 @@ import { inject, injectable } from 'inversify'; import { CoreService } from '../../common/protocol'; import { MonitorConnection } from '../monitor/monitor-connection'; -import { BoardsConfigStore } from '../boards/boards-config-store'; +import { BoardsDataStore } from '../boards/boards-data-store'; import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl'; import { ArduinoMenus } from '../menu/arduino-menus'; import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; @@ -16,8 +16,8 @@ export class UploadSketch extends SketchContribution { @inject(MonitorConnection) protected readonly monitorConnection: MonitorConnection; - @inject(BoardsConfigStore) - protected readonly boardsConfigStore: BoardsConfigStore; + @inject(BoardsDataStore) + protected readonly boardsDataStore: BoardsDataStore; @inject(BoardsServiceClientImpl) protected readonly boardsServiceClientImpl: BoardsServiceClientImpl; @@ -77,7 +77,7 @@ export class UploadSketch extends SketchContribution { if (!boardsConfig.selectedBoard.fqbn) { throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`); } - const fqbn = await this.boardsConfigStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); + const fqbn = await this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); await this.coreService.upload({ sketchUri: sketch.uri, fqbn, diff --git a/arduino-ide-extension/src/browser/contributions/verify-sketch.ts b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts index 6c52783c..3421c5be 100644 --- a/arduino-ide-extension/src/browser/contributions/verify-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts @@ -1,7 +1,7 @@ import { inject, injectable } from 'inversify'; import { ArduinoMenus } from '../menu/arduino-menus'; import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; -import { BoardsConfigStore } from '../boards/boards-config-store'; +import { BoardsDataStore } from '../boards/boards-data-store'; import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl'; import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution'; import { CoreService } from '../../common/protocol'; @@ -12,8 +12,8 @@ export class VerifySketch extends SketchContribution { @inject(CoreService) protected readonly coreService: CoreService; - @inject(BoardsConfigStore) - protected readonly boardsConfigStore: BoardsConfigStore; + @inject(BoardsDataStore) + protected readonly boardsDataStore: BoardsDataStore; @inject(BoardsServiceClientImpl) protected readonly boardsServiceClientImpl: BoardsServiceClientImpl; @@ -65,7 +65,7 @@ export class VerifySketch extends SketchContribution { if (!boardsConfig.selectedBoard.fqbn) { throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`); } - const fqbn = await this.boardsConfigStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); + const fqbn = await this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); await this.coreService.compile({ sketchUri: sketch.uri, fqbn, diff --git a/arduino-ide-extension/src/common/protocol/boards-service.ts b/arduino-ide-extension/src/common/protocol/boards-service.ts index ba0b3dd3..8c6c7dc0 100644 --- a/arduino-ide-extension/src/common/protocol/boards-service.ts +++ b/arduino-ide-extension/src/common/protocol/boards-service.ts @@ -205,6 +205,7 @@ export interface BoardDetails { readonly fqbn: string; readonly requiredTools: Tool[]; readonly configOptions: ConfigOption[]; + readonly programmers: Programmer[]; } export interface Tool { @@ -269,6 +270,23 @@ export interface ConfigValue { readonly selected: boolean; } +export interface Programmer { + readonly name: string; + readonly platform: string; + readonly id: string; +} +export namespace Programmer { + export function equals(left: Programmer | undefined, right: Programmer | undefined): boolean { + if (!left) { + return !right; + } + if (!right) { + return !left; + } + return left.id === right.id && left.name === right.name && left.platform === right.platform; + } +} + export namespace Board { export function is(board: any): board is Board { diff --git a/arduino-ide-extension/src/common/utils.ts b/arduino-ide-extension/src/common/utils.ts index 77dbaf54..7c438918 100644 --- a/arduino-ide-extension/src/common/utils.ts +++ b/arduino-ide-extension/src/common/utils.ts @@ -1 +1,5 @@ export const naturalCompare: (left: string, right: string) => number = require('string-natural-compare').caseInsensitive; + +export function notEmpty(arg: string | undefined | null): arg is string { + return !!arg; +} diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index d70f72a1..a46e1360 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -1,7 +1,7 @@ import { injectable, inject, postConstruct, named } from 'inversify'; import { ILogger } from '@theia/core/lib/common/logger'; import { Deferred } from '@theia/core/lib/common/promise-util'; -import { BoardsService, BoardsPackage, Board, BoardsServiceClient, Port, BoardDetails, Tool, ConfigOption, ConfigValue } from '../common/protocol'; +import { BoardsService, BoardsPackage, Board, BoardsServiceClient, Port, BoardDetails, Tool, ConfigOption, ConfigValue, Programmer } from '../common/protocol'; import { PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq, PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq @@ -10,6 +10,7 @@ import { CoreClientProvider } from './core-client-provider'; import { BoardListReq, BoardListResp, BoardDetailsReq, BoardDetailsResp } from './cli-protocol/commands/board_pb'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; import { Installable } from '../common/protocol/installable'; +import { ListProgrammersAvailableForUploadReq, ListProgrammersAvailableForUploadResp } from './cli-protocol/commands/upload_pb'; @injectable() export class BoardsServiceImpl implements BoardsService { @@ -209,10 +210,10 @@ export class BoardsServiceImpl implements BoardsService { const { client, instance } = coreClient; const { fqbn } = options; - const req = new BoardDetailsReq(); - req.setInstance(instance); - req.setFqbn(fqbn); - const resp = await new Promise((resolve, reject) => client.boardDetails(req, (err, resp) => { + const detailsReq = new BoardDetailsReq(); + detailsReq.setInstance(instance); + detailsReq.setFqbn(fqbn); + const detailsResp = await new Promise((resolve, reject) => client.boardDetails(detailsReq, (err, resp) => { if (err) { reject(err); return; @@ -220,13 +221,13 @@ export class BoardsServiceImpl implements BoardsService { resolve(resp); })); - const requiredTools = resp.getToolsdependenciesList().map(t => { + const requiredTools = detailsResp.getToolsdependenciesList().map(t => { name: t.getName(), packager: t.getPackager(), version: t.getVersion() }); - const configOptions = resp.getConfigOptionsList().map(c => { + const configOptions = detailsResp.getConfigOptionsList().map(c => { label: c.getOptionLabel(), option: c.getOption(), values: c.getValuesList().map(v => { @@ -236,10 +237,28 @@ export class BoardsServiceImpl implements BoardsService { }) }); + const listReq = new ListProgrammersAvailableForUploadReq(); + listReq.setInstance(instance); + listReq.setFqbn(fqbn); + const listResp = await new Promise((resolve, reject) => client.listProgrammersAvailableForUpload(listReq, (err, resp) => { + if (err) { + reject(err); + return; + } + resolve(resp); + })); + + const programmers = listResp.getProgrammersList().map(p => { + id: p.getId(), + name: p.getName(), + platform: p.getPlatform() + }); + return { fqbn, requiredTools, - configOptions + configOptions, + programmers }; }