From f766a18d7b09ff64a03a2908fda0aeb510402b96 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 11 Nov 2025 18:15:46 +0100 Subject: [PATCH] refactor(file-explorer): centralize navigation state in session context and optimize initialization --- packages/app/src/app/file-explorer.tsx | 119 ++++++++++-------- packages/app/src/contexts/session-context.tsx | 3 + 2 files changed, 69 insertions(+), 53 deletions(-) diff --git a/packages/app/src/app/file-explorer.tsx b/packages/app/src/app/file-explorer.tsx index 0a79aa5d7..11d5a444a 100644 --- a/packages/app/src/app/file-explorer.tsx +++ b/packages/app/src/app/file-explorer.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { ActivityIndicator, Image, @@ -20,11 +20,11 @@ export default function FileExplorerScreen() { requestDirectoryListing, requestFilePreview, } = useSession(); - const [currentPath, setCurrentPath] = useState("."); const [selectedEntryPath, setSelectedEntryPath] = useState(null); const agent = agentId ? agents.get(agentId) : undefined; const explorerState = agentId ? fileExplorer.get(agentId) : undefined; + const currentPath = explorerState?.currentPath ?? "."; const directory = explorerState?.directories.get(currentPath); const entries = directory?.entries ?? []; const isLoading = explorerState?.isLoading ?? false; @@ -32,15 +32,32 @@ export default function FileExplorerScreen() { const preview = selectedEntryPath ? explorerState?.files.get(selectedEntryPath) : null; + const shouldShowPreview = Boolean(selectedEntryPath); + + const initializedAgentRef = useRef(null); useEffect(() => { if (!agentId) { + initializedAgentRef.current = null; return; } - setCurrentPath("."); + + if (initializedAgentRef.current === agentId) { + return; + } + + initializedAgentRef.current = agentId; setSelectedEntryPath(null); - requestDirectoryListing(agentId, "."); - }, [agentId, requestDirectoryListing]); + + const hasDirectory = explorerState?.directories.has(currentPath) ?? false; + if (!hasDirectory) { + requestDirectoryListing(agentId, currentPath); + } + }, [agentId, currentPath, explorerState, requestDirectoryListing]); + + useEffect(() => { + setSelectedEntryPath(null); + }, [currentPath]); const parentPath = useMemo(() => { if (currentPath === ".") { @@ -59,7 +76,6 @@ export default function FileExplorerScreen() { } if (entry.kind === "directory") { - setCurrentPath(entry.path); setSelectedEntryPath(null); requestDirectoryListing(agentId, entry.path); return; @@ -75,7 +91,6 @@ export default function FileExplorerScreen() { if (!agentId || !parentPath) { return; } - setCurrentPath(parentPath); setSelectedEntryPath(null); requestDirectoryListing(agentId, parentPath); }, [agentId, parentPath, requestDirectoryListing]); @@ -109,6 +124,50 @@ export default function FileExplorerScreen() { + {shouldShowPreview && ( + + {isLoading && !preview ? ( + + + Loading file... + + ) : !preview ? ( + + No preview available yet + + ) : preview.kind === "text" ? ( + + + {preview.content} + + + ) : preview.kind === "image" && preview.content ? ( + + + + ) : ( + + Binary preview unavailable + + {formatFileSize({ size: preview.size })} + + + )} + + )} + {error ? ( @@ -153,52 +212,6 @@ export default function FileExplorerScreen() { )} - - - {selectedEntryPath && isLoading && !preview ? ( - - - Loading file... - - ) : !selectedEntryPath ? ( - - Select a file to preview - - ) : !preview ? ( - - No preview available yet - - ) : preview.kind === "text" ? ( - - - {preview.content} - - - ) : preview.kind === "image" && preview.content ? ( - - - - ) : ( - - Binary preview unavailable - - {formatFileSize({ size: preview.size })} - - - )} - ); diff --git a/packages/app/src/contexts/session-context.tsx b/packages/app/src/contexts/session-context.tsx index b842fddcc..2b870840c 100644 --- a/packages/app/src/contexts/session-context.tsx +++ b/packages/app/src/contexts/session-context.tsx @@ -119,6 +119,7 @@ export interface AgentFileExplorerState { isLoading: boolean; lastError: string | null; pendingRequest: ExplorerRequestState | null; + currentPath: string; } const createExplorerState = (): AgentFileExplorerState => ({ @@ -127,6 +128,7 @@ const createExplorerState = (): AgentFileExplorerState => ({ isLoading: false, lastError: null, pendingRequest: null, + currentPath: ".", }); @@ -923,6 +925,7 @@ export function SessionProvider({ children, serverUrl }: SessionProviderProps) { isLoading: true, lastError: null, pendingRequest: { path: normalizedPath, mode: "list" }, + currentPath: normalizedPath, })); const msg: WSInboundMessage = {