Skip to content

dashboard: side-by-side v2 dashboard mirroring ref-impl#398

Open
arnauorriols wants to merge 19 commits into
mainfrom
polecat/v2-dashboard
Open

dashboard: side-by-side v2 dashboard mirroring ref-impl#398
arnauorriols wants to merge 19 commits into
mainfrom
polecat/v2-dashboard

Conversation

@arnauorriols
Copy link
Copy Markdown
Member

@arnauorriols arnauorriols commented May 14, 2026

Summary

Adds a v2 dashboard that mounts at #/v2 alongside the existing one. Both dashboards live in the repo simultaneously so the layouts can be compared in-browser; the existing dashboard is unaffected.

The v2 layout mirrors ref-impl's dashboard shell — top tab strip, card-based content surface, page header with optional actions. Palette stays in clawpatrol's existing tokens (canvas/navy/rust) so v2 still feels part of this app.

Design choices

  • Route prefix: #/v2. Hash routing, matches the existing app. The toggle in v1's header links to #/v2; the toggle in v2's shell links to #/.
  • File layout: www/src/v2/ self-contained, with cards/ and pages/ subfolders mirroring ref-impl's component organisation. Nothing in www/src/components/ knows about v2 except ConnectModal and the credential cards, which v2 imports verbatim.
  • Tabs: Overview, Actions, Approvals (ref-impl's "Pending", renamed per the issue), Rules, Analytics, Profiles, Devices, Settings.
  • Read-only: per the issue, every editing affordance from ref-impl is dropped. The only mutating actions kept are HITL approve / deny (the only way to resolve a pending request in clawpatrol today) and the credential connect / disconnect flows that already exist in v1.
  • Credential modals: v2 Settings reuses IntegrationsCards + ConnectModal verbatim. No reimplementation of ref-impl's credential UX.
  • Data: v2 talks to clawpatrol's existing API — /api/state, /api/rules, /api/profiles, /api/analytics, /api/hitl/pending, /api/actions/:id, /api/config. No new endpoints added.

Data-mapping gaps vs ref-impl

ref-impl's data model is richer than clawpatrol's in several places. Rather than extending the backend, these surfaces render empty-state placeholders and the v2 page notes the gap inline:

  • Profiles: ref-impl exposes profile objects with integration lists, session counts, and default LLM/Human approver pointers. clawpatrol's /api/profiles returns a flat string list. v2's Profiles page lists the names with a per-profile device count derived from /api/state.
  • Analytics: ref-impl's AnalyticsPage is a 9-panel canvas dashboard (dot-charts, latency / size heatmaps, status-class-over-time, LLM cost / token streams). clawpatrol's /api/analytics returns events + by-host / by-device aggregates. v2 projects those into summary cards; the canvas-dependent panels would need new backend series.
  • Devices: ref-impl splits registered device from active session and gates new devices behind an approval queue. clawpatrol collapses both into a single Agent keyed by IP, so the "Awaiting approval" device list is absent.
  • Actions: clawpatrol has no dedicated /api/actions list endpoint; v2 taps /api/analytics?range=24h and projects EventRecord rows. Cost / token telemetry from ref-impl's action detail isn't on the wire.

Screenshots

Captured against a minimal screenshot-only gateway config; the live SSE stream is blocked at the proxy layer for v1 capture so headless Chrome completes the page load.

v2 dashboard

  • docs/screenshots/v2-01-overview.png — Overview
  • docs/screenshots/v2-02-actions.png — Actions
  • docs/screenshots/v2-03-approvals.png — Approvals (renamed from Pending)
  • docs/screenshots/v2-04-rules.png — Rules (grouped by family)
  • docs/screenshots/v2-05-analytics.png — Analytics
  • docs/screenshots/v2-06-profiles.png — Profiles
  • docs/screenshots/v2-07-devices.png — Devices
  • docs/screenshots/v2-08-settings.png — Settings (credential modals + HCL viewer)

Existing v1 dashboard, for comparison

  • docs/screenshots/v1-01-main.png — main (agents + live requests)
  • docs/screenshots/v1-02-analytics.png — analytics
  • docs/screenshots/v1-03-settings.png — settings

Test plan

  • Open #/, click "TRY V2" in the header, land on #/v2 with all eight tabs visible.
  • In v2, click each tab and confirm the page renders without console errors.
  • Click "switch to v1" from v2; land back on #/.
  • In v2 Settings, confirm credential cards render and connect / disconnect flows work the same as in v1 Settings.
  • Configure a credential in v1, switch to v2 — the connected state mirrors across.
  • npm run format:check && npm run lint && npm run build from www/ are clean.
  • gofmt -l . and go test ./... from the repo root are clean.

Mounts at #/v2 with its own tab-strip shell (Overview, Actions,
Approvals, Rules, Analytics, Profiles, Devices, Settings). Both
dashboards talk to the same backend; v2 is read-only everywhere
except the credential modals, which are the existing clawpatrol
components reused verbatim.

Toggle link in each shell switches between v1 and v2 without
editing the URL.
@arnauorriols arnauorriols force-pushed the polecat/v2-dashboard branch from 4a1a93c to bee8e05 Compare May 14, 2026 17:30
Copy link
Copy Markdown
Member Author

@arnauorriols arnauorriols left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take new screenshots after the requested changes in the other comments. Also, try adding data (even if it is synthetic data written directly to the sqlite) so that the screenshots are not the empty state.

Comment thread www/src/components/Header.tsx Outdated
title="switch to v2 dashboard"
>
try v2
</a>
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[bot-reply]
Pushed 27d0d9a addressing this comment:

  • Removed the "try v2" link (and its surrounding <a> element) from www/src/components/Header.tsx.

Comment thread www/src/v2/pages/ProfilesPage.tsx Outdated
// Gap: unclaw's per-profile workspace (integrations list,
// default LLM/Human approver pickers, session count) requires
// profile metadata that clawpatrol's read API doesn't surface.
// Renders as empty-state.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extend /api/profiles so that it can serve also this page.

Comment thread www/src/v2/pages/AnalyticsPage.tsx Outdated
<p>
The canvas-based dot charts, gridded heatmaps, and LLM cost-over-time panels that
unclaw's <code className="font-mono text-xs">AnalyticsPage</code> renders would need new
backend endpoints to power. Out of scope for cl-r3e (no new endpoints).
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extend the API to support the latency graph as it is in unclaw. Ignore the llm usage graph and the decisions graph.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[bot-reply]
Pushed f874b95 addressing this comment:

  • Extended /api/analytics with a dots field shaped to match unclaw's per-request projection (t, us, status, host, agent, id)
  • Ported unclaw's LatencySection to the v2 AnalyticsPage — log/linear toggle, color-by host/agent/status, dot scatter + binned histogram
  • LLM usage and decisions graphs intentionally not ported, per your note

arnauorriols and others added 2 commits May 14, 2026 18:38
…ls (cl-8zh4)

/api/profiles now returns []ProfileInfo (name, endpoints[], rule_count,
credentials[]) instead of a flat []string. The v2 ProfilesPage renders
real per-profile metadata; DevicePage maps .name for its picker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arnauorriols
Copy link
Copy Markdown
Member Author

arnauorriols commented May 14, 2026

[bot-reply]
Pushed 243d2c8 addressing this comment:

  • Extended /api/profiles from []string to []ProfileInfo with name, endpoints, rule_count, and credentials (walks endpoint + tunnel credential bindings, dedup-sorted).
  • www/src/v2/pages/ProfilesPage.tsx now renders per-profile endpoints, rule count, and credential chips alongside the device count; dropped the "Gap vs ref-impl" placeholder card.
  • www/src/components/DevicePage.tsx picker maps the new shape to names — no behavior change.

Extends /api/analytics with a `dots` field shaped like unclaw's
per-request projection (t, us, status, host, agent, id), and
ports unclaw's LatencySection — log/linear toggle, color-by
host/agent/status, dot scatter + binned histogram — to the v2
AnalyticsPage. LLM and decisions panels intentionally not ported.
@arnauorriols
Copy link
Copy Markdown
Member Author

Take new screenshots. try adding data (even if it is synthetic data written directly to the sqlite) so that the screenshots are not the empty state.

Reviewer asked for screenshots that aren't the empty state. Captured
against a screenshot-only gateway booted on a fresh sqlite seeded
directly with 8 devices across 4 profiles, 8 coding-agent sessions
(claude / codex with token + ctx counts), 3 connected credentials
(claude / github / notion-oauth), and 480 actions over the last 24h
(allow / deny / approved across http / sql / k8s).

Analytics, Actions, Devices, Profiles, Rules, Settings, and both
Overview pages now render real data. Two pages stay close to empty
state by design:

  - Approvals — HITL pending lives in-memory, not in sqlite; the
    "Nothing waiting on you" copy is what an operator sees when the
    queue is genuinely empty.
  - v1 main — per-agent Reqs / Activity is in-memory too. Devices,
    profiles, and integrations badges all populate from the seed.
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed ccbbaf4 re-capturing all 11 screenshots against a populated database:

  • Booted a screenshot-only gateway with a wireguard control block (config-only — no live traffic), seeded the sqlite clawpatrol.db directly with 8 devices across all 4 profiles (default / support / data / platform), 8 claude+codex sessions with realistic token/context counts, 3 connected credentials (claude OAuth, github OAuth, notion), and 480 actions rows over the last 24h spread across allow / deny / approved verdicts on http / sql / k8s endpoints.
  • v2 #/v2/analytics and v1 #/analytics?range=24h now show the latency dot plot, histogram, top devices, top hosts, and 480-request totals.
  • v2 #/v2/profiles shows real device counts per profile; #/v2/devices lists 8 devices with integration badges; #/v2/rules groups the 28 rules by HTTP / K8S / SQL family.
  • v1 main and v2 overview render the device table with profiles + integration icons; v1+v2 Settings show claude/github connected, the rest awaiting secrets.

Two pages stay near the empty state by design, since the data lives in-memory and not in sqlite:

  • Approvals: hitl.List() reads from an in-memory pool — empty here means an operator really has nothing waiting.
  • v1 main "Live Requests" / per-agent Reqs+Activity: AgentRegistry counters are populated by live traffic; seeding sqlite doesn't feed them. Devices, profiles, and integrations all still populate from the seed.

If having Reqs/Activity render synthetically too is wanted, that needs a code change to hydrate Agent.Reqs / BytesIn / BytesOut from the actions table at boot, which felt out of scope for a screenshot pass — happy to open a follow-up bead for it.

@arnauorriols
Copy link
Copy Markdown
Member Author

  1. Remove the approvals page, and instead highlight the actions that require approval in the actions page. Be creative on how you think this highlighting will work best.
  2. each rule in the rule page can expand to show the last 5 decisions. Clicking on each decision navigates to the action details page
  3. In the profiles page, show the icon of the credential type before the name of the credential. Make sure the icon is not too small. If the credential is connected, give it a green border. Otherwise, without border. Also, take the whole wide of the row for the credential icons
  4. Remove the integrations column in the devices table.
  5. In the rules page, we should only show the rules of one profile at a time. Add a dropdown at the top-right of the page to select the profile. The profile should be routeable with a hash or a query string

Five UX adjustments raised in the PR review:

1. Approvals tab folded into Actions. Pending HITL requests now
   appear as butter-toned highlighted rows at the top of the
   Actions table with inline Approve/Deny buttons. The tab's
   pending-count badge moves onto the Actions tab; /v2/approvals
   redirects to /v2/actions for shareable links that pre-date the
   change.
2. Rule rows expand to show the last five decisions. Each
   decision is a clickable link into the action detail page. Hung
   off a new ?rule= filter on /api/analytics and the previously-
   missing rule/endpoint/approver projections on the same query.
3. Profile credentials get plugin-type icons (postgres logo for
   postgres_credential, etc.) at a readable 24px, take the full
   row width, and gain a green border when connected.
4. Devices table drops the integrations column. Per-credential
   chips live on the Profiles page now, which is the right place
   to see what a device's profile binds.
5. Rules page filters to one profile at a time via a top-right
   dropdown. Selection mirrors into the URL hash as ?profile=<name>
   so a link into a specific profile's rule set is shareable.

(cl-atl0)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed 257b1ce addressing this comment:

  • (1) Removed the Approvals tab; pending HITL requests now appear as highlighted (butter-toned, left-bordered) rows at the top of the Actions table with inline Approve/Deny buttons. The pending count badge moved onto the Actions tab. /v2/approvals redirects to /v2/actions for old links.
  • (2) Each rule row in the Rules page expands on click and lazily fetches the last 5 decisions for that rule (new optional ?rule= filter on /api/analytics); each decision links to the action details page. Also fixed the long-broken Rule/Approver columns by including those projections in the analytics SELECT.
  • (3) Profiles page credentials now render as full-row chips with the plugin-type icon (24px, e.g. postgres logo for postgres_credential) and a green border when the credential is connected.
  • (4) Removed the Integrations column from the Devices table.
  • (5) Rules page now scopes to one profile at a time via a top-right Profile dropdown. The selection is mirrored into the URL hash as ?profile=<name> (e.g. #/v2/rules?profile=eng-platform) for shareable links.

@arnauorriols
Copy link
Copy Markdown
Member Author

The screenshots are not yet good enough:

  1. The actions table does not show any rule or approver. All of them show "-" instead.
  2. Still see an approvals page screenshot. I want to see an screenshot with an action pending approval highlighted in the actions table instead
  3. I want an screenshot showing the expansion of a rule to see the last actions that matched the rule, alongside their verdict
  4. Instead of grouping rules by facet family, group them by endpoint

Two of the four items the reviewer flagged on PR #398 — the other
two are screenshot recaptures that have to happen against a running
dev gateway and aren't tractable from this worktree.

1. dev_seed.go was inserting actions through `endpoint, rule` but
   skipping `approver`, `approver_type`, `approver_by`. The
   analytics query returns those columns, so the Approver column on
   the v2 actions table rendered "—" for every row even when the
   verdict was "approved" / "denied". Populate the three columns
   for approved/denied verdicts (human_approver "ops", named
   reviewer from a small pool), leave NULL otherwise so the
   non-approve allow/deny rows behave like prod.

2. RulesPage grouped by facet family ("HTTPS", "SSH", "POSTGRES").
   Operators reading the page ask "what governs api.github.com?",
   not "what's in the https family?" — regroup by endpoint name
   so each card answers that question directly. The endpoint
   column is dropped from the inner table (the card title carries
   it), and groups are sorted alphabetically for stable ordering.

(cl-u2sf)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed aa43849 addressing two of the four items:

  • Test issue #1 actions table shows "—" for rule/approver: dev_seed.go was inserting actions through endpoint, rule but never approver / approver_type / approver_by, so the analytics query returned NULL for every row. Now populates the three columns for approved/denied verdicts (human_approver "ops", named reviewer from a small pool); leaves NULL on plain allow/deny so the non-approve rows behave like prod.
  • HITL for slack #4 group rules by endpoint: RulesPage now buckets per endpoint name (one card per endpoint) instead of per facet family. The redundant Endpoint column moves into the card title; groups sorted alphabetically.

Items #2 (pending row highlighted in actions screenshot) and #3 (rule-expansion screenshot) are not in this commit — they're screenshot recaptures against a running gateway, which this worktree can't drive headlessly cleanly. The screenshots commited in ccbbaf4 still need to be regenerated against the now-fixed seed, plus the two new framings you asked for. Flagging for the next pass.

Note: I pushed from a temp branch because polecat/v2-dashboard is checked out in another worktree on this rig (commit f874b95, behind origin) — push was a fast-forward, no force, no merge conflict.

@arnauorriols
Copy link
Copy Markdown
Member Author

Can you please take a new set of screenshots after the changes?

Two rounds of review changes (nuka's UX adjustments and raider's
seed/regroup) shipped without screenshots that reflect them.
Recaptured against the same dev-seed shape used by nitro (24
devices, 480 actions over 24h, 14 credentials across 5 profiles)
so the new behaviour is visible in the PR thread.

What's different vs the old captures:

  - Approvals tab is gone — folded into Actions. The new
    v2-02-actions.png shows the pending HITL rows highlighted at
    the top of the table with inline Approve/Deny buttons.
    Pending-count badge moved onto the Actions tab.
  - Rules page regroups by endpoint name (not facet family), and
    a profile picker scopes the view. v2-03-rules.png is captured
    against profile=ops-team via the new ?profile= hash filter
    so all six rule groups are visible.
  - Profiles page renders plugin-type credential icons (postgres /
    notion / slack / clickhouse logos), full-row width, green
    border on connected.
  - Devices page drops the integrations column.
  - Actions table's Approver column now populates for
    approved/denied verdicts — raider's seed fix.

File renames track the new tab order (no more Approvals):

  v2-04-rules     → v2-03-rules
  v2-05-analytics → v2-04-analytics
  v2-06-profiles  → v2-05-profiles
  v2-07-devices   → v2-06-devices
  v2-08-settings  → v2-07-settings
  v2-03-approvals → removed
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed 6e3f141 with a fresh set of screenshots captured against the same dev-seed shape (24 devices, 480 actions, 14 credentials across 5 profiles) so the recent feedback rounds are visible in the PR thread.

What's reflected in the new captures:

  • Actions (v2-02-actions.png) — pending HITL rows are highlighted at the top of the table with inline Approve/Deny; the pending-count badge moved onto the Actions tab.
  • Rules (v2-03-rules.png) — regrouped by endpoint name; captured with ?profile=ops-team so all six rule groups (anthropic-api, github-api, notion-api, pg-corp, slack-hooks, plus the GitHub read/write split) are visible. The Approvals tab is gone.
  • Profiles (v2-05-profiles.png) — plugin-type credential icons (postgres / notion / slack / clickhouse) at 24px, full-row width, green border when connected.
  • Devices (v2-06-devices.png) — integrations column dropped.

File numbering follows the new tab order (Approvals folded into Actions, so v2-03 is now Rules, v2-04 Analytics, …, v2-07 Settings). v2-03-approvals.png removed.

PR #398 review item #3 asked for "a screenshot showing the expansion
of a rule to see the last actions that matched the rule, alongside
their verdict". The Rules page has the expansion behaviour wired up
(click a row → /api/analytics?range=24h&rule=<name>&limit=5 → render
the five most recent matching events), but no captured screenshot
demonstrated it — v2-03-rules.png shows the collapsed listing only.

Captured against the same dev-seed shape used by earlier rounds (24
devices, 500 actions, 2 profiles, the four-endpoint policy that
mirrors what the seeder tags actions with) with the github-reads
row expanded. The capture shows:

  - Rules regrouped by endpoint (cards: ANTHROPIC, GITHUB-API,
    OPENAI, SLACK) — repeats the #4 grouping change.
  - github-reads row expanded under GITHUB-API, with five rows of
    "Last 5 decisions" showing timestamp, device hostname, verdict
    pill (allow/deny), method, and endpoint + path.
  - The profile picker scoped to ops-team (top-right).

Filename uses the `v2-03b-` prefix so v2-03-rules.png (the all-rules-
collapsed view) stays as the canonical Rules screenshot and the
expansion is supplemental — two screenshots covering the regrouping
and expansion behaviours separately.

(cl-u2sf)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed ae16db0 addressing item #3:

  • New screenshot docs/screenshots/v2-03b-rule-expanded.png — captured on the Rules page with ?profile=ops-team and the github-reads row expanded. Shows the "Last 5 decisions" panel inline under the row, with timestamp, device hostname (kira-mac, ci-runner-2, demo-vm-west, ubuntu-dev-2, macbook-sam), verdict pill (allow / deny), method, and endpoint + path for each matching event. The endpoint grouping (anthropic, github-api, openai, slack) and the profile picker (top-right) are visible in the same frame.

Kept the existing v2-03-rules.png (all rules collapsed) as the canonical Rules screenshot — the new file is the supplemental expansion shot, so the two together cover the regrouping (#4) and the expansion (#3) without re-capturing what's already correct.

Captured against the same dev-seed shape (24 devices, 500 actions over 24h) booted from a screenshot-only gateway with a four-endpoint policy that mirrors what dev_seed.go tags actions with, so the expansion has real seeded data behind it.

Items #1 (approver column populated), #2 (pending row highlighted in actions), and #4 (group rules by endpoint) were already addressed by aa43849 + 6e3f141 in the earlier rounds.

PR #398 item #4 second pass. The grouping by endpoint already
landed in aa43849, but a rule declared with `endpoints = [a, b,
c]` emits one RuleSummary per attachment site, so the same row
shows up under each endpoint card with no visual cue that it's
the same rule. Operators reading the second card had no signal
that editing the rule changes what's enforced on the first.

Count distinct endpoints per rule name within the filtered set
and render a "shared · N endpoints" chip on the name cell when
N > 1. Single-endpoint rules render unchanged. Recaptured
v2-03-rules.png against `?profile=ops-team` with a new
multi-endpoint rule (`block-debug-methods` across the four
https endpoints in the profile) so the chip is visible in the
screenshot — the existing single-endpoint rows stay clean.

(cl-pdf2)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed 1ca95f8 closing the loop on item #4 from the 12:43 comment.

The endpoint regrouping itself already landed in aa43849 — the page bucketed rules by endpoint name and v2-03-rules.png (from 6e3f141) reflected that. What was still missing: rules declared with endpoints = [a, b, c] emit one RuleSummary per attachment site, so the same rule renders as a separate row under each endpoint card. Without a marker the operator reading the second card has no way to know it's the same rule — and that editing it changes what's enforced on the first.

What this commit changes:

  • RulesPage.tsx: within the filtered profile, count distinct endpoints per rule name. Single-endpoint rules render unchanged; rules with N > 1 endpoints get a "shared · N endpoints" chip next to the name on every row, with a hover-title spelling out the relationship.
  • docs/screenshots/v2-03-rules.png: re-captured against ?profile=ops-team with a new multi-endpoint rule (block-debug-methods, denies TRACE / CONNECT across the four https endpoints in the ops-team profile) so the chip is visible on its rows. The existing single-endpoint rules (anthropic-allow, github-reads/writes, notion-reads/writes, slack-allow, pg-reads/writes) stay clean — confirms the marker only fires for the multi-attachment case.

No backend change: /api/rules was already emitting one row per (rule × endpoint × profile); the marker is a frontend-only derivation.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 18, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
clawpatrol ac35edd Commit Preview URL

Branch Preview URL
May 19 2026, 01:28 PM

@arnauorriols
Copy link
Copy Markdown
Member Author

In the overview page, I want to see:
First row (3/4 of the vertical space):

  1. (1/4 horizontal space) Recent activity (list of recent actions by any device). This table must include the device and the profile of the device. If all credentials are connected, show a list of connected devices instead.
  2. (3/4 horizontal space) Unconfigured Credentials (credentials that are not yet connected and need action by the user)
    Second row (1/4 vertical space):
  3. (100% horizontal space) Pending Approvals (table with actions that are waiting for human approval). If there's no pending approval, show a table with the most recent rule verdicts.

I don't want the metrics boxes.

Replaces the four-up metrics strip + Integrations / Devices /
Pending cards with the three-panel layout requested in the PR
comment:

  row 1 (~75% vertical):
    [25%] Recent activity — device, profile, verdict, request
    [75%] Unconfigured credentials — list with "Connect →" CTA
          deep-linking into the Settings tab

  row 2 (~25% vertical):
    [100%] Pending approvals — first ten with inline "Review →"
           jump into the Actions tab

Fallback empty-states per the spec:

  Recent activity → Connected devices when every declared
  credential is connected (no "needs attention" rows to surface).

  Pending approvals → Recent rule verdicts when the HITL queue
  is empty.

The panel chrome reuses Card's two-tone header look but is a
local sibling (Panel) because Card's `mb-4` and untensioned body
fight the parent `grid-rows-[3fr_1fr]` height split. Each panel
body is `overflow-auto` so 30+ activity rows don't push the
bottom row off-screen.

Screenshots recaptured against the standard 24-device / 480-
action / 14-credential dev-seed:

  docs/screenshots/v2-01-overview.png             — primary state
  docs/screenshots/v2-01b-overview-no-pending.png — fallback row 2

PR #398 (cl-jg3a)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply] Overview page rebuilt to match the 11:08 spec.

Commit: 5216938 — "v2 dashboard: rebuild Overview per PR #398 11:08 spec"

What changed

The four-up metrics strip and Integrations / Devices / Pending cards are gone. The page now renders the three panels you asked for:

  • Row 1 (~75% vertical):
    • [25% horizontal] Recent activity — list of recent actions across any device, each row showing hostname + profile + verdict + method + endpoint.
    • [75% horizontal] Unconfigured credentials — declared credentials with connected = false, with a "Connect →" CTA that deep-links into the Settings tab.
  • Row 2 (~25% vertical):
    • [100%] Pending approvals — first ten with inline "Review →" jump into the Actions tab.

Empty-state fallbacks (per the spec)

  • Recent activity → Connected devices when every declared credential is connected (nothing to action there).
  • Pending approvals → Recent rule verdicts when the HITL queue is empty.

Screenshots

Both captured against the standard dev-seed (24 devices, 480 actions, 14 credentials across 5 profiles):

  • Primary: docs/screenshots/v2-01-overview.png
  • Fallback row 2 (no pending → recent verdicts): docs/screenshots/v2-01b-overview-no-pending.png

Notes

  • Panel chrome reuses Card's two-tone header look but is a local Panel sibling — Card's mb-4 and untensioned body fight the parent grid-rows-[3fr_1fr] height split. Each panel body is overflow-auto so 30+ activity rows don't push the bottom row off-screen.
  • Page height is h-[calc(100vh-220px)] min-h-[640px] so the 3:1 vertical ratio is visible on a normal screen without forcing scroll on smaller ones.

— cl-jg3a (re-attempt of cl-rogp)

@arnauorriols
Copy link
Copy Markdown
Member Author

  1. In the first row of the overview, let's swap the boxes: 25% credentials, then 75% recent activity
  2. In the profiles page, do not show each credential as a row. What I want is to show pills below the profile. I only want to show credentials, and I want to see them as pills with the credential type logo, and the credential name as label of the pill. They are clickable, with the same behavior as in the settings page. if the credential is already connected, the pill shows a green border
  3. Show activity graph in each device row

Update the screenshots

Three review items from arnauorriols on PR #398:

  1. Overview row-1 columns swap. The 25% column now holds
     Unconfigured credentials and the 75% column holds Recent
     activity / Connected devices. (Old order was credentials at
     75% / activity at 25%.) Header comment updated.

  2. Profiles page renders each profile's credentials as a row of
     pills below the endpoint chips — plugin-type logo + bare name,
     green border when connected, no border when not. Pills are
     anchors to `#/v2/settings?connect=<id>`; the existing
     `pendingConnect` plumbing in IntegrationsCards picks the id up
     and opens the same modal the Settings cards drive (OAuth,
     Tailscale parked URL, slots-secrets — handled per type by
     handleConnect, unchanged). Wired pendingConnect through
     V2App.parseV2Route → V2SettingsPage → IntegrationsCards and
     drop the query string via window.history.replaceState once
     consumed so a reload doesn't reopen the modal.

  3. Devices page adds an Activity column rendering the existing
     Sparkline against Agent.activity (same data the v1 main page
     graphs). Column sits between In/Out and Last seen.

Screenshots recaptured against the standard 24-device / 480-action
/ 14-credential dev-seed (gateway.hcl: /tmp/screenshot-gateway-jg3a.hcl,
state_dir + ports rebased onto chrome's worktree):

  docs/screenshots/v2-01-overview.png             — credentials L / activity R / pending bottom
  docs/screenshots/v2-01b-overview-no-pending.png — same layout, pending → recent verdicts fallback
  docs/screenshots/v2-05-profiles.png             — pills + green-border connected state
  docs/screenshots/v2-06-devices.png              — new Activity column

PR #398 (cl-wxqm)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed c8390a3 addressing this comment:

  • Overview row 1 columns swapped — credentials now in the 25% column, recent activity / connected devices in the 75% column. See docs/screenshots/v2-01-overview.png and v2-01b-overview-no-pending.png.
  • Profiles page renders credentials as horizontal pills (plugin-type logo + bare name, green border when connected). Pills link to #/v2/settings?connect=<id>; the existing pendingConnect flow in IntegrationsCards picks the id up and opens the same modal the Settings cards drive (OAuth / Tailscale parked URL / slots, per credential type). See docs/screenshots/v2-05-profiles.png.
  • Devices table adds an Activity column rendering the existing Sparkline against Agent.activity (same data v1's main page graphs). See docs/screenshots/v2-06-devices.png.
  • All four screenshots recaptured against the standard 24-device / 480-action / 14-credential dev-seed.

@arnauorriols
Copy link
Copy Markdown
Member Author

  1. In the recent activity table of the overview page, show the data as a single row. Include the timestamp, and structure the row sow that the data is vertically aligned into borderless and headerless columns (timestamp, device, profile, method/verb, status-code, path/query, rule verdict, latency
  2. In the credentials table of the overview page, remove the "needs setup" pill, it's redundant. Add the credential type logo.

update the screenshots

…ntial logos

Per @arnauorriols on PR #398 (comment 4478282358):

  1. Recent activity now renders one event per row across borderless,
     headerless columns: timestamp · device · profile · method ·
     status · path · verdict · latency. The old two-line layout
     wasted vertical space and made scanning across the same field
     impossible.
  2. Unconfigured credentials no longer carries the "needs setup"
     pill (Connect → button already implies it) and now leads with
     the credential-type logo via IntegrationIcon, matching the
     iconography on Profiles / Settings.

Both overview screenshots re-captured against the dev-seed shape
(24 devices, 480 actions, 14 credentials) used by prior PR #398
rounds.
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed 7f4a896 addressing this comment:

  • Recent activity: events now render as a single row with borderless, headerless columns (timestamp · device · profile · method · status · path · verdict · latency) — vertically aligned across rows.
  • Unconfigured credentials: dropped the redundant "needs setup" pill; each row now leads with the credential-type logo via IntegrationIcon (same source as Profiles / Settings).
  • Re-captured docs/screenshots/v2-01-overview.png and v2-01b-overview-no-pending.png against the dev-seed shape so the new layout is visible in the PR thread.

@arnauorriols
Copy link
Copy Markdown
Member Author

In the profiles page, I don't want to see the endpoints as pills, only the credentials. And I currently don't see the logos of the credentials (however, it might be due to the screenshot being old). The read-only text at the right of the row is redundant, and should be removed. Move the stats of each profile at the same row as the name of the profile, anchored to the right of the row.

Take a new screenshot of the profiles page after the changes

Four review items from @arnauorriols on PR #398 (comment 4478585004),
all on the Profiles page:

  1. Endpoint pills removed. Profiles used to render endpoint chips
     below the meta line, before the credential pills. The reviewer
     wanted only credentials visible at the row level (the endpoint
     count still appears in the stats summary). Devices already get a
     standalone Endpoints page; the per-profile chip strip was noise.
  2. "read-only" pill removed from the right of each row. The page
     subhead already says profiles live in gateway.hcl; the per-row
     tag was redundant.
  3. Stats moved onto the profile's name row, right-anchored
     (`devices · endpoints · rules · credentials`). Previously they
     occupied their own line under the name, which broke the eye line
     when scanning down the list.
  4. Credential logos already wired through IntegrationIcon — the
     missing-logo report in the comment was a stale screenshot.

Screenshot re-captured against the dev-seed shape (24 devices, 480
actions) the prior PR #398 rounds use.

(cl-hrfl)
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed 385d9a2 addressing this comment on the Profiles page:

  • Removed the endpoint pills (endpoint count still shown in the stats line).
  • Removed the redundant "read-only" tag from each row.
  • Moved the stats line (devices · endpoints · rules · credentials) onto the profile name row, right-anchored.
  • Credential logos already render via IntegrationIcon; the missing-logo report was a stale screenshot. Re-captured docs/screenshots/v2-05-profiles.png against the dev-seed shape.

@arnauorriols
Copy link
Copy Markdown
Member Author

Sync with main, fixing the git conflicts. And replicate the new redentials section of the settings page of v1, into the settings page of v2.

Replicate the v1 settings page credentials section (per-type cards
with expanding details table) in the v2 settings page. The post-merge
v2 page was still wired to IntegrationsCards, which no longer accepts
pendingConnect / onConsumePendingConnect after the main-side
credentials redesign — the type error stopped the build.

Preserve the ?connect=<id> deep link from the Profiles page pills by
firing onConnect for the deep-linked credential from the V2 settings
page itself and immediately clearing the query string.
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Addressed:

  • Synced with main: merged origin/main into polecat/v2-dashboard (67992ef). Only one textual conflict — www/src/App.tsx parseRoute(), where the v2 sub-route dispatch lived next to a const h = window.location.hash rewrite on main. Kept the v2 path (query-string strip + parseV2Route dispatch).
  • Replicated v1 credentials section in v2 settings (1c9e4c1): the v2 settings page now renders CredentialsTypeGrid (per-type cards with the expanding details table) instead of IntegrationsCards. Same connect / disconnect / update flows; the ?connect=<id> deep link from the Profiles pills is preserved at the page level (fires onConnect and drops the query). Without this, the v2 settings page was still passing pendingConnect / onConsumePendingConnect to IntegrationsCards, which the credentials redesign on main removed — tsc --noEmit was breaking on it.

Quality gates: gofmt -l ., go vet ./..., go test ./..., npx oxfmt --check, npm run lint:github, npm run build — all green.

@arnauorriols
Copy link
Copy Markdown
Member Author

sync with main and fix conflicts

Main renamed www/ → dashboard/ in #452. The v2 files were the only
www/src/ content that survived the merge, but they imported sibling
modules via ../lib/api and ../components/* — paths that now live
under dashboard/src/. Moving the v2 tree into dashboard/src/v2/ makes
dashboard/src/App.tsx's existing `import ... from "./v2/V2App"` resolve
and lets `make dashboard` build the bundle (cl-njbp).
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Synced with main and fixed the resulting conflicts:

  • 014524d Merge remote-tracking branch 'origin/main' into polecat/v2-dashboard — straight merge, no textual conflicts.
  • cff6621 v2 dashboard: relocate www/src/v2 → dashboard/src/v2 after main rename — main renamed www/dashboard/ in Prep repo for launch: README rewrite + cmd/clawpatrol move #452, so the v2 tree was orphaned (its ../lib/api / ../components/* imports pointed at a directory that no longer exists). Moved www/src/v2/dashboard/src/v2/ so dashboard/src/App.tsx's existing import { parseV2Route, V2App } from "./v2/V2App" resolves, and updated one comment in V2App.tsx that referenced the old path.

Verified locally: make fmt-check, make lint, make dashboard, go build ./..., go vet ./..., and go test ./... all green.

@arnauorriols
Copy link
Copy Markdown
Member Author

  1. remove any gastown reference in the codebase. I see some comments mentioning "polecats".
  2. Delete all screenshots

Address PR #398 review:
- Remove "Polecat decisions" comment block from V2App.tsx
- Drop local gt path from wg-ephemeral-sessions-design.md
- Delete docs/screenshots/ and site/doc/screenshots/pr-231-settings-page/
@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply]
Pushed ac35edd addressing this comment:

  • Removed the // Polecat decisions... comment block from dashboard/src/v2/V2App.tsx
  • Dropped the local /home/gastown/... path reference from doc/wg-ephemeral-sessions-design.md
  • Deleted all screenshots added by this PR (docs/screenshots/ and site/doc/screenshots/pr-231-settings-page/)

@arnauorriols
Copy link
Copy Markdown
Member Author

[bot-reply] Extending this PR with #474 — adds a Devices table with per-row Status column to the v2 Overview (cl-cw2i). Based on polecat/v2-dashboard so it merges cleanly once this PR lands.

@piscisaureus piscisaureus changed the title dashboard: side-by-side v2 dashboard mirroring unclaw dashboard: side-by-side v2 dashboard mirroring ref-impl May 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