+ | {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/circuit-grid-model.ts b/src/frontend/utils/circuit-grid-model.ts
index faa4a11..fafeca4 100644
--- a/src/frontend/utils/circuit-grid-model.ts
+++ b/src/frontend/utils/circuit-grid-model.ts
@@ -617,7 +617,11 @@ 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" || rowType === "circuitCompact") {
+ if (rowType === "reserveCircuit") {
+ if (circuitFieldKeys.has(key)) return "circuitField";
+ if (deviceFieldKeys.has(key)) return "deviceField";
+ }
+ if (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 a9b11de..30e5ecf 100644
--- a/src/frontend/utils/circuit-grid-projection.ts
+++ b/src/frontend/utils/circuit-grid-projection.ts
@@ -37,6 +37,8 @@ export interface VisibleGridCell {
editable: boolean;
kind: CellKind;
value: GridValue;
+ /** Separate persisted value when the displayed value is derived. */
+ editValue?: GridValue;
}
export interface VisibleGridRow {
@@ -144,6 +146,7 @@ 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"
@@ -155,6 +158,35 @@ 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) {
@@ -178,7 +210,7 @@ function makeVisibleGridRow(
value = circuit.voltage;
}
- return { cellKey: column.key, editable, kind, value };
+ return { cellKey: column.key, editable, kind, value, editValue };
});
return {
@@ -247,6 +279,19 @@ 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/tests/circuit-grid-model.test.ts b/tests/circuit-grid-model.test.ts
index 641a770..475d781 100644
--- a/tests/circuit-grid-model.test.ts
+++ b/tests/circuit-grid-model.test.ts
@@ -133,7 +133,9 @@ 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", "remark"), "deviceField");
+ assert.equal(getCellKind("reserveCircuit", "displayName"), "circuitField");
+ assert.equal(getCellKind("reserveCircuit", "remark"), "circuitField");
+ assert.equal(getCellKind("reserveCircuit", "powerPerUnit"), "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 1a16913..6551aee 100644
--- a/tests/circuit-grid-projection.test.ts
+++ b/tests/circuit-grid-projection.test.ts
@@ -179,9 +179,10 @@ describe("circuit grid projection", () => {
);
});
- it("renders linked downstream boards as separate read-only rows", () => {
+ it("renders one linked downstream board as one compact editable circuit row", () => {
const feeder = {
...reserveCircuit,
+ displayName: undefined,
isReserve: false,
circuitTotalPower: 4,
circuitApparentPower: 5,
@@ -202,19 +203,65 @@ describe("circuit grid projection", () => {
assert.deepEqual(rows.map((row) => row.rowType), [
"section",
"circuitSummary",
- "downstreamBoardLoad",
"placeholder",
]);
- const loadRow = rows[2];
+ const loadRow = rows[1];
assert.equal(
loadRow.cells.find((cell) => cell.cellKey === "displayName")?.value,
- "Unterverteilung UV-02"
+ "UV-02"
+ );
+ assert.equal(
+ loadRow.cells.find((cell) => cell.cellKey === "displayName")?.editValue,
+ ""
);
assert.equal(
loadRow.cells.find((cell) => cell.cellKey === "rowTotalPower")?.value,
4
);
- assert.equal(loadRow.cells.every((cell) => !cell.editable), true);
+ 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);
});
it("shows circuit protection once on each visible circuit row", () => {