fix(workspace): improve file tree refresh behavior and state management

Fix file tree not properly resetting when refreshing workspace directory. Add useEffect hook to reset children state when entry path changes, preventing stale data display. Update handleRefresh to properly clear cache before reload and handle cases where selected files are deleted during refresh. Remove children.length check from loadChildren to allow directory re-expansion after refresh.
This commit is contained in:
Jamie Taylor
2026-01-31 17:50:21 +00:00
parent 3ba5b7ee6c
commit 87a6e71aa9
2 changed files with 75 additions and 10 deletions
+9 -3
View File
@@ -1,4 +1,4 @@
import { useState, useCallback } from 'react'
import { useState, useCallback, useEffect } from 'react'
import { ChevronRight, ChevronDown, Folder, FolderOpen, FileText } from 'lucide-react'
import { motion, AnimatePresence } from 'framer-motion'
import type { DirectoryEntry } from '~/lib/workspace-fs'
@@ -33,12 +33,18 @@ function FileTreeItem({ entry, selectedPath, onSelect, onLoadDirectory, level }:
const [expanded, setExpanded] = useState(false)
const [children, setChildren] = useState<DirectoryEntry[]>([])
const [loading, setLoading] = useState(false)
// Reset children when entry path changes (e.g., on refresh)
useEffect(() => {
setChildren([])
setExpanded(false)
}, [entry.path])
const isSelected = selectedPath === entry.path
const isDirectory = entry.type === 'directory'
const paddingLeft = level * 16 + 8
const loadChildren = useCallback(async () => {
if (!isDirectory || children.length > 0 || !onLoadDirectory) return
if (!isDirectory || !onLoadDirectory) return
setLoading(true)
try {
const entries = await onLoadDirectory(entry.path)
@@ -48,7 +54,7 @@ function FileTreeItem({ entry, selectedPath, onSelect, onLoadDirectory, level }:
} finally {
setLoading(false)
}
}, [entry.path, isDirectory, children.length, onLoadDirectory])
}, [entry.path, isDirectory, onLoadDirectory])
const handleToggle = useCallback(
async (e: React.MouseEvent) => {
+66 -7
View File
@@ -235,15 +235,74 @@ function WorkspacePage() {
const handleRefresh = useCallback(async () => {
if (!workspacePath || !pathValid) return
// Clear cache and reload
setPathCache(new Map())
await loadDirectory(workspacePath)
// Store current selection before clearing cache
const currentSelectedPath = selectedPath
// Reload selected file if any
if (selectedPath) {
await loadFile(selectedPath)
// Clear cache first, then reload
// Use a callback to ensure cache is cleared before loading
setPathCache(new Map())
// Small delay to ensure React has processed the state update
// before we try to load the directory
await new Promise(resolve => setTimeout(resolve, 0))
// Reload root directory - this will repopulate the file tree
// Force reload by bypassing cache check
setLoading(true)
try {
const result = await trpc.workspace.listDirectory.query({
workspaceRoot: workspacePath,
path: workspacePath,
})
if (result.error) {
throw new Error(result.error)
}
// Update cache with fresh data
setPathCache(new Map([[workspacePath, result.entries]]))
} catch (error) {
console.error('Failed to load directory:', error)
} finally {
setLoading(false)
}
}, [workspacePath, pathValid, selectedPath])
// Reload selected file if any (with error handling for deleted files)
if (currentSelectedPath) {
try {
const result = await trpc.workspace.readFile.query({
workspaceRoot: workspacePath,
path: currentSelectedPath,
})
if (result.error) {
// File no longer exists - clear selection gracefully
setSelectedPath(null)
setSelectedFileContent('')
setSelectedFileName('')
setSelectedFileSize(undefined)
setSelectedFileModified(undefined)
setFileError(result.error)
} else {
setSelectedFileContent(result.content)
setSelectedFileName(result.name)
// Get file metadata from the parent directory entry if available
const parentDir = pathCache.get(getParentDirPath(currentSelectedPath) || workspacePath)
const fileEntry = parentDir?.find(e => e.path === currentSelectedPath)
setSelectedFileSize(fileEntry?.size)
setSelectedFileModified(fileEntry?.modifiedAt)
}
} catch (error) {
// File no longer exists - clear selection gracefully
setSelectedPath(null)
setSelectedFileContent('')
setSelectedFileName('')
setSelectedFileSize(undefined)
setSelectedFileModified(undefined)
setFileError(error instanceof Error ? error.message : 'Failed to read file')
}
}
}, [workspacePath, pathValid, selectedPath, loadFile])
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {