import { getClient } from "@/api/AxiosClient"; import { Status, WorkflowRunApiResponse } from "@/api/types"; import { StatusBadge } from "@/components/StatusBadge"; import { Button } from "@/components/ui/button"; import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { useCredentialGetter } from "@/hooks/useCredentialGetter"; import { downloadBlob } from "@/util/downloadBlob"; import { basicLocalTimeFormat, basicTimeFormat } from "@/util/timeFormat"; import { cn } from "@/util/utils"; import { DownloadIcon, Pencil2Icon, PlayIcon } from "@radix-ui/react-icons"; import { useQuery } from "@tanstack/react-query"; import { useNavigate, useSearchParams } from "react-router-dom"; import { WorkflowApiResponse } from "./types/workflowTypes"; import { WorkflowActions } from "./WorkflowActions"; import { WorkflowsPageBanner } from "./WorkflowsPageBanner"; import { WorkflowTitle } from "./WorkflowTitle"; import { useState } from "react"; import { StatusFilterDropdown } from "@/components/StatusFilterDropdown"; function Workflows() { const credentialGetter = useCredentialGetter(); const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); const [statusFilters, setStatusFilters] = useState>([]); const workflowsPage = searchParams.get("workflowsPage") ? Number(searchParams.get("workflowsPage")) : 1; const workflowRunsPage = searchParams.get("workflowRunsPage") ? Number(searchParams.get("workflowRunsPage")) : 1; const { data: workflows, isLoading } = useQuery>({ queryKey: ["workflows", workflowsPage], queryFn: async () => { const client = await getClient(credentialGetter); const params = new URLSearchParams(); params.append("page", String(workflowsPage)); params.append("only_workflows", "true"); return client .get(`/workflows`, { params, }) .then((response) => response.data); }, }); const { data: workflowRuns, isLoading: workflowRunsIsLoading } = useQuery< Array >({ queryKey: ["workflowRuns", { statusFilters }, workflowRunsPage], queryFn: async () => { const client = await getClient(credentialGetter); const params = new URLSearchParams(); params.append("page", String(workflowRunsPage)); statusFilters.forEach((status) => { params.append("status", status); }); return client .get("/workflows/runs", { params, }) .then((response) => response.data); }, refetchOnMount: "always", }); function handleExport() { if (!workflowRuns) { return; // should never happen } const data = ["workflow_run_id,workflow_id,status,created,failure_reason"]; workflowRuns.forEach((workflowRun) => { const row = [ workflowRun.workflow_run_id, workflowRun.workflow_permanent_id, workflowRun.status, workflowRun.created_at, workflowRun.failure_reason ?? "", ]; data.push( row .map(String) // convert every value to String .map((v) => v.replace(new RegExp('"', "g"), '""')) // escape double quotes .map((v) => `"${v}"`) // quote it .join(","), // comma-separated ); }); const contents = data.join("\r\n"); downloadBlob(contents, "export.csv", "data:text/csv;charset=utf-8;"); } function handleRowClick( event: React.MouseEvent, workflowPermanentId: string, ) { if (event.ctrlKey || event.metaKey) { window.open( window.location.origin + `/workflows/${workflowPermanentId}/runs`, "_blank", "noopener,noreferrer", ); return; } navigate(`/workflows/${workflowPermanentId}/runs`); } function handleIconClick( event: React.MouseEvent, path: string, ) { if (event.ctrlKey || event.metaKey) { window.open( window.location.origin + path, "_blank", "noopener,noreferrer", ); return; } navigate(path); } return (

Workflows

ID Title Created At {isLoading ? ( Loading... ) : workflows?.length === 0 ? ( No workflows found ) : ( workflows?.map((workflow) => { return ( { handleRowClick(event, workflow.workflow_permanent_id); }} > {workflow.workflow_permanent_id} { handleRowClick(event, workflow.workflow_permanent_id); }} > {workflow.title} { handleRowClick(event, workflow.workflow_permanent_id); }} title={basicTimeFormat(workflow.created_at)} > {basicLocalTimeFormat(workflow.created_at)}
Open in Editor Create New Run
); }) )}
{ if (workflowsPage === 1) { return; } const params = new URLSearchParams(); params.set( "workflowsPage", String(Math.max(1, workflowsPage - 1)), ); setSearchParams(params, { replace: true }); }} /> {workflowsPage} { const params = new URLSearchParams(); params.set("workflowsPage", String(workflowsPage + 1)); setSearchParams(params, { replace: true }); }} />

Workflow Runs

Workflow Run ID Workflow ID Workflow Title Status Created At {workflowRunsIsLoading ? ( Loading... ) : workflowRuns?.length === 0 ? ( No workflow runs found ) : ( workflowRuns?.map((workflowRun) => { return ( { if (event.ctrlKey || event.metaKey) { window.open( window.location.origin + `/workflows/${workflowRun.workflow_permanent_id}/${workflowRun.workflow_run_id}/overview`, "_blank", "noopener,noreferrer", ); return; } navigate( `/workflows/${workflowRun.workflow_permanent_id}/${workflowRun.workflow_run_id}/overview`, ); }} className="cursor-pointer" > {workflowRun.workflow_run_id} {workflowRun.workflow_permanent_id} {basicLocalTimeFormat(workflowRun.created_at)} ); }) )}
{ if (workflowRunsPage === 1) { return; } const params = new URLSearchParams(); params.set( "workflowRunsPage", String(Math.max(1, workflowRunsPage - 1)), ); setSearchParams(params, { replace: true }); }} /> {workflowRunsPage} { const params = new URLSearchParams(); params.set( "workflowRunsPage", String(workflowRunsPage + 1), ); setSearchParams(params, { replace: true }); }} />
); } export { Workflows };