Frontend Dashboard¶
The dashboard is a Next.js App Router project in frontend/.
Run¶
Default dashboard access uses Docker Compose and does not require local Node.js:
docker compose --profile dashboard up --build api dashboard
Open:
http://127.0.0.1:3000/dashboard
The roboci dev entry point can launch that same path:
roboci dev --docker
For local dashboard development with Node.js:
roboci dev
Open the dashboard URL printed by the command.
To choose ports explicitly:
roboci dev --api-port 8010 --frontend-port 3010
For scripted launches, roboci dev also reads NEXT_PUBLIC_ROBOCI_PORT or ROBOCI_FRONTEND_PORT when --frontend-port is omitted:
NEXT_PUBLIC_ROBOCI_PORT=3010 roboci dev
If the API is protected with ROBOCI_API_TOKEN, pass the same shared token to dashboard fetches with NEXT_PUBLIC_ROBOCI_API_TOKEN. roboci dev does this automatically when it starts both servers and ROBOCI_API_TOKEN is set.
To run only the frontend locally:
cd frontend
npm install
npm run dev
Open:
http://127.0.0.1:3000/dashboard
The dashboard expects the API at:
http://127.0.0.1:8000
Override with:
NEXT_PUBLIC_ROBOCI_API=http://127.0.0.1:8000 npm run dev
If server-rendered dashboard requests need a different API address than the browser, set ROBOCI_SERVER_API too:
ROBOCI_SERVER_API=http://api:8000 NEXT_PUBLIC_ROBOCI_API=http://127.0.0.1:8000 npm run dev
If that API requires a shared token:
NEXT_PUBLIC_ROBOCI_API=http://127.0.0.1:8000 NEXT_PUBLIC_ROBOCI_API_TOKEN=secret-token npm run dev
Override the standalone frontend port with Next.js' --port flag:
NEXT_PUBLIC_ROBOCI_API=http://127.0.0.1:8000 npm run dev -- --port 3010
For production-style local testing, set the same variables when starting Next so server-rendered pages and client-side dashboard actions use the right API:
NEXT_PUBLIC_ROBOCI_API=http://127.0.0.1:8000 npm exec next start
NEXT_PUBLIC_ROBOCI_API=http://127.0.0.1:8000 npm exec next start -- --port 3010
Production builds use Webpack via npm run build. This keeps dynamic App Router pages such as /failures/[failure_id] startable under next start.
Build¶
npm run build
Structure¶
frontend/
app/
dashboard/
run-lab/
runs/
failures/
scenarios/
regressions/
settings/
tags/
components/
lib/
Theme and UI System¶
The dashboard uses a lightweight Material Design-inspired theme without adding a component framework. Theme tokens live in:
frontend/app/globals.css
frontend/tailwind.config.ts
Use semantic Tailwind colors such as bg-surface, bg-surfaceContainer, border-outlineVariant, text-onSurface, text-onSurfaceVariant, bg-primaryContainer, and status roles such as bg-successContainer, bg-errorContainer, bg-warningContainer, and bg-infoContainer. Avoid hard-coded one-off colors in page components unless the value is part of a documented token.
The selectable product themes are controlled by ThemeSwitcher in:
frontend/components/AppShell.tsx
The selector is rendered from /settings only. The selected theme is stored in localStorage under roboci-theme and applied to document.documentElement.dataset.theme without a page reload. app/layout.tsx sets the server default data-theme="blue" and uses suppressHydrationWarning on <html> because the boot script may apply a persisted theme before React hydrates.
Status colors are semantic and should remain independent from the selected product theme:
- passed/success: green
- failed/error: red
- warning: amber
- running/info: blue
- skipped/unknown: neutral
Data Fetching¶
All backend calls go through:
frontend/lib/api.ts
Important functions:
getRuns()clearRuns()getRun(runId)getFailures()getLaunchOptions()getScenarios()getReplay(runId, scenarioId)getTrends()
The API client returns fallbacks on fetch errors. This keeps the UI from crashing, but it can hide backend connection problems. If the dashboard looks empty, check:
http://127.0.0.1:8000/runs
Pages¶
/dashboard¶
File:
frontend/app/dashboard/page.tsx
Shows:
- Closed-loop pass rate.
- Critical failures.
- Regression delta count.
- Assertion failures from the latest closed-loop run.
- Run trends.
- Latest run card.
- Latest closed-loop run card if the newest run is open-loop.
- Confirmable reset action for clearing existing run artifacts.
- Collapsible local artifact tree for the latest run.
- In-dashboard previews for safe root artifacts:
summary.json,metrics.json,regression.json,failures.json,config.yaml, andprovenance.json. - Local-only actions for indexed artifacts that are not previewed through the API, including episode logs, replay files, open-loop files, and reports. The open button asks the local API to launch only indexed run artifacts with the OS default app.
The dashboard distinguishes run types:
closed_loopopenloop
This matters because open-loop runs do not have closed-loop metrics such as success_rate, safety_score, or scenario assertion results.
/run-lab¶
File:
frontend/app/run-lab/page.tsx
Shows:
- Self-serve closed-loop run presets.
- Collision failure demo selection.
- Local scenario and scenario pack selection.
- Search over local scenario ids, names, descriptions, and tags.
- Agent cards with behavior labels.
- Simulator cards with runtime labels.
Scenario tag chips in the local example list are informational. Selecting a pack still launches the full pack.
/runs¶
File:
frontend/app/runs/page.tsx
Shows all runs as cards.
/runs/[run_id]¶
File:
frontend/app/runs/[run_id]/page.tsx
Shows:
- Closed-loop summary stats and scenario table for closed-loop runs.
- Scenario tags plus
?tag=<tag>,?domain=<domain>, and?pack=<pack-id>filtering for closed-loop scenario rows. - Open-loop sample/task/quality/latency stats for open-loop runs.
- Open-loop metrics for open-loop runs.
- Provenance, including Git state, source file hashes, and dataset hashes when present.
- Regression diff.
- Open-by-default local artifact tree.
- Pretty-printed JSON previews for safe root artifacts.
- Local open actions for indexed artifacts that are not previewed through the API.
Open-loop detail pages intentionally omit closed-loop-only cards such as success rate, safety score, collisions, and the scenario table. This prevents a passing open-loop run from looking like a failed or incomplete closed-loop run.
/runs/[run_id]/scenarios/[scenario_id]¶
File:
frontend/app/runs/[run_id]/scenarios/[scenario_id]/page.tsx
Shows:
- Replay viewer.
- Replay scene with ego path, actor positions, event markers, and frame context.
- Metric breakdown.
- Event timeline.
- Scenario tag chips that link back to the filtered run detail page.
/scenarios¶
File:
frontend/app/scenarios/page.tsx
Shows:
- Marketplace packs and local example scenarios.
- Tag chips for marketplace scenario previews and local examples.
?tag=<tag>filtering across marketplace packs and local examples. For example,/scenarios?tag=highwayshows the matching highway pack scenarios and hides unrelated packs.?domain=<domain>marketplace filtering forground_robotics,manipulators, anddrones.?q=<text>marketplace/local search across pack ids, pack names, tasks, metrics, requirements, tags, descriptions, and scenario names.- Pack install/remove buttons backed by the
/scenario-marketplace/{pack_id}/installAPI endpoints. - Counts scoped to the active filter.
/regressions¶
File:
frontend/app/regressions/page.tsx
Reads actual regression.json through GET /runs/{run_id} and displays the Regression Explorer plus the compare workbench.
The explorer separates closed-loop and open-loop regression signals. Each mode has sections for:
- New regressions.
- Resolved regressions.
- Recurring regressions.
- Top degraded scenarios.
- Top improved scenarios.
- Critical safety regressions.
Cards are generated only from regression.json data. They show metric/status delta, previous value, current value, severity, affected scenario or sample context, and links to the run, replay, or failure when the artifact exists. Scenario diffs where the current scenario is missing are shown as status transitions such as success -> missing; they do not link to replay pages or unrelated failures.
The page also includes:
- Compare Runs workbench for baseline diffing.
- Regression diff table/charts for the selected comparison.
- Table of runs with regression artifact status, delta count, and failure count.
If it shows no deltas, run:
roboci baseline create smoke --from <known-good-run-dir>
roboci compare --current runs/latest --baseline-name smoke
/failures¶
File:
frontend/app/failures/page.tsx
Shows failure table with severity, lifecycle status, owner, tag, and search filters. The owner filter includes Unassigned when any failure has no owner.
/failures/[failure_id]¶
File:
frontend/app/failures/[failure_id]/page.tsx
Shows failure detail, tag editor, lifecycle status editor, owner editor, optional fixed/regressed run fields, status history, notes editor, and replay link.
Components¶
RunSummaryCard.tsx¶
Displays either closed-loop or open-loop metrics depending on run_type.
Closed-loop fields:
- pass rate
- safety
- collisions
- runtime
Open-loop fields:
- samples
- ADE
- FDE
- latency
ResetDashboardButton.tsx¶
Client-side dashboard reset control. It asks for confirmation, calls DELETE /runs through clearRuns(), shows how many runs were removed, and refreshes the server-rendered dashboard data.
MetricsChart.tsx¶
Uses Recharts to show run trends.
RegressionDiff.tsx¶
Displays the deltas object from regression.json.
ScenarioRunLauncher.tsx¶
Client-side run launcher used by /run-lab. It builds the launch request from selected scenario packs, local scenarios, agent, simulator, and regression gate settings.
ReplayViewer.tsx¶
Client-side replay controls:
- play/pause button state
- scrubber
- frame stepping
- event markers
- failure deep-link target from
?t=<timestamp>&frame=<frame_index> - jump-to-failure button when a target frame can be resolved
EventTimeline.tsx¶
Readable scenario event list shown beside the replay viewer. It renders normalized timeline events from the replay API, including scenario start, goal reached, collision, near miss, offroad, hard brake, timeout, and assertion failure events. Clicking an event seeks the replay to the closest frame for the event timestamp.
ScenarioReplayPanel.tsx¶
Client wrapper for replay controls and timeline events. It can be used with controlled frame state so page-level replay surfaces stay in sync.
ScenarioReplayWorkspace.tsx¶
Coordinates the scenario detail replay area. It keeps ReplayViewer, EventTimeline, and TrajectoryMap on the same selected frame so scrubber movement, playback, event clicks, and the scene overlay stay in sync.
TrajectoryMap.tsx¶
Renders the replay scene from timeline frames, GeoJSON tracks, and normalized timeline events. The scene shows the driven route, remaining route, current ego pose, visible actors, event markers, route progress, clearance, and active-frame events.
FailureEditor.tsx¶
Client-side editor surface for tags, notes, lifecycle status, owner, fixed-in run, and regressed-in run. Saves use a single failure update request so related edits persist together. The returned failure payload refreshes the visible status history after a successful save.
Replay links are built from replay_url when present, or from run_id, scenario_id, timestamp, and frame_index as a fallback.
Common Issues¶
Dashboard shows zeros¶
Usually the newest run is open-loop. Open-loop runs do not have closed-loop metrics, so the UI must display open-loop metrics instead.
This has been handled by run_type.
Dashboard shows no runs¶
Check:
http://127.0.0.1:8000/runs
If it returns [], restart the backend from the project root or set:
ROBOCI_RUNS_DIR=/absolute/path/to/RoboCI/runs roboci serve
If you just used Reset on the dashboard, [] is expected until you launch or create another run.
Regression diff does not update¶
The dashboard reads regression.json. Normal roboci run writes an empty gate result. Run roboci compare to populate metric deltas.