11import { ConfirmDeletionModal } from '@/components/ConfirmDeletionModal' ;
22import { Button } from '@/components/ui/button' ;
33import { useInstanceClientIdParams } from '@/config/useInstanceClient' ;
4+ import { ColumnFiltersSchema } from '@/features/instance/databases/components/ColumnFilters' ;
45import { PickColumnsDropdown } from '@/features/instance/databases/components/PickColumnsDropdown' ;
56import { TableView } from '@/features/instance/databases/components/TableView' ;
67import { formatBrowseDataTableHeader } from '@/features/instance/databases/functions/formatBrowseDataTableHeader' ;
@@ -12,18 +13,28 @@ import { useDeleteTableRecords } from '@/features/instance/operations/mutations/
1213import { useInsertTableRecords } from '@/features/instance/operations/mutations/insertTableRecords' ;
1314import { useUpdateTableRecords } from '@/features/instance/operations/mutations/updateTableRecords' ;
1415import { getDescribeTableQueryOptions } from '@/features/instance/operations/queries/getDescribeTable' ;
16+ import {
17+ getSearchByConditionsOptions ,
18+ SearchCondition ,
19+ translateColumnFilterToSearchCondition ,
20+ } from '@/features/instance/operations/queries/getSearchByConditions' ;
1521import { getSearchByIdOptions } from '@/features/instance/operations/queries/getSearchById' ;
1622import { getSearchByValueOptions } from '@/features/instance/operations/queries/getSearchByValue' ;
23+ import { useDebounce } from '@/hooks/useDebounce' ;
1724import { useEffectedState } from '@/hooks/useEffectedState' ;
1825import { useInstanceBrowseManagePermission , useInstanceSchemaTablePermission } from '@/hooks/usePermissions' ;
1926import { useRefreshClick } from '@/hooks/useRefreshClick' ;
2027import { useSessionStorage } from '@/hooks/useSessionStorage' ;
28+ import { useToggleCallback } from '@/hooks/useToggleCallback' ;
29+ import { keyBy } from '@/lib/keyBy' ;
2130import { queryClient } from '@/react-query/queryClient' ;
31+ import { zodResolver } from '@hookform/resolvers/zod' ;
2232import { useQuery , useSuspenseQuery } from '@tanstack/react-query' ;
2333import { useNavigate , useParams } from '@tanstack/react-router' ;
2434import { Row , VisibilityState } from '@tanstack/react-table' ;
25- import { ImportIcon , PlusIcon , RefreshCwIcon , Trash } from 'lucide-react' ;
26- import { useCallback , useEffect , useState } from 'react' ;
35+ import { ImportIcon , PlusIcon , RefreshCwIcon , SearchIcon , Trash } from 'lucide-react' ;
36+ import { useCallback , useEffect , useMemo , useState } from 'react' ;
37+ import { useForm } from 'react-hook-form' ;
2738import { toast } from 'sonner' ;
2839
2940export function DatabaseTableView ( ) {
@@ -48,52 +59,85 @@ export function DatabaseTableView() {
4859 ...instanceParams ,
4960 databaseName,
5061 tableName,
51- } )
62+ } ) ,
5263 ) ;
64+ const attributesMap = useMemo ( ( ) => keyBy ( describeTableData . attributes , 'attribute' ) , [ describeTableData ] )
5365 const [ selectedIds , setSelectedIds ] = useEffectedState < null | unknown [ ] > ( null , allParams ) ;
5466 const [ isEditModalOpen , setIsEditModalOpen ] = useState ( false ) ;
5567
56- const { data : searchByIdData } = useQuery (
57- getSearchByIdOptions ( {
58- ...instanceParams ,
59- isEditModalOpen : isEditModalOpen ,
60- databaseName : databaseName ,
61- tableName : tableName ,
62- ids : selectedIds ,
63- } )
64- ) ;
68+ const columnFiltersForm = useForm ( {
69+ resolver : zodResolver ( ColumnFiltersSchema ) ,
70+ } ) ;
71+ const columnFiltersValues = columnFiltersForm . watch ( ) ;
72+ const rawSearchConditions : SearchCondition [ ] | null = useMemo ( ( ) => {
73+ const conditions : SearchCondition [ ] = [ ] ;
74+ for ( const key in columnFiltersValues ) {
75+ if ( columnFiltersValues [ key ] ?. length ) {
76+ conditions . push ( translateColumnFilterToSearchCondition ( key , columnFiltersValues [ key ] , attributesMap [ key ] ) ) ;
77+ }
78+ }
79+ return conditions . length ? conditions : null ;
80+ } , [ attributesMap , columnFiltersValues ] )
81+ const searchConditions = useDebounce ( rawSearchConditions , 500 , JSON . stringify ) ;
6582
6683 const { dataTableColumns, hashAttribute } = formatBrowseDataTableHeader ( describeTableData ) ;
6784 const [ isAddModalOpen , setIsAddModalOpen ] = useState ( false ) ;
6885 const [ isImportCSVModalOpen , setIsImportCSVModalOpen ] = useState ( false ) ;
69- const [ sortTableDataParams , setSortTableDataParams ] = useEffectedState (
86+ const [ sort , setSort ] = useEffectedState (
7087 {
7188 attribute : hashAttribute ,
7289 descending : false ,
7390 } ,
74- allParams
91+ allParams ,
7592 ) ;
7693
7794 const [ totalRecords , setTotalRecords ] = useState ( describeTableData . record_count ) ;
7895 const [ pageIndex , setPageIndex ] = useEffectedState ( 0 , [ databaseName , tableName ] ) ;
7996 const [ pageSize , setPageSize ] = useState ( 20 ) ;
8097 const [ totalPages , setTotalPages ] = useState ( Math . ceil ( describeTableData . record_count / pageSize ) ) ;
8198
99+ // Full list
82100 const {
83- data : tableData ,
101+ data : fullTableData ,
84102 refetch : refetchSearchByValueOptions ,
85103 isFetching : tableDataFetching ,
86104 } = useQuery (
87105 getSearchByValueOptions ( {
106+ enabled : ! searchConditions ,
88107 ...instanceParams ,
89108 databaseName,
90109 tableName,
91110 searchAttribute : hashAttribute ,
92- sortTableDataParams,
111+ sort,
112+ pageSize,
113+ pageIndex,
114+ } ) ,
115+ ) ;
116+ // Filtered list
117+ const { data : filteredTableData } = useQuery (
118+ getSearchByConditionsOptions ( {
119+ enabled : ! ! searchConditions ,
120+ ...instanceParams ,
121+ databaseName,
122+ tableName,
123+ conditions : searchConditions ,
124+ sort,
93125 pageSize,
94126 pageIndex,
95- } )
127+ } ) ,
96128 ) ;
129+ const tableData = searchConditions ? filteredTableData : fullTableData ;
130+ // One by id
131+ const { data : searchByIdData } = useQuery (
132+ getSearchByIdOptions ( {
133+ ...instanceParams ,
134+ enabled : isEditModalOpen ,
135+ databaseName : databaseName ,
136+ tableName : tableName ,
137+ ids : selectedIds ,
138+ } ) ,
139+ ) ;
140+
97141 const { mutate : addTableRecords , isPending : isAddTableRecordsPending } = useInsertTableRecords ( ) ;
98142 const { mutate : updateTableRecords , isPending : isUpdateTableRecordsPending } = useUpdateTableRecords ( ) ;
99143 const { mutate : deleteTableRecords , isPending : isDeleteTableRecordsPending } = useDeleteTableRecords ( ) ;
@@ -119,7 +163,7 @@ export function DatabaseTableView() {
119163 setIsAddModalOpen ( false ) ;
120164 toast . success ( 'Record added successfully' ) ;
121165 } ,
122- }
166+ } ,
123167 ) ;
124168 } ;
125169 const onRecordUpdate = ( data : Record < string , unknown > [ ] ) => {
@@ -137,7 +181,7 @@ export function DatabaseTableView() {
137181 setIsEditModalOpen ( false ) ;
138182 toast . success ( 'Record updated successfully' ) ;
139183 } ,
140- }
184+ } ,
141185 ) ;
142186 } ;
143187
@@ -156,7 +200,7 @@ export function DatabaseTableView() {
156200 setIsEditModalOpen ( false ) ;
157201 toast . success ( 'Record deleted successfully' ) ;
158202 } ,
159- }
203+ } ,
160204 ) ;
161205 } ;
162206
@@ -176,7 +220,7 @@ export function DatabaseTableView() {
176220 setIsEditModalOpen ( ! isEditModalOpen ) ;
177221 } ;
178222 const onColumnClick = ( accessorKey : string , isAscending : boolean ) => {
179- setSortTableDataParams ( {
223+ setSort ( {
180224 attribute : accessorKey ,
181225 descending : ! isAscending ,
182226 } ) ;
@@ -215,10 +259,10 @@ export function DatabaseTableView() {
215259 void navigate ( { to : '../' } ) ;
216260 }
217261 } ,
218- }
262+ } ,
219263 ) ;
220264 } ,
221- [ deleteTable , instanceParams , navigate , tableName ]
265+ [ deleteTable , instanceParams , navigate , tableName ] ,
222266 ) ;
223267
224268 const onDeletionConfirmed = useCallback ( ( ) => {
@@ -231,6 +275,7 @@ export function DatabaseTableView() {
231275 `ColumnDisplayed/${ databaseName } }/${ tableName } ` as 'ColumnDisplayed/{database}/{table}' ,
232276 { } satisfies VisibilityState ,
233277 ) ;
278+ const [ showSearch , toggleShowSearch ] = useToggleCallback ( false ) ;
234279
235280 return (
236281 < >
@@ -268,6 +313,10 @@ export function DatabaseTableView() {
268313 </ div >
269314
270315 < div className = "flex space-x-2" >
316+ < Button variant = "ghost" onClick = { toggleShowSearch } >
317+ < SearchIcon className = "inline-block " />
318+ { showSearch ? 'Clear Search' : 'Search' }
319+ </ Button >
271320 < PickColumnsDropdown
272321 columns = { dataTableColumns }
273322 columnVisibility = { columnVisibility }
@@ -285,6 +334,7 @@ export function DatabaseTableView() {
285334 < TableView < Record < string , unknown > , unknown >
286335 data = { tableData ?. data || [ ] }
287336 isFetching = { tableDataFetching }
337+ showSearch = { showSearch }
288338 columns = { dataTableColumns }
289339 columnVisibility = { columnVisibility }
290340 onRowClick = { onRowClick }
@@ -293,6 +343,7 @@ export function DatabaseTableView() {
293343 totalRecords = { totalRecords }
294344 pageIndex = { pageIndex }
295345 pageSize = { pageSize }
346+ columnFiltersForm = { columnFiltersForm }
296347 setPageIndex = { setPageIndex }
297348 setPageSize = { setPageSize }
298349 />
0 commit comments