import React, { useState, useMemo } from 'react'; import { Link } from 'react-router-dom'; import { useApi } from '../hooks/useApi'; import { getGuardrailRules, getGuardrailHistory, type GuardrailRuleData, type GuardrailTriggerData, } from '../api/client'; // ─── Helpers ──────────────────────────────────────────────────── function formatTimestamp(ts: string): string { try { return new Date(ts).toLocaleString(); } catch { return ts; } } // ─── Main Page ────────────────────────────────────────────────── export default function GuardrailActivity() { const [filterAgent, setFilterAgent] = useState(''); const [filterRule, setFilterRule] = useState(''); const rulesQuery = useApi(() => getGuardrailRules(), []); const historyQuery = useApi(() => getGuardrailHistory({ limit: 200 }), []); const rules = rulesQuery.data?.rules ?? []; const triggers = historyQuery.data?.triggers ?? []; // Build lookup maps const ruleMap = useMemo(() => { const m = new Map(); for (const r of rules) m.set(r.id, r); return m; }, [rules]); // Extract unique agents from rules const agents = useMemo(() => { const set = new Set(); for (const r of rules) if (r.agentId) set.add(r.agentId); return Array.from(set).sort(); }, [rules]); // Filter triggers const filtered = useMemo(() => { return triggers.filter((t) => { const rule = ruleMap.get(t.ruleId); if (!rule) return false; if (filterRule && t.ruleId !== filterRule) return false; if (filterAgent && rule.agentId !== filterAgent) return false; return true; }); }, [triggers, ruleMap, filterRule, filterAgent]); return (

🛡️ Guardrail Activity Feed

← Back to Rules
{/* Filters */}
{(rulesQuery.loading || historyQuery.loading) &&

Loading...

} {rulesQuery.error &&

Error loading rules: {rulesQuery.error}

} {historyQuery.error &&

Error: {historyQuery.error}

} {filtered.length === 0 && !historyQuery.loading && (

No guardrail triggers found.

)} {filtered.length > 0 && ( {filtered.map((t) => { const rule = ruleMap.get(t.ruleId); return ( ); })}
Timestamp Rule Agent Condition Action Dry Run Value / Threshold
{formatTimestamp(t.triggeredAt)} {rule?.name ?? t.ruleId} {rule?.agentId ?? All} {rule?.conditionType ?? '—'} {rule?.actionType ?? '—'} {t.actionExecuted ? LIVE : DRY RUN} {t.conditionValue} / {t.conditionThreshold}
)}
); } // ─── Styles ───────────────────────────────────────────────────── const selectStyle: React.CSSProperties = { padding: '6px 10px', border: '1px solid #d1d5db', borderRadius: '4px', fontSize: '14px', }; const thStyle: React.CSSProperties = { padding: '10px 12px', fontSize: '13px', color: '#64748b', fontWeight: 600 }; const tdStyle: React.CSSProperties = { padding: '10px 12px', fontSize: '13px' }; export { GuardrailActivity };