feat: Analyse-Module auf 100% Runde 2 — CREATE-Forms, Button-Handler, Persistenz
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 36s
CI / test-python-backend-compliance (push) Successful in 36s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 19s

Requirements: ADD-Form + Details-Panel mit Controls/Status-Anzeige
Controls: ADD-Form + Effectiveness-Persistenz via PUT
Evidence: Anzeigen/Herunterladen-Buttons mit fileUrl + disabled-State
Risks: RiskMatrix Cell-Click filtert Risiko-Liste mit Badge + Reset
AI Act: Mock-Daten entfernt, Loading-Skeleton, Edit/Delete-Handler
Audit Checklist: JSON-Export, debounced Notes-Persistenz, Neue Checkliste
Audit Report: Animiertes Skeleton statt Loading-Text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-02 13:13:26 +01:00
parent a50a9810ee
commit fc83ebfd82
7 changed files with 607 additions and 96 deletions

View File

@@ -387,6 +387,7 @@ export default function RisksPage() {
const [editingRisk, setEditingRisk] = useState<Risk | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [matrixFilter, setMatrixFilter] = useState<{ likelihood: number; impact: number } | null>(null)
// Fetch risks from backend on mount
useEffect(() => {
@@ -595,14 +596,43 @@ export default function RisksPage() {
{loading && <LoadingSkeleton />}
{/* Matrix */}
{!loading && <RiskMatrix risks={state.risks} onCellClick={() => {}} />}
{!loading && (
<RiskMatrix
risks={state.risks}
onCellClick={(l, i) => {
if (matrixFilter && matrixFilter.likelihood === l && matrixFilter.impact === i) {
setMatrixFilter(null)
} else {
setMatrixFilter({ likelihood: l, impact: i })
}
}}
/>
)}
{/* Matrix Filter Badge */}
{matrixFilter && (
<div className="flex items-center gap-2">
<span className="px-3 py-1 text-sm bg-purple-100 text-purple-700 rounded-full flex items-center gap-2">
Gefiltert: L={matrixFilter.likelihood} I={matrixFilter.impact}
<button
onClick={() => setMatrixFilter(null)}
className="text-purple-500 hover:text-purple-700 font-bold"
>
&times;
</button>
</span>
</div>
)}
{/* Risk List */}
{!loading && state.risks.length > 0 && (
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-4">Alle Risiken</h3>
<h3 className="text-lg font-semibold text-gray-900 mb-4">
{matrixFilter ? `Risiken (L=${matrixFilter.likelihood}, I=${matrixFilter.impact})` : 'Alle Risiken'}
</h3>
<div className="space-y-4">
{state.risks
.filter(risk => !matrixFilter || (risk.likelihood === matrixFilter.likelihood && risk.impact === matrixFilter.impact))
.sort((a, b) => b.inherentRiskScore - a.inherentRiskScore)
.map(risk => (
<RiskCard