From e67afabb7658df2a0887f92286e10c62a0d231e8 Mon Sep 17 00:00:00 2001 From: Igor Silva Date: Wed, 19 Nov 2025 21:17:55 +0000 Subject: [PATCH] basic implementation, shit UX --- convex/schema.ts | 5 +++++ convex/tasks/public.ts | 12 +++++++++++- src/components/CommandMenu.tsx | 22 +++++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/convex/schema.ts b/convex/schema.ts index 6e4bbbf..3f48e03 100644 --- a/convex/schema.ts +++ b/convex/schema.ts @@ -52,6 +52,11 @@ export default defineSchema({ 'by_owner_status', ['owner', 'status'], ).index( 'by_owner_energyAvailable', ['owner', 'energyBudget.available'], + ).searchIndex( + 'search_tasks', { + searchField: 'title', + filterFields: ['owner'], + } ), // .index( // 'by_embeddingId', ['embeddingId'], diff --git a/convex/tasks/public.ts b/convex/tasks/public.ts index dd69f85..70846a3 100644 --- a/convex/tasks/public.ts +++ b/convex/tasks/public.ts @@ -43,11 +43,21 @@ export const findAll = query({ export const findAllPaginated = query({ args: { paginationOpts: paginationOptionsSchema, + search: z.string().optional(), }, - handler: async (ctx, { paginationOpts }) => { + handler: async (ctx, { paginationOpts, search }) => { // const currentUser = await getCurrentUser(ctx, {}); + // Use search index if search term is provided + if (search && search.trim()) { + return await ctx.db + .query('tasks') + .withSearchIndex('search_tasks', (q) => q.search('title', search.trim()).eq('owner', currentUser._id)) + .paginate(paginationOpts); + } + + // Default query sorted by available budget (descending, highest first) return await ctx.db .query('tasks') .withIndex('by_owner_energyAvailable', (q) => q.eq('owner', currentUser._id)) diff --git a/src/components/CommandMenu.tsx b/src/components/CommandMenu.tsx index 758b9a2..3ae5c79 100644 --- a/src/components/CommandMenu.tsx +++ b/src/components/CommandMenu.tsx @@ -117,10 +117,27 @@ export function CommandMenuDialog() { setSearch(pathname + searchStr); }, [pathname, searchStr]); - const shouldFilter = useMemo(() => { + const isSearching = useMemo(() => { return search !== pathname + searchStr; }, [search, pathname, searchStr]); + const searchQuery = useMemo(() => { + // + if (!isSearching) return undefined; + + return search; + // + }, [isSearching, search]); + + const shouldFilter = useMemo(() => { + // + // Disable client-side filtering when doing server-side search + if (searchQuery) return false; + + return isSearching; + // + }, [searchQuery, isSearching]); + const onSelect = useCallback( (value: string) => { close(); @@ -134,14 +151,13 @@ export function CommandMenuDialog() { // TODO: implement FN+Up/Down to navigate through the list - // TODO: server-side search const { results: tasks, status: paginationStatus, loadMore, } = usePaginatedQuery( api.tasks.public.findAllPaginated, - { paginationOpts: { numItems: PAGE_SIZE, cursor: null } }, + { search: searchQuery }, { initialNumItems: PAGE_SIZE }, );