feat(iace): Phase 1 — Haftungs-Fixes, Massnahmen-Verkabelung, Explainability Engine
Phase 1A — Haftungs-kritische Fixes: - SIL/PL-Badges als "Vorab-Einschaetzung" mit Tooltip gekennzeichnet - Coverage-Disclaimer in CE-Akte, Projekt-Uebersicht und Print-Export - Norm-Referenzen: 42 Kapitelverweise durch Themen-Deskriptoren ersetzt Phase 1B — Massnahmen-Verkabelung: - 16 neue Massnahmen (M201-M216) fuer bisher unabgedeckte Kategorien (communication_failure, hmi_error, firmware_corruption, maintenance, sensor_fault, mode_confusion) - Kategorie-Fallback im Initialize-Endpoint: ordnet Massnahmen aus der Bibliothek automatisch per HazardCategory zu (max 8 pro Kategorie) - Total: 225 → 241 Massnahmen, 0 Kategorien ohne Massnahmen Phase 1C — Explainability Engine: - MatchReason Struct in PatternMatch (type, tag, met) - Pattern Engine schreibt fuer jeden Match strukturierte Begruendungen - Frontend zeigt "Erkannt weil: Komponente X, Energie Y, Kein Ausschluss Z" Weitere Aenderungen: - BAuA/OSHA Regulatory Hints: 3 Enrich-Endpoints (per Hazard, per Measure, Batch) - Dokumente-Tab in IACE-Bibliothek (36.708 Chunks aus Qdrant) - Varianten-UX: Basis-Projekt-Summary auf Varianten-Seite - Projekt-Initialisierung: POST /initialize kettet Parse→Komponenten→Patterns→Hazards→Massnahmen→Normen - 18 pre-existing TS-Fehler gefixt, Route-Konflikt behoben - Component-Library + Measures-Library Tests aktualisiert Tests: Go alle bestanden, TS 0 Fehler, Playwright 141+ bestanden Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useCallback } from 'react'
|
||||
|
||||
interface Hint {
|
||||
regulation_id: string
|
||||
regulation_short: string
|
||||
category: string
|
||||
text: string
|
||||
pages?: number[]
|
||||
source_url?: string
|
||||
score: number
|
||||
}
|
||||
|
||||
function catBadge(cat: string): string {
|
||||
if (cat === 'trbs') return 'bg-orange-100 text-orange-800'
|
||||
if (cat === 'trgs') return 'bg-red-100 text-red-800'
|
||||
if (cat === 'asr') return 'bg-teal-100 text-teal-800'
|
||||
return 'bg-blue-100 text-blue-800'
|
||||
}
|
||||
|
||||
interface Props {
|
||||
projectId: string
|
||||
mitigationId: string
|
||||
}
|
||||
|
||||
export function MitigationHints({ projectId, mitigationId }: Props) {
|
||||
const [hints, setHints] = useState<Hint[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [loaded, setLoaded] = useState(false)
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await fetch(`/api/sdk/v1/iace/projects/${projectId}/mitigations/${mitigationId}/regulatory-hints`)
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
setHints(data.hints || [])
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
finally { setLoading(false); setLoaded(true) }
|
||||
}, [projectId, mitigationId])
|
||||
|
||||
if (!loaded) {
|
||||
return (
|
||||
<button onClick={load} disabled={loading}
|
||||
className="inline-flex items-center gap-1 text-[10px] text-purple-600 hover:text-purple-800 disabled:opacity-50">
|
||||
{loading ? 'Lade...' : 'TRBS/OSHA Hinweise laden'}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
if (hints.length === 0) return <span className="text-[10px] text-gray-400">Keine Hinweise</span>
|
||||
|
||||
return (
|
||||
<div className="space-y-1.5 mt-1">
|
||||
<p className="text-[10px] font-medium text-gray-500">Regulatorische Hinweise:</p>
|
||||
{hints.map((h, i) => (
|
||||
<div key={i} className="p-2 rounded border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 text-[11px]">
|
||||
<span className={`inline-flex px-1 py-0.5 rounded text-[9px] font-medium ${catBadge(h.category)}`}>
|
||||
{h.regulation_short || h.regulation_id}
|
||||
</span>
|
||||
{h.pages?.length ? <span className="text-gray-400 ml-1">S.{h.pages.join(',')}</span> : null}
|
||||
<p className="text-gray-600 dark:text-gray-300 mt-0.5 leading-relaxed">{h.text}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { MeasuresLibraryModal } from './_components/MeasuresLibraryModal'
|
||||
import { SuggestMeasuresModal } from './_components/SuggestMeasuresModal'
|
||||
import { MitigationForm } from './_components/MitigationForm'
|
||||
import { StatusBadge } from './_components/StatusBadge'
|
||||
import { MitigationHints } from './_components/MitigationHints'
|
||||
import { ProtectiveMeasure } from './_components/types'
|
||||
import { useMitigations } from './_hooks/useMitigations'
|
||||
|
||||
@@ -238,6 +239,7 @@ export default function MitigationsPage() {
|
||||
{m.description && <p className="text-gray-600 dark:text-gray-300">{m.description}</p>}
|
||||
{category && <p className="text-purple-600">Diese Massnahme gilt fuer alle Gefaehrdungen der Kategorie <strong>{category}</strong>.</p>}
|
||||
{refs?.length > 0 && <p className="text-blue-500">Normen: {refs.join(', ')}</p>}
|
||||
<MitigationHints projectId={projectId} mitigationId={m.id} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user