From 687717f7c5b6429ba0a9e761103c7f3360426ae9 Mon Sep 17 00:00:00 2001 From: Julian Appel Date: Mon, 4 May 2026 10:38:28 +0200 Subject: [PATCH] Still bugfix editor --- .../components/circuit-tree-editor.tsx | 102 ++++++++++++++---- 1 file changed, 82 insertions(+), 20 deletions(-) diff --git a/src/frontend/components/circuit-tree-editor.tsx b/src/frontend/components/circuit-tree-editor.tsx index fd396d8..b0d8059 100644 --- a/src/frontend/components/circuit-tree-editor.tsx +++ b/src/frontend/components/circuit-tree-editor.tsx @@ -254,6 +254,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str const pendingSelectionAfterReload = useRef(null); const containerRef = useRef(null); const inputRef = useRef(null); + const lastEditingSignatureRef = useRef(null); async function loadTree() { setIsLoading(true); @@ -337,8 +338,14 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str useEffect(() => { if (!editingCell) { + lastEditingSignatureRef.current = null; return; } + const signature = `${editingCell.rowKey}:${editingCell.cellKey}`; + if (lastEditingSignatureRef.current === signature) { + return; + } + lastEditingSignatureRef.current = signature; requestAnimationFrame(() => { inputRef.current?.focus(); inputRef.current?.select(); @@ -378,12 +385,15 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str } function canEditCell(row: GridRow, cellKey: CellKey) { - if (row.kind === "section" || row.kind === "placeholder") { + if (row.kind === "section") { return false; } if (cellKey === "rowTotalPower" || cellKey === "circuitTotalPower") { return false; } + if (row.kind === "placeholder") { + return true; + } if (row.kind === "summary") { return isCircuitField(cellKey); } @@ -494,7 +504,12 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str const draft = editingCell.draft; let nextSelection: SelectedCell | null = { rowKey: editingCell.rowKey, cellKey: editingCell.cellKey }; - if ((row.kind === "summary" || row.kind === "reserve") && isCircuitField(key)) { + if (row.kind === "placeholder") { + const createdSelection = await createFromPlaceholder(row.sectionId, key, draft); + if (createdSelection) { + nextSelection = createdSelection; + } + } else if ((row.kind === "summary" || row.kind === "reserve") && isCircuitField(key)) { await patchCircuit(row.circuit.id, key, draft); } else if (row.kind === "reserve" && isDeviceField(key)) { const created = (await createCircuitDeviceRow(row.circuit.id, { @@ -566,6 +581,41 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str await updateCircuitDeviceRowById(rowId, payload); } + async function createFromPlaceholder(sectionId: string, key: CellKey, draft: string): Promise { + const section = data?.sections.find((entry) => entry.id === sectionId); + if (!section) { + throw new Error("Section not found."); + } + const next = await getNextCircuitIdentifier(sectionId); + const sortOrder = + section.circuits.length > 0 ? Math.max(...section.circuits.map((circuit) => circuit.sortOrder)) + 10 : 10; + const isDevice = isDeviceField(key); + const baseCircuit = (await createCircuit(projectId, circuitListId, { + sectionId, + equipmentIdentifier: next.nextIdentifier, + displayName: "New circuit", + sortOrder, + isReserve: !isDevice, + })) as CircuitTreeCircuitDto; + + if (isDevice) { + const createdRow = (await createCircuitDeviceRow(baseCircuit.id, { + name: "Manual device", + displayName: "Manual device", + phaseType: "single_phase", + quantity: 1, + powerPerUnit: 0, + simultaneityFactor: 1, + cosPhi: 1, + })) as { id: string }; + await patchDeviceRow(createdRow.id, key, draft); + return { rowKey: `compact:${baseCircuit.id}`, cellKey: key }; + } + + await patchCircuit(baseCircuit.id, key, draft); + return { rowKey: `reserve:${baseCircuit.id}`, cellKey: key }; + } + async function handleAddReserveCircuit(sectionId: string) { try { setError(null); @@ -675,6 +725,19 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str } return; } + if (event.key === "Tab" && selectedCell) { + event.preventDefault(); + const idx = editableCells.findIndex( + (cell) => cell.rowKey === selectedCell.rowKey && cell.cellKey === selectedCell.cellKey + ); + if (idx >= 0) { + const target = editableCells[ + event.shiftKey ? Math.max(0, idx - 1) : Math.min(editableCells.length - 1, idx + 1) + ]; + setSelectedCell(target); + } + return; + } const isCtrlPlus = event.ctrlKey && (event.key === "+" || (event.shiftKey && event.key === "=") || event.code === "NumpadAdd"); @@ -824,14 +887,14 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str void saveEditingCell("stay"); } else if (event.key === "Escape") { event.preventDefault(); - setEditingCell(null); - setSelectedCell({ rowKey: row.rowKey, cellKey: column.key }); - requestAnimationFrame(() => containerRef.current?.focus()); - } else if (event.key === "Tab") { - event.preventDefault(); - void saveEditingCell(event.shiftKey ? "prev" : "next"); - } - }} + setEditingCell(null); + setSelectedCell({ rowKey: row.rowKey, cellKey: column.key }); + requestAnimationFrame(() => containerRef.current?.focus()); + } else if (event.key === "Tab") { + event.preventDefault(); + void saveEditingCell(event.shiftKey ? "prev" : "next"); + } + }} onBlur={() => { if (!editingCell) { return; @@ -840,13 +903,12 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str const active = document.activeElement as HTMLElement | null; const insideEditor = !!active && !!containerRef.current && containerRef.current.contains(active); - if (!insideEditor) { - setEditingCell(null); - requestAnimationFrame(() => containerRef.current?.focus()); - } - }); - }} - /> + if (!insideEditor) { + setEditingCell(null); + } + }); + }} + /> ) : ( formatValue(value) )} @@ -858,14 +920,14 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str <>