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 35s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 19s
Profil: machineBuilder-Felder im POST-Body, PATCH-Handler Scope: API-Route (GET/POST), ScopeDecisionTab Props + Buttons, Export-Druckansicht HTML Anwendung: PUT-Handler, Bearbeiten-Button, Pagination/Search Import: Verlauf laden, DELETE-Route, Offline-Badge, ObjectURL Memory-Leak fix Screening: Security-Backlog Button verdrahtet, Scan-Verlauf Module: Detail-Seite, GET-Proxy, Konfigurieren-Button, Modul-erstellen-Modal, Error-Toast Quellen: 10 Proxy-Routen, Tab-Komponenten umgestellt, Dashboard-Tab, blocked_today Bug fix, Datum-Filter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
186 lines
5.6 KiB
TypeScript
186 lines
5.6 KiB
TypeScript
'use client'
|
|
|
|
import React, { useState, useEffect } from 'react'
|
|
import { useParams, useRouter } from 'next/navigation'
|
|
import Link from 'next/link'
|
|
import { AssessmentResultCard } from '@/components/sdk/use-case-assessment/AssessmentResultCard'
|
|
|
|
interface FullAssessment {
|
|
id: string
|
|
title: string
|
|
tenant_id: string
|
|
domain: string
|
|
created_at: string
|
|
use_case_text?: string
|
|
intake?: Record<string, unknown>
|
|
result?: {
|
|
feasibility: string
|
|
risk_level: string
|
|
risk_score: number
|
|
complexity: string
|
|
dsfa_recommended: boolean
|
|
art22_risk: boolean
|
|
training_allowed: string
|
|
summary: string
|
|
recommendation: string
|
|
alternative_approach?: string
|
|
triggered_rules?: Array<{
|
|
rule_code: string
|
|
title: string
|
|
severity: string
|
|
gdpr_ref: string
|
|
}>
|
|
required_controls?: Array<{
|
|
id: string
|
|
title: string
|
|
description: string
|
|
effort: string
|
|
}>
|
|
recommended_architecture?: Array<{
|
|
id: string
|
|
title: string
|
|
description: string
|
|
benefit: string
|
|
}>
|
|
}
|
|
}
|
|
|
|
export default function AssessmentDetailPage() {
|
|
const params = useParams()
|
|
const router = useRouter()
|
|
const assessmentId = params.id as string
|
|
|
|
const [assessment, setAssessment] = useState<FullAssessment | null>(null)
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
useEffect(() => {
|
|
async function load() {
|
|
try {
|
|
const response = await fetch(`/api/sdk/v1/ucca/assessments/${assessmentId}`)
|
|
if (!response.ok) {
|
|
throw new Error('Assessment nicht gefunden')
|
|
}
|
|
const data = await response.json()
|
|
setAssessment(data)
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Fehler beim Laden')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
if (assessmentId) {
|
|
// Try the direct endpoint first; if it fails, try the list endpoint and filter
|
|
load().catch(() => {
|
|
// Fallback: fetch from list
|
|
fetch('/api/sdk/v1/ucca/assessments')
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
const found = (data.assessments || []).find((a: FullAssessment) => a.id === assessmentId)
|
|
if (found) {
|
|
setAssessment(found)
|
|
setError(null)
|
|
}
|
|
})
|
|
.catch(() => {})
|
|
.finally(() => setLoading(false))
|
|
})
|
|
}
|
|
}, [assessmentId])
|
|
|
|
const handleDelete = async () => {
|
|
if (!confirm('Assessment wirklich loeschen?')) return
|
|
try {
|
|
await fetch(`/api/sdk/v1/ucca/assessments/${assessmentId}`, { method: 'DELETE' })
|
|
router.push('/sdk/use-cases')
|
|
} catch {
|
|
// Ignore delete errors
|
|
}
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="flex items-center justify-center h-64">
|
|
<div className="text-gray-500">Lade Assessment...</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (error || !assessment) {
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="bg-red-50 border border-red-200 rounded-lg p-6 text-center">
|
|
<h3 className="text-lg font-semibold text-red-800">Fehler</h3>
|
|
<p className="text-red-600 mt-1">{error || 'Assessment nicht gefunden'}</p>
|
|
</div>
|
|
<Link href="/sdk/use-cases" className="text-purple-600 hover:text-purple-700">
|
|
Zurueck zur Uebersicht
|
|
</Link>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Breadcrumb */}
|
|
<div className="flex items-center gap-2 text-sm text-gray-500">
|
|
<Link href="/sdk/use-cases" className="hover:text-purple-600">Use Cases</Link>
|
|
<span>/</span>
|
|
<span className="text-gray-900">{assessment.title || assessmentId.slice(0, 8)}</span>
|
|
</div>
|
|
|
|
{/* Header */}
|
|
<div className="flex items-start justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-gray-900">{assessment.title || 'Assessment Detail'}</h1>
|
|
<div className="flex items-center gap-4 mt-2 text-sm text-gray-500">
|
|
<span>Domain: {assessment.domain}</span>
|
|
<span>Erstellt: {new Date(assessment.created_at).toLocaleDateString('de-DE')}</span>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Link
|
|
href={`/sdk/use-cases/new?edit=${assessmentId}`}
|
|
className="px-4 py-2 text-sm bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
|
|
>
|
|
Bearbeiten
|
|
</Link>
|
|
<button
|
|
onClick={handleDelete}
|
|
className="px-4 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
|
>
|
|
Loeschen
|
|
</button>
|
|
<Link
|
|
href="/sdk/use-cases"
|
|
className="px-4 py-2 text-sm bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors"
|
|
>
|
|
Zurueck
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Use Case Text */}
|
|
{assessment.use_case_text && (
|
|
<div className="bg-gray-50 rounded-xl border border-gray-200 p-6">
|
|
<h3 className="text-sm font-medium text-gray-500 mb-2">Beschreibung des Anwendungsfalls</h3>
|
|
<p className="text-gray-800 whitespace-pre-wrap">{assessment.use_case_text}</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Result */}
|
|
{assessment.result && (
|
|
<AssessmentResultCard result={assessment.result} />
|
|
)}
|
|
|
|
{/* No Result */}
|
|
{!assessment.result && (
|
|
<div className="bg-yellow-50 border border-yellow-200 rounded-xl p-6 text-center">
|
|
<p className="text-yellow-700">Dieses Assessment hat noch kein Ergebnis.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|