@@ -2,12 +2,20 @@ import {
2
2
ArrowUpCircleIcon ,
3
3
BookOpenIcon ,
4
4
ChatBubbleLeftEllipsisIcon ,
5
+ MagnifyingGlassIcon ,
5
6
PauseIcon ,
6
7
PlayIcon ,
7
8
RectangleStackIcon ,
8
9
} from "@heroicons/react/20/solid" ;
9
10
import { DialogClose } from "@radix-ui/react-dialog" ;
10
- import { Form , useNavigation , useRevalidator , type MetaFunction } from "@remix-run/react" ;
11
+ import {
12
+ Form ,
13
+ useNavigate ,
14
+ useNavigation ,
15
+ useRevalidator ,
16
+ useSearchParams ,
17
+ type MetaFunction ,
18
+ } from "@remix-run/react" ;
11
19
import { type ActionFunctionArgs , type LoaderFunctionArgs } from "@remix-run/server-runtime" ;
12
20
import { type RuntimeEnvironmentType } from "@trigger.dev/database" ;
13
21
import { useEffect , useState } from "react" ;
@@ -61,8 +69,11 @@ import { docsPath, EnvironmentParamSchema, v3BillingPath } from "~/utils/pathBui
61
69
import { PauseEnvironmentService } from "~/v3/services/pauseEnvironment.server" ;
62
70
import { PauseQueueService } from "~/v3/services/pauseQueue.server" ;
63
71
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route" ;
72
+ import { Input } from "~/components/primitives/Input" ;
73
+ import { useThrottle } from "~/hooks/useThrottle" ;
64
74
65
75
const SearchParamsSchema = z . object ( {
76
+ query : z . string ( ) . optional ( ) ,
66
77
page : z . coerce . number ( ) . min ( 1 ) . default ( 1 ) ,
67
78
} ) ;
68
79
@@ -79,7 +90,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
79
90
const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema . parse ( params ) ;
80
91
81
92
const url = new URL ( request . url ) ;
82
- const { page } = SearchParamsSchema . parse ( Object . fromEntries ( url . searchParams ) ) ;
93
+ const { page, query } = SearchParamsSchema . parse ( Object . fromEntries ( url . searchParams ) ) ;
83
94
84
95
const project = await findProjectBySlug ( organizationSlug , projectParam , userId ) ;
85
96
if ( ! project ) {
@@ -101,6 +112,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
101
112
const queueListPresenter = new QueueListPresenter ( ) ;
102
113
const queues = await queueListPresenter . call ( {
103
114
environment,
115
+ query,
104
116
page,
105
117
} ) ;
106
118
@@ -198,7 +210,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
198
210
} ;
199
211
200
212
export default function Page ( ) {
201
- const { environment, queues, success, pagination, code, totalQueues } =
213
+ const { environment, queues, success, pagination, code, totalQueues, hasFilters } =
202
214
useTypedLoaderData < typeof loader > ( ) ;
203
215
204
216
const organization = useOrganization ( ) ;
@@ -285,10 +297,11 @@ export default function Page() {
285
297
{ success ? (
286
298
< div
287
299
className = { cn (
288
- "grid max-h-full min-h-full grid-rows-[1fr ] overflow-x-auto" ,
289
- pagination . totalPages > 1 && "grid-rows-[1fr_auto ]"
300
+ "grid max-h-full min-h-full grid-rows-[auto_1fr ] overflow-x-auto" ,
301
+ pagination . totalPages > 1 && "grid-rows-[auto_1fr_auto ]"
290
302
) }
291
303
>
304
+ < QueueFilters />
292
305
< Table containerClassName = "border-t" >
293
306
< TableHeader >
294
307
< TableRow >
@@ -407,7 +420,11 @@ export default function Page() {
407
420
< TableRow >
408
421
< TableCell colSpan = { 6 } >
409
422
< div className = "grid place-items-center py-6 text-text-dimmed" >
410
- < Paragraph > No queues found</ Paragraph >
423
+ < Paragraph >
424
+ { hasFilters
425
+ ? "No queues found matching your filters"
426
+ : "No queues found" }
427
+ </ Paragraph >
411
428
</ div >
412
429
</ TableCell >
413
430
</ TableRow >
@@ -663,3 +680,39 @@ export function isEnvironmentPauseResumeFormSubmission(
663
680
formData . get ( "action" ) === "environment-resume" )
664
681
) ;
665
682
}
683
+
684
+ export function QueueFilters ( ) {
685
+ const [ searchParams , setSearchParams ] = useSearchParams ( ) ;
686
+
687
+ const handleSearchChange = useThrottle ( ( value : string ) => {
688
+ if ( value ) {
689
+ setSearchParams ( ( prev ) => {
690
+ prev . set ( "query" , value ) ;
691
+ prev . delete ( "page" ) ;
692
+ return prev ;
693
+ } ) ;
694
+ } else {
695
+ setSearchParams ( ( prev ) => {
696
+ prev . delete ( "query" ) ;
697
+ prev . delete ( "page" ) ;
698
+ return prev ;
699
+ } ) ;
700
+ }
701
+ } , 300 ) ;
702
+
703
+ const search = searchParams . get ( "query" ) ?? "" ;
704
+
705
+ return (
706
+ < div className = "flex w-full px-3 pb-3" >
707
+ < Input
708
+ name = "search"
709
+ placeholder = "Search queue name"
710
+ icon = { MagnifyingGlassIcon }
711
+ variant = "tertiary"
712
+ className = "grow"
713
+ defaultValue = { search }
714
+ onChange = { ( e ) => handleSearchChange ( e . target . value ) }
715
+ />
716
+ </ div >
717
+ ) ;
718
+ }
0 commit comments