From 2a25b66a2fc595bcd1a5fc6a4d53ab1cfe4dea5a Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Tue, 9 Jun 2026 18:43:43 +0200 Subject: [PATCH] feat(iace-frontend): expandable detail rows for missing + extra benchmark findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Zugeordnet" tab already expanded to a GT-vs-Engine detail comparison; the "Fehlend" and "Engine Findings" tabs were flat and could not be inspected. Extracted GTDetailBlock / EngineDetailBlock from DetailComparison and made both tables expandable (chevron) — missing rows show the full GT entry, extra rows show the full engine hazard (incl. measures, norms, clarification status). Co-Authored-By: Claude Opus 4.7 --- .../_components/HazardComparisonTable.tsx | 184 +++++++++++------- 1 file changed, 118 insertions(+), 66 deletions(-) diff --git a/admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/HazardComparisonTable.tsx b/admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/HazardComparisonTable.tsx index 0e52e5f1..54a40f07 100644 --- a/admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/HazardComparisonTable.tsx +++ b/admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/HazardComparisonTable.tsx @@ -87,7 +87,7 @@ export function HazardComparisonTable({ matched, missing, extra }: Props) {
{tab === 'matched' && } {tab === 'missing' && } - {tab === 'extra' && } + {tab === 'extra' && }
) @@ -175,6 +175,73 @@ function formatLifecycles(raw: string): string { return raw.split(',').map(s => s.trim()).map(s => LIFECYCLE_LABELS[s] || s).join(', ') } +function Chevron({ open }: { open: boolean }) { + return ( + + + + ) +} + +/** Ground Truth (professional) detail block — reused by matched + missing rows. */ +function GTDetailBlock({ gt }: { gt: GroundTruthEntry }) { + return ( +
+
Ground Truth (Fachmann)
+ + + + + R=${gt.risk_in.r}`} /> + {gt.risk_out.r > 0 && ( + R=${gt.risk_out.r}`} /> + )} + + + {gt.norm_references?.length > 0 && ( + + )} + + {gt.comment && } +
+ ) +} + +/** Engine (automatic) detail block — reused by matched + extra rows. */ +function EngineDetailBlock({ engine, clarStatus, projectId }: { + engine: HazardSummary; clarStatus?: HazardClarStatus; projectId?: string +}) { + return ( +
+
Engine (automatisch)
+ + + + {engine.lifecycle_phase && ( + + )} + + + {engine.affected_person && ( + + )} + {engine.mitigations && engine.mitigations.length > 0 ? ( + + ) : ( + + )} + {clarStatus && clarStatus.total > 0 && ( + + )} + {(() => { + const norms = extractEngineNorms(engine.description) + if (norms.length === 0) return null + return + })()} +
+ ) +} + /** Side-by-side detail comparison of GT entry vs. Engine hazard */ function DetailComparison({ gt, engine, clarStatus, projectId }: { gt: GroundTruthEntry @@ -184,53 +251,8 @@ function DetailComparison({ gt, engine, clarStatus, projectId }: { }) { return (
- {/* Left: Ground Truth */} -
-
Ground Truth (Fachmann)
- - - - - R=${gt.risk_in.r}`} /> - {gt.risk_out.r > 0 && ( - R=${gt.risk_out.r}`} /> - )} - - - {gt.norm_references?.length > 0 && ( - - )} - - {gt.comment && } -
- {/* Right: Engine */} -
-
Engine (automatisch)
- - - - {engine.lifecycle_phase && ( - - )} - - - {engine.affected_person && ( - - )} - {engine.mitigations && engine.mitigations.length > 0 ? ( - - ) : ( - - )} - {clarStatus && clarStatus.total > 0 && ( - - )} - {(() => { - const norms = extractEngineNorms(engine.description) - if (norms.length === 0) return null - return - })()} -
+ +
) } @@ -310,6 +332,7 @@ function DetailRow({ label, gt, multiline }: { label: string; gt: string; multil } function MissingTable({ entries }: { entries: GroundTruthEntry[] }) { + const [expanded, setExpanded] = useState>({}) if (entries.length === 0) return return ( @@ -324,22 +347,37 @@ function MissingTable({ entries }: { entries: GroundTruthEntry[] }) { - {entries.map((e, i) => ( - - - - - - - - - ))} + {entries.map((e, i) => { + const isOpen = expanded[i] + return ( + + setExpanded(p => ({ ...p, [i]: !p[i] }))}> + + + + + + + + {isOpen && ( + + + + )} + + ) + })}
{e.nr}{e.hazard_type}{e.hazard_cause}{e.component_zone}{e.measure_type}
+
{e.nr}
+
{e.hazard_type}{e.hazard_cause}{e.component_zone}{e.measure_type}
) } -function ExtraTable({ entries }: { entries: HazardSummary[] }) { +function ExtraTable({ entries, clarStatusByHazard, projectId }: { + entries: HazardSummary[]; clarStatusByHazard: Record; projectId?: string +}) { + const [expanded, setExpanded] = useState>({}) if (entries.length === 0) return return ( @@ -351,13 +389,27 @@ function ExtraTable({ entries }: { entries: HazardSummary[] }) { - {entries.map((e, i) => ( - - - - - - ))} + {entries.map((e, i) => { + const isOpen = expanded[i] + return ( + + setExpanded(p => ({ ...p, [i]: !p[i] }))}> + + + + + {isOpen && ( + + + + )} + + ) + })}
{e.name}{e.category}{e.zone || '-'}
+
{e.name}
+
{e.category}{e.zone || '-'}
+ +
)