Skip to content

feat(web): make the instance Config screen navigable — section rail + live filter - #740

Merged
edspencer merged 3 commits into
mainfrom
feat/config-ui-redesign
Aug 7, 2026
Merged

feat(web): make the instance Config screen navigable — section rail + live filter#740
edspencer merged 3 commits into
mainfrom
feat/config-ui-redesign

Conversation

@edspencer

Copy link
Copy Markdown
Owner

The instance Config screen rendered ~47 fields in 10 groups as one narrow
column of label-then-field rows: 5,508px — seven screenfuls — with no way to
reach a known setting except scrolling past everything else, and no hierarchy
(driveMode and webDist had identical visual weight).

Why a rail and not tabs

Tabs were the obvious move and are the wrong one: tabs partition, and
partitioning is exactly what defeats a search.
With tabs, "find every field
mentioning token" either can't cross a tab boundary or has to blow the tabs
away to show results — and then the tabs are lying about where you are.

This follows VS Code's settings screen instead: a rail of section links
scroll-spying over one document. "Jump to Branding" and "filter everything"
are both available at once, and neither disables the other.

What's in it

  • Section rail (lg+) with per-group counts, scroll-spy, and a dot marking
    groups that hold unsaved edits. Clicking scrolls; it never switches panes.
  • Live filter over label, dotted key, help text, env var and enum values — so
    an operator who thinks in PADDOCK_* names finds a field by typing one. A
    group whose own label matches keeps all its fields, so "branding" acts like a
    jump. Takes focus on load, gated to (min-width: 1024px) so a phone doesn't
    get the on-screen keyboard thrown over the page. Escape empties it rather than
    blurring, so the way back to the full list is the key you already reached for.
  • "Modified only" lens — just what differs from the built-in default. On a
    real instance that's a handful of rows.
  • Env overrides became a chip + the variable name, with the explanation
    stated once in a legend. Repeating the same two-line amber paragraph beside
    twenty fields was the single largest source of the length on a containerized
    instance.
  • Locked fields are no longer input-shaped. Fourteen dashed boxes in
    "Advanced" read as a form you were being denied rather than a list of facts.
  • Booleans are a switch on the label line, not a checkbox stranded at the far
    right of a 672px row. Short fields pair into two columns; only prompts, lists
    and long paths span.
  • Section boundaries carried by three cues together — a rule, a step in
    vertical rhythm, and a heading that outranks a field label — because any one
    alone still read as a divider inside a list rather than between sections.

5,508px → 3,811px, and reachable by name.

Scope

Client-only. GET /api/instance-config already returns label, key, help, env var
and default per field, so no server change was needed. Behaviour is unchanged:
same dirty-tracking, same patch payload, same restart-required semantics.

Testing

  • Typecheck clean; 949/949 web tests pass, including 6 new ones covering the
    filter (by label, by PADDOCK_* name, empty state), the "Modified only" lens,
    and autofocus — the latter as a pair, since the test that it does not focus
    on a small screen is what stops someone quietly deleting the gate.
  • Two existing assertions were rewritten deliberately: a group label now appears
    in both the rail and the heading (so it matches the heading role, not bare
    text), and the per-field env paragraph became a chip.
  • E2E was not run locally. The suite fails wholesale on the dev box — and
    fails identically on unmodified main, which I checked by stashing and
    rebuilding, so it's environmental rather than this branch. Leaving that to CI.

🤖 Generated with Claude Code

HomeLab Agent and others added 3 commits August 7, 2026 11:41
… live filter

The screen rendered ~47 fields in 10 groups as one narrow column of
label-then-field rows: 5,508px, seven screenfuls, no way to reach a known
setting except scrolling past everything else, and no hierarchy (driveMode and
webDist had identical weight).

Follows VS Code's settings screen rather than tabs, because tabs partition and
that is exactly what defeats a search. A rail of section links scroll-spies over
ONE document, so "jump to Branding" and "find every field mentioning token" are
both available and neither disables the other.

- Section rail (lg+) with per-group counts, scroll-spy, and a dot marking
  groups holding unsaved edits; clicking scrolls rather than switching panes.
- Live filter over label, dotted key, help text, env var and enum values, so an
  operator who thinks in PADDOCK_* names finds a field by typing one. A group
  whose own label matches keeps all its fields.
- "Modified only" lens — on this box that is 20 of 47 rows.
- Two-column grid; only prompts, lists and long paths span both.
- Env overrides became a chip plus the var name, with the explanation stated
  once in a legend. Repeating the same two-line amber paragraph beside twenty
  fields was the single largest source of the length on a containerized
  instance.
- Locked fields are no longer input-shaped; fourteen dashed boxes in "Advanced"
  read as a form you were being denied rather than a list of facts.
- Booleans are a switch on the label line instead of a checkbox stranded at the
  far right of a 672px row.

3,400px from 5,508px, and reachable by name. Behaviour is unchanged: same
dirty-tracking, same patch payload, same restart semantics.

Co-Authored-By: Claude <noreply@anthropic.com>
…ilter

Two follow-ups from review of the redesign.

Section breaks were too quiet — a 14px heading the same size as the rest of the
page, with nothing between one group and the next, so Capabilities did not read
as separate from Sweeper above it. Carried by three cues together now, because
any one alone was still too weak: a full-width rule, a step in vertical rhythm
(a section sits further from the one above it than its own fields sit from each
other), and a heading a clear size and weight above a field label. The first
section takes no rule — nothing above it to divide from.

The filter now takes focus on load. /config is a dedicated screen whose first
move is nearly always "find the setting I came for", so taking focus costs
nothing — but it is gated to `(min-width: 1024px)` so a phone does not get the
on-screen keyboard thrown over the page before it has been read. Escape empties
the box rather than blurring it, so the way back to the full list is the key you
already reached for.

Costs ~400px of the ~2,100px saved (3,400 → 3,811, vs 5,508 originally), which
is a fair trade for a page you can now actually parse.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying paddock with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0675ec3
Status: ✅  Deploy successful!
Preview URL: https://b6f9fc42.paddock-7u2.pages.dev
Branch Preview URL: https://feat-config-ui-redesign.paddock-7u2.pages.dev

View logs

@edspencer
edspencer merged commit 16d9c32 into main Aug 7, 2026
5 checks passed
@edspencer
edspencer deleted the feat/config-ui-redesign branch August 7, 2026 18:28
@github-actions github-actions Bot mentioned this pull request Aug 7, 2026
edspencer added a commit that referenced this pull request Aug 8, 2026
… releases (#762)

* chore(docs): start the 0.56-0.66 What's New pass

* docs(website): split What's New, archiving 0.52 and older

The page had grown to 1,150 lines and 30 releases, which is past the
point where anyone scrolls it. Everything from 0.52 back to 0.29 moves
verbatim to a new 'What's New — earlier releases' page; the main page
keeps 0.53 and newer.

Entries are moved unchanged — the archive is append-only and its
entries are never rewritten, which is the same promise the page already
makes about describing each release as it shipped. Image paths are
unchanged because both pages sit in the same content directory.

Adds the sidebar entry (Starlight does not auto-discover, so an
unlisted page is invisible), a cross-link in both directions, and a
note in the maintainer footer describing how to trim next time.

* docs(website): What's New for 0.63 through 0.66.1

Five new entries. 0.66.0 leads on the Config screen redesign (#740) —
the largest UX change in the range and the one a user meets every time —
with a screenshot of the rail, live filter, env-override legend and the
dirty dot. Also carries the breaking default-port move 4000 -> 7233
(#741) with the operator action spelled out, schemaVersion (#735), the
import -> adopt rename (#748), the destructive-op interlock (#743) and
the sub-agent bar fixes (#750).

0.66.1 is the queued-message release (#751): three silent-loss paths and
the Stop-hands-it-back decision. 0.65 is promote_project (#668). 0.64
leads on path:/managed replacing repoBacked (#709) plus the Changes tab
finally reporting on the checkout (#597). 0.63 is host plugin
inheritance and MCP fidelity (#705), including the batch-mode argv
credential disclosure (#702).

Two claims deliberately qualified against the changelog's framing: the
delete-then-send fix (#742) is called out as batch-only, since the
default session mode was never affected; and the sub-agent bar is not
described as absolute, because the settle heuristic can hold an
interrupted sub-agent for ten minutes.

Also corrects a live error: the 0.59.1-0.60 entry claimed in bold that
--here leaves your ~/.claude alone. That was false for exactly those
versions — --here linked ~/.claude/projects/<dir> at the workspace, and
one report lost 30 transcripts to it before 0.61.1 stopped it. Replaced
with a caution box pointing forward.

* docs(website): a recorded demo of the 0.66 Config screen

The filter and the rail only read in motion, so the entry gets both a
still (rail counts, env chips, legend, dirty dot) and a 22s clip:
filter by env-var name, Modified-only lens, then a rail jump that
scrolls rather than swapping tabs.

Shot on a v0.66.1 rig with no credentials. Two leaks were caught by
looking at the frames rather than trusting the launcher:
PADDOCK_GIT_AUTHOR_EMAIL was inherited and put a real internal address
in the Git identity section, and the Advanced section printed the rig's
scratch paths. The launcher is now an ALLOW-list — it drops every
inherited PADDOCK_* and sets only what it needs — which is the fix
issue #567 argues for, and the frames now show stock defaults and a
~/.paddock install path.

* docs(website): backfill 0.56, 0.57, 0.58 and 0.61.0

These four were never written up — a gap in the middle of the page, not
a tail. 0.61.0 in particular was only reachable by reading the 0.62
entry backwards, where it appears as the thing being removed.

0.61.0 leads on Paddock taking ownership of its Claude home, with a
caution box narrating the whiplash: 0.61.0 isolates the home, 0.61.1
un-isolates the CLI because an isolated home cannot see a macOS
Keychain login, and 0.62 replaces the mechanism entirely. Without that
sentence the three entries read as contradicting each other.

0.58 carries its own caution: everything in it shipped in a CLI that,
installed through npm, printed nothing and exited zero, and stayed that
way across 0.57 and 0.59.0 until 0.59.1. An entry recommending it
without that note would be recommending a broken install. The cause is
described only as the run-directly guard, not attributed to a specific
PR, because the changelog's own attribution does not line up with the
release it shipped in.

0.57 is the environment system prompt, with the audit numbers that
justified it and a note that three candidate rules were measured and
cut. 0.56 is the npm publish, plus the correction that the claude CLI
was never a prerequisite for chats.

Also corrects 'several hundred boot log lines' in the 0.59.1-0.60 entry
to match the changelog's actual figure (about thirty, down to nine).

* docs(website): cut the new What's New entries roughly in half

The nine entries added this pass ran to 314 lines. They read as
changelog archaeology rather than release notes — explaining how each
bug worked before saying what changed, and carrying detail nobody
scanning a What's New page needs.

Now 180 lines, of which 12 are the image and video markup. Each bullet
is one idea in three or four lines: what a user notices first, then only
the context that makes it land. What survives unchanged is the material
that is genuinely load-bearing — the port change's operator action, the
'tabs partition' argument, the batch-only qualifier on the delete-then-
send fix, and the two caution boxes, since those exist to stop a reader
believing something false.

* docs(website): plainer titles, and another pass on length

Titles were making claims rather than saying what changed — 'Nothing you
typed while it was busy goes missing', 'A Config screen you can
navigate', 'A command-line worth running'. They now name the subject:
Queued messages; Config screen, and a new default port; CLI output and
flags; Environment system prompt; npm package.

Prose down from 168 lines to 137 (originally 302). Mostly by cutting
restatement — 0.61.0's four small turn-level fixes were four bullets
saying the same shape of thing and are now one.

* docs(website): bring the older entries into the same style

Retitles every remaining entry to name its subject rather than make a
claim, and cuts them to the same length as the new ones. 0.62's title
becomes 'Granular host Claude inheritance options' as requested.

  Five levers instead of one            -> Granular host Claude inheritance options
  Your ~/.claude, left alone and ...    -> CLI login, and symlinks into your Claude home
  One command, on your own history      -> npx install, --here, and confirmed adoption
  Bring your terminal history with you  -> Adopting Claude Code CLI chats
  Claude, not "the keeper"              -> The "keeper" rename, and Home's attention feeds
  Home says what it's holding           -> Unread badge on the Home link

Lengths: 0.62 115->51, 0.61.1 57->36, 0.59.1-0.60 45->29, 0.55 81->29,
0.54 70->42, 0.53 62->14. The page is 379 lines, down from 1,150.

Everything load-bearing is kept: the breaking env-var table, the
instructions: own warning, the leftover-symlink check with its shell
command, and both caution boxes. All five media assets verified present
in the built output. Frontmatter description rewritten — it still
described 0.62 as 'five independent levers'.

---------

Co-authored-by: HomeLab Agent <homelab-infra@valfenda.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant