Skip to content

feat(dashboards): MVP backend + grid frontend (PR 1 of 3)#217

Closed
BK1031 wants to merge 3 commits into
mainfrom
bk1031/dashboards-mvp
Closed

feat(dashboards): MVP backend + grid frontend (PR 1 of 3)#217
BK1031 wants to merge 3 commits into
mainfrom
bk1031/dashboards-mvp

Conversation

@BK1031

@BK1031 BK1031 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

PR #1 of the dashboards feature. The remaining work splits into:

  • PR Jacobjurek/Rigby #2 — Wire actual chart rendering inside the widget card (refactor SignalWidget to accept seeded queries, embed it in DashboardWidgetCard). Add a settings panel to edit queries inline.
  • PR Ingest vehicle endpoints #3 — Specialty widget types (gauge, big number, dedicated map widget) on top of the same query plumbing.

What landed

Backend (mapache-go + vehicle service):

  • New `Dashboard` + `DashboardWidget` models in `mapache-go`. `Widget.Config` is jsonb so each renderer's settings live in one column without schema churn per widget type. `X/Y/W/H` are react-grid-layout cell coordinates.
  • CRUD under `/dashboards` and `/dashboards/:id/widgets` (widget update is per-widget because RGL fires `UpdateWidget` on every drag/resize release).
  • `AutoMigrate` adds the two tables.
  • A `replace` directive points `mapache-go` at the in-repo copy — drop it + bump the version in `require` once mapache-go is tagged.

Kerbecs:

  • `/api/dashboards` and `/api/dashboards/*` both proxy to the vehicle service.

Dashboard frontend:

  • `/dashboards` — list page with create dialog and card grid.
  • `/dashboards/:id` — detail page with `react-grid-layout`, inline-renamed title, optimistic position/size persistence.
  • `DashboardWidgetCard` is the widget shell (drag handle, title input, remove). The chart pane is a placeholder for PR Ingest auth #1.
  • Sidebar gains a "Dashboards" entry.

Deploy gotchas

  • `react-grid-layout` + `@types/react-grid-layout` are new deps; CI's first run will pull them.
  • The vehicle service's `replace` against `../mapache-go` works for dev + this PR's CI (mapache-go ships in the same repo). If you'd rather release mapache-go first, tag it then bump `require` and drop the replace block.
  • New tables (`dashboard`, `dashboard_widget`) get created via `AutoMigrate` on next vehicle service boot.

Out of scope

Widget settings panel · chart rendering · gauges · big-number widgets · dedicated map widgets · sharing/permissions · dashboard cloning.

BK1031 added 3 commits June 20, 2026 08:04
PR #1 of the dashboards feature — gets the backend + grid layout in
place so the rest of the work is purely widget-side.

mapache-go:
- New Dashboard + DashboardWidget models. Widget.Config is jsonb so
  each renderer carries its own type-specific shape without schema
  churn per widget type. X/Y/W/H are react-grid-layout cell coords.

vehicle service:
- CRUD endpoints under /dashboards and /dashboards/:id/widgets.
- Widget update is granular (PUT per widget) because the grid's
  drag/resize fires UpdateWidget on every release; bundling the whole
  dashboard would make every move pay for the full widget payload.
- AutoMigrate adds the two new tables.
- go.mod gets a `replace` directive against the in-repo mapache-go
  so adding model types doesn't require a tag-and-release detour.
  Drop the replace + bump the version once mapache-go is released.

kerbecs:
- Two new routes: /api/dashboards (list) and /api/dashboards/* (rest).

dashboard frontend:
- DashboardsPage lists existing dashboards in a card grid with a
  create dialog.
- DashboardDetailsPage embeds react-grid-layout with optimistic
  position/size persistence and an inline-renamed title.
- DashboardWidgetCard is the widget shell — drag handle, title input,
  remove. The chart pane is a placeholder for PR #1; PR #2 plugs in
  actual SignalWidget rendering once it's refactored to accept seeded
  queries.
- New sidebar entry "Dashboards" at /dashboards.

Out of scope for PR #1 (parked for #2/#3):
- Actual chart rendering inside the widget card.
- Widget settings panel for editing queries (today's flow seeds them
  on create; PR #2 adds the editor).
- Specialty widget types (gauge, big number, dedicated map).
- Sharing / permissions / duplication.
Stacked onto PR #1's foundation:

SignalWidget — opt-in embedded mode:
- New seedQueries / onQueriesChange props prefill the chip rows from
  saved widget config and bubble subsequent edits back to the parent.
- New seedChartType / onChartTypeChange follow the same contract for
  the chart-type select.
- New refreshIntervalSec prop: when set, the widget re-runs its query
  every N seconds by folding a monotonic tick into the existing
  `fetchKey`. The chart's right edge keeps tracking `now` without
  holding a long-lived stream open. PR-N can drop this for a real
  SSE-driven aggregation hook against /live/sse for sub-second updates.

DashboardWidgetCard:
- Embeds the full SignalWidget when type=signal, wired with seed/change
  props so the widget's queries + chart type persist back through
  /dashboards/:id/widgets/:wid PUT.
- The dashboard's shell (drag handle, title, remove) wraps the
  SignalWidget so the kebab's own delete/hide actions defer to the
  outer card.

DashboardDetailsPage:
- Page-level TimeframePicker (reused from the Signals page) drives
  every widget. `isRolling` is derived from the timeframe ("Past N"
  presets or any custom range ending within 5s of now) and flows into
  each widget; when true, refreshIntervalSec activates 5s polling.
- Fetches signal names once per vehicle for the chip builder's
  autocomplete inside every embedded widget.
- ECharts connect group shared across the dashboard so hover/tooltip/
  dataZoom sync between panels.

Out of scope (follow-ups):
- True SSE-driven streaming + client-side incremental aggregation —
  needed for sub-second blends. The refresh-every-5s pattern here is
  the smallest end-to-end working version.
- Specialty widget types (gauge, big-number, dedicated map) — the
  widget registry is type-keyed so these slot in cleanly later.
- Per-widget timeframe override + per-widget settings dialog.
…ker drawer

Three coupled UX moves on top of the previous chart-rendering commit:

1) SSE-driven live blending
   - New `useLiveTrigger` hook opens an EventSource against the live
     service's /live/sse endpoint with the signal patterns pulled out of
     each query's `where` clause. On each arrival it bumps a throttled
     `tick` (default 500ms). The tick folds into SignalWidget's existing
     fetchKey, so /query/run re-fires the moment a relevant sample
     lands — the backend stays the source of truth for bucket math
     (aggregator semantics differ enough across count/sum/avg/min/max/
     last/p50/p95/p99/stddev that mirroring them client-side would have
     been gnarly + bug-prone).
   - Queries with no `where(name = "...")` filter don't subscribe; we'd
     otherwise have to listen to every signal on the wire. Add a name
     filter to opt into streaming.
   - The 5s setInterval refresh stays as a heartbeat — guarantees the
     chart still moves forward through signal lulls.

2) Chart-only widget + edit dialog
   - New `chartOnly` prop on SignalWidget suppresses the chip-builder
     header and chart-type picker, leaving just the canvas. The Card
     wrapper drops its border/shadow so the widget reads as inline.
   - DashboardWidgetCard renders the chart-only SignalWidget in the
     grid cell and a Pencil button in the card header opens a Dialog
     containing the full-fidelity SignalWidget (chip rows, chart type
     toggle, all the knobs). Card and dialog never both mount at the
     same time, so their internal query state can't drift apart; the
     card's SignalWidget is keyed on the persisted config so the close-
     after-edit path picks up the new seed.

3) Add-widget drawer
   - New `Sheet` UI primitive (Radix Dialog with side-anchored
     animation, right-edge variant). Reusable for any future right-
     edge panel.
   - `AddWidgetDrawer` lists every chart type from the existing
     CHART_TYPES registry with a one-line description per entry; the
     dashboard's "Add widget" button now opens the drawer instead of
     dropping a default bar widget directly. PR-N will extend the list
     with specialty widget types (gauge, big-number, dedicated map).
@BK1031

BK1031 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Faded for now — scope got too broad. Branch preserved (bk1031/dashboards-mvp) in case any of the pieces (SSE streaming, drawer, chart-only widget) are useful later.

@BK1031 BK1031 closed this Jun 20, 2026
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