feat(bx): replace server dropdown with Bx fleet gear - #61
Merged
Conversation
- Implemented Bx sidebar icon in icons.go for consistent UI. - Created pages.templ for the Bx fleet view, including index page, headers, and empty state. - Developed status.go to manage box status monitoring, including polling and SSE for live updates. - Added bx-page.js for client-side behaviors, including row navigation and relative time formatting. - Enhanced box-selector.js and introduced box-switcher.js for improved box selection and navigation.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new built-in Bx (Boxes) fleet gear and replaces the old server dropdown UX with a persistent header chip + command-palette box switcher, backed by a server-side status monitor that streams updates over SSE.
Changes:
- Introduces the
bxgear (fleet page at/bx, JSON status snapshot, SSE events stream, status poller). - Adds the header box-switcher chip + palette UI and client-side behaviors (including
g bshortcut). - Updates request middleware + sidebar rendering to support “no active box” (box-agnostic) navigation.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| gearbox/static/js/common/box-switcher.js | New command-palette switcher UI with SSE-driven status dots |
| gearbox/static/js/common/box-selector.js | Extends legacy switchBox helper to support optional path + clearing context |
| gearbox/static/js/bx/bx-page.js | Fleet page client behaviors (row click, SSE updates, relative timestamps) |
| gearbox/internal/gears/bx/status.go | Background status monitor (polling + subscriptions) producing BoxStatus snapshots |
| gearbox/internal/gears/bx/README.md | Gear documentation (scope, routes, semantics) |
| gearbox/internal/gears/bx/pages.templ | Fleet page server-rendered UI (table + empty state) |
| gearbox/internal/gears/bx/icons.go | Bx SVG icon component |
| gearbox/internal/gears/bx/handlers.go | HTTP handlers for /bx, /bx/api/status, /bx/api/events |
| gearbox/internal/gears/bx/gear.go | Gear registration, lifecycle wiring, permissions, sidebar placement |
| gearbox/internal/framework/templates/layouts/base.templ | Header chip/palette + scope-aware sidebar rendering + bx link |
| gearbox/internal/framework/services/server_adapter.go | Exposes underlying *database.DB for monitor usage |
| gearbox/internal/framework/handler/handler.go | Injects enabled-box roster + resolves active box via ?box_id= |
| gearbox/internal/framework/gear/interface.go | Adds ScopeBoxAgnostic and Scope.IsBoxScoped() helper |
| gearbox/internal/framework/auth/middleware.go | Adds request-context storage for selected box + enabled box roster |
| gearbox/cmd/server/main.go | Registers the new bx gear |
| DESIGN.md | Documents new scope semantics and multi-box UX flow |
- statusMonitor.Start now guards against multi-start with sync.Once
(matches its docstring; previously spawned a new goroutine per call).
- bx.Gear.Start passes its lifecycle ctx through to the monitor instead
of context.Background(), so framework shutdown actually cancels it.
- The per-probe 5s budget is now enforced: probe uses
agent.NewClientWithTimeout(..., m.timeout) instead of the default 30s
agent client. Removed the unused pctx that the old comment promised.
- canViewIntegration("bx") now checks bx:view via
auth.HasPermissionFromContext, matching the handler-side gate and the
SidebarItem.RequiresPermission — so the sidebar no longer renders a
Bx link for users who'd just get a 403 clicking it.
- Fix stale comment on boxTable: the page reconciles via the SSE
snapshot pushed on (re)connect, not a /bx/api/status fetch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-existing dead field from the original commit; golangci-lint v2.8.0 (running on PR CI) flagged it as unused. Removed rather than wired up — m.deps.Logger is already available when logging is needed later. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- box-switcher.js: register the visibilitychange listener once at module load instead of inside subscribeSSE(). Previously each tab-show added a new listener, eventually opening multiple EventSource connections. subscribeSSE() now also short-circuits if evt is already set. - status.go probe(): `/health` is unauthenticated, so a missing API key no longer skips the reachability check. Boxes with an Agent URL but no key now probe normally; if Health() succeeds, the rollup degrades to Yellow with "API key missing — authenticated endpoints unavailable" as a contributor instead of being permanently Gray. - handler.go InjectIntegrationStatus: publish the *full* configured-box roster (not just enabled-and-UsesAgentAPI) so the Bx fleet view and switcher palette can show disabled / partially-configured boxes — the StatusGray semantic only works if those rows are actually rendered. Active-box resolution (?box_id=) still uses the enabled+configured subset; landing on a disabled box has no gears to render anyway. - base.templ box-switcher palette: add `role="dialog"`, `aria-modal="true"`, `aria-labelledby="box-switcher-title"`, a visually- hidden h2 title, `aria-label` on the search input, and `aria-hidden` on the decorative magnifier SVG. Matches the existing confirm/prompt/ alert dialog patterns in this template. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Closes #48.
Summary
bxgear: a fleet view that replaces the server-name dropdown in the top bar. Tabular grid of all configured boxes with sort/filter, click-through to hydrate the per-box sidebar.status.gopolls each box and pushes updates over SSE so the fleet view never shows stale state.box-switcher.js) handles the click-into-box → menu-hydrate → land-on-default-gear flow described in the issue.base.templ) updated so non-box gears (e.g. the fleet view itself) remain available when no box is selected.Test plan
🤖 Generated with Claude Code