Move circuits between groups

This commit is contained in:
2026-07-31 07:58:42 +02:00
parent be9c6f0d52
commit 93ec294759
6 changed files with 336 additions and 21 deletions
+127
View File
@@ -13,6 +13,9 @@ import type {
import type {
CircuitGroupRenumberPlan,
} from "../../domain/services/circuit-group-renumbering";
import type {
CircuitGroupMovePlan,
} from "../../domain/services/circuit-group-move-planning";
export function toCircuitGroupSnapshot(
section: CircuitTreeSectionDto,
@@ -187,6 +190,92 @@ export function canRenumberCircuitGroups(
);
}
export function canMoveCircuitToGroup(
sections: readonly CircuitTreeSectionDto[],
circuitId: string,
targetSectionId: string
) {
const source = sections.find((section) =>
section.circuits.some((circuit) => circuit.id === circuitId)
);
const target = sections.find(
(section) => section.id === targetSectionId
);
return Boolean(
source?.category &&
target?.category &&
source.id !== target.id &&
source.category === target.category
);
}
export function buildCircuitGroupMovePlan(input: {
sections: readonly CircuitTreeSectionDto[];
circuitId: string;
targetSectionId: string;
placement:
| { kind: "end" }
| {
kind: "before" | "after";
targetCircuitId: string;
};
}): CircuitGroupMovePlan {
const sourceGroup = input.sections.find((section) =>
section.circuits.some(
(circuit) => circuit.id === input.circuitId
)
);
const targetGroup = input.sections.find(
(section) => section.id === input.targetSectionId
);
const circuit = sourceGroup?.circuits.find(
(entry) => entry.id === input.circuitId
);
if (
!sourceGroup?.category ||
!sourceGroup.groupNumber ||
!targetGroup?.category ||
!targetGroup.groupNumber ||
!circuit ||
sourceGroup.id === targetGroup.id ||
sourceGroup.category !== targetGroup.category
) {
throw new Error(
"Stromkreise können nur zwischen verschiedenen Gruppen derselben Kategorie verschoben werden."
);
}
parseCircuitNumber(
circuit.equipmentIdentifier,
sourceGroup.category,
sourceGroup.groupNumber
);
const targetCircuitNumbers = targetGroup.circuits.map((entry) =>
parseCircuitNumber(
entry.equipmentIdentifier,
targetGroup.category!,
targetGroup.groupNumber!
)
);
return {
circuitId: circuit.id,
circuitListId: circuit.circuitListId,
expectedSectionId: sourceGroup.id,
targetSectionId: targetGroup.id,
expectedEquipmentIdentifier: circuit.equipmentIdentifier,
targetEquipmentIdentifier: formatCircuitIdentifier(
targetGroup.category,
targetGroup.groupNumber,
Math.max(0, ...targetCircuitNumbers) + 1
),
expectedSortOrder: circuit.sortOrder,
targetSortOrder: getCircuitMoveSortOrder(
targetGroup.circuits,
input.placement
),
};
}
function getNewGroupSortOrder(
category: CircuitGroupCategory,
sections: readonly (CircuitTreeSectionDto & {
@@ -287,3 +376,41 @@ function formatGroupComponentIdentifier(
"Die Stromkreisgruppe enthält eine nicht unterstützte Verteilerkomponente."
);
}
function getCircuitMoveSortOrder(
circuits: CircuitTreeSectionDto["circuits"],
placement:
| { kind: "end" }
| {
kind: "before" | "after";
targetCircuitId: string;
}
) {
const ordered = [...circuits].sort(
(left, right) =>
left.sortOrder - right.sortOrder ||
left.id.localeCompare(right.id)
);
if (placement.kind === "end") {
return ordered.length === 0
? 10
: ordered[ordered.length - 1].sortOrder + 10;
}
const index = ordered.findIndex(
(circuit) => circuit.id === placement.targetCircuitId
);
if (index < 0) {
throw new Error("Der Zielstromkreis wurde nicht gefunden.");
}
const current = ordered[index].sortOrder;
if (placement.kind === "before") {
const previous = ordered[index - 1]?.sortOrder;
return previous === undefined
? current - 10
: previous + (current - previous) / 2;
}
const next = ordered[index + 1]?.sortOrder;
return next === undefined
? current + 10
: current + (next - current) / 2;
}