diff --git a/admin-compliance/app/sdk/gap-analysis/_components/GapDashboard.tsx b/admin-compliance/app/sdk/gap-analysis/_components/GapDashboard.tsx new file mode 100644 index 0000000..5201cb7 --- /dev/null +++ b/admin-compliance/app/sdk/gap-analysis/_components/GapDashboard.tsx @@ -0,0 +1,246 @@ +'use client' + +import React, { useState } from 'react' + +interface GapReport { + profile_name: string + regulations: Array<{ + id: string + name: string + risk_level: string + confidence: number + reasoning: string + requirements?: string[] + }> + summary: { + total_applicable_regulations: number + total_gaps: number + gaps_by_status: Record + gaps_by_severity: Record + overall_compliance_percent: number + estimated_effort_weeks: number + } + gaps: Array<{ + mc_id: string + mc_name: string + regulation: string + status: string + title: string + severity: string + priority: { score: number; rank: number } + recommendation: string + control_count: number + }> +} + +interface Props { + report: GapReport + onBack: () => void +} + +const STATUS_COLORS: Record = { + fulfilled: 'bg-green-100 text-green-800', + partial: 'bg-yellow-100 text-yellow-800', + missing: 'bg-red-100 text-red-800', + unclear: 'bg-gray-100 text-gray-800', +} + +const STATUS_LABELS: Record = { + fulfilled: 'Erfuellt', + partial: 'Teilweise', + missing: 'Offen', + unclear: 'Unklar', +} + +const SEVERITY_COLORS: Record = { + CRITICAL: 'bg-red-600 text-white', + HIGH: 'bg-orange-500 text-white', + MEDIUM: 'bg-yellow-400 text-gray-900', + LOW: 'bg-blue-100 text-blue-800', +} + +export function GapDashboard({ report, onBack }: Props) { + const [filterSeverity, setFilterSeverity] = useState('all') + const [filterStatus, setFilterStatus] = useState('all') + const [expandedGap, setExpandedGap] = useState(null) + + const filteredGaps = report.gaps.filter(g => { + if (filterSeverity !== 'all' && g.severity !== filterSeverity) return false + if (filterStatus !== 'all' && g.status !== filterStatus) return false + return true + }) + + const s = report.summary + + return ( +
+ {/* Back button */} + + + {/* Summary Cards */} +
+ + + = 80 ? 'green' : 'orange'} + /> + +
+ + {/* Applicable Regulations */} +
+

+ Anwendbare Regulierungen +

+
+ {report.regulations.map(reg => ( +
+
+ + {reg.name} + + + {reg.risk_level} + +
+

{reg.reasoning}

+
+ ))} +
+
+ + {/* Filters */} +
+ + + + {filteredGaps.length} von {report.gaps.length} Anforderungen + +
+ + {/* Gap List */} +
+ + + + + + + + + + + + + {filteredGaps.map(gap => ( + + setExpandedGap(expandedGap === gap.mc_id ? null : gap.mc_id)} + > + + + + + + + + {expandedGap === gap.mc_id && ( + + + + )} + + ))} + +
#AnforderungRegulierungStatusPrioritaetControls
{gap.priority.rank} +
{gap.title}
+
{gap.mc_name}
+
{gap.regulation} + + {STATUS_LABELS[gap.status] || gap.status} + + + + {gap.severity} + + {gap.control_count}
+
+

Empfehlung:

+

{gap.recommendation}

+

+ Priority Score: {gap.priority.score.toFixed(1)} | MC: {gap.mc_id} +

+
+
+
+
+ ) +} + +function SummaryCard({ label, value, color }: { label: string; value: string | number; color: string }) { + const bg = { + blue: 'bg-blue-50 border-blue-200', + red: 'bg-red-50 border-red-200', + green: 'bg-green-50 border-green-200', + orange: 'bg-orange-50 border-orange-200', + purple: 'bg-purple-50 border-purple-200', + }[color] || 'bg-gray-50 border-gray-200' + + const text = { + blue: 'text-blue-700', + red: 'text-red-700', + green: 'text-green-700', + orange: 'text-orange-700', + purple: 'text-purple-700', + }[color] || 'text-gray-700' + + return ( +
+

{label}

+

{value}

+
+ ) +} diff --git a/admin-compliance/app/sdk/gap-analysis/_components/ProductWizard.tsx b/admin-compliance/app/sdk/gap-analysis/_components/ProductWizard.tsx new file mode 100644 index 0000000..f78137d --- /dev/null +++ b/admin-compliance/app/sdk/gap-analysis/_components/ProductWizard.tsx @@ -0,0 +1,238 @@ +'use client' + +import React, { useState } from 'react' + +const PRODUCT_TYPES = [ + { value: 'iot', label: 'IoT / Connected Device' }, + { value: 'software', label: 'Software / Desktop App' }, + { value: 'saas', label: 'SaaS / Cloud-Plattform' }, + { value: 'hardware', label: 'Hardware / Elektronik' }, + { value: 'machinery', label: 'Maschine / Anlage' }, + { value: 'medical_device', label: 'Medizinprodukt' }, + { value: 'exchange', label: 'Krypto-Exchange / Fintech' }, + { value: 'other', label: 'Sonstiges' }, +] + +const TECHNOLOGIES = [ + { value: 'ai', label: 'Kuenstliche Intelligenz / ML' }, + { value: 'blockchain', label: 'Blockchain / Smart Contracts' }, + { value: 'cloud', label: 'Cloud-Infrastruktur' }, + { value: 'api', label: 'REST/GraphQL API' }, + { value: 'database', label: 'Datenbank' }, + { value: 'encryption', label: 'Verschluesselung' }, + { value: 'ota_updates', label: 'OTA Software-Updates' }, + { value: 'sensor', label: 'Sensoren' }, + { value: 'actuator', label: 'Aktoren / Motoren' }, + { value: 'network', label: 'Netzwerk-Anbindung' }, + { value: 'camera', label: 'Kamera / Bilderkennung' }, + { value: 'payment', label: 'Zahlungsabwicklung' }, + { value: 'fiat_gateway', label: 'Fiat On/Off-Ramp' }, +] + +const DATA_TYPES = [ + { value: 'personal_data', label: 'Personenbezogene Daten' }, + { value: 'health_data', label: 'Gesundheitsdaten' }, + { value: 'financial_data', label: 'Finanzdaten' }, + { value: 'telemetry', label: 'Telemetrie / Nutzungsdaten' }, +] + +const CERTIFICATIONS = [ + { value: 'ISO27001', label: 'ISO 27001' }, + { value: 'CE', label: 'CE-Kennzeichnung' }, + { value: 'SOC2', label: 'SOC 2' }, + { value: 'ISO13485', label: 'ISO 13485 (Medizin)' }, +] + +interface Props { + onAnalyze: (profile: Record) => void + loading: boolean +} + +export function ProductWizard({ onAnalyze, loading }: Props) { + const [name, setName] = useState('') + const [description, setDescription] = useState('') + const [productType, setProductType] = useState('') + const [technologies, setTechnologies] = useState([]) + const [dataProcessing, setDataProcessing] = useState([]) + const [certifications, setCertifications] = useState([]) + const [connectedToInternet, setConnectedToInternet] = useState(false) + const [hasSoftwareUpdates, setHasSoftwareUpdates] = useState(false) + const [usesAI, setUsesAI] = useState(false) + const [processesPersonalData, setProcessesPersonalData] = useState(false) + const [isCriticalInfra, setIsCriticalInfra] = useState(false) + + const toggleArrayValue = ( + arr: string[], + setter: (v: string[]) => void, + value: string + ) => { + setter(arr.includes(value) ? arr.filter(v => v !== value) : [...arr, value]) + } + + const handleSubmit = () => { + onAnalyze({ + name: name || 'Unbenanntes Produkt', + description, + product_type: productType, + technologies, + data_processing: dataProcessing, + markets: ['EU'], + connected_to_internet: connectedToInternet, + has_software_updates: hasSoftwareUpdates, + uses_ai: usesAI, + processes_personal_data: processesPersonalData, + is_critical_infra_supplier: isCriticalInfra, + existing_certifications: certifications, + }) + } + + return ( +
+ {/* Produktname */} +
+ + setName(e.target.value)} + placeholder="z.B. SmartFactory Gateway Pro" + className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500" + /> +
+ + {/* Beschreibung */} +
+ +