Files
breakpilot-compliance/admin-compliance/components/sdk/obligations/TOMControlPanel.tsx
Benjamin Admin f3ccfe5dcd
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 33s
CI / test-python-backend-compliance (push) Successful in 34s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 17s
fix(ucca): Route-Konflikt :id vs :assessmentId — TOM-Controls Pfad geaendert
GET /obligations/:id/tom-controls → GET /obligations/tom-controls/for-obligation/:obligationId
Gin erlaubt keine unterschiedlichen Param-Namen auf demselben Pfad-Level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:03:48 +01:00

106 lines
3.4 KiB
TypeScript

'use client'
import React, { useState, useEffect } from 'react'
interface TOMControl {
id: string
title: string
description: string
domain_id: string
priority: string
gdpr_articles: string[]
}
interface TOMControlPanelProps {
obligationId: string
onClose: () => void
}
const UCCA_API = '/api/sdk/v1/ucca/obligations'
const DOMAIN_LABELS: Record<string, string> = {
GOV: 'Governance',
HR: 'Human Resources',
IAM: 'Identity & Access',
AC: 'Access Control',
CRYPTO: 'Kryptographie',
LOG: 'Logging & Monitoring',
SDLC: 'Softwareentwicklung',
OPS: 'Betrieb',
NET: 'Netzwerk',
BCP: 'Business Continuity',
VENDOR: 'Lieferanten',
DATA: 'Datenschutz',
}
const PRIORITY_COLORS: Record<string, string> = {
kritisch: 'bg-red-100 text-red-700',
hoch: 'bg-orange-100 text-orange-700',
mittel: 'bg-yellow-100 text-yellow-700',
niedrig: 'bg-green-100 text-green-700',
}
export default function TOMControlPanel({ obligationId, onClose }: TOMControlPanelProps) {
const [controls, setControls] = useState<TOMControl[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
async function load() {
setLoading(true)
setError(null)
try {
const res = await fetch(`${UCCA_API}/tom-controls/for-obligation/${obligationId}`)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()
setControls(data.controls || [])
} catch (e) {
setError(e instanceof Error ? e.message : 'Laden fehlgeschlagen')
} finally {
setLoading(false)
}
}
load()
}, [obligationId])
return (
<div className="bg-white border border-gray-200 rounded-xl overflow-hidden">
<div className="flex items-center justify-between px-5 py-3 bg-gray-50 border-b">
<h3 className="text-sm font-semibold text-gray-900">TOM Controls</h3>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 text-xs">Schliessen</button>
</div>
<div className="p-4">
{loading && <p className="text-xs text-gray-500">Lade Controls...</p>}
{error && <p className="text-xs text-red-600">{error}</p>}
{!loading && !error && controls.length === 0 && (
<p className="text-xs text-gray-400">Keine TOM Controls verknuepft</p>
)}
{!loading && controls.length > 0 && (
<div className="space-y-2">
{controls.map(c => (
<div key={c.id} className="border border-gray-100 rounded-lg p-3 hover:bg-gray-50 transition-colors">
<div className="flex items-center gap-2 mb-1">
<span className="text-xs font-mono text-purple-600">{c.id}</span>
<span className="text-xs text-gray-400">{DOMAIN_LABELS[c.domain_id] || c.domain_id}</span>
{c.priority && (
<span className={`px-1.5 py-0.5 text-[10px] rounded ${PRIORITY_COLORS[c.priority] || 'bg-gray-100 text-gray-600'}`}>
{c.priority}
</span>
)}
</div>
<p className="text-sm font-medium text-gray-900">{c.title}</p>
{c.description && (
<p className="text-xs text-gray-500 mt-1 line-clamp-2">{c.description}</p>
)}
</div>
))}
</div>
)}
</div>
</div>
)
}