From d57fccfaaf0548d5a0d004e7aa9ecd8e61c1af92 Mon Sep 17 00:00:00 2001 From: Jonathan Dobson Date: Tue, 16 Sep 2025 14:47:09 -0400 Subject: [PATCH] Jon/sky 6395 refresh code while workflow is running (#3444) --- .../src/routes/workflows/editor/Workspace.tsx | 2 +- .../src/routes/workflows/editor/utils.ts | 33 ++++--- .../workflows/hooks/useBlockScriptsQuery.ts | 16 +++- .../workflows/workflowRun/WorkflowRunCode.tsx | 87 +++++++++++++------ 4 files changed, 98 insertions(+), 40 deletions(-) diff --git a/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx b/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx index 18e1ffd4..95003131 100644 --- a/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx +++ b/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx @@ -143,7 +143,7 @@ function Workspace({ ? "" : cacheKeyValueParam ? cacheKeyValueParam - : constructCacheKeyValue(cacheKey, workflow), + : constructCacheKeyValue({ codeKey: cacheKey, workflow }), ); useEffect(() => { diff --git a/skyvern-frontend/src/routes/workflows/editor/utils.ts b/skyvern-frontend/src/routes/workflows/editor/utils.ts index 25c0e881..c9b0b55d 100644 --- a/skyvern-frontend/src/routes/workflows/editor/utils.ts +++ b/skyvern-frontend/src/routes/workflows/editor/utils.ts @@ -1,4 +1,5 @@ import { WorkflowApiResponse } from "@/routes/workflows/types/workflowTypes"; +import { WorkflowRunStatusApiResponse } from "@/api/types"; import { isDisplayedInWorkflowEditor, WorkflowEditorParameterTypes, @@ -113,23 +114,29 @@ const getInitialParameters = (workflow: WorkflowApiResponse) => { /** * Attempt to construct a valid code key value from the workflow parameters. */ -const constructCacheKeyValue = ( - codeKey: string, - workflow?: WorkflowApiResponse, -) => { +const constructCacheKeyValue = (opts: { + codeKey: string; + workflow?: WorkflowApiResponse; + workflowRun?: WorkflowRunStatusApiResponse; +}) => { + const { workflow, workflowRun } = opts; + let codeKey = opts.codeKey; + if (!workflow) { return ""; } - const workflowParameters = getInitialParameters(workflow) - .filter((p) => p.parameterType === "workflow") - .reduce( - (acc, parameter) => { - acc[parameter.key] = parameter.defaultValue; - return acc; - }, - {} as Record, - ); + const workflowParameters = workflowRun + ? workflowRun?.parameters ?? {} + : getInitialParameters(workflow) + .filter((p) => p.parameterType === "workflow") + .reduce( + (acc, parameter) => { + acc[parameter.key] = parameter.defaultValue; + return acc; + }, + {} as Record, + ); for (const [name, value] of Object.entries(workflowParameters)) { if (value === null || value === undefined || value === "") { diff --git a/skyvern-frontend/src/routes/workflows/hooks/useBlockScriptsQuery.ts b/skyvern-frontend/src/routes/workflows/hooks/useBlockScriptsQuery.ts index f93e88c1..a40478cc 100644 --- a/skyvern-frontend/src/routes/workflows/hooks/useBlockScriptsQuery.ts +++ b/skyvern-frontend/src/routes/workflows/hooks/useBlockScriptsQuery.ts @@ -7,17 +7,25 @@ type Props = { cacheKey?: string; cacheKeyValue?: string; workflowPermanentId?: string; + pollIntervalMs?: number; }; function useBlockScriptsQuery({ cacheKey, cacheKeyValue, workflowPermanentId, + pollIntervalMs, }: Props) { const credentialGetter = useCredentialGetter(); return useQuery<{ [blockName: string]: string }>({ - queryKey: ["block-scripts", workflowPermanentId, cacheKey, cacheKeyValue], + queryKey: [ + "block-scripts", + workflowPermanentId, + cacheKey, + cacheKeyValue, + pollIntervalMs, + ], queryFn: async () => { const client = await getClient(credentialGetter, "sans-api-v1"); @@ -30,6 +38,12 @@ function useBlockScriptsQuery({ return result.blocks; }, + refetchInterval: () => { + if (!pollIntervalMs || pollIntervalMs === 0) { + return false; + } + return Math.max(2000, pollIntervalMs); + }, enabled: !!workflowPermanentId, }); } diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunCode.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunCode.tsx index 87327aad..314d4a5b 100644 --- a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunCode.tsx +++ b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunCode.tsx @@ -11,10 +11,12 @@ import { } from "@/components/ui/select"; import { Label } from "@/components/ui/label"; import { HelpTooltip } from "@/components/HelpTooltip"; +import { statusIsFinalized } from "@/routes/tasks/types"; import { CodeEditor } from "@/routes/workflows/components/CodeEditor"; import { useBlockScriptsQuery } from "@/routes/workflows/hooks/useBlockScriptsQuery"; import { useCacheKeyValuesQuery } from "@/routes/workflows/hooks/useCacheKeyValuesQuery"; import { useWorkflowQuery } from "@/routes/workflows/hooks/useWorkflowQuery"; +import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery"; import { constructCacheKeyValue } from "@/routes/workflows/editor/utils"; import { WorkflowApiResponse } from "@/routes/workflows/types/workflowTypes"; @@ -72,12 +74,15 @@ function WorkflowRunCode(props?: Props) { const showCacheKeyValueSelector = props?.showCacheKeyValueSelector ?? false; const queryClient = useQueryClient(); const { workflowPermanentId } = useParams(); + const { data: workflowRun } = useWorkflowRunQuery(); const { data: workflow } = useWorkflowQuery({ workflowPermanentId, }); const cacheKey = workflow?.cache_key ?? ""; const [cacheKeyValue, setCacheKeyValue] = useState( - cacheKey === "" ? "" : constructCacheKeyValue(cacheKey, workflow), + cacheKey === "" + ? "" + : constructCacheKeyValue({ codeKey: cacheKey, workflow, workflowRun }), ); const { data: cacheKeyValues } = useCacheKeyValuesQuery({ cacheKey, @@ -85,13 +90,25 @@ function WorkflowRunCode(props?: Props) { page: 1, workflowPermanentId, }); + const isFinalized = workflowRun ? statusIsFinalized(workflowRun) : null; + const parameters = workflowRun?.parameters; + + const { data: blockScripts } = useBlockScriptsQuery({ + cacheKey, + cacheKeyValue, + workflowPermanentId, + pollIntervalMs: !isFinalized ? 3000 : undefined, + }); + const orderedBlockLabels = getOrderedBlockLabels(workflow); + const code = getCode(orderedBlockLabels, blockScripts).join(""); useEffect(() => { setCacheKeyValue( - cacheKeyValues?.values[0] ?? constructCacheKeyValue(cacheKey, workflow), + constructCacheKeyValue({ codeKey: cacheKey, workflow, workflowRun }) ?? + cacheKeyValues?.values[0], ); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [cacheKeyValues, setCacheKeyValue, workflow]); + }, [cacheKeyValues, parameters, setCacheKeyValue, workflow, workflowRun]); useEffect(() => { queryClient.invalidateQueries({ @@ -104,16 +121,13 @@ function WorkflowRunCode(props?: Props) { ], }); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [workflow]); + }, [queryClient, workflow]); - const { data: blockScripts } = useBlockScriptsQuery({ - cacheKey, - cacheKeyValue, - workflowPermanentId, - }); - - const orderedBlockLabels = getOrderedBlockLabels(workflow); - const code = getCode(orderedBlockLabels, blockScripts).join(""); + useEffect(() => { + queryClient.invalidateQueries({ + queryKey: ["block-scripts", workflowPermanentId, cacheKey, cacheKeyValue], + }); + }, [queryClient, workflowRun, workflowPermanentId, cacheKey, cacheKeyValue]); if (code.length === 0) { return ( @@ -123,10 +137,7 @@ function WorkflowRunCode(props?: Props) { ); } - if ( - !showCacheKeyValueSelector || - (cacheKeyValues?.values ?? []).length <= 1 - ) { + if (!showCacheKeyValueSelector || !cacheKey || cacheKey === "") { return (
- - + +