'use client' /** * Evidence Management Page */ import { useState, useEffect, Suspense } from 'react' import { useSearchParams } from 'next/navigation' import Link from 'next/link' import AdminLayout from '@/components/admin/AdminLayout' import { UploadModal, LinkModal } from './_components/EvidenceModals' import { EvidenceCard } from './_components/EvidenceCard' interface Evidence { id: string control_id: string evidence_type: string title: string description: string artifact_path: string | null artifact_url: string | null artifact_hash: string | null file_size_bytes: number | null mime_type: string | null status: string source: string ci_job_id: string | null valid_from: string valid_until: string | null collected_at: string } interface Control { id: string; control_id: string; title: string } const EVIDENCE_TYPE_OPTIONS = [ { value: 'scan_report', label: 'Scan Report' }, { value: 'policy_document', label: 'Policy Dokument' }, { value: 'config_snapshot', label: 'Config Snapshot' }, { value: 'test_result', label: 'Test Ergebnis' }, { value: 'screenshot', label: 'Screenshot' }, { value: 'external_link', label: 'Externer Link' }, { value: 'manual_upload', label: 'Manueller Upload' }, ] function EvidencePageContent({ initialControlId }: { initialControlId: string | null }) { const [evidence, setEvidence] = useState([]) const [controls, setControls] = useState([]) const [loading, setLoading] = useState(true) const [filterControlId, setFilterControlId] = useState(initialControlId || '') const [filterType, setFilterType] = useState('') const [uploadModalOpen, setUploadModalOpen] = useState(false) const [linkModalOpen, setLinkModalOpen] = useState(false) const [uploading, setUploading] = useState(false) const [newEvidence, setNewEvidence] = useState({ control_id: initialControlId || '', evidence_type: 'manual_upload', title: '', description: '', artifact_url: '' }) const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000' useEffect(() => { loadData() }, [filterControlId, filterType]) const loadData = async () => { setLoading(true) try { const params = new URLSearchParams() if (filterControlId) params.append('control_id', filterControlId) if (filterType) params.append('evidence_type', filterType) const [evidenceRes, controlsRes] = await Promise.all([ fetch(`${BACKEND_URL}/api/v1/compliance/evidence?${params}`), fetch(`${BACKEND_URL}/api/v1/compliance/controls`), ]) if (evidenceRes.ok) { const data = await evidenceRes.json(); setEvidence(data.evidence || []) } if (controlsRes.ok) { const data = await controlsRes.json(); setControls(data.controls || []) } } catch (error) { console.error('Failed to load data:', error) } finally { setLoading(false) } } const resetForm = () => { setNewEvidence({ control_id: filterControlId || '', evidence_type: 'manual_upload', title: '', description: '', artifact_url: '' }) } const handleFileUpload = async (file: File) => { if (!newEvidence.control_id || !newEvidence.title) { alert('Bitte alle Pflichtfelder ausfuellen'); return } setUploading(true) try { const formData = new FormData(); formData.append('file', file) const params = new URLSearchParams({ control_id: newEvidence.control_id, evidence_type: newEvidence.evidence_type, title: newEvidence.title }) if (newEvidence.description) params.append('description', newEvidence.description) const res = await fetch(`${BACKEND_URL}/api/v1/compliance/evidence/upload?${params}`, { method: 'POST', body: formData }) if (res.ok) { setUploadModalOpen(false); resetForm(); loadData() } else { alert(`Upload fehlgeschlagen: ${await res.text()}`) } } catch { alert('Upload fehlgeschlagen') } finally { setUploading(false) } } const handleLinkSubmit = async () => { if (!newEvidence.control_id || !newEvidence.title || !newEvidence.artifact_url) { alert('Bitte alle Pflichtfelder ausfuellen'); return } setUploading(true) try { const res = await fetch(`${BACKEND_URL}/api/v1/compliance/evidence`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ control_id: newEvidence.control_id, evidence_type: 'external_link', title: newEvidence.title, description: newEvidence.description, artifact_url: newEvidence.artifact_url, source: 'manual' }), }) if (res.ok) { setLinkModalOpen(false); resetForm(); loadData() } else { alert(`Fehler: ${await res.text()}`) } } catch { alert('Fehler beim Hinzufuegen') } finally { setUploading(false) } } const getControlTitle = (controlUuid: string) => controls.find((c) => c.id === controlUuid)?.control_id || controlUuid return (
Zurueck
{evidence.length} Nachweise
{loading ? (
) : evidence.length === 0 ? (

Keine Nachweise gefunden

) : (
{evidence.map((ev) => )}
)} {uploadModalOpen && setUploadModalOpen(false)} />} {linkModalOpen && setLinkModalOpen(false)} />} ) } function EvidencePageWithParams() { const searchParams = useSearchParams() return } export default function EvidencePage() { return (
}> ) }