55 ChevronUpIcon ,
66 ExclamationTriangleIcon ,
77 LightBulbIcon ,
8- MagnifyingGlassIcon ,
98 UserPlusIcon ,
109 VideoCameraIcon ,
1110} from "@heroicons/react/20/solid" ;
@@ -15,7 +14,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/ser
1514import { DiscordIcon } from "@trigger.dev/companyicons" ;
1615import { formatDurationMilliseconds } from "@trigger.dev/core/v3" ;
1716import type { TaskRunStatus } from "@trigger.dev/database" ;
18- import { Fragment , Suspense , useCallback , useEffect , useRef , useState } from "react" ;
17+ import { Fragment , Suspense , useCallback , useEffect , useMemo , useRef , useState } from "react" ;
1918import type { PanelHandle } from "react-window-splitter" ;
2019import { Bar , BarChart , ResponsiveContainer , Tooltip , type TooltipProps } from "recharts" ;
2120import { TypedAwait , typeddefer , useTypedLoaderData } from "remix-typedjson" ;
@@ -37,7 +36,7 @@ import { Callout } from "~/components/primitives/Callout";
3736import { formatDateTime } from "~/components/primitives/DateTime" ;
3837import { Dialog , DialogContent , DialogHeader , DialogTitle } from "~/components/primitives/Dialog" ;
3938import { Header2 , Header3 } from "~/components/primitives/Headers" ;
40- import { Input } from "~/components/primitives/Input " ;
39+ import { SearchInput } from "~/components/primitives/SearchInput " ;
4140import { NavBar , PageAccessories , PageTitle } from "~/components/primitives/PageHeader" ;
4241import { Paragraph } from "~/components/primitives/Paragraph" ;
4342import { PopoverMenuItem } from "~/components/primitives/Popover" ;
@@ -71,7 +70,8 @@ import {
7170} from "~/components/runs/v3/TaskTriggerSource" ;
7271import { useEnvironment } from "~/hooks/useEnvironment" ;
7372import { useEventSource } from "~/hooks/useEventSource" ;
74- import { useFuzzyFilter } from "~/hooks/useFuzzyFilter" ;
73+ import { useSearchParams } from "~/hooks/useSearchParam" ;
74+ import { matchSorter } from "match-sorter" ;
7575import { useOrganization } from "~/hooks/useOrganizations" ;
7676import { useProject } from "~/hooks/useProject" ;
7777import { findProjectBySlug } from "~/models/project.server" ;
@@ -174,10 +174,19 @@ export default function Page() {
174174 const environment = useEnvironment ( ) ;
175175 const { tasks, activity, runningStats, durations, usefulLinksPreference } =
176176 useTypedLoaderData < typeof loader > ( ) ;
177- const { filterText, setFilterText, filteredItems } = useFuzzyFilter < TaskListItem > ( {
178- items : tasks ,
179- keys : [ "slug" , "filePath" , "triggerSource" ] ,
180- } ) ;
177+ const { value : searchValue } = useSearchParams ( ) ;
178+ const search = searchValue ( "search" ) ?? "" ;
179+ const filteredItems = useMemo ( ( ) => {
180+ const terms = search
181+ . trim ( )
182+ . split ( " " )
183+ . filter ( ( t ) => t !== "" ) ;
184+ if ( terms . length === 0 ) return tasks ;
185+ return terms . reduceRight (
186+ ( results , term ) => matchSorter ( results , term , { keys : [ "slug" , "filePath" , "triggerSource" ] } ) ,
187+ tasks
188+ ) ;
189+ } , [ tasks , search ] ) ;
181190
182191 const hasTasks = tasks . length > 0 ;
183192
@@ -241,16 +250,8 @@ export default function Page() {
241250 < div className = "flex min-w-0 max-w-full flex-col" >
242251 { tasks . length === 0 ? < UserHasNoTasks /> : null }
243252 < div className = "max-h-full overflow-hidden" >
244- < div className = "flex items-center gap-1 p-2" >
245- < Input
246- placeholder = "Search tasks"
247- variant = "tertiary"
248- icon = { MagnifyingGlassIcon }
249- fullWidth = { true }
250- value = { filterText }
251- onChange = { ( e ) => setFilterText ( e . target . value ) }
252- autoFocus
253- />
253+ < div className = "flex items-center justify-between gap-1 p-2" >
254+ < SearchInput placeholder = "Search tasks…" autoFocus />
254255 { ! showUsefulLinks && (
255256 < Button
256257 variant = "secondary/small"
0 commit comments