@@ -24,17 +24,6 @@ function collapseFilament(element: IFilament): IFilamentCollapsed {
2424 return { ...element , "vendor.name" : element . vendor ?. name ?? null } ;
2525}
2626
27- // Keep the quick search local to the currently loaded page instead of changing the server-side query contract.
28- function matchesSearch ( filament : IFilamentCollapsed , searchTerm : string ) : boolean {
29- const needle = searchTerm . trim ( ) . toLowerCase ( ) ;
30- if ( needle . length === 0 ) {
31- return true ;
32- }
33-
34- const haystacks = [ String ( filament . id ) , filament [ "vendor.name" ] ?? "" , filament . name ?? "" , filament . material ?? "" ] ;
35- return haystacks . some ( ( value ) => value . toLowerCase ( ) . includes ( needle ) ) ;
36- }
37-
3827const MIN_TABLE_SCROLL_Y = 180 ;
3928const TABLE_BOTTOM_GAP = 16 ;
4029
@@ -43,9 +32,9 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
4332 const [ selectedItems , setSelectedItems ] = useState < number [ ] > ( [ ] ) ;
4433 const [ messageApi , contextHolder ] = message . useMessage ( ) ;
4534 const navigate = useNavigate ( ) ;
46- const [ searchValue , setSearchValue ] = useState ( "" ) ;
47- const [ serverSearchValue , setServerSearchValue ] = useState ( "" ) ;
4835 const [ tableScrollY , setTableScrollY ] = useState < number > ( 300 ) ;
36+ const [ searchTerm , setSearchTerm ] = useState ( "" ) ;
37+ const [ debouncedSearch , setDebouncedSearch ] = useState ( "" ) ;
4938 const rootRef = useRef < HTMLDivElement | null > ( null ) ;
5039 const tableContainerRef = useRef < HTMLDivElement | null > ( null ) ;
5140
@@ -54,7 +43,7 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
5443 resource : "filament" ,
5544 meta : {
5645 queryParams : {
57- ...( serverSearchValue . trim ( ) . length > 0 ? { search : serverSearchValue . trim ( ) } : { } ) ,
46+ ...( debouncedSearch . length > 0 ? { search : debouncedSearch } : { } ) ,
5847 } ,
5948 } ,
6049 syncWithLocation : false ,
@@ -85,16 +74,9 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
8574 pagination : { currentPage, pageSize } ,
8675 } ;
8776
88- const dataSource : IFilamentCollapsed [ ] = useMemo (
89- ( ) => ( tableProps . dataSource || [ ] ) . map ( ( record ) => ( { ...record } ) ) ,
90- [ tableProps . dataSource ] ,
91- ) ;
92- // Keep typing responsive by narrowing the current page immediately even while the backend query is in flight.
93- const visibleDataSource = useMemo (
94- ( ) => dataSource . filter ( ( filament ) => matchesSearch ( filament , searchValue ) ) ,
95- [ dataSource , searchValue ] ,
96- ) ;
77+ const dataSource = [ ...( tableProps . dataSource ?? [ ] ) ] ;
9778 const selectedSet = useMemo ( ( ) => new Set ( selectedItems ) , [ selectedItems ] ) ;
79+ const paginationTotal = tableProps . pagination ? ( tableProps . pagination . total ?? 0 ) : 0 ;
9880
9981 useEffect ( ( ) => {
10082 const computeScrollHeight = ( ) => {
@@ -130,8 +112,6 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
130112 resizeObserver ?. disconnect ( ) ;
131113 } ;
132114 } , [ ] ) ;
133-
134- const paginationTotal = tableProps . pagination ? ( tableProps . pagination . total ?? 0 ) : 0 ;
135115 const handlePageChange = useCallback (
136116 ( page : number , nextPageSize ?: number ) => {
137117 if ( typeof nextPageSize === "number" && nextPageSize !== pageSize ) {
@@ -145,17 +125,22 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
145125 setPageSize ( size ) ;
146126 setCurrentPage ( 1 ) ;
147127 } , [ ] ) ;
148- const applySearchFilter = useCallback ( ( nextSearch : string ) => {
149- setServerSearchValue ( nextSearch . trim ( ) ) ;
150- setCurrentPage ( 1 ) ;
151- } , [ ] ) ;
152128
153- // Bulk toggles only touch the rows currently visible after search and paging.
129+ // Debounce search input to avoid excessive API calls while typing
130+ useEffect ( ( ) => {
131+ const timer = setTimeout ( ( ) => {
132+ setDebouncedSearch ( searchTerm . trim ( ) ) ;
133+ setCurrentPage ( 1 ) ;
134+ } , 300 ) ;
135+ return ( ) => clearTimeout ( timer ) ;
136+ } , [ searchTerm , setCurrentPage ] ) ;
137+
138+ // Bulk toggles only touch the rows currently visible after paging and server-side filtering.
154139 const selectUnselectFiltered = useCallback (
155140 ( select : boolean ) => {
156141 setSelectedItems ( ( prevSelected ) => {
157142 const nextSelected = new Set ( prevSelected ) ;
158- visibleDataSource . forEach ( ( filament ) => {
143+ dataSource . forEach ( ( filament ) => {
159144 if ( select ) {
160145 nextSelected . add ( filament . id ) ;
161146 } else {
@@ -165,7 +150,7 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
165150 return Array . from ( nextSelected ) ;
166151 } ) ;
167152 } ,
168- [ visibleDataSource ] ,
153+ [ dataSource ] ,
169154 ) ;
170155
171156 const handleSelectItem = useCallback ( ( item : number ) => {
@@ -174,10 +159,9 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
174159 ) ;
175160 } , [ ] ) ;
176161
177- const isAllFilteredSelected =
178- visibleDataSource . length > 0 && visibleDataSource . every ( ( filament ) => selectedSet . has ( filament . id ) ) ;
162+ const isAllFilteredSelected = dataSource . length > 0 && dataSource . every ( ( filament ) => selectedSet . has ( filament . id ) ) ;
179163 const isSomeButNotAllFilteredSelected =
180- visibleDataSource . some ( ( filament ) => selectedSet . has ( filament . id ) ) && ! isAllFilteredSelected ;
164+ dataSource . some ( ( filament ) => selectedSet . has ( filament . id ) ) && ! isAllFilteredSelected ;
181165
182166 const commonProps = {
183167 t,
@@ -227,17 +211,14 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
227211 < Col xs = { 24 } md = { 12 } >
228212 < Input . Search
229213 placeholder = { resolvedSearchPlaceholder }
230- value = { searchValue }
214+ value = { searchTerm }
231215 allowClear
232216 enterButton
233217 onChange = { ( event ) => {
234- const value = event . target . value ;
235- setSearchValue ( value ) ;
236- applySearchFilter ( value ) ;
218+ setSearchTerm ( event . target . value ) ;
237219 } }
238220 onSearch = { ( value ) => {
239- setSearchValue ( value ) ;
240- applySearchFilter ( value ) ;
221+ setSearchTerm ( value ) ;
241222 } }
242223 />
243224 </ Col >
@@ -246,8 +227,7 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
246227 < Col flex = "none" >
247228 < Button
248229 onClick = { ( ) => {
249- setSearchValue ( "" ) ;
250- setServerSearchValue ( "" ) ;
230+ setSearchTerm ( "" ) ;
251231 setFilters ( [ ] , "replace" ) ;
252232 setCurrentPage ( 1 ) ;
253233 } }
@@ -303,7 +283,7 @@ const FilamentSelectModal = ({ description, onPrint, searchPlaceholder }: Props)
303283 rowKey = "id"
304284 tableLayout = "fixed"
305285 pagination = { false }
306- dataSource = { visibleDataSource }
286+ dataSource = { dataSource }
307287 scroll = { { y : tableScrollY , x : "max-content" } }
308288 columns = { removeUndefined ( [
309289 {
0 commit comments