Persist section renumbering
This commit is contained in:
@@ -33,6 +33,9 @@ import {
|
||||
import {
|
||||
buildCircuitSectionReorderAssignments,
|
||||
} from "../utils/circuit-section-reorder-command";
|
||||
import {
|
||||
buildCircuitSectionRenumberAssignments,
|
||||
} from "../utils/circuit-section-renumber-command";
|
||||
import type {
|
||||
CellKey,
|
||||
CellKind,
|
||||
@@ -57,9 +60,8 @@ import {
|
||||
moveCircuitDeviceRowsToNewCircuitCommand,
|
||||
reorderCircuitSectionCommand,
|
||||
reorderCircuitSectionsCommand,
|
||||
renumberCircuitSection,
|
||||
renumberCircuitSectionCommand,
|
||||
redoProjectCommand,
|
||||
updateSectionEquipmentIdentifiers,
|
||||
updateCircuitById,
|
||||
updateCircuitDeviceRowById,
|
||||
undoProjectCommand,
|
||||
@@ -2592,7 +2594,8 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
||||
await handleDeleteCircuit(intent.circuitId);
|
||||
}
|
||||
|
||||
// Explicit renumber action. Undo restores previous BMKs via safe section identifier update.
|
||||
// Explicit renumber action through project history. Sorting and device rows
|
||||
// remain unchanged; the server handles collision-safe identifier swaps.
|
||||
async function handleRenumberSection(sectionId: string) {
|
||||
if (!confirm("Diesen Bereich neu nummerieren? Nur die Stromkreise in diesem Bereich werden geändert.")) {
|
||||
return;
|
||||
@@ -2601,26 +2604,31 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
||||
if (!section) {
|
||||
return;
|
||||
}
|
||||
const before = section.circuits.map((circuit) => ({
|
||||
id: circuit.id,
|
||||
equipmentIdentifier: circuit.equipmentIdentifier,
|
||||
}));
|
||||
const assignments = buildCircuitSectionRenumberAssignments(
|
||||
data?.sections ?? [],
|
||||
sectionId
|
||||
);
|
||||
if (assignments.length === 0) {
|
||||
return;
|
||||
}
|
||||
const label = "Bereich neu nummerieren";
|
||||
await runCommand({
|
||||
label: "Bereich neu nummerieren",
|
||||
label,
|
||||
redo: async () => {
|
||||
await renumberCircuitSection(sectionId);
|
||||
const result = await renumberCircuitSectionCommand(
|
||||
projectId,
|
||||
getExpectedProjectRevision(),
|
||||
sectionId,
|
||||
assignments,
|
||||
label
|
||||
);
|
||||
applyProjectCommandResult(result);
|
||||
return null;
|
||||
},
|
||||
undo: async () => {
|
||||
// Restore prior BMKs through safe bulk endpoint to avoid transient unique collisions.
|
||||
await updateSectionEquipmentIdentifiers(
|
||||
sectionId,
|
||||
before.map((entry) => ({
|
||||
circuitId: entry.id,
|
||||
equipmentIdentifier: entry.equipmentIdentifier,
|
||||
}))
|
||||
);
|
||||
return null;
|
||||
undo: async () => null,
|
||||
persistent: {
|
||||
undoIntent: () => null,
|
||||
redoIntent: () => null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+18
-12
@@ -42,6 +42,9 @@ import type {
|
||||
import type {
|
||||
CircuitSectionsReorderSection,
|
||||
} from "../../domain/models/circuit-sections-reorder-project-command.model";
|
||||
import type {
|
||||
CircuitSectionRenumberAssignment,
|
||||
} from "../../domain/models/circuit-section-renumber-project-command.model";
|
||||
|
||||
async function request<T>(url: string, init?: RequestInit): Promise<T> {
|
||||
const response = await fetch(url, {
|
||||
@@ -319,12 +322,6 @@ export function moveCircuitDeviceRowsToNewCircuitCommand(
|
||||
);
|
||||
}
|
||||
|
||||
export function renumberCircuitSection(sectionId: string) {
|
||||
return request(`/api/circuit-sections/${sectionId}/renumber`, {
|
||||
method: "POST",
|
||||
});
|
||||
}
|
||||
|
||||
export function reorderCircuitSectionCommand(
|
||||
projectId: string,
|
||||
expectedRevision: number,
|
||||
@@ -362,14 +359,23 @@ export function reorderCircuitSectionsCommand(
|
||||
);
|
||||
}
|
||||
|
||||
export function updateSectionEquipmentIdentifiers(
|
||||
export function renumberCircuitSectionCommand(
|
||||
projectId: string,
|
||||
expectedRevision: number,
|
||||
sectionId: string,
|
||||
identifiers: Array<{ circuitId: string; equipmentIdentifier: string }>
|
||||
assignments: CircuitSectionRenumberAssignment[],
|
||||
description: string
|
||||
) {
|
||||
return request(`/api/circuit-sections/${sectionId}/equipment-identifiers`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({ identifiers }),
|
||||
});
|
||||
return executeProjectCommand(
|
||||
projectId,
|
||||
expectedRevision,
|
||||
{
|
||||
schemaVersion: 1,
|
||||
type: "circuit.renumber-section",
|
||||
payload: { sectionId, assignments },
|
||||
},
|
||||
description
|
||||
);
|
||||
}
|
||||
|
||||
export function listFloors(projectId: string) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import type {
|
||||
CircuitSectionRenumberAssignment,
|
||||
} from "../../domain/models/circuit-section-renumber-project-command.model.js";
|
||||
import type { CircuitTreeSectionDto } from "../types.js";
|
||||
|
||||
export function buildCircuitSectionRenumberAssignments(
|
||||
sections: CircuitTreeSectionDto[],
|
||||
sectionId: string
|
||||
): CircuitSectionRenumberAssignment[] {
|
||||
const targetSection = sections.find(
|
||||
(section) => section.id === sectionId
|
||||
);
|
||||
if (!targetSection) {
|
||||
throw new Error("Der Bereich wurde nicht gefunden.");
|
||||
}
|
||||
|
||||
const identifiersOutsideSection = new Set(
|
||||
sections
|
||||
.filter((section) => section.id !== sectionId)
|
||||
.flatMap((section) =>
|
||||
section.circuits.map(
|
||||
(circuit) => circuit.equipmentIdentifier
|
||||
)
|
||||
)
|
||||
);
|
||||
const assignments: CircuitSectionRenumberAssignment[] = [];
|
||||
let suffix = 1;
|
||||
for (const circuit of targetSection.circuits) {
|
||||
let targetEquipmentIdentifier = `${targetSection.prefix}${suffix}`;
|
||||
while (
|
||||
identifiersOutsideSection.has(targetEquipmentIdentifier)
|
||||
) {
|
||||
suffix += 1;
|
||||
targetEquipmentIdentifier = `${targetSection.prefix}${suffix}`;
|
||||
}
|
||||
assignments.push({
|
||||
circuitId: circuit.id,
|
||||
expectedEquipmentIdentifier: circuit.equipmentIdentifier,
|
||||
targetEquipmentIdentifier,
|
||||
});
|
||||
suffix += 1;
|
||||
}
|
||||
|
||||
if (
|
||||
assignments.every(
|
||||
(assignment) =>
|
||||
assignment.expectedEquipmentIdentifier ===
|
||||
assignment.targetEquipmentIdentifier
|
||||
)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
return assignments;
|
||||
}
|
||||
Reference in New Issue
Block a user