diff --git a/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx b/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
index e2c87503..735ed45e 100644
--- a/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
+++ b/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
@@ -5,6 +5,8 @@ import {
WorkflowRunStatusApiResponse,
} from "@/api/types";
import { StatusBadge } from "@/components/StatusBadge";
+import { ZoomableImage } from "@/components/ZoomableImage";
+import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -25,10 +27,22 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
+import { toast } from "@/components/ui/use-toast";
+import { useApiCredential } from "@/hooks/useApiCredential";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
-import { basicTimeFormat } from "@/util/timeFormat";
+import { copyText } from "@/util/copyText";
+import { apiBaseUrl, envCredential } from "@/util/env";
+import { basicTimeFormat, timeFormatWithShortDate } from "@/util/timeFormat";
import { cn } from "@/util/utils";
+import {
+ CopyIcon,
+ Pencil2Icon,
+ PlayIcon,
+ ReaderIcon,
+} from "@radix-ui/react-icons";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
+import fetchToCurl from "fetch-to-curl";
+import { useEffect, useState } from "react";
import {
Link,
useNavigate,
@@ -37,16 +51,9 @@ import {
} from "react-router-dom";
import { TaskActions } from "../tasks/list/TaskActions";
import { TaskListSkeletonRows } from "../tasks/list/TaskListSkeletonRows";
-import { useEffect, useState } from "react";
import { statusIsNotFinalized, statusIsRunningOrQueued } from "../tasks/types";
-import { apiBaseUrl, envCredential } from "@/util/env";
-import { toast } from "@/components/ui/use-toast";
-import { CopyIcon, Pencil2Icon, PlayIcon } from "@radix-ui/react-icons";
+import { CodeEditor } from "./components/CodeEditor";
import { useWorkflowQuery } from "./hooks/useWorkflowQuery";
-import fetchToCurl from "fetch-to-curl";
-import { useApiCredential } from "@/hooks/useApiCredential";
-import { copyText } from "@/util/copyText";
-import { ZoomableImage } from "@/components/ZoomableImage";
type StreamMessage = {
task_id: string;
@@ -112,8 +119,13 @@ function WorkflowRun() {
},
placeholderData: keepPreviousData,
refetchOnMount: workflowRun?.status === Status.Running,
+ refetchOnWindowFocus: workflowRun?.status === Status.Running,
});
+ const currentRunningTask = workflowTasks?.find(
+ (task) => task.status === Status.Running,
+ );
+
const workflowRunIsRunningOrQueued =
workflowRun && statusIsRunningOrQueued(workflowRun);
@@ -189,7 +201,7 @@ function WorkflowRun() {
function getStream() {
if (workflowRun?.status === Status.Created) {
return (
-
+
Workflow has been created.
Stream will start when the workflow is running.
@@ -197,7 +209,7 @@ function WorkflowRun() {
}
if (workflowRun?.status === Status.Queued) {
return (
-
+
Your workflow run is queued.
Stream will start when the workflow is running.
@@ -206,7 +218,7 @@ function WorkflowRun() {
if (workflowRun?.status === Status.Running && streamImgSrc.length === 0) {
return (
-
+
Starting the stream...
);
@@ -215,7 +227,10 @@ function WorkflowRun() {
if (workflowRun?.status === Status.Running && streamImgSrc.length > 0) {
return (
-
+
);
}
@@ -240,7 +255,7 @@ function WorkflowRun() {
-
+
{workflowRunId}
{workflowRunIsLoading ? (
@@ -308,20 +323,72 @@ function WorkflowRun() {
- {getStream()}
-
+ {workflowRun && statusIsNotFinalized(workflowRun) && (
+
+
+
+
+ {workflowRunIsLoading || !currentRunningTask ? (
+
Waiting for a task to start...
+ ) : (
+
+
+
+ {currentRunningTask.task_id}
+
+
+
+
+ {currentRunningTask.request.url}
+
+
+
+
+
+
+
+
+
+
+
+ {currentRunningTask &&
+ timeFormatWithShortDate(currentRunningTask.created_at)}
+
+
+
+
+
+
+ )}
+
+
+ )}
+
- Tasks
+
+ {workflowRunIsRunningOrQueued ? "Previous Blocks" : "Blocks"}
+
-
+
- ID
- URL
- Status
- Created At
-
+
+ ID
+
+ URL
+ Status
+
+ Created At
+
+
@@ -332,39 +399,51 @@ function WorkflowRun() {
No tasks
) : (
- workflowTasks?.map((task) => {
- return (
-
- handleNavigate(event, task.task_id)}
- >
- {task.task_id}
-
- handleNavigate(event, task.task_id)}
- >
- {task.request.url}
-
- handleNavigate(event, task.task_id)}
- >
-
-
- handleNavigate(event, task.task_id)}
- >
- {basicTimeFormat(task.created_at)}
-
-
-
-
-
- );
- })
+ workflowTasks
+ ?.filter(
+ (task) => task.task_id !== currentRunningTask?.task_id,
+ )
+ .map((task) => {
+ return (
+
+
+ handleNavigate(event, task.task_id)
+ }
+ >
+ {task.task_id}
+
+
+ handleNavigate(event, task.task_id)
+ }
+ >
+ {task.request.url}
+
+
+ handleNavigate(event, task.task_id)
+ }
+ >
+
+
+
+ handleNavigate(event, task.task_id)
+ }
+ >
+ {basicTimeFormat(task.created_at)}
+
+
+
+
+
+ );
+ })
)}
@@ -399,23 +478,32 @@ function WorkflowRun() {
-
+ {Object.entries(parameters).length > 0 && (
+
+
+ {Object.entries(parameters).map(([key, value]) => {
+ return (
+
+
+ {typeof value === "string" ? (
+
+ ) : (
+
+ )}
+
+ );
+ })}
+
+ )}
);
}
diff --git a/skyvern-frontend/src/routes/workflows/components/CodeEditor.tsx b/skyvern-frontend/src/routes/workflows/components/CodeEditor.tsx
index 1b4ffe2a..f2050e6b 100644
--- a/skyvern-frontend/src/routes/workflows/components/CodeEditor.tsx
+++ b/skyvern-frontend/src/routes/workflows/components/CodeEditor.tsx
@@ -6,7 +6,7 @@ import { cn } from "@/util/utils";
type Props = {
value: string;
- onChange: (value: string) => void;
+ onChange?: (value: string) => void;
language: "python" | "json";
disabled?: boolean;
minHeight?: string;
diff --git a/skyvern-frontend/src/util/timeFormat.ts b/skyvern-frontend/src/util/timeFormat.ts
index 051480a7..57ad206b 100644
--- a/skyvern-frontend/src/util/timeFormat.ts
+++ b/skyvern-frontend/src/util/timeFormat.ts
@@ -10,4 +10,12 @@ function basicTimeFormat(time: string): string {
return `${dateString} at ${timeString}`;
}
-export { basicTimeFormat };
+function timeFormatWithShortDate(time: string): string {
+ const date = new Date(time);
+ const dateString =
+ date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear();
+ const timeString = date.toLocaleTimeString("en-US");
+ return `${dateString} at ${timeString}`;
+}
+
+export { basicTimeFormat, timeFormatWithShortDate };