diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunBlocks.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunBlocks.tsx deleted file mode 100644 index bb8965496..000000000 --- a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunBlocks.tsx +++ /dev/null @@ -1,411 +0,0 @@ -import { getClient } from "@/api/AxiosClient"; -import { Status, TaskApiResponse } from "@/api/types"; -import { useCredentialGetter } from "@/hooks/useCredentialGetter"; -import { - keepPreviousData, - useQuery, - useQueryClient, -} from "@tanstack/react-query"; -import { - Link, - useNavigate, - useParams, - useSearchParams, -} from "react-router-dom"; -import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { Skeleton } from "@/components/ui/skeleton"; -import { WorkflowBlockCollapsibleContent } from "../WorkflowBlockCollapsibleContent"; -import { - Pagination, - PaginationContent, - PaginationItem, - PaginationLink, - PaginationNext, - PaginationPrevious, -} from "@/components/ui/pagination"; -import { cn } from "@/util/utils"; -import { - statusIsNotFinalized, - statusIsRunningOrQueued, -} from "@/routes/tasks/types"; -import { useEffect, useState } from "react"; -import { envCredential } from "@/util/env"; -import { toast } from "@/components/ui/use-toast"; -import { ZoomableImage } from "@/components/ZoomableImage"; -import { AspectRatio } from "@/components/ui/aspect-ratio"; -import { Label } from "@/components/ui/label"; -import { StatusBadge } from "@/components/StatusBadge"; -import { - localTimeFormatWithShortDate, - timeFormatWithShortDate, -} from "@/util/timeFormat"; -import { Button } from "@/components/ui/button"; -import { ReaderIcon } from "@radix-ui/react-icons"; - -type StreamMessage = { - task_id: string; - status: string; - screenshot?: string; -}; - -let socket: WebSocket | null = null; - -const wssBaseUrl = import.meta.env.VITE_WSS_BASE_URL; - -function WorkflowRunBlocks() { - const navigate = useNavigate(); - const [searchParams, setSearchParams] = useSearchParams(); - const [streamImgSrc, setStreamImgSrc] = useState(""); - const { workflowRunId, workflowPermanentId } = useParams(); - const page = searchParams.get("page") ? Number(searchParams.get("page")) : 1; - const credentialGetter = useCredentialGetter(); - const queryClient = useQueryClient(); - const { data: workflowRun, isLoading: workflowRunIsLoading } = - useWorkflowRunQuery(); - - const workflowRunIsRunningOrQueued = - workflowRun && statusIsRunningOrQueued(workflowRun); - - const showStream = workflowRun && statusIsNotFinalized(workflowRun); - - useEffect(() => { - if (!workflowRunIsRunningOrQueued) { - return; - } - - async function run() { - // Create WebSocket connection. - let credential = null; - if (credentialGetter) { - const token = await credentialGetter(); - credential = `?token=Bearer ${token}`; - } else { - credential = `?apikey=${envCredential}`; - } - if (socket) { - socket.close(); - } - socket = new WebSocket( - `${wssBaseUrl}/stream/workflow_runs/${workflowRunId}${credential}`, - ); - // Listen for messages - socket.addEventListener("message", (event) => { - try { - const message: StreamMessage = JSON.parse(event.data); - if (message.screenshot) { - setStreamImgSrc(message.screenshot); - } - if ( - message.status === "completed" || - message.status === "failed" || - message.status === "terminated" - ) { - socket?.close(); - queryClient.invalidateQueries({ - queryKey: ["workflowRuns"], - }); - queryClient.invalidateQueries({ - queryKey: ["workflowRun", workflowPermanentId, workflowRunId], - }); - queryClient.invalidateQueries({ - queryKey: ["workflowTasks", workflowRunId], - }); - if ( - message.status === "failed" || - message.status === "terminated" - ) { - toast({ - title: "Run Failed", - description: "The workflow run has failed.", - variant: "destructive", - }); - } else if (message.status === "completed") { - toast({ - title: "Run Completed", - description: "The workflow run has been completed.", - variant: "success", - }); - } - } - } catch (e) { - console.error("Failed to parse message", e); - } - }); - - socket.addEventListener("close", () => { - socket = null; - }); - } - run(); - - return () => { - if (socket) { - socket.close(); - socket = null; - } - }; - }, [ - credentialGetter, - workflowRunId, - workflowRunIsRunningOrQueued, - queryClient, - workflowPermanentId, - ]); - - function getStream() { - if (workflowRun?.status === Status.Created) { - return ( -
- Workflow has been created. - Stream will start when the workflow is running. -
- ); - } - if (workflowRun?.status === Status.Queued) { - return ( -
- Your workflow run is queued. - Stream will start when the workflow is running. -
- ); - } - - if (workflowRun?.status === Status.Running && streamImgSrc.length === 0) { - return ( -
- Starting the stream... -
- ); - } - - if (workflowRun?.status === Status.Running && streamImgSrc.length > 0) { - return ( -
- -
- ); - } - return null; - } - - const { data: workflowTasks, isLoading: workflowTasksIsLoading } = useQuery< - Array - >({ - queryKey: ["workflowTasks", workflowRunId, page], - queryFn: async () => { - const client = await getClient(credentialGetter); - const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("page_size", "20"); - return client - .get(`/tasks?workflow_run_id=${workflowRunId}`, { params }) - .then((response) => response.data); - }, - refetchInterval: () => { - if (workflowRun?.status === Status.Running) { - return 5000; - } - return false; - }, - placeholderData: keepPreviousData, - refetchOnMount: workflowRun?.status === Status.Running ? "always" : false, - refetchOnWindowFocus: - workflowRun?.status === Status.Running ? "always" : false, - }); - - const skeleton = ( - - - - - - - - - - - - - - - - - - - - - ); - - const currentRunningTask = workflowTasks?.find( - (task) => task.status === Status.Running, - ); - - function handleNavigate(event: React.MouseEvent, id: string) { - if (event.ctrlKey || event.metaKey) { - window.open( - window.location.origin + `/tasks/${id}/actions`, - "_blank", - "noopener,noreferrer", - ); - } else { - navigate(`/tasks/${id}/actions`); - } - } - - return ( -
- {showStream && ( -
-
-

Live Stream

-
-
-
- {getStream()} -
-
-
Current Task
- {workflowRunIsLoading || !currentRunningTask ? ( -
Waiting for a task to start...
- ) : ( -
-
- - - {currentRunningTask.task_id} - -
-
- - - {currentRunningTask.request.url} - -
-
- - - - -
-
- - - {currentRunningTask && - localTimeFormatWithShortDate( - currentRunningTask.created_at, - )} - -
-
- -
-
- )} -
-
-
- )} -
-
-

Workflow Blocks

-
-
- - - - - - Task Title - - ID - URL - Status - - Created At - - - - - {workflowTasksIsLoading ? ( - skeleton - ) : workflowTasks?.length === 0 ? ( - - Could not find any tasks - - ) : ( - workflowTasks - ?.filter( - (task) => task.task_id !== currentRunningTask?.task_id, - ) - .map((task) => { - return ( - - ); - }) - )} - -
- - - - { - if (page === 1) { - return; - } - const params = new URLSearchParams(); - params.set("page", String(Math.max(1, page - 1))); - setSearchParams(params, { replace: true }); - }} - /> - - - {page} - - - { - const params = new URLSearchParams(); - params.set("page", String(page + 1)); - setSearchParams(params, { replace: true }); - }} - /> - - - -
-
-
- ); -} - -export { WorkflowRunBlocks };