Persist device row moves
This commit is contained in:
@@ -27,6 +27,9 @@ import {
|
||||
buildCircuitDeviceRowInsertSnapshot,
|
||||
buildCircuitInsertSnapshot,
|
||||
} from "../utils/circuit-structure-command";
|
||||
import {
|
||||
buildCircuitDeviceRowMoveAssignments,
|
||||
} from "../utils/circuit-device-row-move-command";
|
||||
import type {
|
||||
CellKey,
|
||||
CellKind,
|
||||
@@ -40,7 +43,6 @@ import {
|
||||
} from "../utils/circuit-grid-projection";
|
||||
import type { VisibleGridRow } from "../utils/circuit-grid-projection";
|
||||
import {
|
||||
deleteCircuitById,
|
||||
deleteCircuitCommand,
|
||||
deleteCircuitDeviceRowCommand,
|
||||
getCircuitTree,
|
||||
@@ -48,8 +50,8 @@ import {
|
||||
insertCircuitCommand,
|
||||
insertCircuitDeviceRowCommand,
|
||||
listProjectDevices,
|
||||
moveCircuitDeviceRowsBulk,
|
||||
moveCircuitDeviceRowById,
|
||||
moveCircuitDeviceRowsCommand,
|
||||
moveCircuitDeviceRowsToNewCircuitCommand,
|
||||
reorderSectionCircuits,
|
||||
renumberCircuitSection,
|
||||
redoProjectCommand,
|
||||
@@ -2230,8 +2232,8 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
||||
});
|
||||
}
|
||||
|
||||
// Handles device-row drag intent (single or bulk) and preserves enough source grouping
|
||||
// for deterministic undo back to original circuits.
|
||||
// Handles single and bulk device-row drag through persistent project history.
|
||||
// Exact source and target positions make undo deterministic.
|
||||
async function handleDeviceRowDropWithIntent(event: DragEvent<HTMLElement>, intent: DeviceRowMoveDropIntent) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@@ -2269,65 +2271,117 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
||||
return;
|
||||
}
|
||||
|
||||
// Device-row drag supports bulk selection, but target intent is always explicit:
|
||||
// move into existing circuit or create new circuit in a target section.
|
||||
const circuits = (data?.sections ?? []).flatMap(
|
||||
(section) => section.circuits
|
||||
);
|
||||
const label =
|
||||
rowIds.length > 1
|
||||
? `${rowIds.length} Gerätezeilen verschieben`
|
||||
: "Gerätezeile verschieben";
|
||||
|
||||
if (intent.kind === "move-to-circuit") {
|
||||
const groupedBySource = new Map<string, string[]>();
|
||||
for (const rowId of rowIds) {
|
||||
const source = sourceByRowId.get(rowId)!;
|
||||
if (!groupedBySource.has(source)) {
|
||||
groupedBySource.set(source, []);
|
||||
}
|
||||
groupedBySource.get(source)!.push(rowId);
|
||||
const targetCircuit = circuits.find(
|
||||
(circuit) => circuit.id === intent.circuitId
|
||||
);
|
||||
if (!targetCircuit) {
|
||||
setError("Der Zielstromkreis ist ungültig.");
|
||||
return;
|
||||
}
|
||||
const moves = buildCircuitDeviceRowMoveAssignments({
|
||||
circuits,
|
||||
rowIds,
|
||||
targetCircuitId: targetCircuit.id,
|
||||
targetDeviceRows: targetCircuit.deviceRows,
|
||||
});
|
||||
if (moves.length === 0) {
|
||||
return;
|
||||
}
|
||||
await runCommand({
|
||||
label: rowIds.length > 1 ? `${rowIds.length} Gerätezeilen verschieben` : "Gerätezeile verschieben",
|
||||
label,
|
||||
redo: async () => {
|
||||
await moveCircuitDeviceRowsBulk({ rowIds, targetCircuitId: intent.circuitId });
|
||||
const result = await moveCircuitDeviceRowsCommand(
|
||||
projectId,
|
||||
getExpectedProjectRevision(),
|
||||
moves,
|
||||
label
|
||||
);
|
||||
applyProjectCommandResult(result);
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
},
|
||||
undo: async () => {
|
||||
for (const [source, ids] of groupedBySource) {
|
||||
await moveCircuitDeviceRowsBulk({ rowIds: ids, targetCircuitId: source });
|
||||
}
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
undo: async () => null,
|
||||
persistent: {
|
||||
undoIntent: () => {
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
},
|
||||
redoIntent: () => {
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let createdCircuitId: string | null = null;
|
||||
const groupedBySource = new Map<string, string[]>();
|
||||
for (const rowId of rowIds) {
|
||||
const source = sourceByRowId.get(rowId)!;
|
||||
if (!groupedBySource.has(source)) {
|
||||
groupedBySource.set(source, []);
|
||||
}
|
||||
groupedBySource.get(source)!.push(rowId);
|
||||
const targetSection = data?.sections.find(
|
||||
(section) => section.id === intent.sectionId
|
||||
);
|
||||
if (!targetSection) {
|
||||
setError("Der Zielbereich ist ungültig.");
|
||||
return;
|
||||
}
|
||||
const newCircuitLabel =
|
||||
rowIds.length > 1
|
||||
? `${rowIds.length} Gerätezeilen in neuen Stromkreis verschieben`
|
||||
: "Gerätezeile in neuen Stromkreis verschieben";
|
||||
await runCommand({
|
||||
label: rowIds.length > 1 ? `${rowIds.length} Gerätezeilen in neuen Stromkreis verschieben` : "Gerätezeile in neuen Stromkreis verschieben",
|
||||
label: newCircuitLabel,
|
||||
redo: async () => {
|
||||
const moved = await moveCircuitDeviceRowsBulk({
|
||||
rowIds,
|
||||
targetSectionId: intent.sectionId,
|
||||
createNewCircuit: true,
|
||||
const next = await getNextCircuitIdentifier(intent.sectionId);
|
||||
const sortOrder =
|
||||
targetSection.circuits.length > 0
|
||||
? Math.max(
|
||||
...targetSection.circuits.map(
|
||||
(circuit) => circuit.sortOrder
|
||||
)
|
||||
) + 10
|
||||
: 10;
|
||||
const targetCircuit = createCircuitSnapshot({
|
||||
sectionId: intent.sectionId,
|
||||
equipmentIdentifier: next.nextIdentifier,
|
||||
displayName: "Neuer Stromkreis",
|
||||
sortOrder,
|
||||
isReserve: true,
|
||||
});
|
||||
createdCircuitId = moved.createdCircuitId ?? null;
|
||||
const moves = buildCircuitDeviceRowMoveAssignments({
|
||||
circuits,
|
||||
rowIds,
|
||||
targetCircuitId: targetCircuit.id,
|
||||
targetDeviceRows: [],
|
||||
});
|
||||
const result =
|
||||
await moveCircuitDeviceRowsToNewCircuitCommand(
|
||||
projectId,
|
||||
getExpectedProjectRevision(),
|
||||
targetCircuit,
|
||||
moves,
|
||||
newCircuitLabel
|
||||
);
|
||||
applyProjectCommandResult(result);
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
},
|
||||
undo: async () => {
|
||||
for (const [source, ids] of groupedBySource) {
|
||||
await moveCircuitDeviceRowsBulk({ rowIds: ids, targetCircuitId: source });
|
||||
}
|
||||
if (createdCircuitId) {
|
||||
await deleteCircuitById(createdCircuitId);
|
||||
}
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
undo: async () => null,
|
||||
persistent: {
|
||||
undoIntent: () => {
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
},
|
||||
redoIntent: () => {
|
||||
pendingSelectedDeviceRowIdsAfterReload.current = rowIds;
|
||||
return null;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user