import { useState } from 'react'; import type { RegulatoryMappingCandidate, RegulatoryMappingDecision, RegulatoryMappingProposal, RegulatoryMappingResponse } from '../../domain/regulatory-mapping'; interface Props { response?: RegulatoryMappingResponse; loading: boolean; error: string; onStart(): void; onDecision(candidate: RegulatoryMappingCandidate, decision: 'accepted' | 'rejected', comment?: string): void; } export function RegulatoryMappingPanel({ response, loading, error, onStart, onDecision }: Props) { const run = response?.run; const proposals = run?.result?.mappings ?? []; const proposalIds = new Set(proposals.map(item => item.controlId)); const proposedCandidates = proposals.flatMap(proposal => { const candidate = run?.candidates.find(item => item.controlId === proposal.controlId); return candidate ? [{ candidate, proposal }] : []; }); const otherCandidates = run?.candidates.filter(item => !proposalIds.has(item.controlId)) ?? []; return

ISO control mapping

Proposals indicate relevance to this finding, not proof of compliance.

{response?.generationEnabled && !['queued', 'running'].includes(response.state) && }
{loading && !response &&

Loading mapping state…

} {error &&

{error}

} {response && !response.generationEnabled &&

{response.disabledReason ?? 'Regulatory mapping is unavailable.'}

} {response && ['queued', 'running'].includes(response.state) &&

{response.state === 'queued' ? 'Mapping queued…' : 'Retrieving and evaluating ISO controls…'}

} {run?.status === 'failed' &&

Mapping stopped safely ({run.errorCode ?? 'unknown error'}). You can start a new run.{run.errorDetail ? <>
{run.errorDetail} : null}

} {run?.status === 'succeeded' && run.result?.outcome !== 'mapped' &&

{run.result?.reason ?? (run.result?.outcome === 'insufficient_context' ? 'Insufficient public context.' : 'No relevant control was proposed.')}

} {proposedCandidates.length > 0 &&
{proposedCandidates.map(item => ) }
} {otherCandidates.length > 0 &&
Other retrieved controls ({otherCandidates.length})
{otherCandidates.map(candidate => )}
}
; } function ControlCandidate({ candidate, proposal, decisions, loading, onDecision }: { candidate: RegulatoryMappingCandidate; proposal?: RegulatoryMappingProposal; decisions: RegulatoryMappingDecision[]; loading: boolean; onDecision(candidate: RegulatoryMappingCandidate, decision: 'accepted' | 'rejected', comment?: string): void; }) { const [comment, setComment] = useState(''); const current = decisions.find(item => item.controlId === candidate.controlId); return

{candidate.annexAControlId} — {candidate.title}

{proposal ? <>{proposal.relationship} · {proposal.confidence} confidence : 'Retrieved candidate'} · score {candidate.score.toFixed(3)}

{current && {current.decision}}
{proposal?.rationale &&

{proposal.rationale}

}
Evidence ({candidate.evidence.length})
; }