"use client"; import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { useTRPC } from "@/integrations/trpc/react"; import { useQuery } from "@tanstack/react-query"; import Header from "@/components/Header"; import { Button } from "@bullstudio/ui/components/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@bullstudio/ui/components/table"; import { Skeleton } from "@bullstudio/ui/components/skeleton"; import { JobStatusBadge, type JobStatus, EmptyState, } from "@bullstudio/ui/shared"; import { Workflow, RefreshCw, Inbox, CheckCircle, XCircle } from "lucide-react"; import dayjs from "@bullstudio/dayjs"; export const Route = createFileRoute("/flows/")({ component: FlowsPage, }); function FlowsPage() { const trpc = useTRPC(); const navigate = useNavigate(); const { data: flows, isLoading, refetch, isFetching, } = useQuery( trpc.flows.list.queryOptions(undefined, { refetchInterval(query) { const flowsData = query.state.data; if (!flowsData || flowsData.length === 0) return false; const hasActiveFlows = flowsData.some( (f) => !["completed", "failed"].includes(f.status) ); return hasActiveFlows ? 2000 : false; }, }) ); const navigateToFlow = (flowId: string, queueName: string) => { navigate({ to: "/flows/$flowId", params: { flowId }, search: { queueName }, }); }; return (
{isLoading ? (
{[...Array(5)].map((_, i) => ( ))}
) : !flows || flows.length === 0 ? ( } title="No flows found" description="Flows will appear here when parent jobs with children are created using BullMQ's FlowProducer" /> ) : (
Flow Queue Status Jobs Created {flows.map((flow) => ( navigateToFlow(flow.id, flow.queueName)} >
{flow.name} {flow.id}
{flow.queueName}
{flow.totalJobs} total
{flow.completedJobs > 0 && ( {flow.completedJobs} )} {flow.failedJobs > 0 && ( {flow.failedJobs} )}
{dayjs(flow.timestamp).fromNow()} {dayjs(flow.timestamp).format("MMM D, HH:mm:ss")}
))}
Showing {flows.length} flow{flows.length !== 1 ? "s" : ""}
)}
); }