The Auto/Manual switch on the Services overview was a plain form POST answered with 303 → /, so the browser loaded a fresh page at the top. The form now also posts via htmx, and setMode returns the services fragment for htmx requests, so the list is swapped in place. Scroll position, search and machine filter are kept. Without JS the form posts and redirects as before.
A refused auto mode answers 409 with HX-Redirect to the service page, which shows the reason. htmx does not swap 4xx responses, so without it the click would do nothing visible.
#services{overflow-anchor:none}: htmx 2.0.4 inserts the new list before removing the old one. Chrome's scroll anchoring held the focused switch in place, so on narrow screens the page jumped to the bottom after a click. The same happened after any SSE refresh while a switch had focus, which this also fixes.
Test plan
New tests TestSetMode_HTMXFromOverviewReturnsServicesFragment and TestSetMode_HTMXRefusedRedirectsToService (red before the fix, green after); go test ./... passes
Browser, real clicks: scrollY unchanged at 390, 700 and 1440 px; switch state changes; no navigation; search and machine filter survive
Browser: SSE-style refresh with a focused switch at 390 px keeps scrollY
Control: with scroll anchoring re-enabled the jump to the bottom returns, so the cause is confirmed
Toggle a few services on a phone against the real master
## Summary
- The Auto/Manual switch on the Services overview was a plain form POST answered with `303 → /`, so the browser loaded a fresh page at the top. The form now also posts via htmx, and `setMode` returns the services fragment for htmx requests, so the list is swapped in place. Scroll position, search and machine filter are kept. Without JS the form posts and redirects as before.
- A refused auto mode answers 409 with `HX-Redirect` to the service page, which shows the reason. htmx does not swap 4xx responses, so without it the click would do nothing visible.
- `#services{overflow-anchor:none}`: htmx 2.0.4 inserts the new list before removing the old one. Chrome's scroll anchoring held the focused switch in place, so on narrow screens the page jumped to the bottom after a click. The same happened after any SSE refresh while a switch had focus, which this also fixes.
## Test plan
- [x] New tests `TestSetMode_HTMXFromOverviewReturnsServicesFragment` and `TestSetMode_HTMXRefusedRedirectsToService` (red before the fix, green after); `go test ./...` passes
- [x] Browser, real clicks: scrollY unchanged at 390, 700 and 1440 px; switch state changes; no navigation; search and machine filter survive
- [x] Browser: SSE-style refresh with a focused switch at 390 px keeps scrollY
- [x] Control: with scroll anchoring re-enabled the jump to the bottom returns, so the cause is confirmed
- [ ] Toggle a few services on a phone against the real master
https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ
The mode switch was a plain form POST answered with 303 to /, so the browser
navigated to a fresh page at the top. The form now also posts via htmx and
the handler returns the services fragment for htmx requests, so the list is
swapped in place; search and machine filter stay applied. A refused auto
answers 409 with HX-Redirect to the service page, since htmx does not swap
4xx responses. Without JS the form still posts and redirects as before.
#services gets overflow-anchor:none. htmx inserts the new list before
removing the old one, and Chrome anchored scrolling on the focused switch,
so on narrow screens the page jumped to the bottom after a click, and after
any SSE refresh while a switch had focus.
Claude-Session: https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ
shcizo
merged commit 2989fa224d into main2026-10-13 12:06:21 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
303 → /, so the browser loaded a fresh page at the top. The form now also posts via htmx, andsetModereturns the services fragment for htmx requests, so the list is swapped in place. Scroll position, search and machine filter are kept. Without JS the form posts and redirects as before.HX-Redirectto the service page, which shows the reason. htmx does not swap 4xx responses, so without it the click would do nothing visible.#services{overflow-anchor:none}: htmx 2.0.4 inserts the new list before removing the old one. Chrome's scroll anchoring held the focused switch in place, so on narrow screens the page jumped to the bottom after a click. The same happened after any SSE refresh while a switch had focus, which this also fixes.Test plan
TestSetMode_HTMXFromOverviewReturnsServicesFragmentandTestSetMode_HTMXRefusedRedirectsToService(red before the fix, green after);go test ./...passeshttps://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ