Skip to content

Commit

Permalink
Add dialog to insert user fields for board that require them to upload (
Browse files Browse the repository at this point in the history
#550)

* Rebuild gRPC protocol interfaces

* Implement methods to get user fields for board/port combination

* Implement dialog to input board user fields

* Add configure and upload step when uploading to board requiring user fields

* Disable Sketch > Configure and Upload menu if board doesn't support user fields

* Fix serial upload not working with all boards

* Update i18n source file

* fix user fields UI

* regenerate cli protocol

* fix localisation

* check if user fields are empty

Co-authored-by: Alberto Iannaccone <a.iannaccone@arduino.cc>
  • Loading branch information
silvanocerza and Alberto Iannaccone authored Nov 25, 2021
1 parent 74bfdc4 commit a090dfe
Show file tree
Hide file tree
Showing 19 changed files with 568 additions and 679 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ export class ArduinoFrontendContribution
'arduino/debug/optimizeForDebugging',
'Optimize for Debugging'
),
order: '4',
order: '5',
});
}

Expand Down
11 changes: 11 additions & 0 deletions arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ import {
UploadCertificateDialogWidget,
} from './dialogs/certificate-uploader/certificate-uploader-dialog';
import { PlotterFrontendContribution } from './serial/plotter/plotter-frontend-contribution';
import {
UserFieldsDialog,
UserFieldsDialogProps,
UserFieldsDialogWidget,
} from './dialogs/user-fields/user-fields-dialog';
import { nls } from '@theia/core/lib/browser/nls';

const ElementQueries = require('css-element-queries/src/ElementQueries');
Expand Down Expand Up @@ -739,4 +744,10 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(UploadCertificateDialogProps).toConstantValue({
title: 'UploadCertificate',
});

bind(UserFieldsDialogWidget).toSelf().inSingletonScope();
bind(UserFieldsDialog).toSelf().inSingletonScope();
bind(UserFieldsDialogProps).toConstantValue({
title: 'UserFields',
});
});
85 changes: 62 additions & 23 deletions arduino-ide-extension/src/browser/boards/boards-service-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
BoardsPackage,
AttachedBoardsChangeEvent,
BoardWithPackage,
BoardUserField,
} from '../../common/protocol';
import { BoardsConfig } from './boards-config';
import { naturalCompare } from '../../common/utils';
Expand Down Expand Up @@ -68,7 +69,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
* This event is also emitted when the board package for the currently selected board was uninstalled.
*/
readonly onBoardsConfigChanged = this.onBoardsConfigChangedEmitter.event;
readonly onAvailableBoardsChanged = this.onAvailableBoardsChangedEmitter.event;
readonly onAvailableBoardsChanged =
this.onAvailableBoardsChangedEmitter.event;
readonly onAvailablePortsChanged = this.onAvailablePortsChangedEmitter.event;

onStart(): void {
Expand Down Expand Up @@ -183,8 +185,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
const selectedAvailableBoard = AvailableBoard.is(selectedBoard)
? selectedBoard
: this._availableBoards.find((availableBoard) =>
Board.sameAs(availableBoard, selectedBoard)
);
Board.sameAs(availableBoard, selectedBoard)
);
if (
selectedAvailableBoard &&
selectedAvailableBoard.selected &&
Expand Down Expand Up @@ -274,6 +276,18 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
return boards;
}

async selectedBoardUserFields(): Promise<BoardUserField[]> {
if (!this._boardsConfig.selectedBoard || !this._boardsConfig.selectedPort) {
return [];
}
const fqbn = this._boardsConfig.selectedBoard.fqbn;
if (!fqbn) {
return [];
}
const protocol = this._boardsConfig.selectedPort.protocol;
return await this.boardsService.getBoardUserFields({ fqbn, protocol });
}

/**
* `true` if the `config.selectedBoard` is defined; hence can compile against the board. Otherwise, `false`.
*/
Expand Down Expand Up @@ -361,14 +375,14 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
const timeoutTask =
!!timeout && timeout > 0
? new Promise<void>((_, reject) =>
setTimeout(
() => reject(new Error(`Timeout after ${timeout} ms.`)),
timeout
setTimeout(
() => reject(new Error(`Timeout after ${timeout} ms.`)),
timeout
)
)
)
: new Promise<void>(() => {
/* never */
});
/* never */
});
const waitUntilTask = new Promise<void>((resolve) => {
let candidate = find(what, this.availableBoards);
if (candidate) {
Expand Down Expand Up @@ -406,7 +420,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
const availableBoards: AvailableBoard[] = [];
const attachedBoards = this._attachedBoards.filter(({ port }) => !!port);
const availableBoardPorts = availablePorts.filter((port) => {
if (port.protocol === "serial") {
if (port.protocol === 'serial') {
// We always show all serial ports, even if there
// is no recognized board connected to it
return true;
Expand All @@ -424,8 +438,12 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
});

for (const boardPort of availableBoardPorts) {
let board = attachedBoards.find(({ port }) => Port.sameAs(boardPort, port));
const lastSelectedBoard = await this.getLastSelectedBoardOnPort(boardPort);
const board = attachedBoards.find(({ port }) =>
Port.sameAs(boardPort, port)
);
const lastSelectedBoard = await this.getLastSelectedBoardOnPort(
boardPort
);

let availableBoard = {} as AvailableBoard;
if (board) {
Expand Down Expand Up @@ -454,11 +472,16 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
availableBoards.push(availableBoard);
}

if (boardsConfig.selectedBoard && !availableBoards.some(({ selected }) => selected)) {
if (
boardsConfig.selectedBoard &&
!availableBoards.some(({ selected }) => selected)
) {
// If the selected board has the same port of an unknown board
// that is already in availableBoards we might get a duplicate port.
// So we remove the one already in the array and add the selected one.
const found = availableBoards.findIndex(board => board.port?.address === boardsConfig.selectedPort?.address);
const found = availableBoards.findIndex(
(board) => board.port?.address === boardsConfig.selectedPort?.address
);
if (found >= 0) {
availableBoards.splice(found, 1);
}
Expand All @@ -475,15 +498,19 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
let hasChanged = availableBoards.length !== currentAvailableBoards.length;
for (let i = 0; !hasChanged && i < availableBoards.length; i++) {
const [left, right] = [availableBoards[i], currentAvailableBoards[i]];
hasChanged = !!AvailableBoard.compare(left, right) || left.selected !== right.selected;
hasChanged =
!!AvailableBoard.compare(left, right) ||
left.selected !== right.selected;
}
if (hasChanged) {
this._availableBoards = availableBoards;
this.onAvailableBoardsChangedEmitter.fire(this._availableBoards);
}
}

protected async getLastSelectedBoardOnPort(port: Port): Promise<Board | undefined> {
protected async getLastSelectedBoardOnPort(
port: Port
): Promise<Board | undefined> {
const key = this.getLastSelectedBoardOnPortKey(port);
return this.getData<Board>(key);
}
Expand All @@ -504,8 +531,11 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
]);
}

protected getLastSelectedBoardOnPortKey(port: Port): string {
return `last-selected-board-on-port:${Port.toString(port)}`;
protected getLastSelectedBoardOnPortKey(port: Port | string): string {
// TODO: we lose the port's `protocol` info (`serial`, `network`, etc.) here if the `port` is a `string`.
return `last-selected-board-on-port:${
typeof port === 'string' ? port : Port.toString(port)
}`;
}

protected async loadState(): Promise<void> {
Expand Down Expand Up @@ -596,13 +626,22 @@ export namespace AvailableBoard {
// 4. Network with recognized boards
// 5. Other protocols with recognized boards
export const compare = (left: AvailableBoard, right: AvailableBoard) => {
if (left.port?.protocol === "serial" && right.port?.protocol !== "serial") {
if (left.port?.protocol === 'serial' && right.port?.protocol !== 'serial') {
return -1;
} else if (left.port?.protocol !== "serial" && right.port?.protocol === "serial") {
} else if (
left.port?.protocol !== 'serial' &&
right.port?.protocol === 'serial'
) {
return 1;
} else if (left.port?.protocol === "network" && right.port?.protocol !== "network") {
} else if (
left.port?.protocol === 'network' &&
right.port?.protocol !== 'network'
) {
return -1;
} else if (left.port?.protocol !== "network" && right.port?.protocol === "network") {
} else if (
left.port?.protocol !== 'network' &&
right.port?.protocol === 'network'
) {
return 1;
} else if (left.port?.protocol === right.port?.protocol) {
// We show all ports, including those that have guessed
Expand All @@ -614,5 +653,5 @@ export namespace AvailableBoard {
}
}
return naturalCompare(left.port?.address!, right.port?.address!);
}
};
}
Loading

0 comments on commit a090dfe

Please sign in to comment.