import * as React from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import type { Agent } from '@sentryagent/idp-sdk'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { ConfirmDialog } from '@/components/ui/dialog'; import { getClient } from '@/lib/client'; type BadgeVariant = 'success' | 'warning' | 'danger'; /** Maps AgentStatus to a Badge variant. */ function statusVariant(status: Agent['status']): BadgeVariant { switch (status) { case 'active': return 'success'; case 'suspended': return 'warning'; case 'decommissioned': return 'danger'; } } /** Formats an ISO timestamp to a readable local date-time string. */ function formatDateTime(iso: string): string { return new Date(iso).toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } interface DetailRowProps { label: string; value: string; } /** Single label/value row in the detail card. */ function DetailRow({ label, value }: DetailRowProps): React.JSX.Element { return (
{label}
{value}
); } type DialogAction = 'suspend' | 'reactivate'; /** * Agent Detail page — shows all agent fields and provides suspend/reactivate actions. * Route: /dashboard/agents/:agentId */ export default function AgentDetail(): React.JSX.Element { const { agentId } = useParams<{ agentId: string }>(); const navigate = useNavigate(); const [agent, setAgent] = React.useState(null); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null); const [actionLoading, setActionLoading] = React.useState(false); const [dialog, setDialog] = React.useState(null); React.useEffect(() => { if (!agentId) return; let cancelled = false; setLoading(true); setError(null); const fetchAgent = async (): Promise => { try { const result = await getClient().agents.getAgent(agentId); if (!cancelled) setAgent(result); } catch (err) { if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load agent.'); } finally { if (!cancelled) setLoading(false); } }; void fetchAgent(); return () => { cancelled = true; }; }, [agentId]); const handleAction = React.useCallback( async (action: DialogAction): Promise => { if (!agentId) return; setActionLoading(true); setDialog(null); try { const newStatus = action === 'suspend' ? 'suspended' : 'active'; const updated = await getClient().agents.updateAgent(agentId, { status: newStatus }); setAgent(updated); } catch (err) { setError(err instanceof Error ? err.message : 'Action failed.'); } finally { setActionLoading(false); } }, [agentId], ); if (loading) { return (
{Array.from({ length: 6 }).map((_, i) => (
))}
); } if (error || !agent) { return (
{error ?? 'Agent not found.'}
); } const dialogConfig = dialog === 'suspend' ? { title: `Suspend agent ${agent.email}?`, description: `Suspending ${agent.email} means it will no longer be able to authenticate.`, confirmLabel: 'Suspend', variant: 'destructive' as const, } : { title: `Reactivate agent ${agent.email}?`, description: `Reactivating ${agent.email} will allow it to authenticate again.`, confirmLabel: 'Reactivate', variant: 'default' as const, }; return (
{/* Back navigation */}

{agent.email}

Agent ID: {agent.agentId}

{agent.status}
{error && (
{error}
)} {/* Detail card */}
{/* Actions */} {agent.status !== 'decommissioned' && (
{agent.status === 'active' && ( )} {agent.status === 'suspended' && ( )}
)} {/* Credentials section */}

Credentials

Manage client secrets for this agent. Rotate or revoke credentials as needed.

{/* Confirm dialog */} {dialog !== null && ( { void handleAction(dialog); }} onCancel={() => { setDialog(null); }} /> )}
); }