Skip to content

Commit b571797

Browse files
Forward tree search text to extension backend (#7)
* tree: forward searchChanged event to extension backend Expose search text updates through vscode-messenger so extensions can implement backend search for large trees. Also document the new onDidSearchChanged event in the tree README. * Rename onDidSearchChanged to onDidSearchChange * Add backend search configuration and increase search debounce
1 parent 73bb78e commit b571797

4 files changed

Lines changed: 53 additions & 7 deletions

File tree

src/tree/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ export class TreeDataProvider implements CDTTreeDataProvider<Example, ExampleDTO
6868
}),
6969
webview.onDidToggleNode(event => {
7070
// Handle toggle
71+
}),
72+
webview.onDidSearchChange(event => {
73+
// Handle search input changes
7174
})
7275
);
7376
}

src/tree/browser/tree.tsx

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import classNames from 'classnames';
1414
import { Resizable } from 're-resizable';
1515
import { default as React, useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
1616
import { debounce } from 'throttle-debounce';
17+
import { HOST_EXTENSION } from 'vscode-messenger-common';
1718
import { findNestedValue } from '../../base';
19+
import { messenger } from '../../browser-types';
1820
import { CommandDefinition } from '../../vscode/webview-types';
1921
import {
2022
CDTTreeItem,
@@ -25,6 +27,7 @@ import {
2527
CDTTreeTableStringColumn,
2628
CDTTreeWebviewContext
2729
} from '../common/index';
30+
import { CDTTreeMessengerType } from '../common/tree-messenger-types';
2831
import ActionCell from './components/cells/ActionCell';
2932
import StringCell from './components/cells/StringCell';
3033
import { ExpandIcon } from './components/expand-icon';
@@ -57,6 +60,17 @@ export type CDTTreeProps<T extends CDTTreeItemResource = CDTTreeItemResource> =
5760
* Function to sort the data source.
5861
*/
5962
dataSourceSorter?: (dataSource: CDTTreeItem<T>[]) => CDTTreeItem<T>[];
63+
/**
64+
* Configuration for search behavior.
65+
*/
66+
search?: {
67+
/**
68+
* Search mode.
69+
* - 'client': filter locally in the webview (default)
70+
* - 'backend': keep current content until backend returns updated data
71+
*/
72+
mode?: 'client' | 'backend';
73+
};
6074
/**
6175
* Configuration for the expansion of the tree table.
6276
*/
@@ -215,18 +229,20 @@ export const CDTTree = <T extends CDTTreeItemResource>(props: CDTTreeProps<T>) =
215229
const ref = React.useRef<HTMLDivElement | null>(null);
216230
const tblRef: Parameters<typeof Table>[0]['ref'] = React.useRef(null);
217231

232+
const isBackendSearch = props.search?.mode === 'backend';
233+
218234
// ==== Data ====
219235

220236
const filteredData = useMemo(() => {
221237
let data = props.dataSource ?? [];
222-
if (globalSearchText) {
238+
if (globalSearchText && !isBackendSearch) {
223239
data = filterTree(data, globalSearchText);
224240
}
225241
if (props.dataSourceSorter) {
226242
data = props.dataSourceSorter([...data]);
227243
}
228244
return data;
229-
}, [props.dataSource, props.dataSourceSorter, globalSearchText]);
245+
}, [props.dataSource, props.dataSourceSorter, globalSearchText, isBackendSearch]);
230246

231247
// ==== Search ====
232248

@@ -238,12 +254,31 @@ export const CDTTree = <T extends CDTTreeItemResource>(props: CDTTreeProps<T>) =
238254
}
239255
}, []);
240256

241-
const onSearchShow = useCallback(() => setGlobalSearchText(globalSearchRef.current?.value()), []);
257+
const notifySearchChanged = useCallback((text: string) => {
258+
messenger.sendNotification(CDTTreeMessengerType.searchChanged, HOST_EXTENSION, { data: { text } });
259+
}, []);
260+
261+
const onSearchShow = useCallback(() => {
262+
const text = globalSearchRef.current?.value() ?? '';
263+
setGlobalSearchText(text);
264+
notifySearchChanged(text);
265+
}, [notifySearchChanged]);
266+
242267
const onSearchHide = useCallback(() => {
243268
setGlobalSearchText(undefined);
244269
autoSelectRowRef.current = true;
245-
}, [autoSelectRowRef]);
246-
const onSearchChange = useMemo(() => debounce(300, (text: string) => setGlobalSearchText(text)), []);
270+
271+
notifySearchChanged('');
272+
}, [notifySearchChanged]);
273+
274+
const onSearchChange = useMemo(
275+
() =>
276+
debounce(600, (text: string) => {
277+
setGlobalSearchText(text);
278+
notifySearchChanged(text);
279+
}),
280+
[notifySearchChanged]
281+
);
247282

248283
// ==== Selection ====
249284

@@ -263,18 +298,20 @@ export const CDTTree = <T extends CDTTreeItemResource>(props: CDTTreeProps<T>) =
263298

264299
const expandedRowKeys = useMemo(() => {
265300
const expanded = new Set(props.expansion?.expandedRowKeys ?? []);
266-
if (globalSearchText) {
301+
if (globalSearchText && !isBackendSearch) {
302+
// client-side search:
267303
// on search expand all nodes that match the search
268304
const matchingExpansion = traverseTree(filteredData, { predicate: item => item.matching ?? false, mapper: getAncestors });
269305
matchingExpansion.forEach(ancestorHierarchy => ancestorHierarchy.forEach(ancestor => expanded.add(ancestor.key)));
270306
} else {
307+
// normal mode or backend-search mode:
271308
// otherwise use the expandedRowKeys from the props but ensure that the selected element is also expanded
272309
if (autoSelectRowRef.current && selection) {
273310
getAncestors(selection).forEach(ancestor => expanded.add(ancestor.key));
274311
}
275312
}
276313
return Array.from(expanded);
277-
}, [filteredData, globalSearchText, props.expansion?.expandedRowKeys, selection, autoSelectRowRef.current]);
314+
}, [filteredData, globalSearchText, isBackendSearch, props.expansion?.expandedRowKeys, selection, autoSelectRowRef.current]);
278315

279316
const handleExpand = useCallback(
280317
(expanded: boolean, record: CDTTreeItem<T>) => {

src/tree/common/tree-messenger-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,5 @@ export namespace CDTTreeMessengerType {
4545
export const toggleNode: NotificationType<CDTTreeNotification<string>> = { method: 'toggleNode' };
4646
export const clickNode: NotificationType<CDTTreeNotification<string>> = { method: 'clickNode' };
4747
export const openSearch: NotificationType<void> = { method: 'openSearch' };
48+
export const searchChanged: NotificationType<CDTTreeNotification<{ text: string }>> = { method: 'searchChanged' };
4849
}

src/tree/vscode/tree-webview-view-provider.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export abstract class CDTTreeWebviewViewProvider<TNode> implements vscode.Webvie
1818
public readonly onDidExecuteCommand = this.onDidExecuteCommandEvent.event;
1919
protected onDidClickNodeEvent = new vscode.EventEmitter<CDTTreeNotification<string>>();
2020
public readonly onDidClickNode = this.onDidClickNodeEvent.event;
21+
protected onDidSearchChangeEvent = new vscode.EventEmitter<CDTTreeNotification<{ text: string }>>();
22+
public readonly onDidSearchChange = this.onDidSearchChangeEvent.event;
2123

2224
protected get extensionUri(): vscode.Uri {
2325
return this.context.extensionUri;
@@ -119,6 +121,9 @@ export abstract class CDTTreeWebviewViewProvider<TNode> implements vscode.Webvie
119121
}),
120122
this.messenger.onNotification(CDTTreeMessengerType.clickNode, event => this.onDidClickNodeEvent.fire(event), {
121123
sender: participant
124+
}),
125+
this.messenger.onNotification(CDTTreeMessengerType.searchChanged, event => this.onDidSearchChangeEvent.fire(event), {
126+
sender: participant
122127
})
123128
];
124129

0 commit comments

Comments
 (0)