PROEDITOR-7: Cloned the Library Manager layout.

To match with the official Arduino editor's UI.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
Akos Kitta
2019-07-17 10:32:28 +02:00
parent cf44fe2ad0
commit 8d838fcce4
19 changed files with 426 additions and 138 deletions

View File

@@ -4,7 +4,7 @@ import { ArduinoComponent } from '../../../common/protocol/arduino-component';
export class ComponentListItem extends React.Component<ComponentListItem.Props> {
private onClick = (event: React.SyntheticEvent<HTMLAnchorElement, Event>) => {
protected onClick = (event: React.SyntheticEvent<HTMLAnchorElement, Event>) => {
const { target } = event.nativeEvent;
if (target instanceof HTMLAnchorElement) {
this.props.windowService.openNewWindow(target.href);
@@ -12,7 +12,7 @@ export class ComponentListItem extends React.Component<ComponentListItem.Props>
}
}
private async install(item: ArduinoComponent) {
protected async install(item: ArduinoComponent): Promise<void> {
await this.props.install(item);
}

View File

@@ -5,12 +5,26 @@ import { ArduinoComponent } from '../../../common/protocol/arduino-component';
export class ComponentList extends React.Component<ComponentList.Props> {
protected container?: HTMLElement;
render(): React.ReactNode {
return <div>
{this.props.items.map(item => <ComponentListItem key={item.name} item={item} windowService={this.props.windowService} install={this.props.install} />)}
return <div
className={'items-container'}
ref={element => this.container = element || undefined}>
{this.props.items.map(item => this.createItem(item))}
</div>;
}
componentDidMount(): void {
if (this.container && this.props.resolveContainer) {
this.props.resolveContainer(this.container);
}
}
protected createItem(item: ArduinoComponent): React.ReactNode {
return <ComponentListItem key={item.name} item={item} windowService={this.props.windowService} install={this.props.install} />
}
}
export namespace ComponentList {
@@ -19,6 +33,7 @@ export namespace ComponentList {
readonly items: ArduinoComponent[];
readonly windowService: WindowService;
readonly install: (comp: ArduinoComponent) => Promise<void>;
readonly resolveContainer?: (element: HTMLElement) => void;
}
}

View File

@@ -1,7 +1,8 @@
import * as React from 'react';
import { WindowService } from '@theia/core/lib/browser/window/window-service';
import { ComponentList } from './component-list';
import { SearchBar } from './search-bar';
import { ComponentList } from './component-list';
import { LibraryService } from '../../../common/protocol/library-service';
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
import { InstallationProgressDialog } from '../installation-progress-dialog';
@@ -21,21 +22,37 @@ export class FilterableListContainer extends React.Component<FilterableListConta
}
render(): React.ReactNode {
return <div className={FilterableListContainer.Styles.FILTERABLE_LIST_CONTAINER_CLASS}>
<SearchBar
filterText={this.state.filterText}
onFilterTextChanged={this.handleFilterTextChange}
/>
<ComponentList
items={this.state.items}
install={this.install.bind(this)}
windowService={this.props.windowService}
/>
return <div className={'filterable-list-container'}>
{this.renderSearchFilter()}
{this.renderSearchBar()}
{this.renderComponentList()}
</div>
}
protected renderSearchFilter(): React.ReactNode {
return undefined;
}
protected renderSearchBar(): React.ReactNode {
return <SearchBar
resolveFocus={this.props.resolveFocus}
filterText={this.state.filterText}
onFilterTextChanged={this.handleFilterTextChange}
/>
}
protected renderComponentList(): React.ReactNode {
return <ComponentList
items={this.state.items}
install={this.install.bind(this)}
windowService={this.props.windowService}
resolveContainer={this.props.resolveContainer}
/>
}
private handleFilterTextChange(filterText: string): void {
this.props.service.search({ query: filterText }).then(result => {
const { props } = this.state;
this.props.service.search({ query: filterText, props }).then(result => {
const { items } = result;
this.setState({
filterText,
@@ -45,15 +62,7 @@ export class FilterableListContainer extends React.Component<FilterableListConta
}
protected sort(items: ArduinoComponent[]): ArduinoComponent[] {
return items.sort((a, b) => {
if (a.name < b.name) {
return -1;
} else if (a.name === b.name) {
return 0;
} else {
return 1;
}
});
return items.sort((left, right) => left.name.localeCompare(right.name));
}
protected async install(comp: ArduinoComponent): Promise<void> {
@@ -61,7 +70,8 @@ export class FilterableListContainer extends React.Component<FilterableListConta
dialog.open();
try {
await this.props.service.install(comp);
const { items } = await this.props.service.search({ query: this.state.filterText });
const { props } = this.state;
const { items } = await this.props.service.search({ query: this.state.filterText, props });
this.setState({ items: this.sort(items) });
} finally {
dialog.close();
@@ -75,19 +85,18 @@ export namespace FilterableListContainer {
export interface Props {
readonly service: ComponentSource;
readonly windowService: WindowService;
readonly resolveContainer?: (element: HTMLElement) => void;
readonly resolveFocus?: (element: HTMLElement | undefined) => void;
}
export interface State {
filterText: string;
items: ArduinoComponent[];
}
export namespace Styles {
export const FILTERABLE_LIST_CONTAINER_CLASS = 'filterable-list-container';
props?: LibraryService.Search.Props;
}
export interface ComponentSource {
search(req: { query: string }): Promise<{ items: ArduinoComponent[] }>
search(req: { query: string, props?: LibraryService.Search.Props }): Promise<{ items: ArduinoComponent[] }>
install(board: ArduinoComponent): Promise<void>;
}

View File

@@ -9,15 +9,22 @@ export class SearchBar extends React.Component<SearchBar.Props> {
render(): React.ReactNode {
return <input
ref={this.setRef}
className={SearchBar.Styles.SEARCH_BAR_CLASS}
type='text'
placeholder='Search'
placeholder='Filter your search...'
size={1}
value={this.props.filterText}
onChange={this.handleFilterTextChange}
/>;
}
private setRef = (element: HTMLElement | null) => {
if (this.props.resolveFocus) {
this.props.resolveFocus(element || undefined);
}
}
private handleFilterTextChange(event: React.ChangeEvent<HTMLInputElement>): void {
this.props.onFilterTextChanged(event.target.value);
}
@@ -29,6 +36,7 @@ export namespace SearchBar {
export interface Props {
filterText: string;
onFilterTextChanged(filterText: string): void;
readonly resolveFocus?: (element: HTMLElement | undefined) => void;
}
export namespace Styles {