import React, { useState, useEffect, useCallback } from 'react'; import { useAuth } from '../context/AuthContext'; import { BarChart2, Cpu, Users, Database, Settings, Trash2, Check, X, Play, RefreshCw, Shield, AlertTriangle, Zap, GitBranch, Info } from 'lucide-react'; const API_BASE = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api'; // ─── Helpers ────────────────────────────────────────────────────────────────── const Spinner = () => ( ); // ─── Tab Components ────────────────────────────────────────────────────────── const OverviewTab = ({ stats, health, onRefresh }: { stats: Partial; health: import('../types/api').SystemHealthResponse | any; onRefresh: () => void }) => (
{/* KPI Grid */}
{[ { label:'Graph Nodes', value: stats?.graph?.nodes ?? stats?.total_nodes ?? '—', icon: }, { label:'Relationships', value: stats?.graph?.relationships ?? stats?.total_relationships ?? '—', icon: }, { label:'Documents', value: stats?.documents?.total ?? stats?.total_documents ?? '—', icon: }, { label:'Est. LLM Cost', value: `$${(stats?.costs?.total_estimated_usd ?? 0).toFixed(4)}`, icon: }, ].map(c => (
{c.label}
{c.icon}
{c.value}
))}
{/* System health */}

System Health

{health ? (
{Object.entries(health).map(([k, v]: [string, any]) => { const isOk = v === true || v === 'ok' || v === 'connected' || v === 'healthy'; const isErr = v === false || v === 'error' || v === 'disconnected'; return (
{k.toUpperCase()}
{typeof v === 'object' ? JSON.stringify(v) : String(v)}
); })}
) : (
Loading health data…
)}
{/* Provider info */} {stats?.system && (

LLM Provider

{Object.entries(stats.system).map(([k, v]: any) => (
{k}: {String(v)}
))}
)}
); const UsersTab = ({ token }: { token: string | null }) => { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [msg, setMsg] = useState(''); const fetchUsers = useCallback(async () => { setLoading(true); try { const res = await fetch(`${API_BASE}/admin/users`, { headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { const json = await res.json(); setUsers(json.users || []); } } finally { setLoading(false); } }, [token]); useEffect(() => { fetchUsers(); }, [fetchUsers]); const updateRole = async (username: string, scopes: string) => { const res = await fetch(`${API_BASE}/admin/users/${username}/role`, { method: 'PUT', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ scopes: [scopes] }) }); if (res.ok) { setUsers(u => u.map(usr => usr.username === username ? { ...usr, scopes: [scopes] } : usr)); setMsg(`Role updated for ${username}`); setTimeout(() => setMsg(''), 3000); } else { setMsg(`Failed to update role for ${username}`); setTimeout(() => setMsg(''), 3000); } }; return (

Registered Users

{msg &&
{msg}
} {loading ? (
) : (
{users.map(u => { const isAdminUser = u.username === 'admin'; const currentScope = u.scopes?.includes('admin') ? 'admin' : (u.scopes?.includes('write') ? 'write' : 'read'); return ( ); })} {users.length === 0 && ( )}
UsernameScopeChange Role
{u.username} {isAdminUser && PROTECTED} {u.scopes?.join(', ') || 'none'} {isAdminUser ? ( ) : ( )}
No users found.
)}
); }; const DocumentsTab = ({ token }: { token: string | null }) => { const [docs, setDocs] = useState([]); const [loading, setLoading] = useState(true); const [msg, setMsg] = useState(''); const fetchDocs = useCallback(async () => { setLoading(true); try { const res = await fetch(`${API_BASE}/admin/documents`, { headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { const json = await res.json(); setDocs(json.documents || []); } } finally { setLoading(false); } }, [token]); useEffect(() => { fetchDocs(); }, [fetchDocs]); const deleteDoc = async (id: string, filename: string) => { if (!window.confirm(`Delete "${filename}" and all its graph data? This cannot be undone.`)) return; const res = await fetch(`${API_BASE}/admin/documents/${id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { setDocs(d => d.filter(doc => doc.id !== id)); setMsg('Document deleted.'); setTimeout(() => setMsg(''), 3000); } }; const reIngestDoc = async (id: string, filename: string) => { setMsg(`Re-ingesting "${filename}"...`); try { const res = await fetch(`${API_BASE}/admin/documents/${id}/reingest`, { method: 'POST', headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { const data = await res.json(); setMsg(`Re-ingestion queued for "${filename}". Task: ${data.task_id?.slice(0,8)}…`); setTimeout(() => { setMsg(''); fetchDocs(); }, 5000); } else { setMsg(`Failed to re-ingest "${filename}"`); setTimeout(() => setMsg(''), 3000); } } catch { setMsg('Network error during re-ingest.'); setTimeout(() => setMsg(''), 3000); } }; return (

Document Vault

{docs.length} documents
{msg &&
{msg}
} {loading ? (
) : (
{docs.map(d => ( ))} {docs.length === 0 && ( )}
IDFilenameStatusActions
{d.id?.substring(0,12)}… {d.filename} {d.status || 'unknown'} {(d.status === 'failed' || d.status === 'pending') && ( )}
No documents uploaded yet.
)}
); }; const GraphCRUDTab = ({ token }: { token: string | null }) => { const [nodes, setNodes] = useState([]); const [query, setQuery] = useState(''); const [loading, setLoading] = useState(false); const [msg, setMsg] = useState(''); const search = async (e?: React.FormEvent) => { e?.preventDefault(); setLoading(true); try { const res = await fetch(`${API_BASE}/admin/graph/nodes?query=${encodeURIComponent(query)}&limit=100`, { headers: { Authorization: `Bearer ${token}` } }); if (res.ok) setNodes((await res.json()).nodes || []); } finally { setLoading(false); } }; const deleteNode = async (id: string) => { if (!window.confirm('Detach and delete this node?')) return; const res = await fetch(`${API_BASE}/admin/graph/nodes/${id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { setNodes(n => n.filter(nd => nd.id !== id)); setMsg('Node deleted.'); setTimeout(() => setMsg(''), 3000); } }; return (

Graph Node Browser

Search and inspect nodes directly in Neo4j. Use label names or property values. DELETE detaches all relationships before removing the node.
{msg &&
{msg}
}
setQuery(e.target.value)} placeholder="Search node labels or properties…" className="search-input flex-1"/>
{nodes.map((n, i) => ( ))} {nodes.length === 0 && ( )}
IDLabelsPropertiesAction
{n.id} {n.labels?.join(', ')} {JSON.stringify(n.properties)}
{loading ? 'Searching…' : 'Enter a search term above to browse nodes.'}
); }; const OntologyGovernanceTab = ({ token }: { token: string | null }) => { const [proposals, setProposals] = useState([]); const [driftReports, setDriftReports] = useState([]); const [loading, setLoading] = useState(true); const [detectLoading, setDetectLoading] = useState(false); const [msg, setMsg] = useState(''); const fetchData = useCallback(async () => { setLoading(true); try { const [propRes, driftRes] = await Promise.all([ fetch(`${API_BASE}/admin/ontology/pending`, { headers: { Authorization: `Bearer ${token}` } }), fetch(`${API_BASE}/ontology/drift`, { headers: { Authorization: `Bearer ${token}` } }), ]); if (propRes.ok) setProposals((await propRes.json()).proposals || []); if (driftRes.ok) setDriftReports((await driftRes.json()).reports || []); } finally { setLoading(false); } }, [token]); useEffect(() => { fetchData(); }, [fetchData]); const handleProposal = async (id: string, action: 'approve' | 'reject') => { const res = await fetch(`${API_BASE}/admin/ontology/${action}/${id}`, { method: 'POST', headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { setProposals(p => p.filter(o => o.id !== id)); setMsg(`Proposal ${action}d.`); setTimeout(() => setMsg(''), 3000); } }; const handleDrift = async (id: string, action: 'approve' | 'reject') => { const res = await fetch(`${API_BASE}/ontology/drift/${id}/${action}`, { method: 'POST', headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { setDriftReports(d => d.filter(r => r.id !== id)); setMsg(`Drift report ${action}d.`); setTimeout(() => setMsg(''), 3000); } }; const detectDrift = async () => { setDetectLoading(true); try { const res = await fetch(`${API_BASE}/ontology/drift/detect`, { method: 'POST', headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { setMsg('Drift detection complete. Refreshing…'); await fetchData(); } } finally { setDetectLoading(false); setTimeout(() => setMsg(''), 4000); } }; return (
{msg &&
{msg}
} {/* Drift detection */}

Ontology Drift Reports

Drift detection samples recent data and suggests additions or changes to the graph schema. Review and approve or reject proposals below.

{loading ?
: (
{driftReports.map(r => (
{r.status || 'pending'} {r.new_entity_types?.length || 0} new types

{r.summary || 'Drift report — review suggested schema changes.'}

))} {driftReports.length === 0 && (
No pending drift reports. Run drift detection above.
)}
)}
{/* Manual proposals */}

Manual Schema Proposals

{proposals.map(o => (
{o.type} {o.name}
))} {proposals.length === 0 && (
No pending manual proposals.
)}
); }; const WorkersTab = ({ token }: { token: string | null }) => { const [tasks, setTasks] = useState(null); const [health, setHealth] = useState(null); const [loading, setLoading] = useState(true); const fetchAll = useCallback(async () => { setLoading(true); try { const [taskRes, healthRes] = await Promise.all([ fetch(`${API_BASE}/admin/tasks`, { headers: { Authorization: `Bearer ${token}` } }), fetch(`${API_BASE}/system/health`, { headers: { Authorization: `Bearer ${token}` } }), ]); if (taskRes.ok) setTasks(await taskRes.json()); if (healthRes.ok) setHealth(await healthRes.json()); } finally { setLoading(false); } }, [token]); useEffect(() => { fetchAll(); }, [fetchAll]); return (

Celery Worker Status

{loading ?
: (
{[ { label:'Active Tasks', value: tasks?.active_tasks ?? tasks?.active ?? 0 }, { label:'Queued Tasks', value: tasks?.queued_tasks ?? tasks?.reserved ?? 0 }, { label:'Completed', value: tasks?.completed_tasks ?? tasks?.total ?? 0 }, { label:'Failed', value: tasks?.failed_tasks ?? 0 }, ].map(m => (
{m.label}
{m.value}
))}
)}
{health && (

Service Health

{Object.entries(health).map(([k, v]: any) => { const ok = v === true || v === 'ok' || v === 'connected' || v === 'healthy'; return (
{k}
{String(v)}
); })}
)}
); }; const EnrichmentTab = ({ token }: { token: string | null }) => { const [loading, setLoading] = useState(false); const [result, setResult] = useState(null); const [batchSize, setBatchSize] = useState(20); const [minConnections, setMinConnections] = useState(1); const [driftLoading, setDriftLoading] = useState(false); const [driftResult, setDriftResult] = useState(null); const runEnrichment = async () => { setLoading(true); setResult(null); try { const res = await fetch(`${API_BASE}/entities/enrich`, { method:'POST', headers:{ Authorization:`Bearer ${token}`, 'Content-Type':'application/json' }, body: JSON.stringify({ batch_size: batchSize, min_connections: minConnections }) }); if (res.ok) setResult(await res.json()); } finally { setLoading(false); } }; const runDrift = async () => { setDriftLoading(true); setDriftResult(null); try { const res = await fetch(`${API_BASE}/ontology/drift/detect`, { method:'POST', headers:{ Authorization:`Bearer ${token}` } }); if (res.ok) setDriftResult(await res.json()); } finally { setDriftLoading(false); } }; return (
{/* Entity Enrichment */}

Entity Enrichment

Synthesize rich LLM-generated profiles for all eligible entities by scanning their neighborhood context in the graph.

setBatchSize(Number(e.target.value))} className="search-input w-full"/>
setMinConnections(Number(e.target.value))} className="search-input w-full"/>
{result && (
✓ {result.message || `Enriched ${result.enriched_count ?? '?'} entities`}
)}
{/* Drift Detection */}

Ontology Drift Detection

Analyse recent data samples to detect schema evolution and generate a drift report for admin review.

{driftResult && (
✓ Drift report created. ID: {driftResult.report_id || driftResult.id || '—'} → Review in Ontology Governance tab.
)}
); }; const SandboxTab = ({ token }: { token: string | null }) => { const [loading, setLoading] = useState(false); const [msg, setMsg] = useState(''); const trigger = async (endpoint: string, label: string) => { setLoading(true); setMsg(''); try { const res = await fetch(`${API_BASE}${endpoint}`, { method:'POST', headers:{ Authorization:`Bearer ${token}` } }); setMsg(res.ok ? `✓ ${label} dispatched to Celery worker.` : `✗ Failed to trigger ${label}.`); } catch { setMsg(`✗ Network error.`); } finally { setLoading(false); } }; return (

MiroFish God-Mode Sandbox

Control the simulation loops that connect Knowledge Graph entities into living agents.

{msg && (
{msg}
)}
{[ { endpoint:'/v1/simulation/generate_personas', label:'Generate Agent Personas', icon:, desc:'Converts raw graph nodes into living psychological profiles for agent simulation.' }, { endpoint:'/v1/simulation/tick', label:'Force Simulation Tick', icon:, desc:'Forces agents to read their local graph memory and output a new interaction edge.' }, ].map(item => (

{item.desc}

))}
); }; // ─── Main Dashboard ─────────────────────────────────────────────────────────── export default function AdminDashboard() { const { token, user } = useAuth(); const [activeTab, setActiveTab] = useState('overview'); const [stats, setStats] = useState(null); const [health, setHealth] = useState(null); const [error, setError] = useState(null); const fetchOverview = useCallback(async () => { if (!token) return; try { const [statsRes, healthRes] = await Promise.all([ fetch(`${API_BASE}/admin/stats`, { headers: { Authorization: `Bearer ${token}` } }), fetch(`${API_BASE}/system/health`, { headers: { Authorization: `Bearer ${token}` } }), ]); if (statsRes.ok) setStats(await statsRes.json()); if (healthRes.ok) setHealth(await healthRes.json()); } catch (err: any) { setError(err.message); } }, [token]); useEffect(() => { fetchOverview(); }, [fetchOverview]); if (user && user.username !== 'admin' && !user.scopes?.includes('admin')) { return (

Access Denied

You need administrative privileges to view this page.

); } const TABS = [ { id:'overview', label:'Overview', icon: }, { id:'users', label:'Users', icon: }, { id:'documents', label:'Documents', icon: }, { id:'graph', label:'Graph CRUD', icon: }, { id:'ontology', label:'Ontology', icon: }, { id:'workers', label:'Workers', icon: }, { id:'enrichment', label:'Enrichment / Drift', icon: }, { id:'sandbox', label:'God-Mode Sandbox', icon: }, ]; return (
{/* Header */}

Admin Control Center

Manage graph data, workers, users, and platform configuration

{error && (
{error}
)}
{/* Sidebar nav */}
{/* Main content */}
{activeTab === 'overview' && } {activeTab === 'users' && } {activeTab === 'documents' && } {activeTab === 'graph' && } {activeTab === 'ontology' && } {activeTab === 'workers' && } {activeTab === 'enrichment' && } {activeTab === 'sandbox' && }
); }