Files
guru-connect/dashboard/src/features/machines/KeyRevealModal.tsx
Mike Swanson 43a9432b81
All checks were successful
Build and Test / Build Agent (Windows) (push) Successful in 6m56s
Build and Test / Build Server (Linux) (push) Successful in 10m15s
Build and Test / Security Audit (push) Successful in 4m12s
Build and Test / Build Summary (push) Successful in 10s
feat(dashboard): GuruConnect v2 operator console (pass 1)
React + Vite + TypeScript SPA: scaffold, operations-terminal design
system, Bearer-token auth, and the Machines view.

- Design system: OKLCH-tinted dark theme (ink-slate + signal-cyan),
  Hanken Grotesk + JetBrains Mono, status-color language
  (online/offline/granted/pending/denied/not_required), motion with
  prefers-reduced-motion honored.
- Auth: token in sessionStorage via ref (never React state), protected
  routes, 401 session teardown, admin-gated per-agent-key UI.
- Machines view: data table (sticky header, keyboard-activated rows,
  skeleton loading, actionable empty/error states), non-blocking detail
  drawer, delete confirm, admin key management with copy-once reveal.
- UI primitives: Modal (focus trap + inert + portal + dialogStack),
  Drawer, Table, Badge/StatusDot, toast, states.
- Typed API client normalizing the two error-envelope shapes.

Passed Code Review (no blockers), impeccable critique-and-polish, and
local gates (tsc/lint/build green). Dev-only Vite proxy to :3002.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 12:51:11 -07:00

73 lines
2.3 KiB
TypeScript

import { Button } from "../../components/ui/Button";
import { Modal } from "../../components/ui/Modal";
import { CopyIcon } from "../../components/layout/icons";
import { useClipboard } from "../../lib/useClipboard";
interface KeyRevealModalProps {
/** The plaintext `cak_...` key, or null when closed. */
plaintextKey: string | null;
onClose: () => void;
}
/**
* Copy-once key reveal. The server returns the plaintext key exactly once on
* creation; this is the only place it is ever shown. The user is warned and
* given a copy button. Closing dismisses it for good.
*/
export function KeyRevealModal({ plaintextKey, onClose }: KeyRevealModalProps) {
const { copied, copy } = useClipboard();
const open = plaintextKey != null;
return (
<Modal
open={open}
title="Agent key created"
onClose={onClose}
footer={<Button variant="primary" onClick={onClose}>Done</Button>}
>
<div className="keyreveal__warn" role="alert">
<svg
className="keyreveal__warnicon"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M10.3 3.7 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.7a2 2 0 0 0-3.4 0Z" />
<path d="M12 9v4M12 17h.01" />
</svg>
<div>
<strong>Copy this key now. You will not see it again.</strong>
<span>
The key is shown only at creation and cannot be recovered. If you
lose it, revoke it and create a new one.
</span>
</div>
</div>
<div className="keyreveal__value">
<code className="keyreveal__key">{plaintextKey}</code>
<Button
variant="ghost"
size="sm"
onClick={() => plaintextKey && void copy(plaintextKey)}
aria-label={copied ? "Key copied to clipboard" : "Copy key to clipboard"}
>
<CopyIcon width={14} height={14} />
{copied ? "Copied" : "Copy"}
</Button>
</div>
<p className="keyreveal__hint">
Use this key to enroll the agent as a persistent, individually revocable
identity.
</p>
</Modal>
);
}