diff --git a/skyvern-frontend/src/components/BrowserStream.tsx b/skyvern-frontend/src/components/BrowserStream.tsx
index c69ac7e1..624923fe 100644
--- a/skyvern-frontend/src/components/BrowserStream.tsx
+++ b/skyvern-frontend/src/components/BrowserStream.tsx
@@ -343,9 +343,12 @@ function BrowserStream({
return (
{isVncConnected && (
@@ -384,7 +387,7 @@ function BrowserStream({
)}
{!isVncConnected && (
-
+
Hm, working on the connection...
Hang tight, we're almost there...
diff --git a/skyvern-frontend/src/components/Splitter.tsx b/skyvern-frontend/src/components/Splitter.tsx
index 74fc7f2e..b0b52670 100644
--- a/skyvern-frontend/src/components/Splitter.tsx
+++ b/skyvern-frontend/src/components/Splitter.tsx
@@ -1,7 +1,7 @@
import { useRef, useState, RefObject } from "react";
-import { useMountEffect } from "@/hooks/useMountEffect";
import { cn } from "@/util/utils";
import { useOnChange } from "@/hooks/useOnChange";
+import { useMountEffect } from "@/hooks/useMountEffect";
function Handle({
direction,
@@ -341,21 +341,30 @@ function Splitter({
const [isDragging, setIsDragging] = useState(false);
useMountEffect(() => {
- if (containerRef.current) {
- const newPosition = normalizeUnitsToPercent(
- containerRef,
- direction,
- firstSizingTarget,
- firstSizing,
- storageKey,
- );
+ // small delay here, to allow for arbitrary layout thrashing to settle;
+ // otherwise we have to rely on an observer for the container size, and
+ // resetting whenever the container resizes it likely incorrect behaviour
+ setTimeout(() => {
+ if (containerRef.current) {
+ const newPosition = normalizeUnitsToPercent(
+ containerRef,
+ direction,
+ firstSizingTarget,
+ firstSizing,
+ storageKey,
+ );
- setSplitPosition(newPosition);
+ setSplitPosition(newPosition);
- if (storageKey) {
- setStoredSizing(firstSizingTarget, storageKey, newPosition.toString());
+ if (storageKey) {
+ setStoredSizing(
+ firstSizingTarget,
+ storageKey,
+ newPosition.toString(),
+ );
+ }
}
- }
+ }, 100);
});
useOnChange(isDragging, (newValue, oldValue) => {
diff --git a/skyvern-frontend/src/router.tsx b/skyvern-frontend/src/router.tsx
index 72edd503..9cf9c2a4 100644
--- a/skyvern-frontend/src/router.tsx
+++ b/skyvern-frontend/src/router.tsx
@@ -13,6 +13,7 @@ import { TaskDetails } from "./routes/tasks/detail/TaskDetails";
import { TaskParameters } from "./routes/tasks/detail/TaskParameters";
import { TaskRecording } from "./routes/tasks/detail/TaskRecording";
import { TasksPage } from "./routes/tasks/list/TasksPage";
+import { Debugger } from "@/routes/workflows/debugger/Debugger";
import { WorkflowPage } from "./routes/workflows/WorkflowPage";
import { WorkflowRun } from "./routes/workflows/WorkflowRun";
import { WorkflowRunParameters } from "./routes/workflows/WorkflowRunParameters";
@@ -110,11 +111,11 @@ const router = createBrowserRouter([
},
{
path: "debug",
- element: ,
+ element: ,
},
{
path: ":workflowRunId/:blockLabel/debug",
- element: ,
+ element: ,
},
{
path: "edit",
diff --git a/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx b/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx
index 27b7f2ae..18e1ffd4 100644
--- a/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx
+++ b/skyvern-frontend/src/routes/workflows/editor/Workspace.tsx
@@ -1,5 +1,5 @@
import { AxiosError } from "axios";
-import { useEffect, useRef, useState, useMemo } from "react";
+import { useEffect, useRef, useState } from "react";
import { nanoid } from "nanoid";
import {
ChevronRightIcon,
@@ -17,6 +17,7 @@ import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { useMountEffect } from "@/hooks/useMountEffect";
import { useDebugSessionQuery } from "../hooks/useDebugSessionQuery";
import { useBlockScriptsQuery } from "@/routes/workflows/hooks/useBlockScriptsQuery";
+import { WorkflowRunStream } from "@/routes/workflows/workflowRun/WorkflowRunStream";
import { useCacheKeyValuesQuery } from "../hooks/useCacheKeyValuesQuery";
import { useBlockScriptStore } from "@/store/BlockScriptStore";
import { useSidebarStore } from "@/store/SidebarStore";
@@ -137,12 +138,6 @@ function Workspace({
const blockScriptStore = useBlockScriptStore();
const cacheKey = workflow?.cache_key ?? "";
- const enableDebugBrowser = useMemo(() => {
- return (
- showBrowser && (activeDebugSession?.vnc_streaming_supported ?? false)
- );
- }, [showBrowser, activeDebugSession?.vnc_streaming_supported]);
-
const [cacheKeyValue, setCacheKeyValue] = useState(
cacheKey === ""
? ""
@@ -215,10 +210,10 @@ function Workspace({
const hasLoopBlock = nodes.some((node) => node.type === "loop");
const hasHttpBlock = nodes.some((node) => node.type === "http_request");
const workflowWidth = hasHttpBlock
- ? "35.1rem"
+ ? "39rem"
: hasLoopBlock
- ? "31.25rem"
- : "30rem";
+ ? "34.25rem"
+ : "34rem";
/**
* Open a new tab (not window) with the browser session URL.
@@ -705,7 +700,7 @@ function Workspace({
{/* infinite canvas and sub panels when not in debug mode */}
- {!enableDebugBrowser && (
+ {!showBrowser && (
{/* infinite canvas */}
)}
{workflowPanelState.content === "parameters" && (
-
+
)}
{workflowPanelState.content === "nodeLibrary" && (
-
+
{
addNode(props);
@@ -768,8 +763,51 @@ function Workspace({
)}
- {/* infinite canvas, sub panels, browser, and timeline when in debug mode */}
- {enableDebugBrowser && (
+ {/* sub panels when in debug mode */}
+ {showBrowser && workflowPanelState.active && (
+
+ {workflowPanelState.content === "cacheKeyValues" && (
+ {
+ setToDeleteCacheKeyValue(cacheKeyValue);
+ setOpenConfirmCacheKeyValueDeleteDialogue(true);
+ }}
+ onPaginate={(page) => {
+ setPage(page);
+ }}
+ onSelect={(cacheKeyValue) => {
+ setCacheKeyValue(cacheKeyValue);
+ setCacheKeyValueFilter("");
+ closeWorkflowPanel();
+ }}
+ />
+ )}
+ {workflowPanelState.content === "parameters" && (
+
+ )}
+ {workflowPanelState.content === "nodeLibrary" && (
+ {
+ addNode(props);
+ }}
+ />
+ )}
+
+ )}
+
+ {/* infinite canvas, browser, and timeline when in debug mode */}
+ {showBrowser && (
- {/* browser & timeline & sub-panels in debug mode */}
+ {/* browser & timeline */}
- {/* sub panels */}
- {workflowPanelState.active && (
-
- {workflowPanelState.content === "cacheKeyValues" && (
- {
- setToDeleteCacheKeyValue(cacheKeyValue);
- setOpenConfirmCacheKeyValueDeleteDialogue(true);
- }}
- onPaginate={(page) => {
- setPage(page);
- }}
- onSelect={(cacheKeyValue) => {
- setCacheKeyValue(cacheKeyValue);
- setCacheKeyValueFilter("");
- closeWorkflowPanel();
- }}
- />
- )}
- {workflowPanelState.content === "parameters" && (
-
- )}
- {workflowPanelState.content === "nodeLibrary" && (
- {
- addNode(props);
- }}
- />
- )}
-
- )}
-
- {/* browser & timeline */}
- {/* browser */}
-
-
- {activeDebugSession &&
- activeDebugSession.browser_session_id &&
- !cycleBrowser.isPending ? (
-
- ) : (
-
- Connecting to your browser...
-
+ {/* VNC browser */}
+ {!activeDebugSession ||
+ (activeDebugSession.vnc_streaming_supported && (
+
+
+ {activeDebugSession &&
+ activeDebugSession.browser_session_id &&
+ !cycleBrowser.isPending ? (
+
+ ) : (
+
+ Connecting to your browser...
+
+
+ )}
- )}
-
-
-
-
Live Browser
+
+
+ Live Browser
+
+ {showBreakoutButton && (
+ breakout()} />
+ )}
+
+ {showPowerButton && (
+
cycle()} />
+ )}
+ reload()}
+ />
+
+
- {showBreakoutButton && (
- breakout()} />
- )}
-
- {showPowerButton && (
-
cycle()} />
- )}
- reload()}
- />
+ ))}
+
+ {/* Screenshot browser} */}
+ {activeDebugSession &&
+ !activeDebugSession.vnc_streaming_supported && (
+
-
-
+ )}
{/* timeline */}
("");
- const showStream = workflowRun && statusIsNotFinalized(workflowRun);
+ const showStream =
+ alwaysShowStream || (workflowRun && statusIsNotFinalized(workflowRun));
const credentialGetter = useCredentialGetter();
const { workflowRunId, workflowPermanentId } = useParams();
const queryClient = useQueryClient();
@@ -149,6 +155,26 @@ function WorkflowRunStream() {
);
}
+
+ if (alwaysShowStream) {
+ if (streamImgSrc?.length > 0) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ Waiting for stream...
+
+ );
+ }
+
return null;
}