feat(iace-ui): component presence/CE review + machine-type dropdown
- Components view: three presence sections (Vorhanden / Nicht vorhanden / Geloescht) with bidirectional move + soft-delete (audit-visible, restorable), so the expert corrects the engine's best-effort negation in both directions. - CE marking per component (bought robot/actuator/SPS) with a clear "validate the integrated safety function (PL/SIL)" note when also safety-relevant. Safe semantics: hazards are not suppressed, only provenance is surfaced. - Project-create form: machine type is now a grouped dropdown from the engine's controlled vocabulary (GET /machine-types) instead of free text. - Knowledge graph: component→hazard edges use the real component_id. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Component, ComponentFormData, LibraryComponent, EnergySource, buildTree } from '../_components/types'
|
||||
import { Component, ComponentFormData, LibraryComponent, EnergySource, PresenceStatus, buildTree } from '../_components/types'
|
||||
|
||||
export function useComponents(projectId: string) {
|
||||
const [components, setComponents] = useState<Component[]>([])
|
||||
@@ -47,16 +47,43 @@ export function useComponents(projectId: string) {
|
||||
return false
|
||||
}
|
||||
|
||||
async function handleDelete(id: string) {
|
||||
if (!confirm('Komponente wirklich loeschen? Unterkomponenten werden ebenfalls entfernt.')) return
|
||||
// Move a component between presence states (vorhanden / nicht_vorhanden /
|
||||
// geloescht). Used for the expert's bidirectional review of auto-detected
|
||||
// components.
|
||||
async function setPresence(id: string, status: PresenceStatus) {
|
||||
try {
|
||||
const res = await fetch(`/api/sdk/v1/iace/projects/${projectId}/components/${id}`, { method: 'DELETE' })
|
||||
const res = await fetch(`/api/sdk/v1/iace/projects/${projectId}/components/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ presence_status: status }),
|
||||
})
|
||||
if (res.ok) await fetchComponents()
|
||||
} catch (err) {
|
||||
console.error('Failed to delete component:', err)
|
||||
console.error('Failed to set presence:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// Mark a component as a bought CE product (robot, actuator, SPS ...). Safe
|
||||
// semantics: no hazard suppression — only provenance + PL/SIL note.
|
||||
async function setCEMarked(id: string, value: boolean) {
|
||||
try {
|
||||
const res = await fetch(`/api/sdk/v1/iace/projects/${projectId}/components/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ce_marked: value }),
|
||||
})
|
||||
if (res.ok) await fetchComponents()
|
||||
} catch (err) {
|
||||
console.error('Failed to set ce_marked:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// Soft-delete: the component moves to the "Geloescht" list (restorable); it is
|
||||
// not removed from the project, so nothing silently disappears.
|
||||
async function handleDelete(id: string) {
|
||||
await setPresence(id, 'geloescht')
|
||||
}
|
||||
|
||||
async function handleAddFromLibrary(libraryComps: LibraryComponent[], energySrcs: EnergySource[]) {
|
||||
const energySourceIds = energySrcs.map(e => e.id)
|
||||
for (const comp of libraryComps) {
|
||||
@@ -88,5 +115,7 @@ export function useComponents(projectId: string) {
|
||||
handleSubmit,
|
||||
handleDelete,
|
||||
handleAddFromLibrary,
|
||||
setPresence,
|
||||
setCEMarked,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user