fix(ui): compact the mode switcher, make its tabs read as tabs, and stop it hiding what the decision needs - #1135
Merged
Merged
Conversation
…ion needs
The dropdown was too text-heavy and scrolled internally, so half the decision sat
below a fold. Every option is now ONE visible line — label, a summary that
carries the cost, and the endpoint chip — with the full explanation on hover and
a docs link per axis. Both tabs measure 390px and fit without scrolling.
The tab row read as loose text because it used `tabs-bordered`, this app's
page-level nav idiom, where a hairline is invisible at dropdown scale. It now
uses `tabs-box` — the segmented control AddServerModal already uses for a
compact one-of-two choice — whose filled active segment is the boundary that
makes the row read as a control. (`tabs-boxed` is the DaisyUI 4 spelling and
renders flat under v5; Dashboard.vue still has that bug independently.)
A QA/UX review of the compaction found things it had hidden or broken, fixed
here:
- **Code Exec's prerequisite was hover-only.** The code-execution surface has no
tool-calling path but the code_execution tool, which refuses while the feature
is off — and it is off by default. Selecting that mode staged a surface that
finds tools and can call none of them, and the pending notice claimed
"/mcp/code serves it now". /api/v1/routing now reports
`code_execution_enabled`, and the row and the notice say so inline, in warning
tone, when it is unmet.
- **No scroll fallback.** Dropping max-height and overflow entirely left the
panel's bottom unreachable at 200% zoom or on a short window — it is
absolutely positioned inside a sticky header the page cannot scroll. A
viewport-relative cap is back; at normal heights it never engages, which the
copy budget in the tests is what keeps true.
- **Two false claims.** Direct did not list "nothing hidden" (quarantine,
disabled and out-of-profile servers are filtered), and Retrieve is not the
"smallest context of the three".
- **Badges that lied.** Under code execution /mcp is pinned to full schemas, so
the header badge and the tab chip no longer repeat a compact/deferred config
the surface does not use. The badge also names the panel's word
("Signatures"), not the raw config value.
- **Accessibility.** Selection was conveyed only by a background tint and an
unlabelled tick: options are now `role="radio"` + `aria-checked` inside
labelled radiogroups. `aria-busy` replaces `disabled` during a write, which
was dropping focus to `<body>` mid-interaction. `aria-haspopup` says `dialog`,
the panel has a role and label, and the muted text meets AA in both themes.
- **One docs link served two axes.** They are separate specs and separate pages.
Not fixed here: below ~1220px the header's right-hand cluster overflows the
viewport and takes the switcher button off-screen with it. That is pre-existing
header layout, not the dropdown, and needs its own change.
Deploying mcpproxy-docs with
|
| Latest commit: |
943704a
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://12824585.mcpproxy-docs.pages.dev |
| Branch Preview URL: | https://claude-mode-switcher-ux-poli.mcpproxy-docs.pages.dev |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
📦 Build ArtifactsWorkflow Run: View Run Available Artifacts
How to DownloadOption 1: GitHub Web UI (easiest)
Option 2: GitHub CLI gh run download 33300226310 --repo smart-mcp-proxy/mcpproxy-go
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Description
Follow-up to #1133, which shipped the header mode switcher. Two problems with it:
the dropdown was too text-heavy and scrolled internally, so half the decision sat below a fold; and the
Surface/Schema detailtabs read as loose text rather than a control.Compaction. Every option is now ONE visible line — label, a summary that carries the cost (the only
real basis for choosing), and the endpoint chip — with the full explanation on hover and a docs link per
axis. Measured on a live instance: both tabs 390px, no scrolling, fits a 700px viewport.
Tabs. They used
tabs-bordered, this app's page-level nav idiom (Settings, ServerDetail), where ahairline under the active item works because there is a long rule to read it against. At dropdown scale it
is invisible. They now use
tabs-box— the segmented controlAddServerModalalready uses for a compactone-of-two choice — whose filled active segment is the boundary that makes the row read as a control, and
the label/value pair now stacks inside the pill instead of wrapping outside it.
What a QA/UX review of the compaction found
Reviewed across five lenses (UX/IA, copy accuracy against the Go backend, accessibility, no-scroll geometry
across viewports and themes, regression), each finding adversarially verified against the running app. 16
confirmed. Several were introduced by the compaction itself:
but the
code_executiontool (buildCodeExecModeToolsomitscall_tool_*), and that tool is a refusingstub while
enable_code_executionis false — which is the default. So the panel would stage a surfacethat finds tools and can call none of them, while the pending notice claimed "/mcp/code serves it now".
GET /api/v1/routingnow reportscode_execution_enabled, and both the option row and the pendingnotice say so inline, in warning tone, when it is unmet.
max-h/overflowgone the panel's bottom became permanently unreachable at 200% zoom or on a shortwindow — it is absolutely positioned inside a sticky header the page cannot scroll into view. A
viewport-relative cap is back. Measured: 700px viewport → 390px panel, no scroll; 420px viewport → caps at
340px, scrolls, last item reachable.
out-of-profile servers are filtered out), and Retrieve is not the "smallest context of the three".
/mcpis pinned to full schemas (Spec 085 FR-011), so theheader badge and the Schema-detail chip no longer repeat a compact/deferred config that surface ignores.
The badge also names the panel's own word ("Signatures") instead of the raw config value ("compact"),
which appeared nowhere in the UI it pointed at.
<svg>— nothing anassistive tech can read. Options are now
role="radio"+aria-checkedinside labelled radiogroups.aria-busyreplacesdisabledduring a write, which was dropping focus to<body>mid-interaction.aria-haspopupsaysdialograther thanmenu, the panel carries a role and label, and the muted textwas raised to pass AA in both themes (the inactive tab's sub-label measured 2.88:1 light / 3.15:1 dark).
Testing
1001 frontend unit tests (20 in
mode-switcher.spec.ts, including new cases for the prerequisite warning,the pending notice that must not promise an unusable surface,
aria-checkedon both axes, and the per-axisdocs links);
internal/httpapiincl. the newcode_execution_enabledfield;golangci-lintv2 clean;swagger regenerated.
Manually verified against a live isolated instance in the exact broken combination
(
routing_mode: code_execution+enable_code_execution: false): the row and the notice both warn, and thepanel measures correctly at 1280x700 and 1280x420.
Notes for the reviewer
switcher button off-screen with it — I confirmed the button itself is unreachable at 781px, so the
clipped dropdown is a symptom, not the cause. That is pre-existing header layout and deserves its own
change rather than a patch inside this component.
deliberate: it proves the information was relocated, not dropped. The copy-length budgets in
mode-switcher.spec.tsare what keep the viewport cap from ever engaging at normal heights.