Extract components and hooks into _components/ and _hooks/ subdirectories to reduce each page.tsx to under 500 LOC (was 1545/1383/1316). Final line counts: evidence=213, process-tasks=304, hazards=157. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
3.4 KiB
TypeScript
74 lines
3.4 KiB
TypeScript
'use client'
|
|
|
|
import type { EvidenceMapping, CoverageReport } from './EvidenceTypes'
|
|
|
|
export function MappingTab({
|
|
mappings,
|
|
coverageReport,
|
|
}: {
|
|
mappings: EvidenceMapping[]
|
|
coverageReport: CoverageReport | null
|
|
}) {
|
|
return (
|
|
<>
|
|
{coverageReport && (
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
|
<p className="text-sm text-gray-500">Gesamt Controls</p>
|
|
<p className="text-3xl font-bold text-gray-900">{coverageReport.total_controls}</p>
|
|
</div>
|
|
<div className="bg-white rounded-xl border border-green-200 p-6">
|
|
<p className="text-sm text-green-600">Mit Nachweis</p>
|
|
<p className="text-3xl font-bold text-green-600">{coverageReport.controls_with_evidence}</p>
|
|
</div>
|
|
<div className="bg-white rounded-xl border border-red-200 p-6">
|
|
<p className="text-sm text-red-600">Ohne Nachweis</p>
|
|
<p className="text-3xl font-bold text-red-600">{coverageReport.controls_without_evidence}</p>
|
|
</div>
|
|
<div className="bg-white rounded-xl border border-purple-200 p-6">
|
|
<p className="text-sm text-purple-600">Abdeckung</p>
|
|
<p className="text-3xl font-bold text-purple-600">{coverageReport.coverage_percent.toFixed(0)}%</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="bg-white rounded-xl shadow-sm border overflow-hidden">
|
|
<div className="p-4 border-b">
|
|
<h3 className="font-semibold text-gray-900">Evidence-Control-Verknuepfungen ({mappings.length})</h3>
|
|
</div>
|
|
{mappings.length === 0 ? (
|
|
<div className="p-8 text-center text-gray-500">
|
|
<p>Noch keine Verknuepfungen erstellt.</p>
|
|
<p className="text-sm mt-1">Fuehren Sie automatische Checks aus, um Nachweise automatisch mit Controls zu verknuepfen.</p>
|
|
</div>
|
|
) : (
|
|
<table className="w-full">
|
|
<thead className="bg-gray-50">
|
|
<tr>
|
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Control</th>
|
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Evidence</th>
|
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Typ</th>
|
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Verifiziert</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-gray-200">
|
|
{mappings.map(m => (
|
|
<tr key={m.id} className="hover:bg-gray-50">
|
|
<td className="px-4 py-3 font-mono text-sm text-purple-600">{m.control_code}</td>
|
|
<td className="px-4 py-3 text-sm text-gray-700">{m.evidence_id.slice(0, 8)}...</td>
|
|
<td className="px-4 py-3">
|
|
<span className="px-2 py-0.5 text-xs rounded bg-blue-100 text-blue-700">{m.mapping_type}</span>
|
|
</td>
|
|
<td className="px-4 py-3 text-sm text-gray-500">
|
|
{m.verified_at ? `${new Date(m.verified_at).toLocaleDateString('de-DE')} von ${m.verified_by || '—'}` : 'Ausstehend'}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
)}
|
|
</div>
|
|
</>
|
|
)
|
|
}
|