Problem
Current web UI is fully static - every interaction requires full page reload. Want more dynamic feel without heavy JavaScript frameworks.
Solution: HTMX
HTMX allows HTML elements to make AJAX requests and swap content, all via HTML attributes. Perfect fit for server-rendered Lucid templates.
Use Cases
Immediate
- Recent Activity panel - auto-refresh every 10s on dashboard
- Ready queue count - live update in navbar/dashboard
- Task status updates - inline status change without page reload
With Worker Observability (t-148)
- Worker activity timeline - stream updates as worker progresses
- Task detail page - live status/activity while worker is running
- Build logs - stream output in real-time
General UX Improvements
- Filter forms - apply filters without full reload (hx-get on form)
- Status dropdowns - inline update (hx-post, hx-swap)
- Pagination - load more without reload
Implementation
Phase 1: Add HTMX + First Use Case
- Add HTMX script tag to pageHead (CDN or vendored)
- Create partial endpoints that return HTML fragments (not full pages)
- Add hx-get + hx-trigger='every 10s' to Recent Activity panel
- Add hx-get + hx-trigger='every 5s' to Ready Queue count
Phase 2: Interactive Forms
- Status update dropdown: hx-post, hx-swap='outerHTML'
- Filter form: hx-get, hx-push-url, hx-target='#task-list'
- Delete confirmation: hx-confirm, hx-delete
Phase 3: Worker Activity Streaming
- SSE endpoint for worker events (Server-Sent Events)
- hx-ext='sse' for live activity feed
- Or polling with hx-trigger='every 2s'
Technical Notes
Partial Endpoints
Need endpoints that return HTML fragments, not full pages:
- GET /partials/recent-activity -> just the activity list HTML
- GET /partials/ready-count -> just the count badge HTML
- GET /partials/task/:id/status -> just the status badge HTML
HTMX Attributes Cheatsheet
- hx-get='/url' - GET request on trigger
- hx-post='/url' - POST request
- hx-trigger='click' | 'every Ns' | 'load'
- hx-target='#id' | 'this' | 'closest .class'
- hx-swap='innerHTML' | 'outerHTML' | 'beforeend'
- hx-push-url='true' - update browser URL
- hx-confirm='Are you sure?' - confirmation dialog
No Build Step
HTMX is a single JS file, no npm/webpack needed. Just add:
<script src='https://unpkg.com/htmx.org@2.0.4'></script>
Or vendor it in Omni/Jr/Web/Static.hs as inline script.
Files to Modify
- Omni/Jr/Web.hs - Add partial endpoints, HTMX script tag
- Omni/Jr/Web/Style.hs - Styles for loading states (.htmx-request)
- New: partial view helpers that return fragments