← Back to task

Commit 7df03171

commit 7df031715fabd6eb84ef315e8fe78dc7d0b7344d
Author: Ben Sima <ben@bensima.com>
Date:   Mon Dec 1 04:21:20 2025

    Fix Agent Log scroll position reset on HTMX poll
    
    Perfect! Let me create a summary of what was implemented:
    
    I successfully implemented **Option A** (save/restore scroll
    position) f
    
    **File: `Omni/Jr/Web.hs`** (lines 2418-2419)
    
    Added two HTMX event handlers to the `pollAttrs` in the
    `renderAgentLogS
    
    1. **`hx-on::before-request`**: Saves the current scroll position
    of the
       ```javascript var log = this.querySelector('.agent-log'); if(log)
       this.dataset.scro ```
    
    2. **`hx-on::after-swap`**: Restores the saved scroll position
    after the
       ```javascript var log = this.querySelector('.agent-log'); if(log &&
       this.dataset.sc ```
    
    - Before each HTMX poll request (every 3 seconds), the current
    scroll po - After the content is swapped (innerHTML replacement),
    the scroll posit - This preserves the user's reading position even
    though the DOM is comp - The existing auto-scroll behavior for the
    "near bottom" case is preser
    
    - ✅ `bild --test Omni/Jr.hs` - All tests pass (12/12) - ✅ `lint
    Omni/Jr/Web.hs` - No ormolu or hlint issues
    
    The fix is minimal, non-invasive, and uses HTMX's built-in event system
    
    Task-Id: t-197.7

diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs
index d5283651..88e04425 100644
--- a/Omni/Jr/Web.hs
+++ b/Omni/Jr/Web.hs
@@ -2414,7 +2414,9 @@ renderAgentLogSection tid events status now = do
             then
               [ Lucid.makeAttribute "hx-get" ("/partials/task/" <> tid <> "/events"),
                 Lucid.makeAttribute "hx-trigger" "every 3s",
-                Lucid.makeAttribute "hx-swap" "innerHTML"
+                Lucid.makeAttribute "hx-swap" "innerHTML",
+                Lucid.makeAttribute "hx-on::before-request" "var log = this.querySelector('.agent-log'); if(log) this.dataset.scroll = log.scrollTop",
+                Lucid.makeAttribute "hx-on::after-swap" "var log = this.querySelector('.agent-log'); if(log && this.dataset.scroll) log.scrollTop = this.dataset.scroll"
               ]
             else []
     Lucid.div_ ([Lucid.class_ "agent-log-section", Lucid.id_ "agent-log-container"] <> pollAttrs) <| do