@@ -2,12 +2,20 @@ import {
22 ArrowUpCircleIcon ,
33 BookOpenIcon ,
44 ChatBubbleLeftEllipsisIcon ,
5+ MagnifyingGlassIcon ,
56 PauseIcon ,
67 PlayIcon ,
78 RectangleStackIcon ,
89} from "@heroicons/react/20/solid" ;
910import { 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" ;
1119import { type ActionFunctionArgs , type LoaderFunctionArgs } from "@remix-run/server-runtime" ;
1220import { type RuntimeEnvironmentType } from "@trigger.dev/database" ;
1321import { useEffect , useState } from "react" ;
@@ -61,8 +69,11 @@ import { docsPath, EnvironmentParamSchema, v3BillingPath } from "~/utils/pathBui
6169import { PauseEnvironmentService } from "~/v3/services/pauseEnvironment.server" ;
6270import { PauseQueueService } from "~/v3/services/pauseQueue.server" ;
6371import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route" ;
72+ import { Input } from "~/components/primitives/Input" ;
73+ import { useThrottle } from "~/hooks/useThrottle" ;
6474
6575const SearchParamsSchema = z . object ( {
76+ query : z . string ( ) . optional ( ) ,
6677 page : z . coerce . number ( ) . min ( 1 ) . default ( 1 ) ,
6778} ) ;
6879
@@ -79,7 +90,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
7990 const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema . parse ( params ) ;
8091
8192 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 ) ) ;
8394
8495 const project = await findProjectBySlug ( organizationSlug , projectParam , userId ) ;
8596 if ( ! project ) {
@@ -101,6 +112,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
101112 const queueListPresenter = new QueueListPresenter ( ) ;
102113 const queues = await queueListPresenter . call ( {
103114 environment,
115+ query,
104116 page,
105117 } ) ;
106118
@@ -198,7 +210,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
198210} ;
199211
200212export default function Page ( ) {
201- const { environment, queues, success, pagination, code, totalQueues } =
213+ const { environment, queues, success, pagination, code, totalQueues, hasFilters } =
202214 useTypedLoaderData < typeof loader > ( ) ;
203215
204216 const organization = useOrganization ( ) ;
@@ -285,10 +297,11 @@ export default function Page() {
285297 { success ? (
286298 < div
287299 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 ]"
290302 ) }
291303 >
304+ < QueueFilters />
292305 < Table containerClassName = "border-t" >
293306 < TableHeader >
294307 < TableRow >
@@ -407,7 +420,11 @@ export default function Page() {
407420 < TableRow >
408421 < TableCell colSpan = { 6 } >
409422 < 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 >
411428 </ div >
412429 </ TableCell >
413430 </ TableRow >
@@ -663,3 +680,39 @@ export function isEnvironmentPauseResumeFormSubmission(
663680 formData . get ( "action" ) === "environment-resume" )
664681 ) ;
665682}
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