import { getClient } from "@/api/AxiosClient"; import { ProxyLocation, Status } from "@/api/types"; import { StatusBadge } from "@/components/StatusBadge"; import { SwitchBarNavigation } from "@/components/SwitchBarNavigation"; import { Button } from "@/components/ui/button"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Skeleton } from "@/components/ui/skeleton"; import { toast } from "@/components/ui/use-toast"; import { useApiCredential } from "@/hooks/useApiCredential"; import { useCredentialGetter } from "@/hooks/useCredentialGetter"; import { apiBaseUrl } from "@/util/env"; import { FileIcon, Pencil2Icon, PlayIcon, ReloadIcon, } from "@radix-ui/react-icons"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Link, Outlet, useParams, useSearchParams } from "react-router-dom"; import { statusIsFinalized, statusIsRunningOrQueued } from "../tasks/types"; import { useWorkflowQuery } from "./hooks/useWorkflowQuery"; import { useWorkflowRunQuery } from "./hooks/useWorkflowRunQuery"; import { WorkflowRunTimeline } from "./workflowRun/WorkflowRunTimeline"; import { useWorkflowRunTimelineQuery } from "./hooks/useWorkflowRunTimelineQuery"; import { findActiveItem } from "./workflowRun/workflowTimelineUtils"; import { Label } from "@/components/ui/label"; import { CodeEditor } from "./components/CodeEditor"; import { cn } from "@/util/utils"; import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area"; import { CopyApiCommandDropdown } from "@/components/CopyApiCommandDropdown"; import { type ApiCommandOptions } from "@/util/apiCommands"; function WorkflowRun() { const [searchParams, setSearchParams] = useSearchParams(); const embed = searchParams.get("embed"); const isEmbedded = embed === "true"; const active = searchParams.get("active"); const { workflowRunId, workflowPermanentId } = useParams(); const credentialGetter = useCredentialGetter(); const apiCredential = useApiCredential(); const queryClient = useQueryClient(); const { data: workflow, isLoading: workflowIsLoading } = useWorkflowQuery({ workflowPermanentId, }); const { data: workflowRun, isLoading: workflowRunIsLoading, isFetched, } = useWorkflowRunQuery(); const { data: workflowRunTimeline } = useWorkflowRunTimelineQuery(); const cancelWorkflowMutation = useMutation({ mutationFn: async () => { const client = await getClient(credentialGetter); return client .post(`/workflows/runs/${workflowRunId}/cancel`) .then((response) => response.data); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["workflowRun", workflowRunId], }); queryClient.invalidateQueries({ queryKey: ["workflowRun", workflowPermanentId, workflowRunId], }); toast({ variant: "success", title: "Workflow Canceled", description: "The workflow has been successfully canceled.", }); }, onError: (error) => { toast({ variant: "destructive", title: "Error", description: error.message, }); }, }); const workflowRunIsRunningOrQueued = workflowRun && statusIsRunningOrQueued(workflowRun); const workflowRunIsFinalized = workflowRun && statusIsFinalized(workflowRun); const selection = findActiveItem( workflowRunTimeline ?? [], active, !!workflowRunIsFinalized, ); const parameters = workflowRun?.parameters ?? {}; const proxyLocation = workflowRun?.proxy_location ?? ProxyLocation.Residential; const maxScreenshotScrolls = workflowRun?.max_screenshot_scrolls ?? null; const title = workflowIsLoading ? ( ) : (

{workflow?.title}

); const workflowFailureReason = workflowRun?.failure_reason ? (
Workflow Failure Reason
{workflowRun.failure_reason}
) : null; function handleSetActiveItem(id: string) { searchParams.set("active", id); setSearchParams(searchParams, { replace: true, }); } const isTaskv2Run = workflowRun && workflowRun.task_v2 !== null; const webhookFailureReasonData = workflowRun?.task_v2?.webhook_failure_reason ?? workflowRun?.webhook_failure_reason; const webhookFailureReason = webhookFailureReasonData ? (
{webhookFailureReasonData}
) : null; const outputs = workflowRun?.outputs; const extractedInformation = typeof outputs === "object" && outputs !== null && "extracted_information" in outputs ? (outputs.extracted_information as Record) : null; const hasSomeExtractedInformation = extractedInformation ? Object.values(extractedInformation).some((value) => value !== null) : false; const hasTaskv2Output = Boolean(isTaskv2Run && workflowRun.task_v2?.output); const hasFileUrls = isFetched && workflowRun && workflowRun.downloaded_file_urls && workflowRun.downloaded_file_urls.length > 0; const fileUrls = hasFileUrls ? (workflowRun.downloaded_file_urls as string[]) : []; const showBoth = (hasSomeExtractedInformation || hasTaskv2Output) && hasFileUrls; const showOutputSection = workflowRunIsFinalized && (hasSomeExtractedInformation || hasFileUrls || hasTaskv2Output || webhookFailureReasonData) && workflowRun.status === Status.Completed; return (
{!isEmbedded && (
{title} {workflowRunIsLoading ? ( ) : workflowRun ? ( ) : null}

{workflowRunId}

({ method: "POST", url: `${apiBaseUrl}/workflows/${workflowPermanentId}/run`, body: { data: workflowRun?.parameters, proxy_location: "RESIDENTIAL", }, headers: { "Content-Type": "application/json", "x-api-key": apiCredential ?? "", }, }) satisfies ApiCommandOptions } /> {workflowRunIsRunningOrQueued && ( Are you sure? Are you sure you want to cancel this workflow run? )} {workflowRunIsFinalized && !isTaskv2Run && ( )}
)} {showOutputSection && (
{(hasSomeExtractedInformation || hasTaskv2Output) && (
)} {hasFileUrls && (
{fileUrls.length > 0 ? ( fileUrls.map((url, index) => { return ( ); }) ) : (
No files downloaded
)}
)} {webhookFailureReason}
)} {workflowFailureReason} {!isEmbedded && ( )}
{ handleSetActiveItem(item.action.action_id); }} onBlockItemSelected={(item) => { handleSetActiveItem(item.workflow_run_block_id); }} onLiveStreamSelected={() => { handleSetActiveItem("stream"); }} onObserverThoughtCardSelected={(item) => { handleSetActiveItem(item.thought_id); }} />
); } export { WorkflowRun };