FileBrowserRouters
Return type for init_router — contains both the browser and virtual collection routers.
source
FileBrowserRouters
def FileBrowserRouters(
browser:APIRouter, collection:APIRouter, urls:VirtualCollectionUrls, render:Callable,
render_selection_oobs:Callable= _no_selection_oobs, update_selection_oobs:Callable= _no_update_selection_oobs,
current_path:Callable= _no_current_path, sync_items:Callable= _no_sync_items
)-> None :
Return value from init_router — both routers, URL bundle, render, and OOB helpers.
Router Initialization
The init_router function creates both the browser-specific router and the virtual collection router, managing internal VC state and the items list as closure state.
source
init_router
def init_router(
config:FileBrowserConfig, # Browser configuration
provider:FileSystemProvider, # File system provider
state_getter:Callable, # Function to get current state
state_setter:Callable, # 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= None , # Optional callbacks
home_path:Optional= None , # Home directory (defaults to provider)
)-> FileBrowserRouters: # Browser + collection routers and URL bundle
Initialize file browser and virtual collection routers.
import tempfile
from pathlib import Path
from fasthtml.common import to_xml
from cjm_fasthtml_file_browser.providers.local import LocalFileSystemProvider
# Create test fixtures
with tempfile.TemporaryDirectory() as tmpdir:
(Path(tmpdir) / "file1.txt" ).write_text("content1" )
(Path(tmpdir) / "file2.py" ).write_text("print('hi')" )
(Path(tmpdir) / "subdir" ).mkdir()
config = FileBrowserConfig()
provider = LocalFileSystemProvider()
_state = BrowserState(current_path= tmpdir)
def get_state(): return _state
def set_state(s):
global _state
_state = s
result = init_router(
config= config,
provider= provider,
state_getter= get_state,
state_setter= set_state,
route_prefix= "/browser" ,
)
# Verify return type
assert isinstance (result, FileBrowserRouters)
assert result.browser.prefix == "/browser"
assert result.collection is not None
assert result.urls.nav_up != ""
assert result.urls.nav_down != ""
assert result.urls.focus_row != ""
assert result.urls.activate != ""
assert result.urls.sort != ""
# Verify render callable produces HTML
assert callable (result.render)
html = to_xml(result.render())
assert "file-browser" in html
assert "file1.txt" in html or "subdir" in html
# Verify render_selection_oobs callable exists
assert callable (result.render_selection_oobs)
print ("Router initialization tests passed!" )
Router initialization tests passed!
# Test render_selection_oobs — targeted checkbox OOB updates
with tempfile.TemporaryDirectory() as tmpdir:
for i in range (5 ):
(Path(tmpdir) / f"file { i} .txt" ).write_text(f"content { i} " )
config = FileBrowserConfig(selection_mode= SelectionMode.MULTIPLE, vc_prefix= "test" )
provider = LocalFileSystemProvider()
_state = BrowserState(current_path= tmpdir)
def get_state(): return _state
def set_state(s):
global _state
_state = s
routers = init_router(
config= config, provider= provider,
state_getter= get_state, state_setter= set_state,
route_prefix= "/browser" ,
)
# Select file0 and file2 in browser state
_state.selection.selected_paths = [str (Path(tmpdir) / "file0.txt" ), str (Path(tmpdir) / "file2.txt" )]
# Get OOBs for paths in current directory
oobs = routers.render_selection_oobs([str (Path(tmpdir) / "file0.txt" ), str (Path(tmpdir) / "file2.txt" )])
assert len (oobs) > 0 , "Should return OOB elements for visible items"
for oob in oobs:
oob_html = to_xml(oob)
assert 'hx-swap-oob="outerHTML"' in oob_html
assert 'col-select' in oob_html
# Paths not in current directory return empty
oobs_empty = routers.render_selection_oobs(["/nonexistent/path.txt" ])
assert oobs_empty == (), f"Expected empty tuple, got { len (oobs_empty)} elements"
print ("render_selection_oobs tests passed!" )
# Test update_selection_oobs — sync + render in one call
with tempfile.TemporaryDirectory() as tmpdir:
for i in range (5 ):
(Path(tmpdir) / f"file { i} .txt" ).write_text(f"content { i} " )
config = FileBrowserConfig(selection_mode= SelectionMode.MULTIPLE, vc_prefix= "upd" )
provider = LocalFileSystemProvider()
_state = BrowserState(current_path= tmpdir)
def get_state(): return _state
def set_state(s):
global _state
_state = s
routers = init_router(
config= config, provider= provider,
state_getter= get_state, state_setter= set_state,
route_prefix= "/browser" ,
)
assert callable (routers.update_selection_oobs)
# Initially no selection
assert _state.selection.selected_paths == []
# update_selection_oobs syncs selection AND returns OOBs
file0 = str (Path(tmpdir) / "file0.txt" )
file2 = str (Path(tmpdir) / "file2.txt" )
oobs = routers.update_selection_oobs([file0, file2], [file0, file2])
# Browser state should now have the selection synced
assert file0 in _state.selection.selected_paths
assert file2 in _state.selection.selected_paths
# OOBs should be returned for visible items
assert len (oobs) > 0
for oob in oobs:
oob_html = to_xml(oob)
assert 'hx-swap-oob="outerHTML"' in oob_html
assert 'col-select' in oob_html
# Deselect file0 — pass new full selection, changed path is file0
oobs2 = routers.update_selection_oobs([file2], [file0])
assert file0 not in _state.selection.selected_paths
assert file2 in _state.selection.selected_paths
print ("update_selection_oobs tests passed!" )
# Test current_path — returns browsed directory path
with tempfile.TemporaryDirectory() as tmpdir:
config = FileBrowserConfig()
provider = LocalFileSystemProvider()
_state = BrowserState(current_path= tmpdir)
def get_state(): return _state
def set_state(s):
global _state
_state = s
routers = init_router(
config= config, provider= provider,
state_getter= get_state, state_setter= set_state,
route_prefix= "/browser" ,
)
assert callable (routers.current_path)
assert routers.current_path() == tmpdir
# Simulate navigation by updating state
_state.current_path = "/some/other/path"
assert routers.current_path() == "/some/other/path"
print ("current_path tests passed!" )