feat(admin): show target health in the dashboard

Add a Health column to the MCP servers and A2A agents tables in
TargetsView. An unhealthy target renders a destructive badge with the
age of its last check and carries the failure count, source, and
scrubbed last error in the title. An unknown target renders an outline
badge and, when it has failed but never succeeded, the same failure
details in its title. A healthy target renders muted text with its last
observed latency and no badge, matching the providers' convention.

Add AdminTargetHealthView to the API types with the wire contract the
Go side emits, a bare formatElapsedAgo helper next to formatAgo, and
column-cell tests for all three states. Regenerate the baked admin
assets.

Claude-Session: https://claude.ai/code/session_01EebV5jyWvYocByNQ3oss1w
This commit is contained in:
2026-09-03 02:49:55 +01:00
parent aad01b8d6f
commit af84ed5eb7
6 changed files with 373 additions and 17 deletions
+39
View File
@@ -316,6 +316,43 @@ export interface AdminTargetCountersView {
requestsPerMonth: number
}
/**
* One configured MCP server's or A2A agent's current health, matching the
* GET /admin/api/targets `health` object the Go side builds against
* (feat/target-health). Two independent sources feed `state`, never
* conflated: 'traffic' is PASSIVE — recorded from the target's own real
* proxied/federated request traffic as it happens, no extra requests
* sent; 'probe' is the gateway's own lazy health check, triggered
* opportunistically by an operator hitting /metrics, /admin, or a listing
* endpoint (never a background poller). `state` is 'unhealthy' once at
* least the configured `failureThreshold` consecutive failures have been
* observed (whether or not this target has ever succeeded), 'healthy'
* once it has succeeded at least once and stays below that threshold, and
* 'unknown' otherwise. `consecutiveFailures` is always present.
*
* 'unknown' reads two different ways server-side, and only ONE of them
* omits the rest of this object (F4, feat/target-health review):
* - never observed by either source at all: every other field is
* omitted — there is truly nothing to report.
* - observed, but never once succeeded, still below `failureThreshold`:
* every other field is PRESENT — `lastCheck`/`lastError`/`latencyMs`/
* `source` all carry a real observation, this target simply has not
* answered successfully yet. Do not treat 'unknown' as "no data" for
* this case; check whether `lastCheck` is set instead.
*
* `lastError` is additionally omitted whenever it is empty (a healthy
* target has nothing to show), and `latencyMs`/`source` are omitted only
* when genuinely not known (the never-observed case above).
*/
export interface AdminTargetHealthView {
state: 'healthy' | 'unhealthy' | 'unknown'
lastCheck?: string
lastError?: string
consecutiveFailures: number
latencyMs?: number
source?: 'probe' | 'traffic'
}
/**
* One configured MCP server's or A2A agent's row in GET /admin/api/targets
* (admin.go: adminTargetView). Access is the group names actually allowed
@@ -329,6 +366,8 @@ export interface AdminTargetView {
url: string
access?: string[]
counters: AdminTargetCountersView
/** See AdminTargetHealthView's own doc comment (feat/target-health) — always present, unlike access above. */
health: AdminTargetHealthView
}
/** GET /admin/api/targets (admin.go: adminTargetsResponse). */