From 1f90055672f95c6cd6f1dd3a50d16b0a10117f11 Mon Sep 17 00:00:00 2001 From: Jonathan Dobson Date: Tue, 28 Oct 2025 15:36:54 -0400 Subject: [PATCH] FE: allow workflow run UI to show browser stream if workflow run has one (#3838) --- .../src/components/BrowserStream.tsx | 5 ++ .../workflowRun/WorkflowRunOverview.tsx | 67 +++++++++++++------ 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/skyvern-frontend/src/components/BrowserStream.tsx b/skyvern-frontend/src/components/BrowserStream.tsx index b3a5473f..dcd14bcd 100644 --- a/skyvern-frontend/src/components/BrowserStream.tsx +++ b/skyvern-frontend/src/components/BrowserStream.tsx @@ -476,6 +476,11 @@ function BrowserStream({ } }, [task, workflow]); + useEffect(() => { + if (!interactive) { + setUserIsControlling(false); + } + }, [interactive]); /** * TODO(jdo): could use zod or smth similar */ diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunOverview.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunOverview.tsx index 77165777..79257887 100644 --- a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunOverview.tsx +++ b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunOverview.tsx @@ -1,4 +1,4 @@ -import { ActionsApiResponse } from "@/api/types"; +import { ActionsApiResponse, Status as WorkflowRunStatus } from "@/api/types"; import { BrowserStream } from "@/components/BrowserStream"; import { AspectRatio } from "@/components/ui/aspect-ratio"; import { ActionScreenshot } from "@/routes/tasks/detail/ActionScreenshot"; @@ -47,22 +47,20 @@ function WorkflowRunOverview() { const { data: workflowRunTimeline, isLoading: workflowRunTimelineIsLoading } = useWorkflowRunTimelineQuery(); + const workflowRunId = workflowRun?.workflow_run_id; + const invalidateQueries = useCallback(() => { - if (workflowRun) { + if (workflowRunId) { queryClient.invalidateQueries({ - queryKey: [ - "workflowRun", - workflowPermanentId, - workflowRun.workflow_run_id, - ], + queryKey: ["workflowRun", workflowPermanentId, workflowRunId], }); queryClient.invalidateQueries({ queryKey: ["workflowRuns"] }); queryClient.invalidateQueries({ - queryKey: ["workflowTasks", workflowRun.workflow_run_id], + queryKey: ["workflowTasks", workflowRunId], }); queryClient.invalidateQueries({ queryKey: ["runs"] }); } - }, [queryClient, workflowPermanentId, workflowRun]); + }, [queryClient, workflowPermanentId, workflowRunId]); if (workflowRunIsLoading || workflowRunTimelineIsLoading) { return ( @@ -87,25 +85,50 @@ function WorkflowRunOverview() { workflowRunIsFinalized, ); - const streamingComponent = workflowRun.browser_session_id ? ( - invalidateQueries()} - /> - ) : ( - + const browserSessionId = workflowRun.browser_session_id; + + const isPaused = + workflowRun && workflowRun.status === WorkflowRunStatus.Paused; + + const showStreamingBrowser = + (!workflowRunIsFinalized && + browserSessionId && + isWorkflowRunBlock(selection) && + selection.block_type === "human_interaction") || + selection === "stream"; + + const shouldShowBrowserStream = !!( + browserSessionId && + !workflowRunIsFinalized && + (selection === "stream" || + (isWorkflowRunBlock(selection) && + selection.block_type === "human_interaction")) ); return ( - {selection === "stream" && streamingComponent} - {selection !== "stream" && isAction(selection) && ( - )} - {isWorkflowRunBlock(selection) && ( + {!shouldShowBrowserStream && selection === "stream" && ( + + )} + {selection !== "stream" && + !showStreamingBrowser && + isAction(selection) && ( + + )} + {isWorkflowRunBlock(selection) && !showStreamingBrowser && (