(null)
@@ -110,7 +118,9 @@ export default function ComponentsPage() {
{tree.map((component) => (
+ onEdit={handleEdit} onDelete={handleDelete} onAddChild={handleAddChild}
+ onMarkAbsent={(id) => setPresence(id, 'nicht_vorhanden')}
+ onToggleCE={setCEMarked} />
))}
@@ -140,6 +150,27 @@ export default function ComponentsPage() {
)
)}
+
+ setPresence(id, 'vorhanden') },
+ { label: 'Loeschen', variant: 'danger', onClick: handleDelete },
+ ]}
+ />
+
+ setPresence(id, 'vorhanden') },
+ ]}
+ />
)
}
diff --git a/admin-compliance/app/sdk/iace/[projectId]/knowledge-graph/_hooks/useKnowledgeGraph.ts b/admin-compliance/app/sdk/iace/[projectId]/knowledge-graph/_hooks/useKnowledgeGraph.ts
index b64f0c38..b5884c87 100644
--- a/admin-compliance/app/sdk/iace/[projectId]/knowledge-graph/_hooks/useKnowledgeGraph.ts
+++ b/admin-compliance/app/sdk/iace/[projectId]/knowledge-graph/_hooks/useKnowledgeGraph.ts
@@ -3,7 +3,7 @@
import { useState, useEffect, useMemo } from 'react'
interface Component { id: string; name: string; component_type: string }
-interface Hazard { id: string; name: string; category: string; operational_states?: string[] }
+interface Hazard { id: string; name: string; category: string; operational_states?: string[]; component_id?: string }
interface Mitigation { id: string; name?: string; title?: string; reduction_type: string; hazard_id?: string; linked_hazard_ids?: string[] }
export interface GraphNode {
@@ -56,6 +56,7 @@ export function useKnowledgeGraph(projectId: string) {
setHazards((j.hazards || j || []).map((h: Record) => ({
id: h.id as string, name: h.name as string, category: h.category as string || '',
operational_states: (h.operational_states || []) as string[],
+ component_id: (h.component_id || '') as string,
})))
}
if (mitRes.ok) {
@@ -89,17 +90,20 @@ export function useKnowledgeGraph(projectId: string) {
})
// Hazard nodes
+ const compIdSet = new Set(components.map((c) => c.id))
hazards.forEach((h) => {
graphNodes.push({
id: `haz-${h.id}`, type: 'hazard',
label: h.name, subLabel: h.category,
color: NODE_COLORS.hazard,
})
- // Edge: first component → hazard (simplified — could be per component_id)
- if (components.length > 0) {
+ // Edge: the component that actually causes this hazard → hazard.
+ // Only drawn when the hazard carries a component_id that maps to a known
+ // component node (no synthetic "all from the first component" edges).
+ if (h.component_id && compIdSet.has(h.component_id)) {
graphEdges.push({
id: `e-comp-haz-${h.id}`,
- source: `comp-${components[0].id}`,
+ source: `comp-${h.component_id}`,
target: `haz-${h.id}`,
label: 'erzeugt',
})
diff --git a/admin-compliance/app/sdk/iace/page.tsx b/admin-compliance/app/sdk/iace/page.tsx
index b792e0be..c86e21f8 100644
--- a/admin-compliance/app/sdk/iace/page.tsx
+++ b/admin-compliance/app/sdk/iace/page.tsx
@@ -134,9 +134,14 @@ export default function IACEDashboardPage() {
machine_type: '',
manufacturer: '',
})
+ const [machineTypes, setMachineTypes] = useState<{ key: string; label_de: string; group: string }[]>([])
useEffect(() => {
fetchProjects()
+ fetch('/api/sdk/v1/iace/machine-types')
+ .then((r) => (r.ok ? r.json() : null))
+ .then((j) => j && setMachineTypes(j.machine_types || []))
+ .catch((err) => console.error('Failed to fetch machine types:', err))
}, [])
async function fetchProjects() {
@@ -308,13 +313,23 @@ export default function IACEDashboardPage() {
- setFormData({ ...formData, machine_type: e.target.value })}
- placeholder="z.B. Industrieroboter"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent dark:bg-gray-700 dark:border-gray-600 dark:text-white"
- />
+ >
+
+ {Array.from(new Set(machineTypes.map((m) => m.group))).map((group) => (
+
+ ))}
+
+
+ Steuert, welche maschinenspezifischen Gefährdungs-Patterns greifen — bitte aus der Liste wählen.
+