diff --git a/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx b/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx index 20b5f317f..3702d092c 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx @@ -111,19 +111,7 @@ export class FilterableListContainer< const { searchable } = this.props; searchable .search(searchOptions) - .then((items) => this.setState({ items: this.sort(items) })); - } - - protected sort(items: T[]): T[] { - const { itemLabel, itemDeprecated } = this.props; - return items.sort((left, right) => { - // always put deprecated items at the bottom of the list - if (itemDeprecated(left)) { - return 1; - } - - return itemLabel(left).localeCompare(itemLabel(right)); - }); + .then((items) => this.setState({ items: this.props.sort(items) })); } protected async install( @@ -139,7 +127,7 @@ export class FilterableListContainer< run: ({ progressId }) => install({ item, progressId, version }), }); const items = await searchable.search(this.state.searchOptions); - this.setState({ items: this.sort(items) }); + this.setState({ items: this.props.sort(items) }); } protected async uninstall(item: T): Promise { @@ -167,7 +155,7 @@ export class FilterableListContainer< run: ({ progressId }) => uninstall({ item, progressId }), }); const items = await searchable.search(this.state.searchOptions); - this.setState({ items: this.sort(items) }); + this.setState({ items: this.props.sort(items) }); } } @@ -204,6 +192,7 @@ export namespace FilterableListContainer { progressId: string; }) => Promise; readonly commandService: CommandService; + readonly sort: (items: T[]) => T[]; } export interface State { diff --git a/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx b/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx index 7e81c9b40..a27fa3cdc 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx @@ -51,9 +51,11 @@ export abstract class ListWidget< */ protected firstActivate = true; + protected readonly defaultSortComparator: (left: T, right: T) => number; + constructor(protected options: ListWidget.Options) { super(); - const { id, label, iconClass } = options; + const { id, label, iconClass, itemDeprecated, itemLabel } = options; this.id = id; this.title.label = label; this.title.caption = label; @@ -63,12 +65,23 @@ export abstract class ListWidget< this.node.tabIndex = 0; // To be able to set the focus on the widget. this.scrollOptions = undefined; this.toDispose.push(this.searchOptionsChangeEmitter); + + this.defaultSortComparator = (left, right): number => { + // always put deprecated items at the bottom of the list + if (itemDeprecated(left)) { + return 1; + } + + return itemLabel(left).localeCompare(itemLabel(right)); + }; } @postConstruct() protected init(): void { this.toDispose.pushAll([ - this.notificationCenter.onIndexUpdateDidComplete(() => this.refresh(undefined)), + this.notificationCenter.onIndexUpdateDidComplete(() => + this.refresh(undefined) + ), this.notificationCenter.onDaemonDidStart(() => this.refresh(undefined)), this.notificationCenter.onDaemonDidStop(() => this.refresh(undefined)), ]); @@ -128,6 +141,30 @@ export abstract class ListWidget< return this.options.installable.uninstall({ item, progressId }); } + protected filterableListSort = (items: T[]): T[] => { + const isArduinoTypeComparator = (left: T, right: T) => { + const aIsArduinoType = left.types.includes('Arduino'); + const bIsArduinoType = right.types.includes('Arduino'); + + if (aIsArduinoType && !bIsArduinoType && !left.deprecated) { + return -1; + } + + if (!aIsArduinoType && bIsArduinoType && !right.deprecated) { + return 1; + } + + return 0; + }; + + return items.sort((left, right) => { + return ( + isArduinoTypeComparator(left, right) || + this.defaultSortComparator(left, right) + ); + }); + }; + render(): React.ReactNode { return ( @@ -145,6 +182,7 @@ export abstract class ListWidget< messageService={this.messageService} commandService={this.commandService} responseService={this.responseService} + sort={this.filterableListSort} /> ); }