Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 79b6b7e

Browse filesBrowse files
Akos Kittakittaakos
Akos Kitta
authored andcommitted
fix: library search boosting
Closes arduino#1106 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent 5d264ef commit 79b6b7e
Copy full SHA for 79b6b7e
Expand file treeCollapse file tree

14 files changed

+627
-346
lines changed

‎arduino-ide-extension/package.json

Copy file name to clipboardExpand all lines: arduino-ide-extension/package.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"build": "tsc && ncp ./src/node/cli-protocol/ ./lib/node/cli-protocol/ && yarn lint",
1818
"watch": "tsc -w",
1919
"test": "mocha \"./lib/test/**/*.test.js\"",
20-
"test:slow": "mocha \"./lib/test/**/*.slow-test.js\"",
20+
"test:slow": "mocha \"./lib/test/**/*.slow-test.js\" --slow 5000",
2121
"test:watch": "mocha --watch --watch-files lib \"./lib/test/**/*.test.js\""
2222
},
2323
"dependencies": {

‎arduino-ide-extension/src/browser/boards/boards-list-widget.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/browser/boards/boards-list-widget.ts
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export class BoardsListWidget extends ListWidget<BoardsPackage, BoardSearch> {
3030
searchable: service,
3131
installable: service,
3232
itemLabel: (item: BoardsPackage) => item.name,
33-
itemDeprecated: (item: BoardsPackage) => item.deprecated,
3433
itemRenderer,
3534
filterRenderer,
3635
defaultSearchOptions: { query: '', type: 'All' },

‎arduino-ide-extension/src/browser/library/library-list-widget.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/browser/library/library-list-widget.ts
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ export class LibraryListWidget extends ListWidget<
4141
searchable: service,
4242
installable: service,
4343
itemLabel: (item: LibraryPackage) => item.name,
44-
itemDeprecated: (item: LibraryPackage) => item.deprecated,
4544
itemRenderer,
4645
filterRenderer,
4746
defaultSearchOptions: { query: '', type: 'All', topic: 'All' },

‎arduino-ide-extension/src/browser/widgets/component-list/component-list.tsx

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/browser/widgets/component-list/component-list.tsx
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ export namespace ComponentList {
147147
export interface Props<T extends ArduinoComponent> {
148148
readonly items: T[];
149149
readonly itemLabel: (item: T) => string;
150-
readonly itemDeprecated: (item: T) => boolean;
151150
readonly itemRenderer: ListItemRenderer<T>;
152151
readonly install: (item: T, version?: Installable.Version) => Promise<void>;
153152
readonly uninstall: (item: T) => Promise<void>;

‎arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx
+4-9Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,11 @@ export class FilterableListContainer<
8282
}
8383

8484
protected renderComponentList(): React.ReactNode {
85-
const { itemLabel, itemDeprecated, itemRenderer } = this.props;
85+
const { itemLabel, itemRenderer } = this.props;
8686
return (
8787
<ComponentList<T>
8888
items={this.state.items}
8989
itemLabel={itemLabel}
90-
itemDeprecated={itemDeprecated}
9190
itemRenderer={itemRenderer}
9291
install={this.install.bind(this)}
9392
uninstall={this.uninstall.bind(this)}
@@ -109,9 +108,7 @@ export class FilterableListContainer<
109108

110109
protected search(searchOptions: S): void {
111110
const { searchable } = this.props;
112-
searchable
113-
.search(searchOptions)
114-
.then((items) => this.setState({ items: this.props.sort(items) }));
111+
searchable.search(searchOptions).then((items) => this.setState({ items }));
115112
}
116113

117114
protected async install(
@@ -127,7 +124,7 @@ export class FilterableListContainer<
127124
run: ({ progressId }) => install({ item, progressId, version }),
128125
});
129126
const items = await searchable.search(this.state.searchOptions);
130-
this.setState({ items: this.props.sort(items) });
127+
this.setState({ items });
131128
}
132129

133130
protected async uninstall(item: T): Promise<void> {
@@ -155,7 +152,7 @@ export class FilterableListContainer<
155152
run: ({ progressId }) => uninstall({ item, progressId }),
156153
});
157154
const items = await searchable.search(this.state.searchOptions);
158-
this.setState({ items: this.props.sort(items) });
155+
this.setState({ items });
159156
}
160157
}
161158

@@ -168,7 +165,6 @@ export namespace FilterableListContainer {
168165
readonly container: ListWidget<T, S>;
169166
readonly searchable: Searchable<T, S>;
170167
readonly itemLabel: (item: T) => string;
171-
readonly itemDeprecated: (item: T) => boolean;
172168
readonly itemRenderer: ListItemRenderer<T>;
173169
readonly filterRenderer: FilterRenderer<S>;
174170
readonly resolveFocus: (element: HTMLElement | undefined) => void;
@@ -192,7 +188,6 @@ export namespace FilterableListContainer {
192188
progressId: string;
193189
}) => Promise<void>;
194190
readonly commandService: CommandService;
195-
readonly sort: (items: T[]) => T[];
196191
}
197192

198193
export interface State<T, S extends Searchable.Options> {

‎arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx
+1-39Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,9 @@ export abstract class ListWidget<
5353
*/
5454
protected firstActivate = true;
5555

56-
protected readonly defaultSortComparator: (left: T, right: T) => number;
57-
5856
constructor(protected options: ListWidget.Options<T, S>) {
5957
super();
60-
const { id, label, iconClass, itemDeprecated, itemLabel } = options;
58+
const { id, label, iconClass } = options;
6159
this.id = id;
6260
this.title.label = label;
6361
this.title.caption = label;
@@ -67,15 +65,6 @@ export abstract class ListWidget<
6765
this.node.tabIndex = 0; // To be able to set the focus on the widget.
6866
this.scrollOptions = undefined;
6967
this.toDispose.push(this.searchOptionsChangeEmitter);
70-
71-
this.defaultSortComparator = (left, right): number => {
72-
// always put deprecated items at the bottom of the list
73-
if (itemDeprecated(left)) {
74-
return 1;
75-
}
76-
77-
return itemLabel(left).localeCompare(itemLabel(right));
78-
};
7968
}
8069

8170
@postConstruct()
@@ -144,30 +133,6 @@ export abstract class ListWidget<
144133
return this.options.installable.uninstall({ item, progressId });
145134
}
146135

147-
protected filterableListSort = (items: T[]): T[] => {
148-
const isArduinoTypeComparator = (left: T, right: T) => {
149-
const aIsArduinoType = left.types.includes('Arduino');
150-
const bIsArduinoType = right.types.includes('Arduino');
151-
152-
if (aIsArduinoType && !bIsArduinoType && !left.deprecated) {
153-
return -1;
154-
}
155-
156-
if (!aIsArduinoType && bIsArduinoType && !right.deprecated) {
157-
return 1;
158-
}
159-
160-
return 0;
161-
};
162-
163-
return items.sort((left, right) => {
164-
return (
165-
isArduinoTypeComparator(left, right) ||
166-
this.defaultSortComparator(left, right)
167-
);
168-
});
169-
};
170-
171136
render(): React.ReactNode {
172137
return (
173138
<FilterableListContainer<T, S>
@@ -178,14 +143,12 @@ export abstract class ListWidget<
178143
install={this.install.bind(this)}
179144
uninstall={this.uninstall.bind(this)}
180145
itemLabel={this.options.itemLabel}
181-
itemDeprecated={this.options.itemDeprecated}
182146
itemRenderer={this.options.itemRenderer}
183147
filterRenderer={this.options.filterRenderer}
184148
searchOptionsDidChange={this.searchOptionsChangeEmitter.event}
185149
messageService={this.messageService}
186150
commandService={this.commandService}
187151
responseService={this.responseService}
188-
sort={this.filterableListSort}
189152
/>
190153
);
191154
}
@@ -218,7 +181,6 @@ export namespace ListWidget {
218181
readonly installable: Installable<T>;
219182
readonly searchable: Searchable<T, S>;
220183
readonly itemLabel: (item: T) => string;
221-
readonly itemDeprecated: (item: T) => boolean;
222184
readonly itemRenderer: ListItemRenderer<T>;
223185
readonly filterRenderer: FilterRenderer<S>;
224186
readonly defaultSearchOptions: S;

‎arduino-ide-extension/src/common/protocol/arduino-component.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/common/protocol/arduino-component.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Installable } from './installable';
22

33
export interface ArduinoComponent {
44
readonly name: string;
5-
readonly deprecated: boolean;
5+
readonly deprecated?: boolean;
66
readonly author: string;
77
readonly summary: string;
88
readonly description: string;

‎arduino-ide-extension/src/common/protocol/searchable.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/common/protocol/searchable.ts
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import URI from '@theia/core/lib/common/uri';
2+
import type { ArduinoComponent } from './arduino-component';
23

34
export interface Searchable<T, O extends Searchable.Options> {
45
search(options: O): Promise<T[]>;
@@ -31,3 +32,31 @@ export namespace Searchable {
3132
}
3233
}
3334
}
35+
36+
// IDE2 must keep the library search order from the CLI but do additional boosting
37+
// https://github.com/arduino/arduino-ide/issues/1106
38+
// This additional search result boosting considers the following groups: 'Arduino', '', 'Arduino-Retired', and 'Retired'.
39+
// If two libraries fall into the same group, the original index is the tiebreaker.
40+
export type SortGroup = 'Arduino' | '' | 'Arduino-Retired' | 'Retired';
41+
const sortGroupOrder: Record<SortGroup, number> = {
42+
Arduino: 0,
43+
'': 1,
44+
'Arduino-Retired': 2,
45+
Retired: 3,
46+
};
47+
48+
export function sortComponents<T extends ArduinoComponent>(
49+
components: T[],
50+
group: (component: T) => SortGroup
51+
): T[] {
52+
return components
53+
.map((component, index) => ({ ...component, index }))
54+
.sort((left, right) => {
55+
const leftGroup = group(left);
56+
const rightGroup = group(right);
57+
if (leftGroup === rightGroup) {
58+
return left.index - right.index;
59+
}
60+
return sortGroupOrder[leftGroup] - sortGroupOrder[rightGroup];
61+
});
62+
}

‎arduino-ide-extension/src/node/boards-service-impl.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/node/boards-service-impl.ts
+15-1Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
BoardWithPackage,
1818
BoardUserField,
1919
BoardSearch,
20+
sortComponents,
21+
SortGroup,
2022
} from '../common/protocol';
2123
import {
2224
PlatformInstallRequest,
@@ -405,7 +407,8 @@ export class BoardsServiceImpl
405407
}
406408

407409
const filter = this.typePredicate(options);
408-
return [...packages.values()].filter(filter);
410+
const boardsPackages = [...packages.values()].filter(filter);
411+
return sortComponents(boardsPackages, boardsPackageSortGroup);
409412
}
410413

411414
private typePredicate(
@@ -559,3 +562,14 @@ function isMissingPlatformError(error: unknown): boolean {
559562
}
560563
return false;
561564
}
565+
566+
function boardsPackageSortGroup(boardsPackage: BoardsPackage): SortGroup {
567+
const types: string[] = [];
568+
if (boardsPackage.types.includes('Arduino')) {
569+
types.push('Arduino');
570+
}
571+
if (boardsPackage.deprecated) {
572+
types.push('Retired');
573+
}
574+
return types.join('-') as SortGroup;
575+
}

‎arduino-ide-extension/src/node/library-service-impl.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/node/library-service-impl.ts
+30-12Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
1-
import { injectable, inject } from '@theia/core/shared/inversify';
1+
import { ILogger, notEmpty } from '@theia/core';
2+
import { FileUri } from '@theia/core/lib/node';
3+
import { inject, injectable } from '@theia/core/shared/inversify';
4+
import { duration } from '../common/decorators';
5+
import {
6+
NotificationServiceServer,
7+
ResponseService,
8+
sortComponents,
9+
SortGroup,
10+
} from '../common/protocol';
11+
import { Installable } from '../common/protocol/installable';
212
import {
313
LibraryDependency,
414
LibraryLocation,
515
LibraryPackage,
616
LibrarySearch,
717
LibraryService,
818
} from '../common/protocol/library-service';
9-
import { CoreClientAware } from './core-client-provider';
1019
import { BoardDiscovery } from './board-discovery';
1120
import {
1221
InstalledLibrary,
1322
Library,
23+
LibraryInstallLocation,
1424
LibraryInstallRequest,
1525
LibraryListRequest,
1626
LibraryListResponse,
1727
LibraryLocation as GrpcLibraryLocation,
1828
LibraryRelease,
1929
LibraryResolveDependenciesRequest,
20-
LibraryUninstallRequest,
21-
ZipLibraryInstallRequest,
2230
LibrarySearchRequest,
2331
LibrarySearchResponse,
24-
LibraryInstallLocation,
32+
LibraryUninstallRequest,
33+
ZipLibraryInstallRequest,
2534
} from './cli-protocol/cc/arduino/cli/commands/v1/lib_pb';
26-
import { Installable } from '../common/protocol/installable';
27-
import { ILogger, notEmpty } from '@theia/core';
28-
import { FileUri } from '@theia/core/lib/node';
29-
import { ResponseService, NotificationServiceServer } from '../common/protocol';
35+
import { CoreClientAware } from './core-client-provider';
3036
import { ExecuteWithProgress } from './grpc-progressible';
31-
import { duration } from '../common/decorators';
3237

3338
@injectable()
3439
export class LibraryServiceImpl
@@ -108,7 +113,10 @@ export class LibraryServiceImpl
108113

109114
const typePredicate = this.typePredicate(options);
110115
const topicPredicate = this.topicPredicate(options);
111-
return items.filter((item) => typePredicate(item) && topicPredicate(item));
116+
const libraries = items.filter(
117+
(item) => typePredicate(item) && topicPredicate(item)
118+
);
119+
return sortComponents(libraries, librarySortGroup);
112120
}
113121

114122
private typePredicate(
@@ -448,7 +456,6 @@ function toLibrary(
448456
name: '',
449457
exampleUris: [],
450458
installable: false,
451-
deprecated: false,
452459
location: 0,
453460
...pkg,
454461

@@ -462,3 +469,14 @@ function toLibrary(
462469
types: lib.getTypesList(),
463470
};
464471
}
472+
473+
// Libraries do not have a deprecated property. The deprecated information is inferred if 'Retired' is in 'types'
474+
function librarySortGroup(library: LibraryPackage): SortGroup {
475+
const types: string[] = [];
476+
for (const type of ['Arduino', 'Retired']) {
477+
if (library.types.includes(type)) {
478+
types.push(type);
479+
}
480+
}
481+
return types.join('-') as SortGroup;
482+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.