From 3fe9fa7ca81e203bbdee3495983fb8fbfb8cf08e Mon Sep 17 00:00:00 2001 From: Pouzor Date: Sun, 29 Mar 2026 19:24:22 +0200 Subject: [PATCH] feat: add inline edit for services in detail panel Replaces service badge with in-place form when pencil icon is clicked. State is scoped to nodeId so switching nodes auto-resets edit/add forms. --- .../src/components/panels/DetailPanel.tsx | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/panels/DetailPanel.tsx b/frontend/src/components/panels/DetailPanel.tsx index 93a0abc..e5b0f5b 100644 --- a/frontend/src/components/panels/DetailPanel.tsx +++ b/frontend/src/components/panels/DetailPanel.tsx @@ -18,13 +18,16 @@ export function DetailPanel({ onEdit }: DetailPanelProps) { const { nodes, selectedNodeId, setSelectedNode, deleteNode, updateNode } = useCanvasStore() const node = nodes.find((n) => n.id === selectedNodeId) - const [addingService, setAddingService] = useState(false) + const [addingForNode, setAddingForNode] = useState(null) const [newSvc, setNewSvc] = useState(EMPTY_FORM) - const [editingIndex, setEditingIndex] = useState(null) + const [editingFor, setEditingFor] = useState<{ nodeId: string; index: number } | null>(null) const [editSvc, setEditSvc] = useState(EMPTY_FORM) if (!node || node.data.type === 'groupRect') return null + const addingService = addingForNode === node.id + const editingIndex = editingFor?.nodeId === node.id ? editingFor.index : null + const { data } = node const statusColor = STATUS_COLORS[data.status] const host = data.ip ?? data.hostname @@ -45,33 +48,34 @@ export function DetailPanel({ onEdit }: DetailPanelProps) { } updateNode(node.id, { services: [...(data.services ?? []), svc] }) setNewSvc(EMPTY_FORM) - setAddingService(false) + setAddingForNode(null) } const handleRemoveService = (index: number) => { - const updated = data.services.filter((_, i) => i !== index) + const updated = (data.services ?? []).filter((_, i) => i !== index) updateNode(node.id, { services: updated }) - if (editingIndex === index) setEditingIndex(null) + if (editingIndex === index) setEditingFor(null) } const handleStartEdit = (index: number) => { - const svc = data.services[index] + const svc = (data.services ?? [])[index] + if (!svc) return setEditSvc({ port: String(svc.port), protocol: svc.protocol, service_name: svc.service_name }) - setEditingIndex(index) - setAddingService(false) + setEditingFor({ nodeId: node.id, index }) + setAddingForNode(null) } const handleSaveEdit = () => { if (editingIndex === null) return const port = parseInt(editSvc.port, 10) if (!editSvc.service_name.trim() || isNaN(port) || port < 1 || port > 65535) return - const updated = data.services.map((svc, i) => + const updated = (data.services ?? []).map((svc, i) => i === editingIndex ? { ...svc, port, protocol: editSvc.protocol, service_name: editSvc.service_name.trim() } : svc ) updateNode(node.id, { services: updated }) - setEditingIndex(null) + setEditingFor(null) } return ( @@ -141,7 +145,7 @@ export function DetailPanel({ onEdit }: DetailPanelProps) { Services{data.services.length > 0 ? ` (${data.services.length})` : ''}