'use client' /** * RemediationPlan — Abstellmaßnahmen + Ticket-Formulierung. * * Aus den offenen Punkten (result.results, Haupt-Engine) je Finding eine * Maßnahme + einen fertigen Ticket-Text ableiten und übergabebereit machen * (Kopieren / JSON-Export). SCOPE: BreakPilot formuliert NUR — Ticketsystem, * Jira-Sync und Feedback-Loop baut ein anderes Team. Keine zweite Engine. */ import React, { useState } from 'react' import { DOC_TYPE_LABELS, type DocResult } from './ChecklistView' type Priority = 'Hoch' | 'Mittel' | 'Niedrig' interface Remediation { docType: string docLabel: string checkLabel: string action: string ticketTitle: string ticketBody: string priority: Priority } const PRIO_RANK: Record = { Hoch: 0, Mittel: 1, Niedrig: 2 } const PRIO_COLOR: Record = { Hoch: 'bg-red-100 text-red-700', Mittel: 'bg-amber-100 text-amber-700', Niedrig: 'bg-blue-100 text-blue-700', } function toPriority(sev: string): Priority { const s = (sev || '').toUpperCase() if (s === 'HIGH' || s === 'CRITICAL') return 'Hoch' if (s === 'MEDIUM') return 'Mittel' return 'Niedrig' } function buildRemediations(docs: DocResult[]): Remediation[] { const out: Remediation[] = [] for (const d of docs) { if (d.error) continue const docLabel = DOC_TYPE_LABELS[d.doc_type] || d.doc_type const failed = d.checks.filter( c => !c.passed && !c.skipped && c.severity !== 'INFO', ) for (const c of failed) { const action = c.hint || `${c.label} im ${docLabel} ergänzen.` out.push({ docType: d.doc_type, docLabel, checkLabel: c.label, action, ticketTitle: `Compliance: ${docLabel} – ${c.label}`, ticketBody: `Dokument: ${docLabel}\nPrüfpunkt: ${c.label}\n` + `Status: nicht erfüllt\nMaßnahme: ${action}`, priority: toPriority(c.severity), }) } } return out.sort((a, b) => PRIO_RANK[a.priority] - PRIO_RANK[b.priority]) } export function RemediationPlan({ results }: { results: any }) { const items = buildRemediations(results.results || []) const [copied, setCopied] = useState(null) if (items.length === 0) { return (
Keine offenen Pflichtangaben — kein Handlungsbedarf.
) } function copyTicket(i: number, body: string) { navigator.clipboard?.writeText(body) setCopied(i) window.setTimeout(() => setCopied(null), 1500) } function exportAll() { const payload = items.map(it => ({ title: it.ticketTitle, body: it.ticketBody, priority: it.priority, doc_type: it.docType, })) const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json', }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = 'breakpilot-tickets.json' a.click() URL.revokeObjectURL(url) } return (

Abstellmaßnahmen & Tickets ({items.length})

{items.map((it, i) => (
{it.priority} {it.docLabel}: {it.checkLabel}
{it.action}
))}
) }