forked from jappel/leistungsbilanz-ts
Add proposed cable-sizing module
Isolated module (mirrors src/external-model/ dependency direction) that adds an on-demand, DIN VDE 0298-4 referenced cable cross-section calculator: a click-on-a-circuit input mask for laying method, insulation, ambient temperature, grouping and voltage-drop limit that suggests a cross-section for the circuit cableCrossSection/cableLength fields. Applying a suggestion goes through the existing circuit.update command (expectedRevision, undo/redo) unchanged - nothing here writes to circuits directly or touches the revision/command system. See docs/cable-sizing-module.md for the full rationale, API contract, verification status and maintenance plan. Proposal, not yet reviewed by the project owner - see the docs file. 423 existing + 11 new tests pass, build:api/build:web/typecheck:scripts clean.
This commit is contained in:
parent
a17e2e3f4b
commit
1d030971dd
17 changed files with 4179 additions and 2 deletions
|
|
@ -137,6 +137,7 @@ import type {
|
|||
import { DistributionBoardComponentModal } from "./distribution-board-component-modal";
|
||||
import { CircuitGroupModal } from "./circuit-group-modal";
|
||||
import { CircuitProtectionModal } from "./circuit-protection-modal";
|
||||
import { CableSizingModal } from "./cable-sizing-modal";
|
||||
import {
|
||||
circuitGroupCategoryLabels,
|
||||
type CircuitGroupCategory,
|
||||
|
|
@ -278,6 +279,8 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
useState<CircuitGroupEditorIntent | null>(null);
|
||||
const [protectionEditorCircuit, setProtectionEditorCircuit] =
|
||||
useState<CircuitTreeCircuitDto | null>(null);
|
||||
const [cableSizingEditorCircuit, setCableSizingEditorCircuit] =
|
||||
useState<CircuitTreeCircuitDto | null>(null);
|
||||
const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]);
|
||||
const [isProjectDeviceDrawerOpen, setIsProjectDeviceDrawerOpen] =
|
||||
useState(false);
|
||||
|
|
@ -1398,6 +1401,30 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
});
|
||||
}
|
||||
|
||||
async function handleApplyCableSizing(patch: {
|
||||
cableCrossSection: string;
|
||||
cableLength?: number;
|
||||
}) {
|
||||
const circuit = cableSizingEditorCircuit;
|
||||
if (!circuit) {
|
||||
return;
|
||||
}
|
||||
await runCommand({
|
||||
label: "Kabel dimensionieren",
|
||||
redo: async () => {
|
||||
const result = await updateCircuitById(
|
||||
projectId,
|
||||
getExpectedProjectRevision(),
|
||||
circuit.id,
|
||||
patch
|
||||
);
|
||||
applyProjectCommandResult(result);
|
||||
setCableSizingEditorCircuit(null);
|
||||
return null;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function handleRedo() {
|
||||
if (historyBusy || isSaving || !historyState || historyState.redoDepth === 0) {
|
||||
return;
|
||||
|
|
@ -3139,6 +3166,15 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
onSave={handleSaveCircuitProtection}
|
||||
/>
|
||||
) : null}
|
||||
{cableSizingEditorCircuit ? (
|
||||
<CableSizingModal
|
||||
circuit={cableSizingEditorCircuit}
|
||||
isSaving={isSaving}
|
||||
projectId={projectId}
|
||||
onClose={() => setCableSizingEditorCircuit(null)}
|
||||
onApply={handleApplyCableSizing}
|
||||
/>
|
||||
) : null}
|
||||
<div className="editor-toolbar">
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -4240,10 +4276,15 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
row.circuit &&
|
||||
row.rowType !== "deviceRow"
|
||||
);
|
||||
const isCableSizingTrigger = Boolean(
|
||||
column.key === "cableCrossSection" &&
|
||||
row.circuit &&
|
||||
row.rowType !== "deviceRow"
|
||||
);
|
||||
return (
|
||||
<td
|
||||
key={column.key}
|
||||
className={`${column.numeric ? "num" : ""} ${cell.editable ? "cell-editable" : ""} ${isProtectionTrigger ? "cell-protection-trigger" : ""} ${isSelected ? "cell-selected" : ""} ${hasIdentifierConflict ? "cell-invalid" : ""} ${
|
||||
className={`${column.numeric ? "num" : ""} ${cell.editable ? "cell-editable" : ""} ${isProtectionTrigger ? "cell-protection-trigger" : ""} ${isCableSizingTrigger ? "cell-cable-sizing-trigger" : ""} ${isSelected ? "cell-selected" : ""} ${hasIdentifierConflict ? "cell-invalid" : ""} ${
|
||||
Boolean(row.device) && column.key === "displayName" && (row.rowType === "deviceRow" || row.rowType === "circuitCompact")
|
||||
? "device-drag-handle"
|
||||
: ""
|
||||
|
|
@ -4263,7 +4304,9 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
title={
|
||||
isProtectionTrigger
|
||||
? "Schutzgerät bearbeiten"
|
||||
: column.key === "equipmentIdentifier" &&
|
||||
: isCableSizingTrigger
|
||||
? "Kabel dimensionieren"
|
||||
: column.key === "equipmentIdentifier" &&
|
||||
row.circuit &&
|
||||
(row.rowType === "circuitCompact" ||
|
||||
row.rowType === "circuitSummary" ||
|
||||
|
|
@ -4342,6 +4385,10 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
setProtectionEditorCircuit(row.circuit!);
|
||||
return;
|
||||
}
|
||||
if (isCableSizingTrigger) {
|
||||
setCableSizingEditorCircuit(row.circuit!);
|
||||
return;
|
||||
}
|
||||
if (cell.editable) {
|
||||
handleRowSelectionClick(row, column.key, {
|
||||
ctrlKey: event.ctrlKey,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue