Der gewählte Abgang ist 1-phasig. Bitte prüfen, ob diese
diff --git a/src/db/repositories/circuit-structure-project-command.repository.ts b/src/db/repositories/circuit-structure-project-command.repository.ts
index 4841616..e7cfcb2 100644
--- a/src/db/repositories/circuit-structure-project-command.repository.ts
+++ b/src/db/repositories/circuit-structure-project-command.repository.ts
@@ -40,7 +40,7 @@ export class CircuitStructureProjectCommandRepository
this.database,
input,
(tx) =>
- this.applyInTransaction(
+ this.applyCommand(
tx,
input.projectId,
input.source,
@@ -49,11 +49,7 @@ export class CircuitStructureProjectCommandRepository
);
}
- /**
- * Applies the circuit write inside an already-owned project transaction.
- * Composite project commands use this without creating a second revision.
- */
- applyInTransaction(
+ private applyCommand(
database: AppDatabase,
projectId: string,
source: ExecuteCircuitStructureCommandInput["source"],
diff --git a/src/db/repositories/distribution-board-structure-project-command.repository.ts b/src/db/repositories/distribution-board-structure-project-command.repository.ts
index 115705b..9346df7 100644
--- a/src/db/repositories/distribution-board-structure-project-command.repository.ts
+++ b/src/db/repositories/distribution-board-structure-project-command.repository.ts
@@ -1,5 +1,4 @@
import { and, asc, eq, inArray } from "drizzle-orm";
-import { isDeepStrictEqual } from "node:util";
import {
assertDistributionBoardDeleteProjectCommand,
assertDistributionBoardInsertProjectCommand,
@@ -18,20 +17,6 @@ import {
type DistributionBoardUpdateProjectCommand,
type DistributionBoardUpdateValues,
} from "../../domain/models/distribution-board-project-command.model.js";
-import {
- assertDistributionBoardFeederCircuitProjectCommand,
- createDistributionBoardCreateFeederCircuitProjectCommand,
- createDistributionBoardRemoveFeederCircuitProjectCommand,
- distributionBoardCreateFeederCircuitCommandType,
- distributionBoardRemoveFeederCircuitCommandType,
- type DistributionBoardFeederCircuitProjectCommand,
-} from "../../domain/models/distribution-board-feeder-circuit-project-command.model.js";
-import {
- circuitDeleteCommandType,
- circuitInsertCommandType,
- createCircuitDeleteProjectCommand,
- createCircuitInsertProjectCommand,
-} from "../../domain/models/circuit-structure-project-command.model.js";
import type {
DistributionBoardStructureProjectCommandStore,
ExecuteDistributionBoardStructureCommandInput,
@@ -46,7 +31,6 @@ import { floors } from "../schema/floors.js";
import { projects } from "../schema/projects.js";
import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js";
import { assertBoardsAreNotReferencedAsFeeders } from "./distribution-board-feeding-deletion-guard.persistence.js";
-import { CircuitStructureProjectCommandRepository } from "./circuit-structure-project-command.repository.js";
export class DistributionBoardStructureProjectCommandRepository
implements DistributionBoardStructureProjectCommandStore
@@ -78,30 +62,6 @@ export class DistributionBoardStructureProjectCommandRepository
);
}
- executeFeederCircuit(
- input: Omit<
- ExecuteDistributionBoardStructureCommandInput,
- "command"
- > & {
- command: DistributionBoardFeederCircuitProjectCommand;
- }
- ) {
- assertDistributionBoardFeederCircuitProjectCommand(input.command);
- if (
- input.source === "user" &&
- input.command.type === distributionBoardRemoveFeederCircuitCommandType
- ) {
- throw new Error(
- "Generated feeder circuits may only be removed through project history."
- );
- }
- return executeProjectCommandTransaction(
- this.database,
- input,
- (tx) => this.applyFeederCircuitCommand(tx, input)
- );
- }
-
private applyCommand(
database: AppDatabase,
projectId: string,
@@ -407,64 +367,6 @@ export class DistributionBoardStructureProjectCommandRepository
return inverse;
}
- private applyFeederCircuitCommand(
- database: AppDatabase,
- input: Omit<
- ExecuteDistributionBoardStructureCommandInput,
- "command"
- > & {
- command: DistributionBoardFeederCircuitProjectCommand;
- }
- ): DistributionBoardFeederCircuitProjectCommand {
- const circuitRepository =
- new CircuitStructureProjectCommandRepository(database);
- const { circuit, boardUpdate } = input.command.payload;
- if (
- input.command.type === distributionBoardCreateFeederCircuitCommandType
- ) {
- const circuitInverse = circuitRepository.applyInTransaction(
- database,
- input.projectId,
- input.source,
- createCircuitInsertProjectCommand(circuit)
- );
- if (circuitInverse.type !== circuitDeleteCommandType) {
- throw new Error("Created feeder circuit returned an invalid inverse.");
- }
- const boardInverse = this.update(database, {
- ...input,
- command: boardUpdate,
- });
- return createDistributionBoardRemoveFeederCircuitProjectCommand(
- circuit,
- boardInverse
- );
- }
-
- const boardInverse = this.update(database, {
- ...input,
- command: boardUpdate,
- });
- const circuitInverse = circuitRepository.applyInTransaction(
- database,
- input.projectId,
- input.source,
- createCircuitDeleteProjectCommand(circuit.id, circuit.circuitListId)
- );
- if (
- circuitInverse.type !== circuitInsertCommandType ||
- !isDeepStrictEqual(circuitInverse.payload.circuit, circuit)
- ) {
- throw new Error(
- "Generated feeder circuit changed before history removal."
- );
- }
- return createDistributionBoardCreateFeederCircuitProjectCommand(
- circuit,
- boardInverse
- );
- }
-
private assertFeedingReference(
database: AppDatabase,
projectId: string,
diff --git a/src/domain/models/distribution-board-feeder-circuit-project-command.model.ts b/src/domain/models/distribution-board-feeder-circuit-project-command.model.ts
deleted file mode 100644
index a1fc035..0000000
--- a/src/domain/models/distribution-board-feeder-circuit-project-command.model.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import {
- assertCircuitInsertProjectCommand,
- circuitInsertCommandType,
- circuitStructureCommandSchemaVersion,
- type CircuitSnapshot,
-} from "./circuit-structure-project-command.model.js";
-import {
- assertDistributionBoardUpdateProjectCommand,
- type DistributionBoardUpdateProjectCommand,
-} from "./distribution-board-project-command.model.js";
-import type { SerializedProjectCommand } from "./project-command.model.js";
-
-export const distributionBoardCreateFeederCircuitCommandType =
- "distribution-board.create-feeder-circuit" as const;
-export const distributionBoardRemoveFeederCircuitCommandType =
- "distribution-board.remove-feeder-circuit" as const;
-export const distributionBoardFeederCircuitCommandSchemaVersion = 1 as const;
-
-export interface DistributionBoardFeederCircuitCommandPayload {
- circuit: CircuitSnapshot;
- boardUpdate: DistributionBoardUpdateProjectCommand;
-}
-
-export interface DistributionBoardCreateFeederCircuitProjectCommand
- extends SerializedProjectCommand {
- schemaVersion: typeof distributionBoardFeederCircuitCommandSchemaVersion;
- type: typeof distributionBoardCreateFeederCircuitCommandType;
-}
-
-export interface DistributionBoardRemoveFeederCircuitProjectCommand
- extends SerializedProjectCommand {
- schemaVersion: typeof distributionBoardFeederCircuitCommandSchemaVersion;
- type: typeof distributionBoardRemoveFeederCircuitCommandType;
-}
-
-export type DistributionBoardFeederCircuitProjectCommand =
- | DistributionBoardCreateFeederCircuitProjectCommand
- | DistributionBoardRemoveFeederCircuitProjectCommand;
-
-export function createDistributionBoardCreateFeederCircuitProjectCommand(
- circuit: CircuitSnapshot,
- boardUpdate: DistributionBoardUpdateProjectCommand
-): DistributionBoardCreateFeederCircuitProjectCommand {
- const command: DistributionBoardCreateFeederCircuitProjectCommand = {
- schemaVersion: distributionBoardFeederCircuitCommandSchemaVersion,
- type: distributionBoardCreateFeederCircuitCommandType,
- payload: { circuit, boardUpdate },
- };
- assertDistributionBoardFeederCircuitProjectCommand(command);
- return command;
-}
-
-export function createDistributionBoardRemoveFeederCircuitProjectCommand(
- circuit: CircuitSnapshot,
- boardUpdate: DistributionBoardUpdateProjectCommand
-): DistributionBoardRemoveFeederCircuitProjectCommand {
- const command: DistributionBoardRemoveFeederCircuitProjectCommand = {
- schemaVersion: distributionBoardFeederCircuitCommandSchemaVersion,
- type: distributionBoardRemoveFeederCircuitCommandType,
- payload: { circuit, boardUpdate },
- };
- assertDistributionBoardFeederCircuitProjectCommand(command);
- return command;
-}
-
-export function assertDistributionBoardFeederCircuitProjectCommand(
- command: SerializedProjectCommand
-): asserts command is DistributionBoardFeederCircuitProjectCommand {
- if (
- command.schemaVersion !==
- distributionBoardFeederCircuitCommandSchemaVersion ||
- (command.type !== distributionBoardCreateFeederCircuitCommandType &&
- command.type !== distributionBoardRemoveFeederCircuitCommandType) ||
- !isPlainObject(command.payload)
- ) {
- throw new Error("Unsupported distribution-board feeder-circuit command.");
- }
-
- const { circuit, boardUpdate } = command.payload;
- if (!isPlainObject(boardUpdate)) {
- throw new Error("Feeder-circuit command requires a board update.");
- }
- assertCircuitInsertProjectCommand({
- schemaVersion: circuitStructureCommandSchemaVersion,
- type: circuitInsertCommandType,
- payload: { circuit },
- });
- const boardUpdateCommand =
- boardUpdate as unknown as SerializedProjectCommand;
- assertDistributionBoardUpdateProjectCommand(boardUpdateCommand);
-
- const typedCircuit = circuit as CircuitSnapshot;
- const typedBoardUpdate: DistributionBoardUpdateProjectCommand =
- boardUpdateCommand;
- if (typedCircuit.deviceRows.length !== 0 || !typedCircuit.isReserve) {
- throw new Error(
- "A generated feeder circuit must be empty before the board load is linked."
- );
- }
- const feedingBoard = getChangeValue(
- typedBoardUpdate,
- "feedingDistributionBoardId"
- );
- const feedingCircuit = getChangeValue(
- typedBoardUpdate,
- "feedingCircuitId"
- );
- if (feedingBoard === undefined || feedingCircuit === undefined) {
- throw new Error(
- "Feeder-circuit commands must update both logical feeding references."
- );
- }
- if (
- command.type === distributionBoardCreateFeederCircuitCommandType &&
- (typeof feedingBoard !== "string" || feedingCircuit !== typedCircuit.id)
- ) {
- throw new Error(
- "The created feeder circuit must be linked by the distribution-board update."
- );
- }
-}
-
-function getChangeValue(
- command: DistributionBoardUpdateProjectCommand,
- field: "feedingDistributionBoardId" | "feedingCircuitId"
-) {
- return command.payload.changes.find((change) => change.field === field)?.value;
-}
-
-function isPlainObject(value: unknown): value is Record {
- return value !== null && typeof value === "object" && !Array.isArray(value);
-}
diff --git a/src/domain/ports/distribution-board-structure-project-command.store.ts b/src/domain/ports/distribution-board-structure-project-command.store.ts
index 6dd8d8f..f0cb5c9 100644
--- a/src/domain/ports/distribution-board-structure-project-command.store.ts
+++ b/src/domain/ports/distribution-board-structure-project-command.store.ts
@@ -1,6 +1,5 @@
import type { DistributionBoardStructureProjectCommand } from "../models/distribution-board-structure-project-command.model.js";
import type { DistributionBoardUpdateProjectCommand } from "../models/distribution-board-project-command.model.js";
-import type { DistributionBoardFeederCircuitProjectCommand } from "../models/distribution-board-feeder-circuit-project-command.model.js";
import type {
AppendedProjectRevision,
ProjectRevisionSource,
@@ -36,15 +35,4 @@ export interface DistributionBoardStructureProjectCommandStore {
revision: AppendedProjectRevision;
inverse: DistributionBoardUpdateProjectCommand;
};
- executeFeederCircuit(
- input: Omit<
- ExecuteDistributionBoardStructureCommandInput,
- "command"
- > & {
- command: DistributionBoardFeederCircuitProjectCommand;
- }
- ): {
- revision: AppendedProjectRevision;
- inverse: DistributionBoardFeederCircuitProjectCommand;
- };
}
diff --git a/src/domain/services/project-command.service.ts b/src/domain/services/project-command.service.ts
index 35dd9e8..cf1f740 100644
--- a/src/domain/services/project-command.service.ts
+++ b/src/domain/services/project-command.service.ts
@@ -45,11 +45,6 @@ import {
assertDistributionBoardUpdateProjectCommand,
distributionBoardUpdateCommandType,
} from "../models/distribution-board-project-command.model.js";
-import {
- assertDistributionBoardFeederCircuitProjectCommand,
- distributionBoardCreateFeederCircuitCommandType,
- distributionBoardRemoveFeederCircuitCommandType,
-} from "../models/distribution-board-feeder-circuit-project-command.model.js";
import {
assertDistributionBoardComponentDeleteProjectCommand,
assertDistributionBoardComponentInsertProjectCommand,
@@ -423,14 +418,6 @@ export class ProjectCommandService implements ProjectCommandExecutor {
command: input.command,
}).revision;
}
- case distributionBoardCreateFeederCircuitCommandType:
- case distributionBoardRemoveFeederCircuitCommandType: {
- assertDistributionBoardFeederCircuitProjectCommand(input.command);
- return this.distributionBoardStructureStore.executeFeederCircuit({
- ...input,
- command: input.command,
- }).revision;
- }
case distributionBoardComponentInsertCommandType: {
assertDistributionBoardComponentInsertProjectCommand(
input.command
diff --git a/src/frontend/components/circuit-tree-editor.tsx b/src/frontend/components/circuit-tree-editor.tsx
index f75b64e..bac08ce 100644
--- a/src/frontend/components/circuit-tree-editor.tsx
+++ b/src/frontend/components/circuit-tree-editor.tsx
@@ -1766,7 +1766,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
const currentDisplay =
mode === "replaceWithTypedChar" && cell.cellKey !== "phaseType"
? typedChar ?? ""
- : String(visibleCell.editValue ?? visibleCell.value ?? "");
+ : String(visibleCell.value ?? "");
focusTokenRef.current += 1;
setEditingCell({
...cell,
@@ -4077,9 +4077,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
key={row.rowKey}
className={`${
row.rowType === "circuitSummary"
- ? row.downstreamBoardLoad
- ? "feeder-circuit-row"
- : "summary-row"
+ ? "summary-row"
: row.rowType === "deviceRow"
? "device-row"
: row.rowType === "downstreamBoardLoad"
@@ -4710,19 +4708,11 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
tabIndex={-1}
/>
0
- }
+ disabled={isSaving}
icon={Trash2}
label="Stromkreis löschen"
onClick={() => void handleDeleteCircuit(row.circuit!.id)}
tabIndex={-1}
- title={
- (row.circuit.downstreamBoardLoads?.length ?? 0) > 0
- ? "Speist eine Unterverteilung – zuerst deren Einspeisung ändern"
- : undefined
- }
variant="danger"
/>
>
diff --git a/src/frontend/print/print-document.tsx b/src/frontend/print/print-document.tsx
index a13d7e1..5a0152b 100644
--- a/src/frontend/print/print-document.tsx
+++ b/src/frontend/print/print-document.tsx
@@ -431,25 +431,6 @@ function CircuitRows({ circuit }: { circuit: CircuitTreeCircuitDto }) {
);
}
- if (rows.length === 0 && downstreamBoards.length === 1) {
- const boardLabel =
- downstreamBoards[0].boardNumber ?? downstreamBoards[0].name;
- return (
-
- | {circuit.equipmentIdentifier} |
-
- {boardLabel}
- {circuit.displayName ? (
- · {circuit.displayName}
- ) : null}
- |
- – |
- | | |
- {formatKilowatt(circuit.circuitTotalPower)} |
- {circuitCells}
-
- );
- }
if (rows.length === 1 && downstreamBoards.length === 0) {
const row = rows[0];
const title = circuit.displayName ?? row.displayName;
diff --git a/src/frontend/utils/api.ts b/src/frontend/utils/api.ts
index 8f5a878..8473bfa 100644
--- a/src/frontend/utils/api.ts
+++ b/src/frontend/utils/api.ts
@@ -366,22 +366,20 @@ export function createDistributionBoard(
);
}
-export type UpdateDistributionBoardInput = {
- floorId: string | null;
- supplyType: NonNullable;
- simultaneityFactor: number;
-} & Partial &
- Partial<
- Pick<
- DistributionBoardDto,
- "feedingDistributionBoardId" | "feedingCircuitId"
- >
- >;
-
export function updateDistributionBoard(
projectId: string,
distributionBoardId: string,
- input: UpdateDistributionBoardInput,
+ input: {
+ floorId: string | null;
+ supplyType: NonNullable;
+ simultaneityFactor: number;
+ } & Partial &
+ Partial<
+ Pick<
+ DistributionBoardDto,
+ "feedingDistributionBoardId" | "feedingCircuitId"
+ >
+ >,
expectedRevision: number
) {
return request(
@@ -393,41 +391,6 @@ export function updateDistributionBoard(
);
}
-export function createFeederCircuitAndUpdateDistributionBoard(
- projectId: string,
- distributionBoardId: string,
- input: UpdateDistributionBoardInput & {
- feedingDistributionBoardId: string;
- feedingCircuitId: string;
- },
- circuit: CircuitSnapshot,
- expectedRevision: number
-) {
- return executeProjectCommand(
- projectId,
- expectedRevision,
- {
- schemaVersion: 1,
- type: "distribution-board.create-feeder-circuit",
- payload: {
- circuit,
- boardUpdate: {
- schemaVersion: 2,
- type: "distribution-board.update",
- payload: {
- distributionBoardId,
- changes: Object.entries(input).map(([field, value]) => ({
- field,
- value,
- })),
- },
- },
- },
- },
- "Einspeiseabgang anlegen und Verteilung verknüpfen"
- );
-}
-
export const documentLogoUrl = "/api/document-branding/logo";
export function getDocumentBranding() {
diff --git a/src/frontend/utils/circuit-grid-model.ts b/src/frontend/utils/circuit-grid-model.ts
index fafeca4..faa4a11 100644
--- a/src/frontend/utils/circuit-grid-model.ts
+++ b/src/frontend/utils/circuit-grid-model.ts
@@ -617,11 +617,7 @@ export function getCellKind(rowType: RowType, key: CellKey): CellKind {
if (rowType === "deviceRow") return deviceFieldKeys.has(key) ? "deviceField" : "readonly";
if (rowType === "downstreamBoardLoad") return "readonly";
if (rowType === "circuitSummary") return circuitFieldKeys.has(key) ? "circuitField" : "readonly";
- if (rowType === "reserveCircuit") {
- if (circuitFieldKeys.has(key)) return "circuitField";
- if (deviceFieldKeys.has(key)) return "deviceField";
- }
- if (rowType === "circuitCompact") {
+ if (rowType === "reserveCircuit" || rowType === "circuitCompact") {
if (deviceFieldKeys.has(key)) return "deviceField";
if (circuitFieldKeys.has(key)) return "circuitField";
}
diff --git a/src/frontend/utils/circuit-grid-projection.ts b/src/frontend/utils/circuit-grid-projection.ts
index 30e5ecf..a9b11de 100644
--- a/src/frontend/utils/circuit-grid-projection.ts
+++ b/src/frontend/utils/circuit-grid-projection.ts
@@ -37,8 +37,6 @@ export interface VisibleGridCell {
editable: boolean;
kind: CellKind;
value: GridValue;
- /** Separate persisted value when the displayed value is derived. */
- editValue?: GridValue;
}
export interface VisibleGridRow {
@@ -146,7 +144,6 @@ function makeVisibleGridRow(
const kind = getCellKind(rowType, column.key);
const editable = kind === "circuitField" || kind === "deviceField";
let value: GridValue;
- let editValue: GridValue | undefined;
if (rowType === "downstreamBoardLoad" && downstreamBoardLoad) {
value = column.key === "displayName"
@@ -158,35 +155,6 @@ function makeVisibleGridRow(
: column.key === "remark"
? "Automatisch aus der verknüpften Verteilung"
: undefined;
- } else if (
- rowType === "circuitSummary" &&
- circuit &&
- downstreamBoardLoad &&
- circuit.deviceRows.length === 0
- ) {
- if (column.key === "displayName") {
- const boardLabel =
- downstreamBoardLoad.boardNumber ?? downstreamBoardLoad.name;
- value = circuit.displayName
- ? `${boardLabel} · ${circuit.displayName}`
- : boardLabel;
- editValue = circuit.displayName ?? "";
- } else if (column.key === "cosPhi") {
- value = circuit.circuitCosPhi;
- } else if (
- kind === "computed" &&
- circuitOnlyColumns.has(column.key)
- ) {
- value = getCircuitValue(circuit, column.key);
- } else if (kind === "circuitField") {
- value = getCircuitValue(circuit, column.key);
- } else if (column.key === "rowTotalPower") {
- value = circuit.circuitTotalPower;
- } else if (column.key === "circuitTotalPower") {
- value = circuit.circuitTotalPower;
- } else if (column.key === "voltage") {
- value = circuit.voltage;
- }
} else if (rowType === "placeholder") {
value = column.key === "equipmentIdentifier" ? "-frei-" : undefined;
} else if (kind === "deviceField" && device) {
@@ -210,7 +178,7 @@ function makeVisibleGridRow(
value = circuit.voltage;
}
- return { cellKey: column.key, editable, kind, value, editValue };
+ return { cellKey: column.key, editable, kind, value };
});
return {
@@ -279,19 +247,6 @@ export function buildVisibleGridRowsWithStructure(
const downstreamLoads = circuit.downstreamBoardLoads ?? [];
if (circuit.deviceRows.length === 0 && downstreamLoads.length === 0) {
rows.push(makeVisibleGridRow("reserveCircuit", section.id, circuit));
- } else if (
- circuit.deviceRows.length === 0 &&
- downstreamLoads.length === 1
- ) {
- rows.push(
- makeVisibleGridRow(
- "circuitSummary",
- section.id,
- circuit,
- undefined,
- downstreamLoads[0]
- )
- );
} else if (circuit.deviceRows.length === 1 && downstreamLoads.length === 0) {
rows.push(makeVisibleGridRow("circuitCompact", section.id, circuit, circuit.deviceRows[0]));
} else {
diff --git a/src/frontend/utils/distribution-board-feeder-circuit.ts b/src/frontend/utils/distribution-board-feeder-circuit.ts
deleted file mode 100644
index c2c7f43..0000000
--- a/src/frontend/utils/distribution-board-feeder-circuit.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import type { CircuitSnapshot } from "../../domain/models/circuit-structure-project-command.model.js";
-import type {
- CircuitTreeResponseDto,
- CircuitTreeSectionDto,
-} from "../types";
-import { buildCircuitInsertSnapshot } from "./circuit-structure-command";
-
-export function getDefaultFeederCircuitSection(
- tree: CircuitTreeResponseDto | undefined
-) {
- if (!tree) return undefined;
- return (
- tree.sections.find((section) => section.category === "three_phase") ??
- tree.sections.find((section) => section.category !== undefined)
- );
-}
-
-export function getNextFeederCircuitIdentifier(
- section: CircuitTreeSectionDto
-) {
- let highestSuffix = 0;
- for (const circuit of section.circuits) {
- if (!circuit.equipmentIdentifier.startsWith(section.prefix)) continue;
- const suffix = circuit.equipmentIdentifier.slice(section.prefix.length);
- if (!/^\d+$/.test(suffix)) continue;
- highestSuffix = Math.max(highestSuffix, Number(suffix));
- }
- return `${section.prefix}${highestSuffix + 1}`;
-}
-
-export function buildFeederCircuitSnapshot(input: {
- id: string;
- tree: CircuitTreeResponseDto;
- sectionId: string;
- displayName: string;
-}): CircuitSnapshot {
- const section = input.tree.sections.find(
- (candidate) => candidate.id === input.sectionId
- );
- if (!section || !section.category) {
- throw new Error("Die gewählte Stromkreisgruppe ist nicht verfügbar.");
- }
- const snapshot = buildCircuitInsertSnapshot({
- id: input.id,
- circuitListId: input.tree.circuitListId,
- category: section.category,
- deviceRows: [],
- values: {
- sectionId: section.id,
- equipmentIdentifier: getNextFeederCircuitIdentifier(section),
- displayName: input.displayName.trim() || undefined,
- sortOrder:
- section.circuits.length === 0
- ? 10
- : Math.max(...section.circuits.map((circuit) => circuit.sortOrder)) +
- 10,
- voltage:
- section.category === "three_phase"
- ? input.tree.threePhaseVoltageV
- : input.tree.singlePhaseVoltageV,
- isReserve: true,
- },
- });
- // A distribution-board feeder is not a generic final circuit. Its protection
- // must be selected from the calculated load and cable, so no 16 A group
- // default is persisted here.
- return { ...snapshot, protectionDevice: null };
-}
diff --git a/src/frontend/utils/project-version-history.ts b/src/frontend/utils/project-version-history.ts
index eb195d0..146cda8 100644
--- a/src/frontend/utils/project-version-history.ts
+++ b/src/frontend/utils/project-version-history.ts
@@ -32,10 +32,6 @@ const commandTypeLabels: Record = {
"project.update-settings": "Projekteinstellungen bearbeitet",
"distribution-board.insert": "Verteilung angelegt",
"distribution-board.update": "Verteilung bearbeitet",
- "distribution-board.create-feeder-circuit":
- "Einspeiseabgang angelegt und verknüpft",
- "distribution-board.remove-feeder-circuit":
- "Einspeiseabgang und Verknüpfung entfernt",
"distribution-board.delete": "Verteilung entfernt",
"distribution-board.insert-subtree": "Verteilung vollständig eingefügt",
"distribution-board.delete-subtree": "Verteilung vollständig entfernt",
diff --git a/tests/circuit-grid-model.test.ts b/tests/circuit-grid-model.test.ts
index 475d781..641a770 100644
--- a/tests/circuit-grid-model.test.ts
+++ b/tests/circuit-grid-model.test.ts
@@ -133,9 +133,7 @@ describe("circuit grid model", () => {
assert.equal(getCellKind("circuitCompact", "equipmentIdentifier"), "circuitField");
assert.equal(getCellKind("circuitSummary", "displayName"), "circuitField");
assert.equal(getCellKind("deviceRow", "displayName"), "deviceField");
- assert.equal(getCellKind("reserveCircuit", "displayName"), "circuitField");
- assert.equal(getCellKind("reserveCircuit", "remark"), "circuitField");
- assert.equal(getCellKind("reserveCircuit", "powerPerUnit"), "deviceField");
+ assert.equal(getCellKind("reserveCircuit", "remark"), "deviceField");
assert.equal(getCellKind("placeholder", "displayName"), "deviceField");
assert.equal(getCellKind("deviceRow", "equipmentIdentifier"), "readonly");
assert.equal(getCellKind("circuitSummary", "controlRequirement"), "circuitField");
diff --git a/tests/circuit-grid-projection.test.ts b/tests/circuit-grid-projection.test.ts
index 6551aee..1a16913 100644
--- a/tests/circuit-grid-projection.test.ts
+++ b/tests/circuit-grid-projection.test.ts
@@ -179,10 +179,9 @@ describe("circuit grid projection", () => {
);
});
- it("renders one linked downstream board as one compact editable circuit row", () => {
+ it("renders linked downstream boards as separate read-only rows", () => {
const feeder = {
...reserveCircuit,
- displayName: undefined,
isReserve: false,
circuitTotalPower: 4,
circuitApparentPower: 5,
@@ -203,65 +202,19 @@ describe("circuit grid projection", () => {
assert.deepEqual(rows.map((row) => row.rowType), [
"section",
"circuitSummary",
+ "downstreamBoardLoad",
"placeholder",
]);
- const loadRow = rows[1];
+ const loadRow = rows[2];
assert.equal(
loadRow.cells.find((cell) => cell.cellKey === "displayName")?.value,
- "UV-02"
- );
- assert.equal(
- loadRow.cells.find((cell) => cell.cellKey === "displayName")?.editValue,
- ""
+ "Unterverteilung UV-02"
);
assert.equal(
loadRow.cells.find((cell) => cell.cellKey === "rowTotalPower")?.value,
4
);
- assert.equal(
- loadRow.cells.find((cell) => cell.cellKey === "displayName")?.kind,
- "circuitField"
- );
- });
-
- it("keeps separate read-only rows for several linked downstream boards", () => {
- const feeder = {
- ...reserveCircuit,
- isReserve: false,
- circuitTotalPower: 6,
- circuitApparentPower: 7,
- circuitCosPhi: 6 / 7,
- downstreamBoardLoads: [
- {
- distributionBoardId: "board-a",
- name: "Unterverteilung A",
- boardNumber: "UV-A",
- activePowerKw: 4,
- apparentPowerKva: 5,
- cosPhi: 0.8,
- },
- {
- distributionBoardId: "board-b",
- name: "Unterverteilung B",
- boardNumber: "UV-B",
- activePowerKw: 2,
- apparentPowerKva: 2,
- cosPhi: 1,
- },
- ],
- };
- const rows = buildVisibleGridRowsWithStructure(
- [{ ...sections[0], circuits: [feeder] }],
- { headerComponents: [], footerComponents: [] }
- );
- assert.deepEqual(rows.map((row) => row.rowType), [
- "section",
- "circuitSummary",
- "downstreamBoardLoad",
- "downstreamBoardLoad",
- "placeholder",
- ]);
- assert.equal(rows[2].cells.every((cell) => !cell.editable), true);
+ assert.equal(loadRow.cells.every((cell) => !cell.editable), true);
});
it("shows circuit protection once on each visible circuit row", () => {
diff --git a/tests/distribution-board-feeder-circuit-project-command.repository.test.ts b/tests/distribution-board-feeder-circuit-project-command.repository.test.ts
deleted file mode 100644
index d4d2c26..0000000
--- a/tests/distribution-board-feeder-circuit-project-command.repository.test.ts
+++ /dev/null
@@ -1,240 +0,0 @@
-import path from "node:path";
-import assert from "node:assert/strict";
-import { describe, it } from "node:test";
-import { eq } from "drizzle-orm";
-import { migrate } from "drizzle-orm/better-sqlite3/migrator";
-import {
- createDatabaseContext,
- type DatabaseContext,
-} from "../src/db/database-context.js";
-import { DistributionBoardStructureProjectCommandRepository } from "../src/db/repositories/distribution-board-structure-project-command.repository.js";
-import { ProjectHistoryRepository } from "../src/db/repositories/project-history.repository.js";
-import { circuits } from "../src/db/schema/circuits.js";
-import { distributionBoards } from "../src/db/schema/distribution-boards.js";
-import { projects } from "../src/db/schema/projects.js";
-import {
- assertDistributionBoardFeederCircuitProjectCommand,
- createDistributionBoardCreateFeederCircuitProjectCommand,
-} from "../src/domain/models/distribution-board-feeder-circuit-project-command.model.js";
-import { createDistributionBoardUpdateProjectCommand } from "../src/domain/models/distribution-board-project-command.model.js";
-import {
- createDistributionBoardInsertProjectCommand,
- createDistributionBoardStructureSnapshot,
-} from "../src/domain/models/distribution-board-structure-project-command.model.js";
-import { buildCircuitInsertSnapshot } from "../src/frontend/utils/circuit-structure-command.js";
-
-function createTestDatabase(): DatabaseContext {
- const context = createDatabaseContext(":memory:");
- migrate(context.db, {
- migrationsFolder: path.resolve("src", "db", "migrations"),
- });
- context.db
- .insert(projects)
- .values({ id: "project-1", name: "Test project" })
- .run();
- return context;
-}
-
-function setupBoards(
- context: DatabaseContext,
- repository: DistributionBoardStructureProjectCommandRepository
-) {
- const source = createDistributionBoardStructureSnapshot(
- "project-1",
- "NSHV"
- );
- const downstream = createDistributionBoardStructureSnapshot(
- "project-1",
- "UV EG"
- );
- repository.execute({
- projectId: "project-1",
- expectedRevision: 0,
- source: "user",
- command: createDistributionBoardInsertProjectCommand(source),
- });
- repository.execute({
- projectId: "project-1",
- expectedRevision: 1,
- source: "user",
- command: createDistributionBoardInsertProjectCommand(downstream),
- });
- const section = source.sections.find(
- (candidate) => candidate.key === "three_phase"
- )!;
- const circuit = {
- ...buildCircuitInsertSnapshot({
- id: "feeder-circuit",
- circuitListId: source.circuitList.id,
- category: "three_phase",
- deviceRows: [],
- values: {
- sectionId: section.id,
- equipmentIdentifier: `${section.prefix}1`,
- displayName: undefined,
- sortOrder: 10,
- voltage: 400,
- isReserve: true,
- },
- }),
- protectionDevice: null,
- };
- const boardUpdate = createDistributionBoardUpdateProjectCommand(
- downstream.distributionBoard.id,
- {
- feedingDistributionBoardId: source.distributionBoard.id,
- feedingCircuitId: circuit.id,
- }
- );
- const command =
- createDistributionBoardCreateFeederCircuitProjectCommand(
- circuit,
- boardUpdate
- );
- return { source, downstream, circuit, command };
-}
-
-describe("distribution-board feeder-circuit project command", () => {
- it("creates and links one feeder atomically and supports undo and redo", () => {
- const context = createTestDatabase();
- try {
- const repository =
- new DistributionBoardStructureProjectCommandRepository(context.db);
- const history = new ProjectHistoryRepository(context.db);
- const { source, downstream, circuit, command } = setupBoards(
- context,
- repository
- );
-
- repository.executeFeederCircuit({
- projectId: "project-1",
- expectedRevision: 2,
- source: "user",
- command,
- });
- assert.ok(
- context.db
- .select()
- .from(circuits)
- .where(eq(circuits.id, circuit.id))
- .get()
- );
- assert.deepEqual(
- context.db
- .select({
- boardId: distributionBoards.feedingDistributionBoardId,
- circuitId: distributionBoards.feedingCircuitId,
- })
- .from(distributionBoards)
- .where(eq(distributionBoards.id, downstream.distributionBoard.id))
- .get(),
- {
- boardId: source.distributionBoard.id,
- circuitId: circuit.id,
- }
- );
-
- const undo = history.getNextCommand("project-1", "undo");
- assert.ok(undo);
- assertDistributionBoardFeederCircuitProjectCommand(undo.command);
- repository.executeFeederCircuit({
- projectId: "project-1",
- expectedRevision: 3,
- source: "undo",
- historyTargetChangeSetId: undo.changeSetId,
- command: undo.command,
- });
- assert.equal(
- context.db
- .select()
- .from(circuits)
- .where(eq(circuits.id, circuit.id))
- .get(),
- undefined
- );
- assert.deepEqual(
- context.db
- .select({
- boardId: distributionBoards.feedingDistributionBoardId,
- circuitId: distributionBoards.feedingCircuitId,
- })
- .from(distributionBoards)
- .where(eq(distributionBoards.id, downstream.distributionBoard.id))
- .get(),
- { boardId: null, circuitId: null }
- );
-
- const redo = history.getNextCommand("project-1", "redo");
- assert.ok(redo);
- assertDistributionBoardFeederCircuitProjectCommand(redo.command);
- repository.executeFeederCircuit({
- projectId: "project-1",
- expectedRevision: 4,
- source: "redo",
- historyTargetChangeSetId: redo.changeSetId,
- command: redo.command,
- });
- assert.equal(
- context.db
- .select({ equipmentIdentifier: circuits.equipmentIdentifier })
- .from(circuits)
- .where(eq(circuits.id, circuit.id))
- .get()?.equipmentIdentifier,
- circuit.equipmentIdentifier
- );
- } finally {
- context.close();
- }
- });
-
- it("rolls back unlinking when the generated circuit changed before undo", () => {
- const context = createTestDatabase();
- try {
- const repository =
- new DistributionBoardStructureProjectCommandRepository(context.db);
- const history = new ProjectHistoryRepository(context.db);
- const { downstream, circuit, command } = setupBoards(context, repository);
- repository.executeFeederCircuit({
- projectId: "project-1",
- expectedRevision: 2,
- source: "user",
- command,
- });
- context.db
- .update(circuits)
- .set({ displayName: "Außerhalb der Historie geändert" })
- .where(eq(circuits.id, circuit.id))
- .run();
-
- const undo = history.getNextCommand("project-1", "undo");
- assert.ok(undo);
- assertDistributionBoardFeederCircuitProjectCommand(undo.command);
- assert.throws(
- () =>
- repository.executeFeederCircuit({
- projectId: "project-1",
- expectedRevision: 3,
- source: "undo",
- historyTargetChangeSetId: undo.changeSetId,
- command: undo.command,
- }),
- /changed before history removal/
- );
- const board = context.db
- .select()
- .from(distributionBoards)
- .where(eq(distributionBoards.id, downstream.distributionBoard.id))
- .get();
- assert.equal(board?.feedingCircuitId, circuit.id);
- assert.ok(
- context.db
- .select()
- .from(circuits)
- .where(eq(circuits.id, circuit.id))
- .get()
- );
- } finally {
- context.close();
- }
- });
-});
diff --git a/tests/distribution-board-feeder-circuit.test.ts b/tests/distribution-board-feeder-circuit.test.ts
deleted file mode 100644
index fb143da..0000000
--- a/tests/distribution-board-feeder-circuit.test.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import assert from "node:assert/strict";
-import { describe, it } from "node:test";
-import {
- buildFeederCircuitSnapshot,
- getDefaultFeederCircuitSection,
- getNextFeederCircuitIdentifier,
-} from "../src/frontend/utils/distribution-board-feeder-circuit.js";
-import type { CircuitTreeResponseDto } from "../src/frontend/types.js";
-import { createFeederCircuitAndUpdateDistributionBoard } from "../src/frontend/utils/api.js";
-
-function tree(): CircuitTreeResponseDto {
- return {
- circuitListId: "list-main",
- distributionBoardId: "board-main",
- distributionBoardName: "NSHV",
- currentRevision: 2,
- singlePhaseVoltageV: 230,
- threePhaseVoltageV: 400,
- distributionBoardSimultaneityFactor: 1,
- distributionBoardTotalPower: 0,
- distributionBoardTotalPowerWithSimultaneityFactor: 0,
- headerComponents: [],
- footerComponents: [],
- sections: [
- {
- id: "single",
- key: "single_phase",
- category: "single_phase",
- groupNumber: 1,
- displayName: "1-phasig 1",
- prefix: "-2F1.",
- sortOrder: 10,
- sectionTotalPower: 0,
- components: [],
- circuits: [],
- },
- {
- id: "three",
- key: "three_phase",
- category: "three_phase",
- groupNumber: 1,
- displayName: "3-phasig 1",
- prefix: "-3F1.",
- sortOrder: 20,
- sectionTotalPower: 0,
- components: [],
- circuits: [
- {
- id: "existing-2",
- circuitListId: "list-main",
- sectionId: "three",
- equipmentIdentifier: "-3F1.2",
- sortOrder: 10,
- isReserve: true,
- circuitTotalPower: 0,
- circuitApparentPower: 0,
- circuitCosPhi: 1,
- deviceRows: [],
- downstreamBoardLoads: [],
- },
- {
- id: "existing-5",
- circuitListId: "list-main",
- sectionId: "three",
- equipmentIdentifier: "-3F1.5",
- sortOrder: 30,
- isReserve: true,
- circuitTotalPower: 0,
- circuitApparentPower: 0,
- circuitCosPhi: 1,
- deviceRows: [],
- downstreamBoardLoads: [],
- },
- ],
- },
- ],
- };
-}
-
-describe("distribution-board feeder circuit planning", () => {
- it("prefers a three-phase section and does not fill BMK gaps", () => {
- const input = tree();
- const section = getDefaultFeederCircuitSection(input)!;
- assert.equal(section.id, "three");
- assert.equal(getNextFeederCircuitIdentifier(section), "-3F1.6");
- });
-
- it("builds an empty circuit with stable id, optional name and defaults", () => {
- const input = tree();
- const snapshot = buildFeederCircuitSnapshot({
- id: "new-feeder",
- tree: input,
- sectionId: "three",
- displayName: " ",
- });
- assert.equal(snapshot.id, "new-feeder");
- assert.equal(snapshot.equipmentIdentifier, "-3F1.6");
- assert.equal(snapshot.displayName, null);
- assert.equal(snapshot.sortOrder, 40);
- assert.equal(snapshot.voltage, 400);
- assert.equal(snapshot.isReserve, true);
- assert.deepEqual(snapshot.deviceRows, []);
- assert.equal(snapshot.protectionDevice, null);
- });
-
- it("sends circuit creation and board linking as one project command", async () => {
- const input = tree();
- const circuit = buildFeederCircuitSnapshot({
- id: "new-feeder",
- tree: input,
- sectionId: "three",
- displayName: "",
- });
- const requests: Array<{ url: string; method: string; body: any }> = [];
- const originalFetch = globalThis.fetch;
- globalThis.fetch = async (request, init) => {
- requests.push({
- url: String(request),
- method: init?.method ?? "GET",
- body: JSON.parse(String(init?.body)),
- });
- return new Response(JSON.stringify({}), {
- status: 200,
- headers: { "Content-Type": "application/json" },
- });
- };
- try {
- await createFeederCircuitAndUpdateDistributionBoard(
- "project-1",
- "board-child",
- {
- floorId: null,
- supplyType: "AV",
- simultaneityFactor: 0.8,
- feedingDistributionBoardId: "board-main",
- feedingCircuitId: circuit.id,
- },
- circuit,
- 7
- );
- } finally {
- globalThis.fetch = originalFetch;
- }
- assert.equal(requests.length, 1);
- assert.equal(requests[0].url, "/api/projects/project-1/commands");
- assert.equal(requests[0].method, "POST");
- assert.equal(requests[0].body.expectedRevision, 7);
- assert.equal(
- requests[0].body.command.type,
- "distribution-board.create-feeder-circuit"
- );
- assert.equal(requests[0].body.command.payload.circuit.id, "new-feeder");
- assert.deepEqual(
- requests[0].body.command.payload.boardUpdate.payload.changes
- .filter((change: { field: string }) =>
- change.field.startsWith("feeding")
- )
- .map((change: { field: string; value: unknown }) => [
- change.field,
- change.value,
- ]),
- [
- ["feedingDistributionBoardId", "board-main"],
- ["feedingCircuitId", "new-feeder"],
- ]
- );
- });
-});