@@ -14,7 +14,9 @@ import classNames from 'classnames';
1414import { Resizable } from 're-resizable' ;
1515import { default as React , useCallback , useEffect , useLayoutEffect , useMemo , useState } from 'react' ;
1616import { debounce } from 'throttle-debounce' ;
17+ import { HOST_EXTENSION } from 'vscode-messenger-common' ;
1718import { findNestedValue } from '../../base' ;
19+ import { messenger } from '../../browser-types' ;
1820import { CommandDefinition } from '../../vscode/webview-types' ;
1921import {
2022 CDTTreeItem ,
@@ -25,6 +27,7 @@ import {
2527 CDTTreeTableStringColumn ,
2628 CDTTreeWebviewContext
2729} from '../common/index' ;
30+ import { CDTTreeMessengerType } from '../common/tree-messenger-types' ;
2831import ActionCell from './components/cells/ActionCell' ;
2932import StringCell from './components/cells/StringCell' ;
3033import { 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 > ) => {
0 commit comments