feat(dashboard): GuruConnect v2 Sessions view (pass 2)
All checks were successful
All checks were successful
Active-sessions table with consent-state badges, viewer-token Join, and disconnect, built on the v2 session API and existing UI primitives. - Sessions table: machine, mode (managed/attended), consent badge (granted/pending+pulse/denied/not_required), viewers, started, duration, status. Sticky header, skeleton load, empty/error states. - Join action mints a session-scoped viewer token (POST /api/sessions/:id/viewer-token) and reveals it with the /ws/viewer relay URL and copy buttons. The static viewer.html is intentionally not targeted: it sends the raw login JWT, which the v2 viewer plane rejects. In-dashboard web viewer ships in a later pass. - Authz split mirrors the server mint gate: admin or control permission gets Control; view permission gets View only; neither hides the action. Server remains authoritative; the minted token carries the signed access claim. - Disconnect via confirm dialog (DELETE /api/sessions/:id), invalidates the sessions query. List polls every 8s so consent transitions surface. Passed Code Review (no blockers) and local gates (tsc/lint/build green). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
36
dashboard/src/api/sessions.ts
Normal file
36
dashboard/src/api/sessions.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { http } from "./client";
|
||||
import type { Session, ViewerTokenResponse } from "./types";
|
||||
|
||||
/**
|
||||
* GET /api/sessions — all live sessions known to the relay's in-memory session
|
||||
* manager (active + offline-persistent). Requires an authenticated dashboard
|
||||
* JWT; any authenticated user may list.
|
||||
*/
|
||||
export function listSessions(signal?: AbortSignal): Promise<Session[]> {
|
||||
return http.get<Session[]>("/api/sessions", signal);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/sessions/:id/viewer-token — mint a short-lived, session-scoped
|
||||
* viewer token. The server decides the access mode from the caller's
|
||||
* permissions: admin or `control` permission gets a `control` token, otherwise
|
||||
* a `view_only` token. A caller with neither `control` nor `view` gets 403.
|
||||
* The access mode is stamped into the signed token; this response only echoes
|
||||
* it. (See server/src/api/sessions.rs::mint_viewer_token.)
|
||||
*/
|
||||
export function mintViewerToken(
|
||||
sessionId: string,
|
||||
): Promise<ViewerTokenResponse> {
|
||||
return http.post<ViewerTokenResponse>(
|
||||
`/api/sessions/${encodeURIComponent(sessionId)}/viewer-token`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/sessions/:id — disconnect/end a live session. The relay sends a
|
||||
* Disconnect to the agent. Returns 200 on success, 404 if the session is not
|
||||
* found. Requires an authenticated dashboard JWT (not admin-gated server-side).
|
||||
*/
|
||||
export function endSession(sessionId: string): Promise<void> {
|
||||
return http.del<void>(`/api/sessions/${encodeURIComponent(sessionId)}`);
|
||||
}
|
||||
Reference in New Issue
Block a user