cjm-fasthtml-file-browser
Install
pip install cjm_fasthtml_file_browserProject Structure
nbs/
├── components/ (4)
│ ├── browser.ipynb # Main file browser component with virtualized collection rendering.
│ ├── item.ipynb # File type icons, cell render callback for virtual collection, and empty/error state components.
│ ├── path_bar.ipynb # Path display, breadcrumbs navigation, and optional path input for the file browser.
│ └── utils.ipynb # Sorting and filtering utilities for file listings.
├── core/ (4)
│ ├── config.ipynb # Configuration dataclasses and enums for the file browser.
│ ├── html_ids.ipynb # HTML ID constants for HTMX targeting in the file browser.
│ ├── models.ipynb # Core data models for the file browser including DirectoryListing, BrowserSelection, and BrowserState.
│ └── protocols.ipynb # Protocol definitions for extensible file system providers.
├── providers/ (1)
│ └── local.ipynb # Local file system provider for interactive directory navigation.
└── routes/ (1)
└── handlers.ipynb # Route handlers, router initialization, and virtual collection wiring for the file browser.
Total: 10 notebooks across 5 directories
Module Dependencies
graph LR
components_browser[components.browser<br/>Browser]
components_item[components.item<br/>Item]
components_path_bar[components.path_bar<br/>Path Bar]
components_utils[components.utils<br/>Utils]
core_config[core.config<br/>Config]
core_html_ids[core.html_ids<br/>HTML IDs]
core_models[core.models<br/>Models]
core_protocols[core.protocols<br/>Protocols]
providers_local[providers.local<br/>Local Provider]
routes_handlers[routes.handlers<br/>Handlers]
components_browser --> core_models
components_browser --> components_path_bar
components_browser --> components_item
components_browser --> core_html_ids
components_browser --> core_config
components_item --> core_config
components_item --> core_models
components_path_bar --> components_item
components_path_bar --> core_html_ids
components_path_bar --> core_config
components_utils --> core_config
core_protocols --> core_models
providers_local --> core_models
providers_local --> core_protocols
routes_handlers --> components_browser
routes_handlers --> core_config
routes_handlers --> providers_local
routes_handlers --> core_protocols
routes_handlers --> components_utils
routes_handlers --> components_item
routes_handlers --> core_models
21 cross-module dependencies detected
CLI Reference
No CLI commands found in this project.
Module Overview
Detailed documentation for each module in the project:
Browser (browser.ipynb)
Main file browser component with virtualized collection rendering.
Import
from cjm_fasthtml_file_browser.components.browser import (
render_file_browser
)Functions
def render_file_browser(
items: list, # Current filtered/sorted FileInfo list
config: FileBrowserConfig, # Browser configuration
state: BrowserState, # Browser state (path, selection)
listing: DirectoryListing, # Raw directory listing (for path bar)
vc_config: VirtualCollectionConfig, # Virtual collection config
vc_state: VirtualCollectionState, # Virtual collection state
vc_ids: VirtualCollectionHtmlIds, # Virtual collection HTML IDs
vc_btn_ids: VirtualCollectionButtonIds, # Virtual collection button IDs
urls: VirtualCollectionUrls, # Virtual collection URL bundle
render_cell: Callable, # Cell render callback
navigate_url: str, # URL for directory navigation
refresh_url: str, # URL for refresh
path_input_url: str = "", # URL for path input (optional)
home_path: str = "", # Home directory path
hx_target: Optional[str] = None, # Override HTMX target (default: container_id)
) -> Any: # Complete file browser component
"Render the complete file browser with virtualized collection."Variables
_FB_GO_PARENT_CALLBACK = 'fbGoParentDir'Config (config.ipynb)
Configuration dataclasses and enums for the file browser.
Import
from cjm_fasthtml_file_browser.core.config import (
SelectionMode,
FileColumn,
ViewConfig,
FilterConfig,
FileBrowserCallbacks,
FileBrowserConfig
)Classes
class SelectionMode(str, Enum):
"File selection modes."class FileColumn(str, Enum):
"Available columns for list view."@dataclass
class ViewConfig:
"View display configuration."
columns: List[FileColumn] = field(...)
default_sort: FileColumn = FileColumn.NAME # Default sort column
sort_folders_first: bool = True # Sort folders before files
allow_sort_toggle: bool = True # Allow user to change sort@dataclass
class FilterConfig:
"Filtering configuration."
allowed_extensions: Optional[List[str]] # Include only these extensions (None = all)
show_directories: bool = True # Show directories
show_hidden: bool = False # Show hidden files/directories
show_system_files: bool = False # Show system files
custom_filter: Optional[Callable[[FileInfo], bool]] # Custom filter function
def matches(
self,
file_info: FileInfo # File to check against filter
) -> bool: # True if file passes filter
"Check if a file matches the filter criteria."@dataclass
class FileBrowserCallbacks:
"Event callbacks for customization."
on_navigate: Optional[Callable[[str], None]] # Called when directory changes
on_select: Optional[Callable[[str], None]] # Called when file selected
on_selection_change: Optional[Callable[[List[str]], None]] # Called when selection changes
on_open: Optional[Callable[[str], None]] # Called on file double-click/enter
validate_selection: Optional[Callable[[str], Tuple[bool, str]]] # Validate before select
validate_navigation: Optional[Callable[[str], Tuple[bool, str]]] # Validate before navigate@dataclass
class FileBrowserConfig:
"Main configuration for file browser."
provider: Optional[Any] # FileSystemProvider, defaults to local
start_path: Optional[str] # Initial path (defaults to home)
selection_mode: SelectionMode = SelectionMode.SINGLE
selectable_types: Literal['files', 'directories', 'both'] = 'files'
max_selections: Optional[int] # For MULTIPLE mode
view: ViewConfig = field(...)
filter: FilterConfig = field(...)
show_path_bar: bool = True
show_path_input: bool = False # Direct path entry field
show_breadcrumbs: bool = True
bookmarks: Optional[List[Tuple[str, str]]] # [(label, path), ...]
show_bookmarks: bool = False
container_id: str = 'file-browser'
content_id: str = 'file-browser-content'
path_bar_id: str = 'file-browser-path'
listing_id: str = 'file-browser-listing'
vc_prefix: str = '' # Prefix for virtual collection IDs (auto-generated if empty)
def can_select(
self,
file_info: FileInfo # File to check
) -> bool: # True if file can be selected
"Check if a file/directory can be selected based on config."Handlers (handlers.ipynb)
Route handlers, router initialization, and virtual collection wiring for the file browser.
Import
from cjm_fasthtml_file_browser.routes.handlers import (
FileBrowserRouters,
init_router
)Functions
def _no_selection_oobs(changed_paths: List[str]) -> Tuple:
"""Default no-op for render_selection_oobs."""
return ()
def _no_update_selection_oobs(selected_paths: List[str], changed_paths: List[str]) -> Tuple
"Default no-op for render_selection_oobs."def _no_update_selection_oobs(selected_paths: List[str], changed_paths: List[str]) -> Tuple:
"""Default no-op for update_selection_oobs."""
return ()
def _no_current_path() -> str
"Default no-op for update_selection_oobs."def _no_current_path() -> str:
"""Default no-op for current_path."""
return ""
def _no_sync_items() -> None
"Default no-op for current_path."def _no_sync_items() -> None:
"""Default no-op for sync_items."""
pass
@dataclass
class FileBrowserRouters
"Default no-op for sync_items."def _handle_navigate(
provider: FileSystemProvider, # File system provider
state_getter: Callable[[], BrowserState], # Function to get current state
state_setter: Callable[[BrowserState], None], # Function to save state
callbacks: Optional[FileBrowserCallbacks], # Optional callbacks
path: str, # Path to navigate to
render_fn: Callable[[BrowserState], Any], # Function to render browser
) -> Any: # Rendered browser component
"Handle navigation to a new directory."def _handle_path_input(
provider: FileSystemProvider, # File system provider
state_getter: Callable[[], BrowserState], # Function to get current state
state_setter: Callable[[BrowserState], None], # Function to save state
callbacks: Optional[FileBrowserCallbacks], # Optional callbacks
path: str, # Path input by user
render_fn: Callable[[BrowserState], Any], # Function to render browser
navigate_fn: Callable[[str], Any], # Function to handle navigation
) -> Any: # Rendered browser component
"Handle direct path input."def _handle_select(
config: FileBrowserConfig, # Browser configuration
state_getter: Callable[[], BrowserState], # Function to get current state
state_setter: Callable[[BrowserState], None], # Function to save state
callbacks: Optional[FileBrowserCallbacks], # Optional callbacks
path: str, # Path to select/deselect
render_fn: Callable[[BrowserState], Any], # Function to render browser
) -> Any: # Rendered browser component
"Handle file selection."def _handle_refresh(
state_getter: Callable[[], BrowserState], # Function to get current state
render_fn: Callable[[BrowserState], Any], # Function to render browser
) -> Any: # Rendered browser component
"Handle refresh (re-render with current state)."def _handle_toggle_select(
item: FileInfo, # File item to toggle
row_index: int, # Row index in VC items list
config: FileBrowserConfig, # Browser configuration
state_getter: Callable[[], BrowserState], # Function to get current state
state_setter: Callable[[BrowserState], None], # Function to save state
callbacks: Optional[FileBrowserCallbacks], # Optional callbacks
sel_change_accepts_request: bool, # Whether on_selection_change accepts request param
columns: Tuple[ColumnDef, ...], # VC column definitions
vc_state: VirtualCollectionState, # VC state (for total_items, cursor)
vc_ids: VirtualCollectionHtmlIds, # VC HTML IDs
render_cell: Callable, # Cell renderer callback
request: Any = None, # Optional HTMX request
) -> Any: # Tuple of OOB elements (checkbox cell + callback extras)
"Toggle file selection and return targeted OOB checkbox update."def _build_selection_oobs(
changed_paths: List[str], # File/folder paths whose checkbox state changed
columns: Tuple[ColumnDef, ...], # VC column definitions
items: List[FileInfo], # Current directory items
vc_state: VirtualCollectionState, # VC state (for window bounds)
vc_ids: VirtualCollectionHtmlIds, # VC HTML IDs
render_cell: Callable, # Cell renderer callback
) -> Tuple[Any, ...]: # OOB cell elements for visible items only
"Return OOB checkbox cell updates for changed paths visible in the browser."def _sync_and_build_selection_oobs(
selected_paths: List[str], # New full selection state (replaces browser selection)
changed_paths: List[str], # Paths whose checkbox state changed
state_getter: Callable[[], BrowserState], # Function to get current state
state_setter: Callable[[BrowserState], None], # Function to save state
columns: Tuple[ColumnDef, ...], # VC column definitions
items: List[FileInfo], # Current directory items
vc_state: VirtualCollectionState, # VC state (for window bounds)
vc_ids: VirtualCollectionHtmlIds, # VC HTML IDs
render_cell: Callable, # Cell renderer callback
) -> Tuple[Any, ...]: # OOB cell elements for visible changed items
"Sync selection state into browser and return targeted checkbox OOBs."def _build_columns(
config: FileBrowserConfig, # Browser config
) -> Tuple[ColumnDef, ...]: # Column definitions for virtual collection
"Build ColumnDef tuple from browser config, conditionally including checkbox column."def _rebuild_items(
provider: FileSystemProvider, # File system provider
state: BrowserState, # Browser state with current_path
config: FileBrowserConfig, # Browser config (for filter/sort)
) -> List[FileInfo]: # Filtered and sorted item list
"List, filter, and sort directory contents."def init_router(
config: FileBrowserConfig, # Browser configuration
provider: FileSystemProvider, # File system provider
state_getter: Callable[[], BrowserState], # Function to get current state
state_setter: Callable[[BrowserState], None], # Function to save state
route_prefix: str = "/browser", # Route prefix for browser routes
vc_route_prefix: str = "", # Route prefix for VC routes (auto: {route_prefix}/vc)
callbacks: Optional[FileBrowserCallbacks] = None, # Optional callbacks
home_path: Optional[str] = None, # Home directory (defaults to provider)
) -> FileBrowserRouters: # Browser + collection routers and URL bundle
"Initialize file browser and virtual collection routers."Classes
@dataclass
class FileBrowserRouters:
"Return value from init_router — both routers, URL bundle, render, and OOB helpers."
browser: APIRouter # File-specific routes (navigate, select, refresh, path_input)
collection: APIRouter # Virtual collection routes (nav, focus, activate, sort, viewport)
urls: VirtualCollectionUrls # URL bundle for rendering
render: Callable # () -> Any, renders the full file browser component
render_selection_oobs: Callable = field(...) # (changed_paths) -> Tuple, targeted checkbox OOBs
update_selection_oobs: Callable = field(...) # (selected_paths, changed_paths) -> Tuple, sync + OOBs
current_path: Callable = field(...) # () -> str, current browsed directory path
sync_items: Callable = field(...) # () -> None, rebuild items from current browser stateHTML IDs (html_ids.ipynb)
HTML ID constants for HTMX targeting in the file browser.
Import
from cjm_fasthtml_file_browser.core.html_ids import (
FileBrowserHtmlIds
)Classes
class FileBrowserHtmlIds:
"Default HTML IDs for file browser components."
def item_id(
cls,
index: int # Item index in the listing
) -> str: # HTML ID for the item
"Generate item ID for a specific index."
def as_selector(
cls,
html_id: str # HTML ID
) -> str: # CSS selector for the ID
"Convert HTML ID to CSS selector."Item (item.ipynb)
File type icons, cell render callback for virtual collection, and empty/error state components.
Import
from cjm_fasthtml_file_browser.components.item import (
FILE_TYPE_ICONS,
BROWSER_ICONS,
create_file_cell_renderer,
render_empty_state,
render_error_state
)Functions
def _get_file_icon(
file_info: FileInfo, # File to get icon for
size: int = 4 # Icon size (Tailwind scale)
) -> Any: # Lucide icon component
"Get the appropriate icon for a file based on its type."def create_file_cell_renderer(
config: FileBrowserConfig, # Browser config (for selection state access)
get_selection: Callable, # () -> BrowserSelection, returns current selection
select_url: str = "", # URL for checkbox click selection route
) -> Callable: # render_cell(item: FileInfo, ctx: CellRenderContext) -> Any
"""
Create a render_cell callback for the virtual collection.
Returns a closure that renders cell content based on column key.
"""def render_empty_state(
message: str = "No files found", # Message to display
icon_name: str = "folder-open" # Lucide icon name
) -> Any: # Empty state component
"Render empty state for when a directory has no matching items."def render_error_state(
error_message: str # Error message to display
) -> Any: # Error state component
"Render error state for when directory access fails."Variables
FILE_TYPE_ICONS: Dict[FileType, str]
BROWSER_ICONS: Dict[str, str]Local Provider (local.ipynb)
Local file system provider for interactive directory navigation.
Import
from cjm_fasthtml_file_browser.providers.local import (
LocalFileSystemProvider
)Classes
class LocalFileSystemProvider:
def __init__(
self,
extension_mapping: Optional[ExtensionMapping] = None # For file type detection
)
"Local file system provider for interactive navigation."
def __init__(
self,
extension_mapping: Optional[ExtensionMapping] = None # For file type detection
)
"Initialize with optional extension mapping."
def name(self) -> str: # Provider identifier
"""Provider identifier."""
return "local"
@property
def root_path(self) -> str: # Root path (filesystem root)
"Provider identifier."
def root_path(self) -> str: # Root path (filesystem root)
"""Root path for this provider."""
return "/"
@property
def path_separator(self) -> str: # Path separator
"Root path for this provider."
def path_separator(self) -> str: # Path separator
"""Path separator character."""
return os.sep
def _get_file_info(
self,
path: Path # Path object
) -> Optional[FileInfo]: # FileInfo or None on error
"Path separator character."
def list_directory(
self,
path: str # Directory path to list
) -> DirectoryListing: # Directory contents
"List contents of a directory."
async def list_directory_async(
self,
path: str # Directory path to list
) -> DirectoryListing: # Directory contents
"Async list contents of a directory."
def get_file_info(
self,
path: str # Path to file/directory
) -> Optional[FileInfo]: # FileInfo or None if not found
"Get metadata for a single file/directory."
def get_parent_path(
self,
path: str # Current path
) -> Optional[str]: # Parent path, or None if at root
"Get parent directory path."
def join_path(
self,
base: str, # Base path
*parts: str # Path parts to join
) -> str: # Joined path
"Join path components."
def normalize_path(
self,
path: str # Path to normalize
) -> str: # Normalized/resolved path
"Normalize/resolve a path."
def is_valid_path(
self,
path: str # Path to validate
) -> Tuple[bool, Optional[str]]: # (valid, error_message)
"Validate path."
def path_exists(
self,
path: str # Path to check
) -> bool: # True if path exists
"Check if path exists."
def is_directory(
self,
path: str # Path to check
) -> bool: # True if path is a directory
"Check if path is a directory."
def get_home_path(self) -> str: # User's home directory
"Get the user's home directory."Models (models.ipynb)
Core data models for the file browser including DirectoryListing, BrowserSelection, and BrowserState.
Import
from cjm_fasthtml_file_browser.core.models import (
DirectoryListing,
BrowserSelection,
BrowserState
)Classes
@dataclass
class DirectoryListing:
"Result of listing a directory."
path: str # Current directory path
items: List[FileInfo] # Directory contents
parent_path: Optional[str] # Parent directory (None if at root)
provider_name: str = 'local' # Source provider
total_items: int = 0 # Total count (for pagination)
error: Optional[str] # Error message if listing failed
@dataclass
class BrowserSelection:
"Current selection state."
selected_paths: List[str] = field(...) # Selected file paths
last_selected: Optional[str] # Most recently selected (for shift-click)
def add(
self,
path: str # Path to add to selection
) -> None: # Modifies selection in place
"Add a path to the selection."
def remove(
self,
path: str # Path to remove from selection
) -> None: # Modifies selection in place
"Remove a path from the selection."
def clear(self) -> None: # Modifies selection in place
"""Clear all selections."""
self.selected_paths.clear()
self.last_selected = None
def toggle(
self,
path: str # Path to toggle
) -> None: # Modifies selection in place
"Clear all selections."
def toggle(
self,
path: str # Path to toggle
) -> None: # Modifies selection in place
"Toggle selection of a path."
def is_selected(
self,
path: str # Path to check
) -> bool: # True if path is selected
"Check if a path is selected."
def set_single(
self,
path: str # Path to set as single selection
) -> None: # Modifies selection in place
"Set a single path as the only selection (for single-select mode)."@dataclass
class BrowserState:
"Complete browser state for persistence/restore."
current_path: str # Current directory path
selection: BrowserSelection = field(...) # Selection state
sort_by: str = 'name' # Sort field
sort_descending: bool = False # Sort direction
filter_extensions: Optional[List[str]] # Active extension filter
def to_dict(self) -> Dict[str, Any]: # Serializable dictionary
"""Convert state to a serializable dictionary."""
return {
"current_path": self.current_path,
"Convert state to a serializable dictionary."
def from_dict(
cls,
data: Dict[str, Any] # Dictionary with state data
) -> "BrowserState": # Restored BrowserState instance
"Create a BrowserState from a dictionary."Path Bar (path_bar.ipynb)
Path display, breadcrumbs navigation, and optional path input for the file browser.
Import
from cjm_fasthtml_file_browser.components.path_bar import (
parse_path_segments,
render_breadcrumbs,
render_path_input,
render_nav_buttons,
render_path_bar
)Functions
def parse_path_segments(
path: str, # Full path to parse
separator: str = "/" # Path separator
) -> List[Tuple[str, str]]: # List of (name, full_path) tuples
"Parse a path into breadcrumb segments."def render_breadcrumbs(
current_path: str, # Current directory path
navigate_url: str, # URL for navigation
hx_target: Optional[str] = None, # HTMX target for swaps
max_segments: int = 5, # Max segments to show (0 = all)
breadcrumbs_id: Optional[str] = None, # HTML ID for breadcrumbs
) -> Any: # Breadcrumbs component
"Render path as breadcrumb navigation."def render_path_input(
current_path: str, # Current path to display
navigate_url: str, # URL for navigation
hx_target: Optional[str] = None, # HTMX target for swaps
input_id: Optional[str] = None, # HTML ID for input
) -> Any: # Path input component
"Render a text input for direct path entry."def render_nav_buttons(
parent_path: Optional[str], # Parent directory path (None if at root)
home_path: str, # Home directory path
navigate_url: str, # URL for navigation
refresh_url: Optional[str] = None, # URL for refresh (if different)
hx_target: Optional[str] = None, # HTMX target for swaps
) -> Any: # Navigation buttons component
"Render quick navigation buttons."def render_path_bar(
current_path: str, # Current directory path
parent_path: Optional[str], # Parent directory path
home_path: str, # Home directory path
config: FileBrowserConfig, # Browser configuration
navigate_url: str, # URL for navigation
refresh_url: Optional[str] = None, # URL for refresh
hx_target: Optional[str] = None, # HTMX target for swaps
path_bar_id: Optional[str] = None, # HTML ID for path bar
) -> Any: # Path bar component
"Render the complete path bar."Protocols (protocols.ipynb)
Protocol definitions for extensible file system providers.
Import
from cjm_fasthtml_file_browser.core.protocols import (
FileSystemProvider
)Classes
@runtime_checkable
class FileSystemProvider(Protocol):
"Protocol for file system access backends."
def name(self) -> str: # Provider identifier (e.g., 'local', 's3', 'gdrive')
"""Provider identifier."""
...
@property
def root_path(self) -> str: # Root path for this provider
"Provider identifier."
def root_path(self) -> str: # Root path for this provider
"""Root path for this provider."""
...
@property
def path_separator(self) -> str: # Path separator character
"Root path for this provider."
def path_separator(self) -> str: # Path separator character
"""Path separator character."""
...
def list_directory(
self,
path: str # Directory path to list
) -> DirectoryListing: # Directory contents and metadata
"Path separator character."
def list_directory(
self,
path: str # Directory path to list
) -> DirectoryListing: # Directory contents and metadata
"List contents of a directory."
async def list_directory_async(
self,
path: str # Directory path to list
) -> DirectoryListing: # Directory contents and metadata
"Async list contents of a directory."
def get_file_info(
self,
path: str # Path to file/directory
) -> Optional[FileInfo]: # FileInfo or None if not found
"Get metadata for a single file/directory."
def get_parent_path(
self,
path: str # Current path
) -> Optional[str]: # Parent path, or None if at root
"Get parent directory path."
def join_path(
self,
base: str, # Base path
*parts: str # Path parts to join
) -> str: # Joined path
"Join path components."
def normalize_path(
self,
path: str # Path to normalize
) -> str: # Normalized/resolved path
"Normalize/resolve a path."
def is_valid_path(
self,
path: str # Path to validate
) -> Tuple[bool, Optional[str]]: # (valid, error_message)
"Validate path, return (valid, error_message)."
def path_exists(
self,
path: str # Path to check
) -> bool: # True if path exists
"Check if path exists."
def is_directory(
self,
path: str # Path to check
) -> bool: # True if path is a directory
"Check if path is a directory."Utils (utils.ipynb)
Sorting and filtering utilities for file listings.
Import
from cjm_fasthtml_file_browser.components.utils import (
sort_files,
filter_files
)Functions
def sort_files(
files: List[FileInfo], # Files to sort
sort_by: str = "name", # Sort field
descending: bool = False, # Sort direction
folders_first: bool = True # Sort folders before files
) -> List[FileInfo]: # Sorted file list
"Sort files by the specified field."def filter_files(
files: List[FileInfo], # Files to filter
filter_config: FilterConfig # Filter configuration
) -> List[FileInfo]: # Filtered file list
"Filter files based on configuration."