/home/techb158/cosmic-risk.abdallabala.com/src/app/dashboard
NameSizeModeActions
layout.jsx3040644editdlrm
page.jsx1278360644editdlrm
Edit: /home/techb158/cosmic-risk.abdallabala.com/src/app/dashboard/page.jsx (127836B)
'use client'; import { useEffect, useState, useCallback, useMemo } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { api } from '../../lib/api-client'; import ErrorBoundary from '../../components/ErrorBoundary'; const ORG_TABS = ['Overview', 'Projects', 'Risks', 'Mitigations', 'Gate', 'Indicators', 'Experiments', 'Reports', 'Integrations', 'Audit', 'Members']; const PAGE_SIZE = 20; const DIMENSIONS = ['Organizational', 'Technical', 'Human', 'Governance', 'Legal', 'Ethical', 'Operational']; const LIFECYCLE_PHASES = ['Design', 'Development', 'Testing', 'Deployment']; const RISK_STATUSES = ['OPEN', 'IN_MITIGATION', 'ACCEPTED', 'CLOSED']; const MITIGATION_STATUSES = ['NOT_STARTED', 'IN_PROGRESS', 'DONE', 'REJECTED']; function useToast() { const [toasts, setToasts] = useState([]); const add = useCallback((message, type = 'success') => { const id = Date.now() + Math.random(); setToasts(prev => [...prev, { id, message, type }]); setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 3000); }, []); return { toasts, add }; } function ToastContainer({ toasts }) { if (!toasts.length) return null; return (
{toasts.map(t => (
{t.message}
))}
); } function SearchInput({ value, onChange, placeholder }) { return (
onChange(e.target.value)} placeholder={placeholder || 'Search...'} />
); } function sortData(list, sortKey, sortDir) { if (!sortKey) return list; return [...list].sort((a, b) => { const va = a[sortKey], vb = b[sortKey]; if (va == null) return 1; if (vb == null) return -1; const cmp = typeof va === 'number' ? va - vb : String(va).localeCompare(String(vb)); return sortDir === 'asc' ? cmp : -cmp; }); } function Badge({ children, className }) { return {children}; } function FormField({ label, children }) { return (
{children}
); } function InlineInput({ value, onChange, type = 'text', min, max, style: extraStyle }) { return onChange(e.target.value)} min={min} max={max} style={{ width: '100%', ...extraStyle }} />; } function InlineSelect({ value, onChange, options }) { const items = options || []; return ( ); } function ConfirmDelete({ label, onConfirm, onCancel, deleting }) { return (
e.stopPropagation()} style={{ maxWidth: 380 }}>

Delete {label}?

This cannot be undone.

); } function OverviewTab({ project, dashboard }) { const panels = useMemo(() => { if (!dashboard) return []; const s = dashboard.summary || {}; return [ { label: 'Overall AI Risk Score', value: `${s.overallScore ?? '-'}/100`, cls: (s.overallScore || 0) >= 50 ? 'bad' : (s.overallScore || 0) >= 25 ? 'warn' : 'good', sub: `${s.riskLevel || '-'} residual exposure` }, { label: 'Deployment Gate', value: s.gateStatus ?? '-', cls: s.gateStatus === 'READY' ? 'good' : s.gateStatus === 'WARNING' ? 'warn' : 'bad', sub: dashboard.gate?.message || '' }, { label: 'Open Risks', value: s.openRisks ?? 0, cls: (s.openRisks || 0) > 10 ? 'bad' : (s.openRisks || 0) > 3 ? 'warn' : 'good', sub: `${s.totalRisks || 0} total risks tracked` }, { label: 'Mitigation Completion', value: `${s.mitigationCompletion ?? 0}%`, cls: (s.mitigationCompletion || 0) < 40 ? 'bad' : (s.mitigationCompletion || 0) < 70 ? 'warn' : 'good', sub: 'Average progress across active risks' }, { label: 'Critical Risks', value: s.criticalRisks ?? 0, cls: (s.criticalRisks || 0) > 0 ? 'bad' : 'good', sub: `${s.highRisks || 0} high risks also active` }, ]; }, [dashboard]); if (!dashboard) return

Loading dashboard data...

; const s = dashboard.summary || {}; const triangle = dashboard.governanceTriangle || {}; const lifecycleReadiness = dashboard.lifecycleReadiness || []; const dimensionResidual = dashboard.dimensionResidual || []; const dims = dimensionResidual.length > 0 ? dimensionResidual : [ { name: 'Organizational', score: triangle.organizational || 0 }, { name: 'Technical', score: triangle.technical || 0 }, { name: 'Human', score: triangle.human || 0 }, ]; const getDim = (name) => { const d = dims.find(x => x.name.toLowerCase() === name.toLowerCase()); return d ? Math.round(d.score || 0) : 0; }; const orgScore = getDim('Organizational'); const techScore = getDim('Technical'); const humanScore = getDim('Human'); const triClass = (s) => s >= 75 ? 'blocked' : s >= 50 ? 'warning' : 'pass'; const topRisks = dashboard.topRisks || []; return ( <>

Integrated Measurement Framework for AI Project Risks

{project?.projectType || 'AI-Enabler'} · {project?.currentLifecyclePhase || 'Assessment'} · Assessment {new Date(dashboard.project?.assessmentDate || Date.now()).toISOString().split('T')[0]}

{/* Summary Cards */}
{panels.map(p => (

{p.label}

{p.value}
{p.sub}
))}
{/* AI Governance Triangle */}
6.2

AI Governance Triangle

Organizational, technical, and human residual risk.

{orgScore} {techScore} {humanScore} Organizational Technical Human AI Risks Governance · Metrology · Evidence
{/* Dimension Scores */}
Risk dimensions

Dimension scores

Normalized residual risk exposure by dashboard dimension.

{dims.map(d => { const score = Math.round(d.score || 0); const barColor = score >= 75 ? 'var(--blocked)' : score >= 50 ? 'var(--warn)' : 'var(--accent)'; return (
{d.name} {score}/100
); })}
{/* Lifecycle Readiness Map */}
AI lifecycle

Lifecycle readiness map

Dashboard backbone from needs identification through deployment and monitoring.

{lifecycleReadiness.map((phase, i) => { const readinessColor = phase.readinessScore >= 70 ? 'var(--accent)' : phase.readinessScore >= 50 ? 'var(--warn)' : 'var(--danger)'; return (
{phase.code || `LC-${String(i + 1).padStart(2, '0')}`} {phase.name} Readiness {phase.readinessScore || 0}/100 {phase.openRisks} open risks
); })}
{/* Top Risks */}

Top Risks

Highest residual risk exposure — Prioritized by current residual score after mitigation progress.

{topRisks.length === 0 ? (

No risks found

) : (
{topRisks.map((risk, i) => { const levelCls = risk.residualSeverity === 'Critical' ? 'bad' : risk.residualSeverity === 'High' ? 'bad' : risk.residualSeverity === 'Moderate' ? 'warn' : 'good'; return ( ); })}
ID Risk Dimension Residual Level Owner
{risk.id ? `R-${String(risk.id).slice(-4).toUpperCase()}` : `R-${String(i + 1).padStart(3, '0')}`} {risk.title || risk.description || 'Untitled'} {risk.dimension || '-'} {risk.residualScore}/100 {risk.residualSeverity || 'Unknown'} {risk.ownerDisplayName || 'Unassigned'}
)}
); } function RiskFormModal({ project, onClose, onSaved, toast }) { const [saving, setSaving] = useState(false); const [form, setForm] = useState({ title: '', description: '', dimension: '', domain: '', lifecyclePhase: '', probability: 50, impact: 50, detectability: 50, ownerDisplayName: '' }); const set = key => value => setForm(f => ({ ...f, [key]: value })); const handleSave = async () => { if (!form.title.trim()) { toast.add('Title is required', 'error'); return; } if (!form.dimension) { toast.add('Dimension is required', 'error'); return; } setSaving(true); try { await api.post(`/api/projects/${project.id}/risks`, form); toast.add('Risk created'); onSaved(); } catch (e) { toast.add(e.message || 'Failed to create risk', 'error'); } finally { setSaving(false); } }; return (
e.stopPropagation()} style={{ maxWidth: 500 }}>

New Risk