diff --git a/packages/ui/src/components/session/project-context/MemorySection.tsx b/packages/ui/src/components/session/project-context/MemorySection.tsx index 45c8e22a..61b4ea42 100644 --- a/packages/ui/src/components/session/project-context/MemorySection.tsx +++ b/packages/ui/src/components/session/project-context/MemorySection.tsx @@ -1,3 +1,4 @@ +import { matchesRankQuery } from '@/lib/search/fuzzySearch'; import React from 'react'; import { toast } from '@/components/ui'; @@ -186,13 +187,10 @@ export const MemorySection: React.FC<{ }; }, [markViewed, viewKey]); - const visibleEntries = React.useMemo(() => { - const needle = query.trim().toLowerCase(); - if (!needle) return entries; - return entries.filter((entry) => ( - entry.title.toLowerCase().includes(needle) || entry.body.toLowerCase().includes(needle) - )); - }, [entries, query]); + const visibleEntries = React.useMemo( + () => entries.filter((entry) => matchesRankQuery([entry.title, entry.body], query)), + [entries, query], + ); const handleDelete = React.useCallback(async (memoryId: string) => { if (!await deleteEntry(scope, memoryId)) { diff --git a/packages/ui/src/components/session/project-context/NotesSection.tsx b/packages/ui/src/components/session/project-context/NotesSection.tsx index a01b4d84..1f85be2c 100644 --- a/packages/ui/src/components/session/project-context/NotesSection.tsx +++ b/packages/ui/src/components/session/project-context/NotesSection.tsx @@ -1,3 +1,4 @@ +import { matchesRankQuery } from '@/lib/search/fuzzySearch'; import React from 'react'; import { toast } from '@/components/ui'; @@ -178,11 +179,10 @@ export const NotesSection: React.FC<{ const saveNoteBody = useProjectContextStore((state) => state.saveNoteBody); const deleteNote = useProjectContextStore((state) => state.deleteNote); - const visibleNotes = React.useMemo(() => { - const needle = query.trim().toLowerCase(); - if (!needle) return notes; - return notes.filter((note) => note.body.toLowerCase().includes(needle)); - }, [notes, query]); + const visibleNotes = React.useMemo( + () => notes.filter((note) => matchesRankQuery([note.body], query)), + [notes, query], + ); // The store keeps the failure reason; without passing it through, every // failure looks identical to the user and tells them nothing about the cause. diff --git a/packages/ui/src/components/session/project-context/PlansSection.tsx b/packages/ui/src/components/session/project-context/PlansSection.tsx index ef15d99e..a5d00fc1 100644 --- a/packages/ui/src/components/session/project-context/PlansSection.tsx +++ b/packages/ui/src/components/session/project-context/PlansSection.tsx @@ -1,3 +1,4 @@ +import { matchesRankQuery } from '@/lib/search/fuzzySearch'; import React from 'react'; import { toast } from '@/components/ui'; @@ -146,11 +147,10 @@ export const PlansSection: React.FC<{ [onTogglePinned, projectRef, t] ); - const visiblePlans = React.useMemo(() => { - const needle = query.trim().toLowerCase(); - if (!needle) return plans; - return plans.filter((plan) => plan.title.toLowerCase().includes(needle)); - }, [plans, query]); + const visiblePlans = React.useMemo( + () => plans.filter((plan) => matchesRankQuery([plan.title], query)), + [plans, query], + ); const handleOpenPlan = React.useCallback( (plan: ProjectPlanLink) => { diff --git a/packages/ui/src/components/session/project-context/TodosSection.tsx b/packages/ui/src/components/session/project-context/TodosSection.tsx index fe028ac4..788dc583 100644 --- a/packages/ui/src/components/session/project-context/TodosSection.tsx +++ b/packages/ui/src/components/session/project-context/TodosSection.tsx @@ -1,3 +1,4 @@ +import { matchesRankQuery } from '@/lib/search/fuzzySearch'; import React from 'react'; import { DndContext, @@ -183,11 +184,10 @@ export const TodosSection: React.FC<{ const completedTodoCount = todos.reduce((count, todo) => count + (todo.completed ? 1 : 0), 0); // Filtering is display-only: every handler above still edits the full list, // so reordering or clearing while a filter is active cannot drop hidden items. - const visibleTodos = React.useMemo(() => { - const needle = query.trim().toLowerCase(); - if (!needle) return todos; - return todos.filter((todo) => todo.text.toLowerCase().includes(needle)); - }, [query, todos]); + const visibleTodos = React.useMemo( + () => todos.filter((todo) => matchesRankQuery([todo.text], query)), + [query, todos], + ); return (