'use client' import { Shield, ArrowLeft, ExternalLink, CheckCircle2, Lock, FileText, BookOpen, Scale, Pencil, Trash2, Eye, Clock, } from 'lucide-react' import type { CanonicalControl } from '../_types' import { EFFORT_LABELS } from '../_types' import { SeverityBadge, StateBadge, LicenseRuleBadge } from './Badges' // Defensive coercers: backend has rows where evidence/requirements/test_procedure/open_anchors // are JSON-encoded strings instead of arrays. .map() on a string throws — coerce here. function asArray(v: unknown): T[] { if (Array.isArray(v)) return v as T[] if (typeof v === 'string' && v.trim().startsWith('[')) { try { const p = JSON.parse(v); return Array.isArray(p) ? p : [] } catch { return [] } } return [] } function asStringArray(v: unknown): string[] { return asArray(v).map(x => typeof x === 'string' ? x : JSON.stringify(x)) } type EvidenceItem = string | { type?: string; description?: string } function asEvidenceArray(v: unknown): EvidenceItem[] { return asArray(v) } export function ControlDetailView({ ctrl, onBack, onEdit, onDelete, onReview, }: { ctrl: CanonicalControl onBack: () => void onEdit: () => void onDelete: (controlId: string) => void onReview: (controlId: string, action: string) => void }) { return (
{/* Header */}
{ctrl.control_id}

{ctrl.title}

{ctrl.risk_score !== null && Risiko-Score: {ctrl.risk_score}/10} {ctrl.implementation_effort && Aufwand: {EFFORT_LABELS[ctrl.implementation_effort] || ctrl.implementation_effort}}
{/* Objective & Rationale */}

Ziel

{ctrl.objective}

Begruendung

{ctrl.rationale}

{/* Scope */}

Geltungsbereich

{asStringArray(ctrl.scope?.platforms).length > 0 && (

Plattformen

{asStringArray(ctrl.scope?.platforms).map(p => ( {p} ))}
)} {asStringArray(ctrl.scope?.components).length > 0 && (

Komponenten

{asStringArray(ctrl.scope?.components).map(c => ( {c} ))}
)} {asStringArray(ctrl.scope?.data_classes).length > 0 && (

Datenklassen

{asStringArray(ctrl.scope?.data_classes).map(d => ( {d} ))}
)}
{/* Requirements */}

Anforderungen

    {asStringArray(ctrl.requirements).map((req, i) => (
  1. {i + 1} {req}
  2. ))}
{/* Test Procedure */}

Pruefverfahren

    {asStringArray(ctrl.test_procedure).map((step, i) => (
  1. {step}
  2. ))}
{/* Evidence */}

Nachweisanforderungen

{asEvidenceArray(ctrl.evidence).map((ev, i) => (
{typeof ev === 'string' ? (

{ev}

) : ( <> {ev.type && {ev.type}}

{ev.description ?? JSON.stringify(ev)}

)}
))}
{/* Open Anchors — THE KEY SECTION */}

Open-Source-Referenzen

({asArray(ctrl.open_anchors).length} Quellen)

Dieses Control basiert auf frei verfuegbarem Wissen. Alle Referenzen sind offen und oeffentlich zugaenglich.

{asArray<{ framework?: string; ref?: string; url?: string }>(ctrl.open_anchors).map((anchor, i) => (
{anchor.framework}

{anchor.ref}

Quelle
))}
{/* Tags */} {asStringArray(ctrl.tags).length > 0 && (

Tags

{asStringArray(ctrl.tags).map(tag => ( {tag} ))}
)} {/* License & Citation Info */} {ctrl.license_rule && (

Lizenzinformationen

{ctrl.source_citation && (

Quelle: {ctrl.source_citation.source}

{ctrl.source_citation.license &&

Lizenz: {ctrl.source_citation.license}

} {ctrl.source_citation.license_notice &&

Hinweis: {ctrl.source_citation.license_notice}

} {ctrl.source_citation.url && ( Originalquelle )}
)} {ctrl.source_original_text && (
Originaltext anzeigen

{ctrl.source_original_text}

)} {ctrl.license_rule === 3 && (

Eigenstaendig formuliert — keine Originalquelle gespeichert

)}
)} {/* Generation Metadata (internal) */} {ctrl.generation_metadata && (

Generierungsdetails (intern)

Pfad: {String(ctrl.generation_metadata.processing_path || '-')}

{ctrl.generation_metadata.similarity_status && (

Similarity: {String(ctrl.generation_metadata.similarity_status)}

)} {Array.isArray(ctrl.generation_metadata.similar_controls) && (

Aehnliche Controls:

{(ctrl.generation_metadata.similar_controls as Array>).map((s, i) => (

{String(s.control_id)} — {String(s.title)} ({String(s.similarity)})

))}
)}
)} {/* Review Actions */} {['needs_review', 'too_close', 'duplicate'].includes(ctrl.release_state) && (

Review erforderlich

)}
) }