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
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>
106 lines
3.4 KiB
TypeScript
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>
|
|
)
|
|
}
|