diff --git a/server/routes/objects.ts b/server/routes/objects.ts index 998381dc..48680a9c 100644 --- a/server/routes/objects.ts +++ b/server/routes/objects.ts @@ -85,11 +85,12 @@ const app = new Hono() const parent = c.req.query('path') ?? c.req.query('parent') ?? '' const status = c.req.query('status') ?? 'active' const typeFilter = c.req.query('type') + const search = c.req.query('search') const page = Number(c.req.query('page') ?? '1') const pageSize = Number(c.req.query('pageSize') ?? '20') const db = c.get('platform').db - const result = await listMatters(db, orgId, { parent, status, typeFilter, page, pageSize }) + const result = await listMatters(db, orgId, { parent, status, typeFilter, search, page, pageSize }) return c.json(result) }) .post('/', zValidator('json', createMatterSchema), async (c) => { diff --git a/server/services/matter.ts b/server/services/matter.ts index a83fd63b..6255d3e0 100644 --- a/server/services/matter.ts +++ b/server/services/matter.ts @@ -68,6 +68,7 @@ interface ListFilters { page: number pageSize: number typeFilter?: string + search?: string } export async function listMatters( @@ -78,7 +79,9 @@ export async function listMatters( const offset = (filters.page - 1) * filters.pageSize const conditions = [eq(matters.orgId, orgId), eq(matters.status, filters.status)] const typeCond = filters.typeFilter ? typeFilterCondition(filters.typeFilter) : undefined - if (typeCond) { + if (filters.search) { + conditions.push(like(matters.name, `%${filters.search}%`)) + } else if (typeCond) { conditions.push(typeCond) conditions.push(eq(matters.dirtype, DirType.FILE)) } else { diff --git a/src/components/files/file-manager.tsx b/src/components/files/file-manager.tsx index 528ce933..1fe448b6 100644 --- a/src/components/files/file-manager.tsx +++ b/src/components/files/file-manager.tsx @@ -79,15 +79,16 @@ export function FileManager({ initialPath, filterType }: FileManagerProps) { const [previewFile, setPreviewFile] = useState(null) const [previewOpen, setPreviewOpen] = useState(false) const [searchQuery, setSearchQuery] = useState('') + const [debouncedSearch, setDebouncedSearch] = useState('') - const query = useFilesQuery(currentPath, filterType) + useEffect(() => { + const timer = setTimeout(() => setDebouncedSearch(searchQuery), 300) + return () => clearTimeout(timer) + }, [searchQuery]) + + const query = useFilesQuery(currentPath, filterType, debouncedSearch || undefined) const mutations = useFileMutations(currentPath) - const allItems = query.data?.items ?? [] - const items = useMemo( - () => - searchQuery ? allItems.filter((item) => item.name.toLowerCase().includes(searchQuery.toLowerCase())) : allItems, - [allItems, searchQuery], - ) + const items = query.data?.items ?? [] // biome-ignore lint/correctness/useExhaustiveDependencies: clear selection and search when path changes useEffect(() => { diff --git a/src/components/files/hooks/use-files-query.ts b/src/components/files/hooks/use-files-query.ts index f4ca5a8e..4c0b6066 100644 --- a/src/components/files/hooks/use-files-query.ts +++ b/src/components/files/hooks/use-files-query.ts @@ -3,9 +3,9 @@ import { listObjectsByPath } from '@/lib/api' const FILES_PAGE_SIZE = 500 -export function useFilesQuery(path: string, typeFilter?: string) { +export function useFilesQuery(path: string, typeFilter?: string, search?: string) { return useQuery({ - queryKey: ['objects', 'active', 'path', path, typeFilter ?? ''], - queryFn: () => listObjectsByPath(path, 'active', 1, FILES_PAGE_SIZE, typeFilter), + queryKey: ['objects', 'active', 'path', path, typeFilter ?? '', search ?? ''], + queryFn: () => listObjectsByPath(path, 'active', 1, FILES_PAGE_SIZE, { type: typeFilter, search }), }) } diff --git a/src/lib/api.ts b/src/lib/api.ts index f0fc7a98..85602e10 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -21,9 +21,16 @@ export function listObjects(parent: string, status = 'active', page = 1, pageSiz ) } -export function listObjectsByPath(path: string, status = 'active', page = 1, pageSize = 500, type?: string) { +export function listObjectsByPath( + path: string, + status = 'active', + page = 1, + pageSize = 500, + opts?: { type?: string; search?: string }, +) { const query: Record = { path, status, page: String(page), pageSize: String(pageSize) } - if (type) query.type = type + if (opts?.type) query.type = opts.type + if (opts?.search) query.search = opts.search return unwrap>(objects.index.$get({ query })) }