diff --git a/skyvern-frontend/src/components/SwitchBarNavigation.tsx b/skyvern-frontend/src/components/SwitchBarNavigation.tsx
index c7943184..26587072 100644
--- a/skyvern-frontend/src/components/SwitchBarNavigation.tsx
+++ b/skyvern-frontend/src/components/SwitchBarNavigation.tsx
@@ -4,6 +4,7 @@ import { NavLink, useSearchParams } from "react-router-dom";
type Option = {
label: string;
to: string;
+ icon?: React.ReactNode;
};
type Props = {
@@ -23,13 +24,18 @@ function SwitchBarNavigation({ options }: Props) {
key={option.to}
className={({ isActive }) => {
return cn(
- "cursor-pointer rounded-sm px-3 py-2 hover:bg-slate-700",
+ "flex cursor-pointer items-center justify-center rounded-sm px-3 py-2 text-center hover:bg-slate-700",
{
"bg-slate-700": isActive,
},
);
}}
>
+ {option.icon && (
+
+ {option.icon}
+
+ )}
{option.label}
);
@@ -38,4 +44,4 @@ function SwitchBarNavigation({ options }: Props) {
);
}
-export { SwitchBarNavigation };
+export { SwitchBarNavigation, type Option as SwitchBarNavigationOption };
diff --git a/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx b/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
index d25b62d8..9be8e5e0 100644
--- a/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
+++ b/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
@@ -1,7 +1,11 @@
+import { useEffect, useState } from "react";
import { getClient } from "@/api/AxiosClient";
import { ProxyLocation, Status } from "@/api/types";
import { StatusBadge } from "@/components/StatusBadge";
-import { SwitchBarNavigation } from "@/components/SwitchBarNavigation";
+import {
+ SwitchBarNavigation,
+ type SwitchBarNavigationOption,
+} from "@/components/SwitchBarNavigation";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -19,6 +23,7 @@ import { useApiCredential } from "@/hooks/useApiCredential";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { apiBaseUrl } from "@/util/env";
import {
+ CodeIcon,
FileIcon,
Pencil2Icon,
PlayIcon,
@@ -38,6 +43,9 @@ import { cn } from "@/util/utils";
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import { CopyApiCommandDropdown } from "@/components/CopyApiCommandDropdown";
import { type ApiCommandOptions } from "@/util/apiCommands";
+import { useBlockScriptsQuery } from "@/routes/workflows/hooks/useBlockScriptsQuery";
+import { constructCacheKeyValue } from "@/routes/workflows/editor/utils";
+import { useCacheKeyValuesQuery } from "@/routes/workflows/hooks/useCacheKeyValuesQuery";
function WorkflowRun() {
const [searchParams, setSearchParams] = useSearchParams();
@@ -53,7 +61,7 @@ function WorkflowRun() {
workflowPermanentId,
});
- const hasScript = false;
+ const cacheKey = workflow?.cache_key ?? "";
const {
data: workflowRun,
@@ -61,6 +69,44 @@ function WorkflowRun() {
isFetched,
} = useWorkflowRunQuery();
+ const isFinalized = workflowRun ? statusIsFinalized(workflowRun) : null;
+
+ const [hasPublishedCode, setHasPublishedCode] = useState(false);
+
+ const [cacheKeyValue, setCacheKeyValue] = useState(
+ cacheKey === ""
+ ? ""
+ : constructCacheKeyValue({ codeKey: cacheKey, workflow, workflowRun }),
+ );
+
+ const { data: cacheKeyValues } = useCacheKeyValuesQuery({
+ cacheKey,
+ debounceMs: 100,
+ page: 1,
+ workflowPermanentId,
+ });
+
+ useEffect(() => {
+ setCacheKeyValue(
+ constructCacheKeyValue({ codeKey: cacheKey, workflow, workflowRun }) ??
+ cacheKeyValues?.values[0],
+ );
+ }, [cacheKey, cacheKeyValues, setCacheKeyValue, workflow, workflowRun]);
+
+ const { data: blockScriptsPublished } = useBlockScriptsQuery({
+ cacheKey,
+ cacheKeyValue,
+ workflowPermanentId,
+ pollIntervalMs: !hasPublishedCode && !isFinalized ? 3000 : undefined,
+ status: "published",
+ workflowRunId: workflowRun?.workflow_run_id,
+ });
+
+ useEffect(() => {
+ const keys = Object.keys(blockScriptsPublished ?? {});
+ setHasPublishedCode(keys.length > 0);
+ }, [blockScriptsPublished, setHasPublishedCode]);
+
const { data: workflowRunTimeline } = useWorkflowRunTimelineQuery();
const cancelWorkflowMutation = useMutation({
@@ -208,7 +254,9 @@ function WorkflowRun() {
webhookFailureReasonData) &&
workflowRun.status === Status.Completed;
- const switchBarOptions = [
+ const isGeneratingCode = !isFinalized && !hasPublishedCode;
+
+ const switchBarOptions: SwitchBarNavigationOption[] = [
{
label: "Overview",
to: "overview",
@@ -225,14 +273,16 @@ function WorkflowRun() {
label: "Recording",
to: "recording",
},
- ];
-
- if (!hasScript) {
- switchBarOptions.push({
+ {
label: "Code",
to: "code",
- });
- }
+ icon: !isGeneratingCode ? (
+