Manage circuit groups

This commit is contained in:
2026-07-31 07:32:46 +02:00
parent 756e307bd8
commit 0c92fbd09e
8 changed files with 480 additions and 2 deletions
@@ -47,6 +47,12 @@ import {
import {
buildCircuitSectionRenumberAssignments,
} from "../utils/circuit-section-renumber-command";
import {
buildNewCircuitGroupSnapshot,
canDeleteCircuitGroup,
renameCircuitGroupSnapshot,
toCircuitGroupSnapshot,
} from "../utils/circuit-group-editing";
import {
buildDistributionBoardComponentSnapshot,
getNextComponentSortOrder,
@@ -71,12 +77,14 @@ import type { VisibleGridRow } from "../utils/circuit-grid-projection";
import {
deleteCircuitCommand,
deleteCircuitDeviceRowCommand,
deleteCircuitGroupCommand,
deleteDistributionBoardComponentCommand,
getCircuitTree,
getNextCircuitIdentifier,
getProjectHistory,
insertCircuitCommand,
insertCircuitDeviceRowCommand,
insertCircuitGroupCommand,
insertDistributionBoardComponentCommand,
listProjectDevices,
moveCircuitDeviceRowsCommand,
@@ -87,6 +95,7 @@ import {
redoProjectCommand,
updateCircuitById,
updateCircuitDeviceRowById,
updateCircuitGroupCommand,
updateDistributionBoardComponentCommand,
undoProjectCommand,
} from "../utils/api";
@@ -107,6 +116,8 @@ import type {
CircuitSnapshot,
} from "../../domain/models/circuit-structure-project-command.model";
import { DistributionBoardComponentModal } from "./distribution-board-component-modal";
import { CircuitGroupModal } from "./circuit-group-modal";
import type { CircuitGroupCategory } from "../../shared/constants/circuit-group";
type SaveDirection = "stay" | "next" | "prev";
type StartEditMode = "selectExisting" | "replaceWithTypedChar";
@@ -187,6 +198,10 @@ type StructureComponentEditorIntent =
component: CircuitTreeComponentDto;
};
type CircuitGroupEditorIntent =
| { kind: "create" }
| { kind: "edit"; section: CircuitTreeResponseDto["sections"][number] };
function getFullColumnLabel(column: ColumnDef): string {
return column.fullLabel ?? column.label;
}
@@ -229,6 +244,8 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
const [isSaving, setIsSaving] = useState(false);
const [componentEditorIntent, setComponentEditorIntent] =
useState<StructureComponentEditorIntent | null>(null);
const [circuitGroupEditorIntent, setCircuitGroupEditorIntent] =
useState<CircuitGroupEditorIntent | null>(null);
const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]);
const [isProjectDeviceDrawerOpen, setIsProjectDeviceDrawerOpen] =
useState(false);
@@ -1138,6 +1155,76 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
});
}
async function handleSaveCircuitGroup(values: {
category: CircuitGroupCategory;
displayName: string;
}) {
const intent = circuitGroupEditorIntent;
if (!intent || !data) {
return;
}
await runCommand({
label:
intent.kind === "create"
? "Stromkreisgruppe hinzufügen"
: "Stromkreisgruppe bearbeiten",
redo: async () => {
const result =
intent.kind === "create"
? await insertCircuitGroupCommand(
projectId,
getExpectedProjectRevision(),
buildNewCircuitGroupSnapshot({
id: crypto.randomUUID(),
circuitListId,
category: values.category,
displayName: values.displayName,
sections: data.sections,
})
)
: await (() => {
const expected = toCircuitGroupSnapshot(
intent.section,
circuitListId
);
return updateCircuitGroupCommand(
projectId,
getExpectedProjectRevision(),
expected,
renameCircuitGroupSnapshot(expected, values.displayName)
);
})();
applyProjectCommandResult(result);
setCircuitGroupEditorIntent(null);
return null;
},
});
}
async function handleDeleteEmptyCircuitGroup(
section: CircuitTreeResponseDto["sections"][number]
) {
if (!canDeleteCircuitGroup(section)) {
return;
}
if (!confirm(`Leere Stromkreisgruppe „${section.displayName}“ entfernen?`)) {
return;
}
await runCommand({
label: "Leere Stromkreisgruppe entfernen",
redo: async () => {
const result = await deleteCircuitGroupCommand(
projectId,
getExpectedProjectRevision(),
toCircuitGroupSnapshot(section, circuitListId)
);
applyProjectCommandResult(result);
setCircuitGroupEditorIntent(null);
return null;
},
});
}
async function handleRedo() {
if (historyBusy || isSaving || !historyState || historyState.redoDepth === 0) {
return;
@@ -2735,6 +2822,18 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
}
/>
) : null}
{circuitGroupEditorIntent ? (
<CircuitGroupModal
initialSection={
circuitGroupEditorIntent.kind === "edit"
? circuitGroupEditorIntent.section
: undefined
}
isSaving={isSaving}
onClose={() => setCircuitGroupEditorIntent(null)}
onSave={handleSaveCircuitGroup}
/>
) : null}
<div className="editor-toolbar">
<button
type="button"
@@ -2798,6 +2897,13 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
>
Verteilergerät hinzufügen
</button>
<button
type="button"
disabled={isSaving || historyBusy}
onClick={() => setCircuitGroupEditorIntent({ kind: "create" })}
>
Stromkreisgruppe hinzufügen
</button>
<button
type="button"
onClick={clearSortAndFilters}
@@ -3302,6 +3408,34 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
</span>
</div>
<div className="section-actions">
<button
type="button"
tabIndex={-1}
disabled={!section.category || !section.groupNumber}
onClick={() =>
setCircuitGroupEditorIntent({
kind: "edit",
section,
})
}
>
Gruppe bearbeiten
</button>
<button
type="button"
tabIndex={-1}
disabled={!canDeleteCircuitGroup(section)}
title={
canDeleteCircuitGroup(section)
? undefined
: "Befüllte Gruppen werden später über einen eigenen Warn- und Löschdialog entfernt."
}
onClick={() =>
void handleDeleteEmptyCircuitGroup(section)
}
>
Gruppe entfernen
</button>
<button
type="button"
tabIndex={-1}