From 7a86a82107dd04f4f57e5e9f0494b2c7b90eec2b Mon Sep 17 00:00:00 2001 From: Shuchang Zheng Date: Thu, 22 Jan 2026 20:44:56 -0800 Subject: [PATCH] browser sessions v2 - frontend (#4514) Co-authored-by: Benji Visser --- .../src/components/BrowserStream.tsx | 9 +--- .../routes/browserSessions/BrowserSession.tsx | 43 +++++++++++-------- .../browserSessions/BrowserSessionVideo.tsx | 26 ++++++++--- .../hooks/useCreateBrowserSessionMutation.ts | 21 +++++++++ .../workflows/types/browserSessionTypes.ts | 1 + 5 files changed, 68 insertions(+), 32 deletions(-) diff --git a/skyvern-frontend/src/components/BrowserStream.tsx b/skyvern-frontend/src/components/BrowserStream.tsx index 1a4cf311..0a1a1549 100644 --- a/skyvern-frontend/src/components/BrowserStream.tsx +++ b/skyvern-frontend/src/components/BrowserStream.tsx @@ -31,12 +31,7 @@ import { type MessageInExfiltratedEvent, } from "@/store/useRecordingStore"; import { useSettingsStore } from "@/store/SettingsStore"; -import { - environment, - wssBaseUrl, - newWssBaseUrl, - getRuntimeApiKey, -} from "@/util/env"; +import { wssBaseUrl, newWssBaseUrl, getRuntimeApiKey } from "@/util/env"; import { copyText } from "@/util/copyText"; import { cn } from "@/util/utils"; @@ -223,7 +218,7 @@ function BrowserStream({ let credentialQueryParam = runtimeApiKey ? `apikey=${runtimeApiKey}` : ""; - if (environment !== "local" && credentialGetter) { + if (credentialGetter) { const token = await credentialGetter(); credentialQueryParam = token ? `token=Bearer ${token}` : ""; } diff --git a/skyvern-frontend/src/routes/browserSessions/BrowserSession.tsx b/skyvern-frontend/src/routes/browserSessions/BrowserSession.tsx index 3eca1fe5..de1cd3dd 100644 --- a/skyvern-frontend/src/routes/browserSessions/BrowserSession.tsx +++ b/skyvern-frontend/src/routes/browserSessions/BrowserSession.tsx @@ -30,9 +30,6 @@ type TabName = "stream" | "videos"; function BrowserSession() { const { browserSessionId } = useParams(); - const [hasBrowserSession, setHasBrowserSession] = useState(false); - const [browserSession, setBrowserSession] = - useState(null); const [activeTab, setActiveTab] = useState("stream"); const [isDialogOpen, setIsDialogOpen] = useState(false); @@ -42,22 +39,17 @@ function BrowserSession() { queryKey: ["browserSession", browserSessionId], queryFn: async () => { const client = await getClient(credentialGetter, "sans-api-v1"); - - try { - const response = await client.get( - `/browser_sessions/${browserSessionId}`, - ); - setHasBrowserSession(true); - setBrowserSession(response.data); - return response.data; - } catch (error) { - setHasBrowserSession(false); - setBrowserSession(null); - return null; - } + const response = await client.get( + `/browser_sessions/${browserSessionId}`, + ); + return response.data; }, + refetchInterval: (query) => + query.state.data?.status === "running" ? 5000 : false, }); + const browserSession = query.data; + const closeBrowserSessionMutation = useCloseBrowserSessionMutation({ browserSessionId, onSuccess: () => { @@ -76,7 +68,7 @@ function BrowserSession() { ); } - if (!hasBrowserSession) { + if (query.isError || !browserSession) { return (
@@ -96,7 +88,20 @@ function BrowserSession() {
Browser Session
{browserSession && (
-
+
+ + {browserSession.status} +
{browserSession.browser_session_id}
@@ -141,7 +146,7 @@ function BrowserSession() { ]} /> - {browserSessionId && ( + {browserSessionId && browserSession?.status === "running" && (
- Video recordings will appear here when the browser session is active - and recording + {isSessionRunning + ? "Recordings will be available after the session completes" + : "No recordings were created for this session"}
@@ -93,19 +107,19 @@ function BrowserSessionVideo() {
- {recording.url ? ( + {getRecordingUrl(recording.url) ? (
{ + let errorMessage = + "Browser session could not be started. Please try again."; + if (error && typeof error === "object") { + const axiosError = error as { + response?: { data?: { detail?: string } }; + message?: string; + }; + if (axiosError.response?.data?.detail) { + errorMessage = axiosError.response.data.detail; + } else if (axiosError.message) { + errorMessage = axiosError.message; + } + } + toast({ + variant: "destructive", + title: "Failed to create browser session", + description: errorMessage, + }); + }, }); } diff --git a/skyvern-frontend/src/routes/workflows/types/browserSessionTypes.ts b/skyvern-frontend/src/routes/workflows/types/browserSessionTypes.ts index 67f78ef4..579212ec 100644 --- a/skyvern-frontend/src/routes/workflows/types/browserSessionTypes.ts +++ b/skyvern-frontend/src/routes/workflows/types/browserSessionTypes.ts @@ -6,6 +6,7 @@ interface BrowserSession { runnable_id: string | null; runnable_type: string | null; started_at: string | null; + status: string; timeout: number | null; vnc_streaming_supported: boolean; }