diff --git a/AGENTS.md b/AGENTS.md index 93e5108..9ef5b87 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -476,17 +476,6 @@ downstream board's demand after its own board simultaneity factor to the chosen feeding circuit as a read-only virtual row. Recursive chains and several boards on one circuit are supported. A board-only link affects hierarchy but adds no load until a feeding circuit is selected. -The distribution-board dialog can create one empty feeder circuit and link it -in the same `distribution-board.create-feeder-circuit` project command. Its -history inverse restores the complete previous board update before removing -only the unchanged generated circuit; Redo reuses its UUID and BMK. No -CircuitDeviceRow is created. The three-phase group is suggested, the optional -circuit display name stays empty by default, and protection remains open for -planner sizing. A circuit with exactly one downstream board and no device rows -is rendered as one compact row using the live board number/name; several -downstream boards or additional devices retain summary and child rows. Editing -the name or remark of an empty reserve circuit changes the circuit itself and -does not implicitly create a device row. Distribution-board floor assignment and a project-enabled supply type use `distribution-board.update`; both values are snapshot/export fields and one persistent undo step. diff --git a/docs/circuit-list-editor-api.md b/docs/circuit-list-editor-api.md index de724aa..a8173f5 100644 --- a/docs/circuit-list-editor-api.md +++ b/docs/circuit-list-editor-api.md @@ -269,13 +269,6 @@ commands. Endpoints, payloads and calculation rules: `docs/estimate-balance.md`. submitted info fields, are restored together by persistent Undo/Redo - `fedFrom` remains free text for external feeds such as HAK, metering, transformer or generator and for supplementary notes -- The project-command endpoint additionally accepts - `distribution-board.create-feeder-circuit` with an empty complete circuit - snapshot and an embedded version-2 `distribution-board.update`. Both writes - are one transaction, revision and Undo step. The generated circuit has no - device row; Redo keeps its UUID and BMK. The history-only inverse - `distribution-board.remove-feeder-circuit` restores the previous board values - and removes only the unchanged circuit. - `POST /projects/:projectId/distribution-boards/:distributionBoardId/copy` - body: `{ "name": "UV-02 Kopie", "expectedRevision": 14 }` - duplicates the complete distribution-board subtree with new owning UUIDs @@ -353,9 +346,7 @@ commands. Endpoints, payloads and calculation rules: `docs/estimate-balance.md`. footer components. Circuit and component protection devices use their separate one-to-one DTOs. Calculated row, circuit, section and board totals remain included. Circuit totals contain the demand of linked downstream - boards. `downstreamBoardLoads` exposes those contributions as read-only - values; the grid combines exactly one downstream board without device rows - into the circuit row and keeps child rows for mixed or multiple loads. + boards. `downstreamBoardLoads` exposes those contributions as read-only rows; `feedingReference` resolves the current board/circuit labels by id. Response sketch: diff --git a/docs/current-architecture.md b/docs/current-architecture.md index 71b7feb..920002d 100644 --- a/docs/current-architecture.md +++ b/docs/current-architecture.md @@ -477,21 +477,6 @@ Verweise nicht. Der speisende Stromkreis muss zur speisenden Verteilung gehören Selbstverweise und Zyklen werden abgelehnt. Löschbefehle für referenzierte Verteilungen und Stromkreise, einschließlich Unterbaum- und Undo-Pfaden, werden vor der Datenbankänderung fachlich gesperrt. -Im Bearbeiten-Dialog kann nach Auswahl der speisenden Verteilung direkt ein -neuer Einspeiseabgang geplant werden. Die Oberfläche schlägt die dreiphasige -Gruppe und das nächste BMK vor. Der Befehl -`distribution-board.create-feeder-circuit` legt den leeren Stromkreis an und -wendet die vollständige Verteilungsänderung in derselben Transaktion und -Revision an; es entsteht keine Gerätezeile. Schutz und Leitung bleiben bewusst -offen, weil sie aus Last und Verlegebedingungen geplant werden müssen. Undo -stellt zuerst die vorherigen Verteilungswerte wieder her und entfernt danach -nur den unveränderten erzeugten Stromkreis; Redo verwendet UUID und BMK erneut. -Bei genau einer gespeisten Unterverteilung ohne Gerätezeilen projiziert das -Grid nur eine kompakte Stromkreiszeile mit dem über die ID aufgelösten -Verteilernamen. Erst mehrere Unterverteilungen oder zusätzliche Geräte erzeugen -Sammel- und Unterzeilen. Anzeigename und Bemerkung eines leeren -Reservestromkreises gehören zum Stromkreis und erzeugen beim Bearbeiten keine -Gerätezeile. Die projektweite Circuit-Tree-Projektion berechnet rekursiv die Lasten aller Verteilungen. Die Leistung einer Unterverteilung nach ihrem eigenen Verteiler-GZF wird als virtuelle, schreibgeschützte Zeile genau dem gewählten diff --git a/docs/print-view.md b/docs/print-view.md index ecc00e2..a843030 100644 --- a/docs/print-view.md +++ b/docs/print-view.md @@ -38,9 +38,8 @@ automatisch bei späteren Änderungen in einem anderen Tab. 3. **Verteilerpläne (quer, je Verteiler)** – Titelleiste mit Verteilernummer, Bezeichnung, Örtlichkeit, Netzart, „Gespeist von“ und Pgl; darunter Kopfkomponenten, Gruppen, Stromkreise - (reine 1:1-Einspeiseabgänge kompakt in einer Zeile; sonst mehrzeilig mit - Sammelzeile, eingerückten Gerätezeilen und schreibgeschützten - Unterverteilungszeilen), + (mehrzeilige mit Sammelzeile, eingerückten Gerätezeilen und + schreibgeschützten Unterverteilungszeilen), Gruppensummen und Verteilersumme. Fehlende Kabelangaben sind als „offen“ markiert. Die Titelleiste steht im Tabellenkopf und wiederholt sich beim Drucken auf Folgeseiten. diff --git a/src/app/globals.css b/src/app/globals.css index 88df3e9..d14431b 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1537,10 +1537,6 @@ a.kpi:hover { background: var(--panel-bg-subtle); } -.tree-grid .feeder-circuit-row td:nth-child(2) { - font-weight: 600; -} - .tree-grid .device-row td:first-child { color: var(--text-faint); } diff --git a/src/app/projects/[projectId]/page.tsx b/src/app/projects/[projectId]/page.tsx index 37813c1..4a99cf0 100644 --- a/src/app/projects/[projectId]/page.tsx +++ b/src/app/projects/[projectId]/page.tsx @@ -47,7 +47,6 @@ import { import { copyGlobalDeviceToProject, copyDistributionBoard, - createFeederCircuitAndUpdateDistributionBoard, copyProjectDeviceToGlobal, createDistributionBoard, createProjectDevice, @@ -72,12 +71,6 @@ import { updateProjectDevice, updateProjectSettings, } from "../../../frontend/utils/api"; -import { createClientId } from "../../../frontend/utils/client-id"; -import { - buildFeederCircuitSnapshot, - getDefaultFeederCircuitSection, - getNextFeederCircuitIdentifier, -} from "../../../frontend/utils/distribution-board-feeder-circuit"; import type { BuildingDto, CircuitListDto, @@ -153,7 +146,6 @@ const boardFilterCollapsedStorageKey = "leistungsbilanz:overview-filter-collapsed:distribution-boards"; const projectDeviceFilterCollapsedStorageKey = "leistungsbilanz:overview-filter-collapsed:project-devices"; -const createFeederCircuitSelectValue = "__create_feeder_circuit__"; export default function ProjectDetailPage() { const params = useParams<{ projectId: string }>(); @@ -183,12 +175,6 @@ export default function ProjectDetailPage() { const [editingBoardCopyName, setEditingBoardCopyName] = useState(""); const [editingFeedingBoardId, setEditingFeedingBoardId] = useState(""); const [editingFeedingCircuitId, setEditingFeedingCircuitId] = useState(""); - const [isCreatingFeederCircuit, setIsCreatingFeederCircuit] = - useState(false); - const [editingFeederCircuitSectionId, setEditingFeederCircuitSectionId] = - useState(""); - const [editingFeederCircuitDisplayName, setEditingFeederCircuitDisplayName] = - useState(""); const [editingBoardInfo, setEditingBoardInfo] = useState( toDistributionBoardInfoDraft({ @@ -364,21 +350,6 @@ export default function ProjectDetailPage() { const selectedFeedingCircuit = selectedFeedingCircuits.find( ({ circuit }) => circuit.id === editingFeedingCircuitId ); - const feederCircuitSections = - selectedFeedingTree?.sections.filter( - (section) => section.category !== undefined - ) ?? []; - const selectedNewFeederCircuitSection = feederCircuitSections.find( - (section) => section.id === editingFeederCircuitSectionId - ); - const newFeederCircuitIdentifier = selectedNewFeederCircuitSection - ? getNextFeederCircuitIdentifier(selectedNewFeederCircuitSection) - : null; - const selectedFeedingCircuitCategory = - selectedFeedingCircuit?.section.category ?? - (isCreatingFeederCircuit - ? selectedNewFeederCircuitSection?.category - : undefined); const selectedFeedingBoard = boards.find( (board) => board.id === editingFeedingBoardId ); @@ -585,9 +556,6 @@ export default function ProjectDetailPage() { setEditingBoardInfo(toDistributionBoardInfoDraft(board)); setEditingFeedingBoardId(board.feedingDistributionBoardId ?? ""); setEditingFeedingCircuitId(board.feedingCircuitId ?? ""); - setIsCreatingFeederCircuit(false); - setEditingFeederCircuitSectionId(""); - setEditingFeederCircuitDisplayName(""); } function openBoardCreator() { @@ -616,56 +584,28 @@ export default function ProjectDetailPage() { setIsSaving(true); setError(null); try { - const boardInput = { - floorId: editingBoardFloorId || null, - supplyType: editingBoardSupplyType, - simultaneityFactor, - feedingDistributionBoardId: editingFeedingBoardId || null, - feedingCircuitId: editingFeedingCircuitId || null, - ...fromDistributionBoardInfoDraft(editingBoardInfo), - }; - let result; - if (isCreatingFeederCircuit) { - if (!editingFeedingBoardId || !selectedFeedingTree) { - throw new Error("Bitte eine speisende Verteilung wählen."); - } - if (!selectedNewFeederCircuitSection) { - throw new Error( - "Bitte eine Stromkreisgruppe für den neuen Abgang wählen." - ); - } - const circuit = buildFeederCircuitSnapshot({ - id: createClientId(), - tree: selectedFeedingTree, - sectionId: selectedNewFeederCircuitSection.id, - displayName: editingFeederCircuitDisplayName, - }); - result = await createFeederCircuitAndUpdateDistributionBoard( - projectId, - editingBoard.id, - { - ...boardInput, - feedingDistributionBoardId: editingFeedingBoardId, - feedingCircuitId: circuit.id, - }, - circuit, - project.currentRevision - ); - } else { - result = await updateDistributionBoard( - projectId, - editingBoard.id, - boardInput, - project.currentRevision - ); - } + const result = await updateDistributionBoard( + projectId, + editingBoard.id, + { + floorId: editingBoardFloorId || null, + supplyType: editingBoardSupplyType, + simultaneityFactor, + feedingDistributionBoardId: editingFeedingBoardId || null, + feedingCircuitId: editingFeedingCircuitId || null, + ...fromDistributionBoardInfoDraft(editingBoardInfo), + }, + project.currentRevision + ); + setBoards((current) => + current.map((board) => + board.id === result.distributionBoard.id + ? result.distributionBoard + : board + ) + ); applyProjectRevision(result.history.currentRevision); - const [updatedBoards, updatedTrees] = await Promise.all([ - listDistributionBoards(projectId), - getProjectCircuitTrees(projectId), - ]); - setBoards(updatedBoards); - setCircuitTrees(updatedTrees.trees); + setCircuitTrees((await getProjectCircuitTrees(projectId)).trees); setEditingBoard(null); } catch (err) { setError( @@ -1627,16 +1567,8 @@ export default function ProjectDetailPage() { className="form-select" id="feeding-distribution-board" onChange={(event) => { - const boardId = event.target.value; - setEditingFeedingBoardId(boardId); + setEditingFeedingBoardId(event.target.value); setEditingFeedingCircuitId(""); - setIsCreatingFeederCircuit(false); - setEditingFeederCircuitSectionId( - getDefaultFeederCircuitSection( - circuitTreeByBoardId.get(boardId) - )?.id ?? "" - ); - setEditingFeederCircuitDisplayName(""); }} value={editingFeedingBoardId} > @@ -1656,31 +1588,10 @@ export default function ProjectDetailPage() { className="form-select" disabled={!editingFeedingBoardId} id="feeding-circuit" - onChange={(event) => { - if (event.target.value === createFeederCircuitSelectValue) { - setEditingFeedingCircuitId(""); - setIsCreatingFeederCircuit(true); - setEditingFeederCircuitSectionId( - (current) => - current || - getDefaultFeederCircuitSection(selectedFeedingTree)?.id || - "" - ); - return; - } - setIsCreatingFeederCircuit(false); - setEditingFeedingCircuitId(event.target.value); - }} - value={ - isCreatingFeederCircuit - ? createFeederCircuitSelectValue - : editingFeedingCircuitId - } + onChange={(event) => setEditingFeedingCircuitId(event.target.value)} + value={editingFeedingCircuitId} > - {selectedFeedingCircuits.map(({ circuit }) => (