source
render_queue_item
def render_queue_item(
config:SortableQueueConfig, # Queue configuration
ids:SortableQueueHtmlIds, # HTML ID generators
urls:SortableQueueUrls, # URL endpoints
item:dict , # Queue item data
index:int , # 0-based position in queue
render_content:Callable, # Callback for custom item content
extra_attrs:Optional= None , # Additional HTML attributes per item
)-> Any: # Li element
Render a single queue item with drag handle, position, custom content, and remove button.
source
render_sortable_queue
def render_sortable_queue(
config:SortableQueueConfig, # Queue configuration
ids:SortableQueueHtmlIds, # HTML ID generators
urls:SortableQueueUrls, # URL endpoints
queue_items:List, # Ordered list of queue item dicts
render_content:Callable, # Callback for custom item content
render_empty:Optional= None , # Custom empty state (default provided)
render_header_actions:Optional= None , # Custom header actions
render_footer:Optional= None , # Optional footer content
extra_item_attrs:Optional= None , # Additional data-* attributes per item
container_classes:tuple = (), # Additional classes on container div
)-> Any: # Queue panel element
Render the complete sortable queue panel.
Tests
from fasthtml.common import to_xml
# Test setup
config = SortableQueueConfig(prefix= "test" )
ids_obj = SortableQueueHtmlIds(prefix= "test" )
urls = SortableQueueUrls(reorder= "/q/reorder" , remove= "/q/remove" , clear= "/q/clear" )
test_items = [{"id" : "a" , "name" : "Alpha" }, {"id" : "b" , "name" : "Beta" }]
def test_render_content(item, index):
return Span(item["name" ], cls= "grow" )
# --- render_queue_item ---
li_xml = to_xml(render_queue_item(config, ids_obj, urls, test_items[0 ], 0 , test_render_content))
assert 'id="test-queue-item-a"' in li_xml
assert 'name="item"' in li_xml and 'value="a"' in li_xml # Hidden input
assert "drag-handle" in li_xml # Drag handle class
assert "1." in li_xml # 1-based position
assert "Alpha" in li_xml # Custom content
assert "/q/remove" in li_xml # Remove button target
assert 'queue-item' in li_xml # Item class
# --- render_sortable_queue with items ---
panel_xml = to_xml(render_sortable_queue(config, ids_obj, urls, test_items, test_render_content))
assert 'id="test-queue-container"' in panel_xml
assert 'id="test-queue-list"' in panel_xml
assert 'hx-trigger="end"' in panel_xml
assert 'hx-include="this"' in panel_xml # HTMX 2.x requirement
assert "Selected" in panel_xml # Title
assert "/q/reorder" in panel_xml # Reorder URL
assert "/q/clear" in panel_xml # Clear button
assert "Alpha" in panel_xml and "Beta" in panel_xml # Both items rendered
assert "sortable" in panel_xml # Sortable class on ul
# --- render_sortable_queue empty state ---
empty_xml = to_xml(render_sortable_queue(config, ids_obj, urls, [], test_render_content))
assert 'id="test-queue-container"' in empty_xml
assert 'id="test-queue-empty"' in empty_xml
assert "No items selected" in empty_xml
assert "test-queue-list" not in empty_xml # No list when empty
assert "/q/clear" not in empty_xml # No clear button when empty
# --- Custom empty state ---
def custom_empty():
return P("Nothing here!" )
custom_empty_xml = to_xml(render_sortable_queue(config, ids_obj, urls, [], test_render_content, render_empty= custom_empty))
assert "Nothing here!" in custom_empty_xml
# --- Custom footer ---
def test_footer(items_list):
return Div(f" { len (items_list)} items total" , id = "footer" )
footer_xml = to_xml(render_sortable_queue(config, ids_obj, urls, test_items, test_render_content, render_footer= test_footer))
assert "2 items total" in footer_xml
print ("All rendering tests passed" )
All rendering tests passed