feat(web): migrate dashboard checkboxes to @nous-research/ui + DS polish (#28814)
* feat(web): migrate dashboard checkboxes to @nous-research/ui + DS polish
Replaces the hand-rolled shadcn-style Checkbox in web/src/components/ui/
with the Nous DS Checkbox (Radix-backed) from @nous-research/ui, bumps
the DS to 0.14.2, and picks up two regressions surfaced by the bump.
Checkbox migration
- bump @nous-research/ui 0.14.0 → ^0.14.2 and remove
web/src/components/ui/checkbox.tsx
- migrate ProfilesPage and ModelPickerDialog to the DS Checkbox API
(onCheckedChange, paired <Label htmlFor>)
- expose Checkbox on the dashboard plugin SDK
(web/src/plugins/registry.ts) so plugin bundles can use the same
DS component
- migrate the kanban dashboard plugin's 7 native <input type="checkbox">
call sites to the SDK Checkbox, with a native-input fallback shim so
the bundle still renders against older hosts that predate the SDK export
Fix: missing font registrations after the 0.14.x split
- import @nous-research/ui/styles/fonts.css before globals.css in
web/src/index.css. As of 0.14.x, globals.css only declares the
--font-* variables (Collapse, Mondwest, Rules Compressed/Expanded);
the @font-face registrations now live in a separate fonts.css, so
without this import the DS components silently fall back to a system
font stack and look unstyled.
Fix: right-align page header toolbars on sm+ viewports
- The mobile dashboard polish in #28127 flipped four pages'
setEnd(...) wrappers from justify-end to w-full ... justify-start
so toolbars stack below the title and align left on small screens.
But the outer end slot in PageHeaderProvider already has
sm:justify-end, and that has no effect when its only child is
w-full — once a flex child fills the row, the parent's justify-*
can't move it. The toolbar pinned to the *left* of the right-side
sm:max-w-md (~448px) slot, making the buttons appear to float a
couple-hundred pixels off the right edge on Analytics, Models, Logs,
and Plugins.
- Re-add sm:justify-end on the inner wrapper of each affected page,
preserving the mobile stacked layout.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(nix): update web npmDeps hash for package-lock bump
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(nix): refresh npm lockfile hashes
* chore(ci): re-trigger checks after nix lockfile hash fix
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
feat(dashboard): support serving under URL prefix via X-Forwarded-Prefix
The Hermes dashboard previously assumed it was served at the root of its
host (e.g. https://kanban.tilos.com/). When mounted behind a path-prefix
reverse proxy (e.g. https://mission-control.tilos.com/hermes/), the SPA
404'd because:
- index.html shipped absolute /assets/index-*.js URLs
- React Router had no basename
- The plugin loader hit /dashboard-plugins/<name>/... at the root host
- CSS in the bundle had absolute url(/fonts/...) references
This patch makes the dashboard prefix-aware at runtime, no rebuild
required. The proxy injects 'X-Forwarded-Prefix: /hermes' on every
request and the Python server:
- Rewrites href/src in served index.html to '${prefix}/assets/...'
- Injects 'window.__HERMES_BASE_PATH__="${prefix}"' for the SPA to read
- Rewrites url() refs in CSS at serve time
The SPA reads window.__HERMES_BASE_PATH__ once at boot and:
- Prefixes all /api/... fetches via api.ts
- Prefixes all /dashboard-plugins/... script/css URLs in usePlugins
- Sets <BrowserRouter basename={...}> so client-side routing works
When no X-Forwarded-Prefix header is present, behavior is unchanged
(empty prefix => serves at root, kanban.tilos.com keeps working).
Refs: MC-AUTO-13