diff --git a/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowNodeLibraryPanel.tsx b/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowNodeLibraryPanel.tsx index 0aa02f18..b3fe47e6 100644 --- a/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowNodeLibraryPanel.tsx +++ b/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowNodeLibraryPanel.tsx @@ -1,6 +1,6 @@ import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area"; import { useWorkflowPanelStore } from "@/store/WorkflowPanelStore"; -import { useState } from "react"; +import { useState, useRef, useEffect } from "react"; import { Cross2Icon, PlusIcon, @@ -232,10 +232,45 @@ function WorkflowNodeLibraryPanel({ onNodeClick, first }: Props) { const workflowPanelData = useWorkflowPanelStore( (state) => state.workflowPanelState.data, ); + const workflowPanelActive = useWorkflowPanelStore( + (state) => state.workflowPanelState.active, + ); const closeWorkflowPanel = useWorkflowPanelStore( (state) => state.closeWorkflowPanel, ); const [search, setSearch] = useState(""); + const inputRef = useRef(null); + + useEffect(() => { + // Focus the input when the panel becomes active + if (workflowPanelActive && inputRef.current) { + // Use multiple approaches to ensure focus works + const focusInput = () => { + if (inputRef.current) { + inputRef.current.focus(); + inputRef.current.select(); // Also select any existing text + } + }; + + // Try immediate focus + focusInput(); + + // Also try with a small delay for animations/transitions + const timeoutId = setTimeout(() => { + focusInput(); + }, 100); + + // And try with a longer delay as backup + const backupTimeoutId = setTimeout(() => { + focusInput(); + }, 300); + + return () => { + clearTimeout(timeoutId); + clearTimeout(backupTimeoutId); + }; + } + }, [workflowPanelActive]); const filteredItems = nodeLibraryItems.filter((item) => { if (workflowPanelData?.disableLoop && item.nodeType === "loop") { @@ -288,6 +323,9 @@ function WorkflowNodeLibraryPanel({ onNodeClick, first }: Props) { }} placeholder="Search blocks..." className="pl-9" + ref={inputRef} + autoFocus + tabIndex={0} /> diff --git a/skyvern-frontend/src/store/useOptimisticallyRequestBrowserSessionId.ts b/skyvern-frontend/src/store/useOptimisticallyRequestBrowserSessionId.ts deleted file mode 100644 index cf9bed0f..00000000 --- a/skyvern-frontend/src/store/useOptimisticallyRequestBrowserSessionId.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { create } from "zustand"; -import { AxiosInstance } from "axios"; - -export interface BrowserSessionData { - browser_session_id: string | null; - expires_at: number | null; // seconds since epoch -} - -interface OptimisticBrowserSessionIdState extends BrowserSessionData { - run: (client: AxiosInstance) => Promise; -} - -const SESSION_KEY = "skyvern.optimisticBrowserSession"; -const SESSION_TIMEOUT_MINUTES = 60; - -export const useOptimisticallyRequestBrowserSessionId = - create((set) => ({ - browser_session_id: null, - expires_at: null, - run: async (client) => { - const stored = localStorage.getItem(SESSION_KEY); - if (stored) { - try { - const parsed = JSON.parse(stored); - const { browser_session_id, expires_at } = parsed; - const now = Math.floor(Date.now() / 1000); // seconds since epoch - - if ( - browser_session_id && - typeof browser_session_id === "string" && - expires_at && - typeof expires_at === "number" && - now < expires_at - ) { - set({ browser_session_id, expires_at }); - return { browser_session_id, expires_at }; - } - } catch (e) { - // pass - } - } - - const resp = await client.post("/browser_sessions", { - timeout: SESSION_TIMEOUT_MINUTES * 60, // accepts seconds, so have to mult - }); - const { browser_session_id: newBrowserSessionId, timeout } = resp.data; - const newExpiresAt = Math.floor(Date.now() / 1000) + timeout * 0.9; - set({ - browser_session_id: newBrowserSessionId, - expires_at: newExpiresAt, - }); - localStorage.setItem( - SESSION_KEY, - JSON.stringify({ - browser_session_id: newBrowserSessionId, - expires_at: newExpiresAt, - }), - ); - - return { - browser_session_id: newBrowserSessionId, - expires_at: newExpiresAt, - }; - }, - }));