5.1 KiB
FileBrowserPanel Refactoring Plan
1. The Problem
FileBrowserPanel.tsx has grown to over 1300 lines. It currently handles:
- VFS state fetching (path, mount, nodes, search queries, filter resolution).
- Keyboard shortcuts and navigation logic (global arrow keys, F3 search overlay, focus trapping).
- Selection state (
selected,focusIdx, multi-select logic). - UI display parameters (viewMode, zoom state, dual/single layout sizes).
- A heavy rendering component tree (FileGridView, FileListView, FileTree, many modals, lightboxes, AILayout wizards).
2. Refactoring Goals
We need to decouple the data logic from the UI logic, separate the heavy sub-views, and share common capabilities across different view renderers (list, grid, tree).
Crucially, the file browser UI must become a generic "Shell". The VFS implementation should just be one Adapter. By extracting the generic FileBrowserUI, we can plug in other data adapters in the future (like usePageAdapter for UserPage.tsx), rendering arbitrary models (Pages, Posts, Contacts) with the exact same robust Tree/List/Grid explorer UI.
2.1 Extract Custom Hooks
We should split the huge block of useState/useEffect hooks into contextual hooks:
-
useVfsAdapter(mount, path, glob, accessToken)Acts as the data provider. Translates VFS endpoints into standardizedINodeUI models. Handles fetching directories, caches, extractingreadmedata, resolving breadcrumbs. (Future adapters likeusePageAdapterwould conform to this exact same hook interface but fetch from/api/pages)- Returns:
nodes,sorted,loading,error,readmeContent,updatePath,updateMount,refresh().
- Returns:
-
useSelection(sortedNodes, onSelect)Handles array of selected items, focus index, and logic to select single/multiple (ctrlKey/shiftKey) elements. We can share this directly with list, tree, and thumb renderers.- Returns:
selected,focusIdx,setFocusIdx,setSelected,handleItemClick,clearSelection.
- Returns:
-
useKeyboardNavigation(params)Abstracts away global keybinds (e.g. F3 for search), container arrow navigation, copy/paste, backspace (up folder), and enter (open).- Takes dependency on
focusIdxandselectedfromuseSelection().
- Takes dependency on
-
useFilePreview(accessToken)Manages the state for open lightboxes (Image/Video, Docs, Iframe, Text) rather than having all state at the root ofFileBrowserPanel.- Returns:
lightboxNode,setLightboxNode,previewComponent(pre-rendered JSX based on what's active).
- Returns:
2.2 Break Out UI Sub-components
Currently, the rendered output mixes complex file-fetching logic with the actual modal HTML.
FilePreviewContainerMove allLightboxinstantiations (e.g.,ImageLightbox,SpreadsheetLightbox,ThreeDViewer,PdfLightbox) into a single child component. PassselectedFileor active view node to it.LayoutToolbarWrapperSimplify howFileBrowserToolbaris rendered, connecting it purely to an abstracted state object rather than 30 independent props pass-throughs.SearchDialog&FilterDialogManagement Currently inline or tightly coupled; should be separated into aDialogRendererwrapper or use a generic dialog context.
2.3 Universal Interface for Viewers
The Tree, List, and Grid renderers all replicate basic file display logic. By passing a shared Context or generic store (e.g., a ViewerControlContext), each one can trigger:
openFile(INode)goUp()selectFile(INode, multi)This standardizes the event-actions instead of passing 10+ props.
3. Recommended Actions & Phasing
Phase 1: State ExtractionExtractuseSelectionanduseFilePreviewhooks fromFileBrowserPanel.tsxwithout moving component rendering. Validate that deep link auto-open and search selections still function correctly.Phase 2: VFS ExtractionExtractuseVFSBrowserso directory fetching and sorting logic becomes completely separated from React rendering constraints.- Phase 3: Component Cleanup
Move all
Lightbox...conditionally rendered objects at the bottom of the file into a<PreviewOverlayManager />component layer. - Phase 4: Shared Navigation Interface
Connect
FileTree,FileListView,FileGridViewto the shareduseSelection/useKeyboardNavigationevents so behavior is strictly unified without duplicate<div onKeyDown...code.
4. Edge Cases to Preserve
- Deep Linking (
?file=) /initialFileprop: Needs to wait for async directory fetch completion before snapping focus and dispatchingonSelect. - Escape Key Handling:
Treeview requires focus onlistRef, grids/views require focus oncontainerRef. F3 global event logic uses[data-active-panel]. Any refactor must strictly preserve this arbitration logic. - Jail Prop Security: When a container is "jailed" to a parent directory,
updatePathmust refuse to navigate up past the rootjailPath. - VFS Sorting: Always display folders before files, then sort according to Name/Size/Date
(SortBy).