Fix dialogs UI scalability (#1311)

* make dialogs scroll when scaling up the UI

* add unit of measure to settings step input

* wrap settings dialog items when scaling up the UI

* fix dialogs width when scaling up the UI

* rework board config UI to make it scale up better

* refactor ide updater dialog: move buttons outside the dialog content

* refactor ide updater dialog: clean-up code and rename events

* fix board config dialog title case and and remove double ellipsis
This commit is contained in:
Alberto Iannaccone
2022-08-18 16:42:16 +02:00
committed by GitHub
parent 79ea0fa9a6
commit de32bddc20
20 changed files with 378 additions and 301 deletions

View File

@@ -453,7 +453,10 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(BoardsConfigDialogWidget).toSelf().inSingletonScope();
bind(BoardsConfigDialog).toSelf().inSingletonScope();
bind(BoardsConfigDialogProps).toConstantValue({
title: nls.localize('arduino/common/selectBoard', 'Select Board'),
title: nls.localize(
'arduino/board/boardConfigDialogTitle',
'Select Other Board and Port'
),
});
// Core service

View File

@@ -1,4 +1,8 @@
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
import {
injectable,
inject,
postConstruct,
} from '@theia/core/shared/inversify';
import { Message } from '@theia/core/shared/@phosphor/messaging';
import { DialogProps, Widget, DialogError } from '@theia/core/lib/browser';
import { AbstractDialog } from '../theia/dialogs/dialogs';
@@ -28,7 +32,7 @@ export class BoardsConfigDialog extends AbstractDialog<BoardsConfig.Config> {
@inject(BoardsConfigDialogProps)
protected override readonly props: BoardsConfigDialogProps
) {
super(props);
super({ ...props, maxWidth: 500 });
this.contentNode.classList.add('select-board-dialog');
this.contentNode.appendChild(this.createDescription());
@@ -65,14 +69,6 @@ export class BoardsConfigDialog extends AbstractDialog<BoardsConfig.Config> {
const head = document.createElement('div');
head.classList.add('head');
const title = document.createElement('div');
title.textContent = nls.localize(
'arduino/board/configDialogTitle',
'Select Other Board & Port'
);
title.classList.add('title');
head.appendChild(title);
const text = document.createElement('div');
text.classList.add('text');
head.appendChild(text);

View File

@@ -258,14 +258,14 @@ export class BoardsConfig extends React.Component<
override render(): React.ReactNode {
return (
<div className="body">
<>
{this.renderContainer('boards', this.renderBoards.bind(this))}
{this.renderContainer(
'ports',
this.renderPorts.bind(this),
this.renderPortsFooter.bind(this)
)}
</div>
</>
);
}

View File

@@ -1,5 +1,9 @@
import * as React from '@theia/core/shared/react';
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import {
inject,
injectable,
postConstruct,
} from '@theia/core/shared/inversify';
import { DialogProps } from '@theia/core/lib/browser/dialogs';
import { AbstractDialog } from '../../theia/dialogs/dialogs';
import { Widget } from '@theia/core/shared/@phosphor/widgets';
@@ -153,6 +157,7 @@ export class UploadCertificateDialog extends AbstractDialog<void> {
'Upload SSL Root Certificates'
),
});
this.node.id = 'certificate-uploader-dialog-container';
this.contentNode.classList.add('certificate-uploader-dialog');
this.acceptButton = undefined;
}

View File

@@ -101,6 +101,7 @@ export class UploadFirmwareDialog extends AbstractDialog<void> {
protected override readonly props: UploadFirmwareDialogProps
) {
super({ title: UploadFirmware.Commands.OPEN.label || '' });
this.node.id = 'firmware-uploader-dialog-container';
this.contentNode.classList.add('firmware-uploader-dialog');
this.acceptButton = undefined;
}

View File

@@ -1,4 +1,3 @@
import { WindowService } from '@theia/core/lib/browser/window/window-service';
import { nls } from '@theia/core/lib/common';
import { shell } from 'electron';
import * as React from '@theia/core/shared/react';
@@ -7,36 +6,32 @@ import ReactMarkdown from 'react-markdown';
import { ProgressInfo, UpdateInfo } from '../../../common/protocol/ide-updater';
import ProgressBar from '../../components/ProgressBar';
export type IDEUpdaterComponentProps = {
updateInfo: UpdateInfo;
windowService: WindowService;
export interface UpdateProgress {
progressInfo?: ProgressInfo | undefined;
downloadFinished?: boolean;
downloadStarted?: boolean;
progress?: ProgressInfo;
error?: Error;
onDownload: () => void;
onClose: () => void;
onSkipVersion: () => void;
onCloseAndInstall: () => void;
};
}
export interface IDEUpdaterComponentProps {
updateInfo: UpdateInfo;
updateProgress: UpdateProgress;
}
export const IDEUpdaterComponent = ({
updateInfo: { version, releaseNotes },
downloadStarted = false,
downloadFinished = false,
windowService,
progress,
error,
onDownload,
onClose,
onSkipVersion,
onCloseAndInstall,
updateInfo,
updateProgress: {
downloadStarted = false,
downloadFinished = false,
progressInfo,
error,
},
}: IDEUpdaterComponentProps): React.ReactElement => {
const changelogDivRef = React.useRef() as React.MutableRefObject<
HTMLDivElement
>;
const { version, releaseNotes } = updateInfo;
const changelogDivRef =
React.useRef() as React.MutableRefObject<HTMLDivElement>;
React.useEffect(() => {
if (!!releaseNotes) {
if (!!releaseNotes && changelogDivRef.current) {
let changelog: string;
if (typeof releaseNotes === 'string') changelog = releaseNotes;
else
@@ -58,12 +53,7 @@ export const IDEUpdaterComponent = ({
changelogDivRef.current
);
}
}, [releaseNotes]);
const closeButton = (
<button onClick={onClose} type="button" className="theia-button secondary">
{nls.localize('arduino/ide-updater/notNowButton', 'Not now')}
</button>
);
}, [updateInfo]);
const DownloadCompleted: () => React.ReactElement = () => (
<div className="ide-updater-dialog--downloaded">
@@ -80,19 +70,6 @@ export const IDEUpdaterComponent = ({
'Close the software and install the update on your machine.'
)}
</div>
<div className="buttons-container">
{closeButton}
<button
onClick={onCloseAndInstall}
type="button"
className="theia-button close-and-install"
>
{nls.localize(
'arduino/ide-updater/closeAndInstallButton',
'Close and Install'
)}
</button>
</div>
</div>
);
@@ -104,7 +81,7 @@ export const IDEUpdaterComponent = ({
'Downloading the latest version of the Arduino IDE.'
)}
</div>
<ProgressBar percent={progress?.percent} showPercentage />
<ProgressBar percent={progressInfo?.percent} showPercentage />
</div>
);
@@ -130,46 +107,14 @@ export const IDEUpdaterComponent = ({
)}
</div>
{releaseNotes && (
<div className="dialogRow">
<div className="changelog-container" ref={changelogDivRef} />
<div className="dialogRow changelog-container">
<div className="changelog" ref={changelogDivRef} />
</div>
)}
<div className="buttons-container">
<button
onClick={onSkipVersion}
type="button"
className="theia-button secondary skip-version"
>
{nls.localize(
'arduino/ide-updater/skipVersionButton',
'Skip Version'
)}
</button>
<div className="push"></div>
{closeButton}
<button
onClick={onDownload}
type="button"
className="theia-button primary"
>
{nls.localize('arduino/ide-updater/downloadButton', 'Download')}
</button>
</div>
</div>
</div>
);
const onGoToDownloadClick = (
event: React.SyntheticEvent<HTMLAnchorElement, Event>
) => {
const { target } = event.nativeEvent;
if (target instanceof HTMLAnchorElement) {
event.nativeEvent.preventDefault();
windowService.openNewWindow(target.href, { external: true });
onClose();
}
};
const GoToDownloadPage: () => React.ReactElement = () => (
<div className="ide-updater-dialog--go-to-download-page">
<div>
@@ -178,19 +123,6 @@ export const IDEUpdaterComponent = ({
"An update for the Arduino IDE is available, but we're not able to download and install it automatically. Please go to the download page and download the latest version from there."
)}
</div>
<div className="buttons-container">
{closeButton}
<a
className="theia-button primary"
href="https://www.arduino.cc/en/software#experimental-software"
onClick={onGoToDownloadClick}
>
{nls.localize(
'arduino/ide-updater/goToDownloadButton',
'Go To Download'
)}
</a>
</div>
</div>
);

View File

@@ -1,113 +1,57 @@
import * as React from '@theia/core/shared/react';
import { inject, injectable } from '@theia/core/shared/inversify';
import {
inject,
injectable,
postConstruct,
} from '@theia/core/shared/inversify';
import { DialogProps } from '@theia/core/lib/browser/dialogs';
import { AbstractDialog } from '../../theia/dialogs/dialogs';
import { Widget } from '@theia/core/shared/@phosphor/widgets';
import { Message } from '@theia/core/shared/@phosphor/messaging';
import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';
import { nls } from '@theia/core';
import { IDEUpdaterComponent } from './ide-updater-component';
import { IDEUpdaterComponent, UpdateProgress } from './ide-updater-component';
import {
IDEUpdater,
IDEUpdaterClient,
ProgressInfo,
SKIP_IDE_VERSION,
UpdateInfo,
} from '../../../common/protocol/ide-updater';
import { LocalStorageService } from '@theia/core/lib/browser';
import { WindowService } from '@theia/core/lib/browser/window/window-service';
const DOWNLOAD_PAGE_URL =
'https://www.arduino.cc/en/software#experimental-software';
@injectable()
export class IDEUpdaterDialogWidget extends ReactWidget {
protected isOpen = new Object();
updateInfo: UpdateInfo;
progressInfo: ProgressInfo | undefined;
error: Error | undefined;
downloadFinished: boolean;
downloadStarted: boolean;
onClose: () => void;
private _updateInfo: UpdateInfo;
private _updateProgress: UpdateProgress = {};
@inject(IDEUpdater)
protected readonly updater: IDEUpdater;
@inject(IDEUpdaterClient)
protected readonly updaterClient: IDEUpdaterClient;
@inject(LocalStorageService)
protected readonly localStorageService: LocalStorageService;
@inject(WindowService)
protected windowService: WindowService;
init(updateInfo: UpdateInfo, onClose: () => void): void {
this.updateInfo = updateInfo;
this.progressInfo = undefined;
this.error = undefined;
this.downloadStarted = false;
this.downloadFinished = false;
this.onClose = onClose;
this.updaterClient.onError((e) => {
this.error = e;
this.update();
});
this.updaterClient.onDownloadProgressChanged((e) => {
this.progressInfo = e;
this.update();
});
this.updaterClient.onDownloadFinished((e) => {
this.downloadFinished = true;
this.update();
});
}
async onSkipVersion(): Promise<void> {
this.localStorageService.setData<string>(
SKIP_IDE_VERSION,
this.updateInfo.version
);
this.close();
}
override close(): void {
super.close();
this.onClose();
}
onDispose(): void {
if (this.downloadStarted && !this.downloadFinished)
this.updater.stopDownload();
}
async onDownload(): Promise<void> {
this.progressInfo = undefined;
this.downloadStarted = true;
this.error = undefined;
this.updater.downloadUpdate();
setUpdateInfo(updateInfo: UpdateInfo): void {
this._updateInfo = updateInfo;
this.update();
}
onCloseAndInstall(): void {
this.updater.quitAndInstall();
mergeUpdateProgress(updateProgress: UpdateProgress): void {
this._updateProgress = { ...this._updateProgress, ...updateProgress };
this.update();
}
get updateInfo(): UpdateInfo {
return this._updateInfo;
}
get updateProgress(): UpdateProgress {
return this._updateProgress;
}
protected render(): React.ReactNode {
return !!this.updateInfo ? (
<form>
<IDEUpdaterComponent
updateInfo={this.updateInfo}
windowService={this.windowService}
downloadStarted={this.downloadStarted}
downloadFinished={this.downloadFinished}
progress={this.progressInfo}
error={this.error}
onClose={this.close.bind(this)}
onSkipVersion={this.onSkipVersion.bind(this)}
onDownload={this.onDownload.bind(this)}
onCloseAndInstall={this.onCloseAndInstall.bind(this)}
/>
</form>
return !!this._updateInfo ? (
<IDEUpdaterComponent
updateInfo={this._updateInfo}
updateProgress={this._updateProgress}
/>
) : null;
}
}
@@ -118,7 +62,19 @@ export class IDEUpdaterDialogProps extends DialogProps {}
@injectable()
export class IDEUpdaterDialog extends AbstractDialog<UpdateInfo> {
@inject(IDEUpdaterDialogWidget)
protected readonly widget: IDEUpdaterDialogWidget;
private readonly widget: IDEUpdaterDialogWidget;
@inject(IDEUpdater)
private readonly updater: IDEUpdater;
@inject(IDEUpdaterClient)
private readonly updaterClient: IDEUpdaterClient;
@inject(LocalStorageService)
private readonly localStorageService: LocalStorageService;
@inject(WindowService)
private readonly windowService: WindowService;
constructor(
@inject(IDEUpdaterDialogProps)
@@ -130,10 +86,26 @@ export class IDEUpdaterDialog extends AbstractDialog<UpdateInfo> {
'Software Update'
),
});
this.node.id = 'ide-updater-dialog-container';
this.contentNode.classList.add('ide-updater-dialog');
this.acceptButton = undefined;
}
@postConstruct()
protected init(): void {
this.updaterClient.onUpdaterDidFail((error) => {
this.appendErrorButtons();
this.widget.mergeUpdateProgress({ error });
});
this.updaterClient.onDownloadProgressDidChange((progressInfo) => {
this.widget.mergeUpdateProgress({ progressInfo });
});
this.updaterClient.onDownloadDidFinish(() => {
this.appendInstallButtons();
this.widget.mergeUpdateProgress({ downloadFinished: true });
});
}
get value(): UpdateInfo {
return this.widget.updateInfo;
}
@@ -143,24 +115,123 @@ export class IDEUpdaterDialog extends AbstractDialog<UpdateInfo> {
Widget.detach(this.widget);
}
Widget.attach(this.widget, this.contentNode);
this.appendInitialButtons();
super.onAfterAttach(msg);
this.update();
}
private clearButtons(): void {
while (this.controlPanel.firstChild) {
this.controlPanel.removeChild(this.controlPanel.firstChild);
}
this.closeButton = undefined;
}
private appendNotNowButton(): void {
this.appendCloseButton(
nls.localize('arduino/ide-updater/notNowButton', 'Not now')
);
if (this.closeButton) {
this.addCloseAction(this.closeButton, 'click');
}
}
private appendInitialButtons(): void {
this.clearButtons();
const skipVersionButton = this.createButton(
nls.localize('arduino/ide-updater/skipVersionButton', 'Skip Version')
);
skipVersionButton.classList.add('secondary');
skipVersionButton.classList.add('skip-version-button');
this.addAction(skipVersionButton, this.skipVersion.bind(this), 'click');
this.controlPanel.appendChild(skipVersionButton);
this.appendNotNowButton();
const downloadButton = this.createButton(
nls.localize('arduino/ide-updater/downloadButton', 'Download')
);
this.addAction(downloadButton, this.startDownload.bind(this), 'click');
this.controlPanel.appendChild(downloadButton);
downloadButton.focus();
}
private appendInstallButtons(): void {
this.clearButtons();
this.appendNotNowButton();
const closeAndInstallButton = this.createButton(
nls.localize(
'arduino/ide-updater/closeAndInstallButton',
'Close and Install'
)
);
this.addAction(
closeAndInstallButton,
this.closeAndInstall.bind(this),
'click'
);
this.controlPanel.appendChild(closeAndInstallButton);
closeAndInstallButton.focus();
}
private appendErrorButtons(): void {
this.clearButtons();
this.appendNotNowButton();
const goToDownloadPageButton = this.createButton(
nls.localize('arduino/ide-updater/goToDownloadButton', 'Go To Download')
);
this.addAction(
goToDownloadPageButton,
this.openDownloadPage.bind(this),
'click'
);
this.controlPanel.appendChild(goToDownloadPageButton);
goToDownloadPageButton.focus();
}
private openDownloadPage(): void {
this.windowService.openNewWindow(DOWNLOAD_PAGE_URL, { external: true });
this.close();
}
private skipVersion(): void {
this.localStorageService.setData<string>(
SKIP_IDE_VERSION,
this.widget.updateInfo.version
);
this.close();
}
private startDownload(): void {
this.widget.mergeUpdateProgress({
downloadStarted: true,
});
this.clearButtons();
this.updater.downloadUpdate();
}
private closeAndInstall() {
this.updater.quitAndInstall();
this.close();
}
override async open(
data: UpdateInfo | undefined = undefined
): Promise<UpdateInfo | undefined> {
if (data && data.version) {
this.widget.init(data, this.close.bind(this));
this.widget.mergeUpdateProgress({
progressInfo: undefined,
downloadStarted: false,
downloadFinished: false,
error: undefined,
});
this.widget.setUpdateInfo(data);
return super.open();
}
}
protected override onUpdateRequest(msg: Message): void {
super.onUpdateRequest(msg);
this.widget.update();
}
protected override onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
this.widget.activate();
@@ -168,6 +239,12 @@ export class IDEUpdaterDialog extends AbstractDialog<UpdateInfo> {
override close(): void {
this.widget.dispose();
if (
this.widget.updateProgress?.downloadStarted &&
!this.widget.updateProgress?.downloadFinished
) {
this.updater.stopDownload();
}
super.close();
}
}

View File

@@ -188,15 +188,17 @@ export class SettingsComponent extends React.Component<
/>
{nls.localize('arduino/preferences/automatic', 'Automatic')}
</label>
<SettingsStepInput
value={scalePercentage}
setSettingsStateValue={this.setInterfaceScale}
step={scaleStep}
maxValue={maxScale}
minValue={minScale}
classNames={{ input: 'theia-input small with-margin' }}
/>
%
<div>
<SettingsStepInput
value={scalePercentage}
setSettingsStateValue={this.setInterfaceScale}
step={scaleStep}
maxValue={maxScale}
minValue={minScale}
unitOfMeasure="%"
classNames={{ input: 'theia-input small with-margin' }}
/>
</div>
</div>
<div className="flex-line">
<select

View File

@@ -7,14 +7,22 @@ interface SettingsStepInputProps {
step: number;
maxValue: number;
minValue: number;
unitOfMeasure?: string;
classNames?: { [key: string]: string };
}
const SettingsStepInput: React.FC<SettingsStepInputProps> = (
props: SettingsStepInputProps
) => {
const { value, setSettingsStateValue, step, maxValue, minValue, classNames } =
props;
const {
value,
setSettingsStateValue,
step,
maxValue,
minValue,
unitOfMeasure,
classNames,
} = props;
const clamp = (value: number, min: number, max: number): number => {
return Math.min(Math.max(value, min), max);
@@ -86,6 +94,7 @@ const SettingsStepInput: React.FC<SettingsStepInputProps> = (
&#9662;
</button>
</div>
{unitOfMeasure && `${unitOfMeasure}`}
</div>
);
};

View File

@@ -5,36 +5,43 @@ import { IDEUpdaterClient } from '../../common/protocol/ide-updater';
@injectable()
export class IDEUpdaterClientImpl implements IDEUpdaterClient {
protected readonly onErrorEmitter = new Emitter<Error>();
protected readonly onCheckingForUpdateEmitter = new Emitter<void>();
protected readonly onUpdateAvailableEmitter = new Emitter<UpdateInfo>();
protected readonly onUpdateNotAvailableEmitter = new Emitter<UpdateInfo>();
protected readonly onDownloadProgressEmitter = new Emitter<ProgressInfo>();
protected readonly onDownloadFinishedEmitter = new Emitter<UpdateInfo>();
protected readonly onUpdaterDidFailEmitter = new Emitter<Error>();
protected readonly onUpdaterDidCheckForUpdateEmitter = new Emitter<void>();
protected readonly onUpdaterDidFindUpdateAvailableEmitter =
new Emitter<UpdateInfo>();
protected readonly onUpdaterDidNotFindUpdateAvailableEmitter =
new Emitter<UpdateInfo>();
protected readonly onDownloadProgressDidChangeEmitter =
new Emitter<ProgressInfo>();
protected readonly onDownloadDidFinishEmitter = new Emitter<UpdateInfo>();
readonly onError = this.onErrorEmitter.event;
readonly onCheckingForUpdate = this.onCheckingForUpdateEmitter.event;
readonly onUpdateAvailable = this.onUpdateAvailableEmitter.event;
readonly onUpdateNotAvailable = this.onUpdateNotAvailableEmitter.event;
readonly onDownloadProgressChanged = this.onDownloadProgressEmitter.event;
readonly onDownloadFinished = this.onDownloadFinishedEmitter.event;
readonly onUpdaterDidFail = this.onUpdaterDidFailEmitter.event;
readonly onUpdaterDidCheckForUpdate =
this.onUpdaterDidCheckForUpdateEmitter.event;
readonly onUpdaterDidFindUpdateAvailable =
this.onUpdaterDidFindUpdateAvailableEmitter.event;
readonly onUpdaterDidNotFindUpdateAvailable =
this.onUpdaterDidNotFindUpdateAvailableEmitter.event;
readonly onDownloadProgressDidChange =
this.onDownloadProgressDidChangeEmitter.event;
readonly onDownloadDidFinish = this.onDownloadDidFinishEmitter.event;
notifyError(message: Error): void {
this.onErrorEmitter.fire(message);
notifyUpdaterFailed(message: Error): void {
this.onUpdaterDidFailEmitter.fire(message);
}
notifyCheckingForUpdate(message: void): void {
this.onCheckingForUpdateEmitter.fire(message);
notifyCheckedForUpdate(message: void): void {
this.onUpdaterDidCheckForUpdateEmitter.fire(message);
}
notifyUpdateAvailable(message: UpdateInfo): void {
this.onUpdateAvailableEmitter.fire(message);
notifyUpdateAvailableFound(message: UpdateInfo): void {
this.onUpdaterDidFindUpdateAvailableEmitter.fire(message);
}
notifyUpdateNotAvailable(message: UpdateInfo): void {
this.onUpdateNotAvailableEmitter.fire(message);
notifyUpdateAvailableNotFound(message: UpdateInfo): void {
this.onUpdaterDidNotFindUpdateAvailableEmitter.fire(message);
}
notifyDownloadProgressChanged(message: ProgressInfo): void {
this.onDownloadProgressEmitter.fire(message);
this.onDownloadProgressDidChangeEmitter.fire(message);
}
notifyDownloadFinished(message: UpdateInfo): void {
this.onDownloadFinishedEmitter.fire(message);
this.onDownloadDidFinishEmitter.fire(message);
}
}

View File

@@ -2,9 +2,11 @@ div#select-board-dialog {
margin: 5px;
}
div#select-board-dialog .selectBoardContainer .body {
div#select-board-dialog .selectBoardContainer {
display: flex;
gap: 10px;
overflow: hidden;
max-height: 100%;
}
.select-board-dialog .head {
@@ -19,12 +21,13 @@ div.dialogContent.select-board-dialog > div.head .title {
margin-bottom: 10px;
}
div#select-board-dialog .selectBoardContainer .body .list .item.selected {
div#select-board-dialog .selectBoardContainer .list .item.selected {
background: var(--theia-secondaryButton-hoverBackground);
}
div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
color: var(--theia-list-activeSelectionIconForeground);
div#select-board-dialog .selectBoardContainer .list .item.selected i {
color: var(--theia-arduino-branding-primary);
}
#select-board-dialog .selectBoardContainer .search,
@@ -34,7 +37,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
background: var(--theia-editor-background);
}
#select-board-dialog .selectBoardContainer .body .search input {
#select-board-dialog .selectBoardContainer .search input {
border: none;
width: 100%;
height: auto;
@@ -46,58 +49,63 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
color: var(--theia-input-foreground);
}
#select-board-dialog .selectBoardContainer .body .search input:focus {
#select-board-dialog .selectBoardContainer .search input:focus {
box-shadow: none;
}
#select-board-dialog .selectBoardContainer .body .container {
#select-board-dialog .selectBoardContainer .container {
flex: 1;
padding: 0px 10px 0px 0px;
min-width: 240px;
max-width: 240px;
overflow: hidden;
max-height: 100%;
}
#select-board-dialog .selectBoardContainer .body .left.container .content {
#select-board-dialog .selectBoardContainer .container .content {
display: flex;
flex-direction: column;
max-height: 100%;
}
#select-board-dialog .selectBoardContainer .left.container .content {
margin: 0 5px 0 0;
}
#select-board-dialog .selectBoardContainer .body .right.container .content {
#select-board-dialog .selectBoardContainer .right.container .content {
margin: 0 0 0 5px;
}
#select-board-dialog .selectBoardContainer .body .container .content .title {
#select-board-dialog .selectBoardContainer .container .content .title {
color: var(--theia-editorWidget-foreground);
padding: 0px 0px 10px 0px;
text-transform: uppercase;
}
#select-board-dialog .selectBoardContainer .body .container .content .footer {
#select-board-dialog .selectBoardContainer .container .content .footer {
padding: 10px 5px 10px 0px;
}
#select-board-dialog .selectBoardContainer .body .container .content .loading {
#select-board-dialog .selectBoardContainer .container .content .loading {
font-size: var(--theia-ui-font-size1);
color: var(--theia-editorWidget-foreground);
padding: 10px 5px 10px 10px;
text-transform: uppercase;
/* The max, min-height comes from `.body .list` 200px + 47px top padding - 2 * 10px top padding */
/* The max, min-height comes from `.list` 200px + 47px top padding - 2 * 10px top padding */
max-height: 227px;
min-height: 227px;
}
#select-board-dialog .selectBoardContainer .body .list .item {
#select-board-dialog .selectBoardContainer .list .item {
padding: 10px 5px 10px 10px;
display: flex;
justify-content: end;
white-space: nowrap;
overflow-x: hidden;
flex: 1 0;
}
#select-board-dialog .selectBoardContainer .body .list .item .selected-icon {
#select-board-dialog .selectBoardContainer .list .item .selected-icon {
margin-left: auto;
}
#select-board-dialog .selectBoardContainer .body .list .item .details {
#select-board-dialog .selectBoardContainer .list .item .details {
font-size: var(--theia-ui-font-size1);
opacity: var(--theia-mod-disabled-opacity);
width: 155px; /* used heuristics for the calculation */
@@ -106,43 +114,36 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
text-overflow: ellipsis;
}
#select-board-dialog .selectBoardContainer .body .list .item.missing {
#select-board-dialog .selectBoardContainer .list .item.missing {
opacity: var(--theia-mod-disabled-opacity);
}
#select-board-dialog .selectBoardContainer .body .list .item:hover {
#select-board-dialog .selectBoardContainer .list .item:hover {
background: var(--theia-secondaryButton-hoverBackground);
}
#select-board-dialog .selectBoardContainer .body .list .label {
max-width: 215px;
width: 215px;
#select-board-dialog .selectBoardContainer .list .label {
white-space: pre;
overflow: hidden;
text-overflow: ellipsis;
}
#select-board-dialog .selectBoardContainer .body .list {
#select-board-dialog .selectBoardContainer .list {
max-height: 200px;
min-height: 200px;
overflow-y: auto;
}
#select-board-dialog .selectBoardContainer .body .ports.list {
#select-board-dialog .selectBoardContainer .ports.list {
margin: 47px 0px 0px 0px; /* 47 is 37 as input height for the `Boards`, plus 10 margin bottom. */
}
#select-board-dialog .selectBoardContainer .body .search {
#select-board-dialog .selectBoardContainer .search {
margin-bottom: 10px;
display: flex;
align-items: center;
padding-right: 5px;
}
.p-Widget.dialogOverlay .dialogContent.select-board-dialog {
width: 500px;
}
.arduino-boards-toolbar-item-container {
align-items: center;
background: var(--theia-arduino-toolbar-dropdown-background);
@@ -264,10 +265,20 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
/* High Contrast Theme rules */
/* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/
.hc-black.hc-theia.theia-hc #select-board-dialog .selectBoardContainer .body .list .item:hover {
.hc-black.hc-theia.theia-hc #select-board-dialog .selectBoardContainer .list .item:hover {
outline: 1px dashed var(--theia-focusBorder);
}
.hc-black.hc-theia.theia-hc div#select-board-dialog .selectBoardContainer .body .list .item.selected {
.hc-black.hc-theia.theia-hc div#select-board-dialog .selectBoardContainer .list .item.selected {
outline: 1px solid var(--theia-focusBorder);
}
@media only screen and (max-height: 400px) {
div.dialogContent.select-board-dialog > div.head {
display: none;
}
#select-board-dialog .selectBoardContainer .container .content .title {
display: none;
}
}

View File

@@ -1,4 +1,4 @@
.certificate-uploader-dialog {
#certificate-uploader-dialog-container > .dialogBlock {
width: 600px;
}

View File

@@ -9,11 +9,13 @@
total = padding + margin = 96px
*/
max-width: calc(100% - 96px) !important;
min-width: unset;
max-height: 560px;
padding: 0 28px;
}
.p-Widget.dialogOverlay .dialogBlock .dialogTitle {
padding: 36px 0 28px;
padding: 20px 0;
font-weight: 500;
background-color: transparent;
font-size: var(--theia-ui-font-size2);
@@ -28,6 +30,7 @@
.p-Widget.dialogOverlay .dialogBlock .dialogContent {
padding: 0;
overflow: auto;
}
.p-Widget.dialogOverlay .dialogBlock .dialogContent > input {
@@ -75,3 +78,10 @@
.fa.disabled {
opacity: .4;
}
@media only screen and (max-height: 560px) {
.p-Widget.dialogOverlay .dialogBlock {
max-height: 400px;
}
}

View File

@@ -1,4 +1,4 @@
.firmware-uploader-dialog {
#firmware-uploader-dialog-container > .dialogBlock {
width: 600px;
}
@@ -11,7 +11,6 @@
}
.firmware-uploader-dialog .dialogRow > button{
width: 33%;
margin-right: 3px;
}

View File

@@ -1,4 +1,4 @@
.ide-updater-dialog {
#ide-updater-dialog-container > .dialogBlock {
width: 546px;
}
@@ -10,6 +10,10 @@
display: flex;
}
.ide-updater-dialog--downloading {
flex: 1;
}
.ide-updater-dialog--logo-container {
margin-right: 28px;
}
@@ -23,37 +27,49 @@
.dialogContent.ide-updater-dialog
.ide-updater-dialog--content
.ide-updater-dialog--new-version-text.dialogSection {
display: flex;
flex: 1;
flex-direction: column;
margin-top: 0;
min-width: 0;
}
.ide-updater-dialog .changelog-container {
.ide-updater-dialog .changelog {
color: var(--theia-editor-foreground);
background-color: var(--theia-editor-background);
border: 1px solid var(--theia-editorWidget-border);
border-radius: 2px;
font-size: 12px;
height: 180px;
overflow: auto;
padding: 0 12px;
cursor: text;
}
.ide-updater-dialog .changelog-container a {
.dialogContent.ide-updater-dialog
.ide-updater-dialog--content
.ide-updater-dialog--new-version-text
.dialogRow.changelog-container {
align-items: flex-start;
border: 1px solid var(--theia-editorWidget-border);
border-radius: 2px;
overflow: auto;
max-height: 180px;
}
.ide-updater-dialog .changelog a {
color: var(--theia-textLink-foreground);
}
.ide-updater-dialog .changelog-container a:hover {
.ide-updater-dialog .changelog a:hover {
text-decoration: underline;
cursor: pointer;
}
.ide-updater-dialog .changelog-container code {
.ide-updater-dialog .changelog code {
background: var(--theia-textBlockQuote-background);
border-radius: 2px;
padding: 0 2px;
}
.ide-updater-dialog .changelog-container a code {
.ide-updater-dialog .changelog a code {
color: var(--theia-textLink-foreground);
}
@@ -77,3 +93,14 @@
.ide-updater-dialog .buttons-container .push {
margin-right: auto;
}
.ide-updater-dialog--content {
max-height: 100%;
overflow: hidden;
display: flex;
}
#ide-updater-dialog-container .skip-version-button {
margin-left: 79px;
margin-right: auto;
}

View File

@@ -21,6 +21,7 @@
display: flex;
align-items: center;
white-space: nowrap;
flex-wrap: wrap;
}
.arduino-settings-dialog .with-margin {

View File

@@ -12,7 +12,7 @@
display: none;
flex-direction: column;
position: absolute;
right: 0px;
right: 14px;
top: 50%;
transform: translate(0px, -50%);
height: calc(100% - 4px);

View File

@@ -56,16 +56,16 @@ export interface IDEUpdater extends JsonRpcServer<IDEUpdaterClient> {
export const IDEUpdaterClient = Symbol('IDEUpdaterClient');
export interface IDEUpdaterClient {
onError: Event<Error>;
onCheckingForUpdate: Event<void>;
onUpdateAvailable: Event<UpdateInfo>;
onUpdateNotAvailable: Event<UpdateInfo>;
onDownloadProgressChanged: Event<ProgressInfo>;
onDownloadFinished: Event<UpdateInfo>;
notifyError(message: Error): void;
notifyCheckingForUpdate(message: void): void;
notifyUpdateAvailable(message: UpdateInfo): void;
notifyUpdateNotAvailable(message: UpdateInfo): void;
onUpdaterDidFail: Event<Error>;
onUpdaterDidCheckForUpdate: Event<void>;
onUpdaterDidFindUpdateAvailable: Event<UpdateInfo>;
onUpdaterDidNotFindUpdateAvailable: Event<UpdateInfo>;
onDownloadProgressDidChange: Event<ProgressInfo>;
onDownloadDidFinish: Event<UpdateInfo>;
notifyUpdaterFailed(message: Error): void;
notifyCheckedForUpdate(message: void): void;
notifyUpdateAvailableFound(message: UpdateInfo): void;
notifyUpdateAvailableNotFound(message: UpdateInfo): void;
notifyDownloadProgressChanged(message: ProgressInfo): void;
notifyDownloadFinished(message: UpdateInfo): void;
}

View File

@@ -19,13 +19,13 @@ export class IDEUpdaterImpl implements IDEUpdater {
constructor() {
this.updater.on('checking-for-update', (e) => {
this.clients.forEach((c) => c.notifyCheckingForUpdate(e));
this.clients.forEach((c) => c.notifyCheckedForUpdate(e));
});
this.updater.on('update-available', (e) => {
this.clients.forEach((c) => c.notifyUpdateAvailable(e));
this.clients.forEach((c) => c.notifyUpdateAvailableFound(e));
});
this.updater.on('update-not-available', (e) => {
this.clients.forEach((c) => c.notifyUpdateNotAvailable(e));
this.clients.forEach((c) => c.notifyUpdateAvailableNotFound(e));
});
this.updater.on('download-progress', (e) => {
this.clients.forEach((c) => c.notifyDownloadProgressChanged(e));
@@ -34,7 +34,7 @@ export class IDEUpdaterImpl implements IDEUpdater {
this.clients.forEach((c) => c.notifyDownloadFinished(e));
});
this.updater.on('error', (e) => {
this.clients.forEach((c) => c.notifyError(e));
this.clients.forEach((c) => c.notifyUpdaterFailed(e));
});
}
@@ -58,10 +58,8 @@ export class IDEUpdaterImpl implements IDEUpdater {
this.isAlreadyChecked = true;
}
const {
updateInfo,
cancellationToken,
} = await this.updater.checkForUpdates();
const { updateInfo, cancellationToken } =
await this.updater.checkForUpdates();
this.cancellationToken = cancellationToken;
if (this.updater.currentVersion.compare(updateInfo.version) === -1) {
@@ -104,7 +102,7 @@ export class IDEUpdaterImpl implements IDEUpdater {
await this.updater.downloadUpdate(this.cancellationToken);
} catch (e) {
if (e.message === 'cancelled') return;
this.clients.forEach((c) => c.notifyError(e));
this.clients.forEach((c) => c.notifyUpdaterFailed(e));
}
}