Remove circuit structure preview
This commit is contained in:
@@ -111,8 +111,8 @@ Primary circuit-first editor route:
|
|||||||
|
|
||||||
- `/projects/:projectId/circuit-lists/:circuitListId/tree-edit`
|
- `/projects/:projectId/circuit-lists/:circuitListId/tree-edit`
|
||||||
|
|
||||||
The sibling `/tree` route is a read-only structure preview. Old
|
Old `/projects/:projectId/circuit-lists` bookmarks redirect to the project
|
||||||
`/projects/:projectId/circuit-lists` bookmarks redirect to the project page.
|
page. A future print view will provide a dedicated read-only presentation.
|
||||||
|
|
||||||
## Future Persistence Direction
|
## Future Persistence Direction
|
||||||
|
|
||||||
|
|||||||
@@ -305,35 +305,6 @@ a.kpi:hover {
|
|||||||
min-width: 8rem;
|
min-width: 8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.circuit-tree-table .section-row td {
|
|
||||||
background: #e9eef8;
|
|
||||||
border-top: 2px solid #c6d3ea;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circuit-tree-table .summary-row td {
|
|
||||||
background: #f5f8fd;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circuit-tree-table .device-row td {
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circuit-tree-table .reserve-row td {
|
|
||||||
background: #f8fbff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circuit-tree-table .placeholder-row td {
|
|
||||||
background: #f7f7f7;
|
|
||||||
color: #6c757d;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circuit-tree-table .indented-cell {
|
|
||||||
padding-left: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-editor-shell {
|
.tree-editor-shell {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ export default function CircuitTreeEditPage() {
|
|||||||
<p className="text-secondary mb-0">Stromkreise und zugeordnete Geräte bearbeiten.</p>
|
<p className="text-secondary mb-0">Stromkreise und zugeordnete Geräte bearbeiten.</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex gap-2">
|
<div className="d-flex gap-2">
|
||||||
<Link
|
|
||||||
href={`/projects/${params.projectId}/circuit-lists/${params.circuitListId}/tree`}
|
|
||||||
className="btn btn-outline-secondary btn-sm"
|
|
||||||
>
|
|
||||||
Strukturvorschau
|
|
||||||
</Link>
|
|
||||||
<Link href={`/projects/${params.projectId}`} className="btn btn-outline-secondary btn-sm">
|
<Link href={`/projects/${params.projectId}`} className="btn btn-outline-secondary btn-sm">
|
||||||
Zum Projekt
|
Zum Projekt
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useParams } from "next/navigation";
|
|
||||||
import { CircuitTreePreview } from "../../../../../../frontend/components/circuit-tree-preview";
|
|
||||||
|
|
||||||
export default function CircuitTreePreviewPage() {
|
|
||||||
const params = useParams<{ projectId: string; circuitListId: string }>();
|
|
||||||
const projectId = params.projectId;
|
|
||||||
const circuitListId = params.circuitListId;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<main className="container py-4">
|
|
||||||
<div className="d-flex justify-content-between align-items-center mb-3">
|
|
||||||
<div>
|
|
||||||
<h1 className="h4 mb-1">Vorschau der Stromkreisstruktur</h1>
|
|
||||||
<p className="text-secondary mb-0">
|
|
||||||
Schreibgeschützte Vorschau der Bereiche, Stromkreise und Gerätezeilen.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Link
|
|
||||||
href={`/projects/${projectId}/circuit-lists/${circuitListId}/tree-edit`}
|
|
||||||
className="btn btn-outline-primary btn-sm"
|
|
||||||
>
|
|
||||||
Editor öffnen
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href={`/projects/${projectId}`}
|
|
||||||
className="btn btn-outline-secondary btn-sm"
|
|
||||||
>
|
|
||||||
Zum Projekt
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CircuitTreePreview projectId={projectId} circuitListId={circuitListId} />
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { Fragment } from "react";
|
|
||||||
import { getCircuitTree } from "../utils/api";
|
|
||||||
import type { CircuitTreeCircuitDto, CircuitTreeResponseDto } from "../types";
|
|
||||||
import {
|
|
||||||
formatCellValue,
|
|
||||||
formatValue,
|
|
||||||
getCircuitSectionLabel,
|
|
||||||
} from "../utils/circuit-grid-model";
|
|
||||||
|
|
||||||
function renderCircuitSummaryLabel(circuit: CircuitTreeCircuitDto) {
|
|
||||||
if (circuit.displayName?.trim()) {
|
|
||||||
return circuit.displayName;
|
|
||||||
}
|
|
||||||
if (circuit.deviceRows.length > 1) {
|
|
||||||
return `${circuit.deviceRows.length} Geräte`;
|
|
||||||
}
|
|
||||||
return "Reserve";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CircuitTreePreview(props: { projectId: string; circuitListId: string }) {
|
|
||||||
const { projectId, circuitListId } = props;
|
|
||||||
const [data, setData] = useState<CircuitTreeResponseDto | null>(null);
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsLoading(true);
|
|
||||||
setError(null);
|
|
||||||
getCircuitTree(projectId, circuitListId)
|
|
||||||
.then(setData)
|
|
||||||
.catch((err: unknown) =>
|
|
||||||
setError(err instanceof Error ? err.message : "Die Stromkreisstruktur konnte nicht geladen werden.")
|
|
||||||
)
|
|
||||||
.finally(() => setIsLoading(false));
|
|
||||||
}, [projectId, circuitListId]);
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return <div className="alert alert-info">Stromkreisstruktur wird geladen …</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return <div className="alert alert-danger">{error}</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data || !data.sections.length) {
|
|
||||||
return <div className="alert alert-secondary">Keine Bereiche oder Stromkreise vorhanden.</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasAnyCircuits = data.sections.some((section) => section.circuits.length > 0);
|
|
||||||
if (!hasAnyCircuits) {
|
|
||||||
return <div className="alert alert-secondary">Bereiche sind vorhanden, enthalten aber noch keine Stromkreise.</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="card shadow-sm">
|
|
||||||
<div className="card-body">
|
|
||||||
<div className="table-responsive">
|
|
||||||
<table className="table table-sm align-middle circuit-tree-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Betriebsmittelkennzeichen</th>
|
|
||||||
<th>Anzeigename</th>
|
|
||||||
<th>Phasenart</th>
|
|
||||||
<th>Anschlussart</th>
|
|
||||||
<th>Kostengruppe</th>
|
|
||||||
<th>Kategorie</th>
|
|
||||||
<th>Ebene</th>
|
|
||||||
<th>Raumnummer</th>
|
|
||||||
<th>Raumname</th>
|
|
||||||
<th className="text-end">Anzahl</th>
|
|
||||||
<th className="text-end">Leistung / Gerät [kW]</th>
|
|
||||||
<th className="text-end">Gleichzeitigkeit</th>
|
|
||||||
<th className="text-end">cos φ</th>
|
|
||||||
<th className="text-end">Gesamtsumme [kW]</th>
|
|
||||||
<th>Schutzart</th>
|
|
||||||
<th className="text-end">Bemessungsstrom</th>
|
|
||||||
<th>Charakteristik</th>
|
|
||||||
<th>Kabeltyp</th>
|
|
||||||
<th>Kabelquerschnitt</th>
|
|
||||||
<th className="text-end">Kabellänge</th>
|
|
||||||
<th>Bemerkung</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{data.sections.map((section) => (
|
|
||||||
<SectionRows key={section.id} section={section} />
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SectionRows(props: { section: CircuitTreeResponseDto["sections"][number] }) {
|
|
||||||
const { section } = props;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<tr className="section-row">
|
|
||||||
<td colSpan={21}>
|
|
||||||
<strong>{getCircuitSectionLabel(section)}</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{section.circuits.map((circuit) => {
|
|
||||||
if (circuit.deviceRows.length === 0) {
|
|
||||||
return (
|
|
||||||
<tr key={circuit.id} className="reserve-row">
|
|
||||||
<td>{circuit.equipmentIdentifier}</td>
|
|
||||||
<td>{circuit.displayName?.trim() || "Reserve"}</td>
|
|
||||||
<td colSpan={11}>-</td>
|
|
||||||
<td className="text-end">
|
|
||||||
{formatCellValue(circuit.circuitTotalPower, "circuitTotalPower")}
|
|
||||||
</td>
|
|
||||||
<td>{circuit.protectionDevice?.type ?? "-"}</td>
|
|
||||||
<td className="text-end">
|
|
||||||
{formatValue(circuit.protectionDevice?.ratedCurrentA, "protectionRatedCurrent")}
|
|
||||||
</td>
|
|
||||||
<td>{circuit.protectionDevice?.tripCharacteristic ?? circuit.protectionDevice?.fuseUtilizationCategory ?? "-"}</td>
|
|
||||||
<td>{circuit.cableType ?? "-"}</td>
|
|
||||||
<td>{circuit.cableCrossSection ?? "-"}</td>
|
|
||||||
<td className="text-end">{formatValue(circuit.cableLength, "cableLength")}</td>
|
|
||||||
<td>{circuit.remark ?? "-"}</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (circuit.deviceRows.length === 1) {
|
|
||||||
const row = circuit.deviceRows[0];
|
|
||||||
return (
|
|
||||||
<tr key={circuit.id} className={circuit.isReserve ? "reserve-row" : ""}>
|
|
||||||
<td>{circuit.equipmentIdentifier}</td>
|
|
||||||
<td>{row.displayName || row.name}</td>
|
|
||||||
<td>{formatValue(row.phaseType ?? undefined, "phaseType")}</td>
|
|
||||||
<td>{row.connectionKind ?? "-"}</td>
|
|
||||||
<td>{row.costGroup ?? "-"}</td>
|
|
||||||
<td>{row.category ?? "-"}</td>
|
|
||||||
<td>{row.level ?? "-"}</td>
|
|
||||||
<td>{row.roomNumberSnapshot ?? "-"}</td>
|
|
||||||
<td>{row.roomNameSnapshot ?? "-"}</td>
|
|
||||||
<td className="text-end">{formatCellValue(row.quantity, "quantity")}</td>
|
|
||||||
<td className="text-end">{formatCellValue(row.powerPerUnit, "powerPerUnit")}</td>
|
|
||||||
<td className="text-end">
|
|
||||||
{formatValue(row.simultaneityFactor, "simultaneityFactor")}
|
|
||||||
</td>
|
|
||||||
<td className="text-end">{formatValue(row.cosPhi, "cosPhi")}</td>
|
|
||||||
<td className="text-end">{formatCellValue(row.rowTotalPower, "rowTotalPower")}</td>
|
|
||||||
<td>{circuit.protectionDevice?.type ?? "-"}</td>
|
|
||||||
<td className="text-end">
|
|
||||||
{formatValue(circuit.protectionDevice?.ratedCurrentA, "protectionRatedCurrent")}
|
|
||||||
</td>
|
|
||||||
<td>{circuit.protectionDevice?.tripCharacteristic ?? circuit.protectionDevice?.fuseUtilizationCategory ?? "-"}</td>
|
|
||||||
<td>{circuit.cableType ?? "-"}</td>
|
|
||||||
<td>{circuit.cableCrossSection ?? "-"}</td>
|
|
||||||
<td className="text-end">{formatValue(circuit.cableLength, "cableLength")}</td>
|
|
||||||
<td>{row.remark ?? circuit.remark ?? "-"}</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment key={circuit.id}>
|
|
||||||
<tr key={`${circuit.id}-summary`} className="summary-row">
|
|
||||||
<td>{circuit.equipmentIdentifier}</td>
|
|
||||||
<td>{renderCircuitSummaryLabel(circuit)}</td>
|
|
||||||
<td colSpan={11}>-</td>
|
|
||||||
<td className="text-end">
|
|
||||||
{formatCellValue(circuit.circuitTotalPower, "circuitTotalPower")}
|
|
||||||
</td>
|
|
||||||
<td>{circuit.protectionDevice?.type ?? "-"}</td>
|
|
||||||
<td className="text-end">
|
|
||||||
{formatValue(circuit.protectionDevice?.ratedCurrentA, "protectionRatedCurrent")}
|
|
||||||
</td>
|
|
||||||
<td>{circuit.protectionDevice?.tripCharacteristic ?? circuit.protectionDevice?.fuseUtilizationCategory ?? "-"}</td>
|
|
||||||
<td>{circuit.cableType ?? "-"}</td>
|
|
||||||
<td>{circuit.cableCrossSection ?? "-"}</td>
|
|
||||||
<td className="text-end">{formatValue(circuit.cableLength, "cableLength")}</td>
|
|
||||||
<td>{circuit.remark ?? "-"}</td>
|
|
||||||
</tr>
|
|
||||||
{circuit.deviceRows.map((row) => (
|
|
||||||
<tr key={row.id} className="device-row">
|
|
||||||
<td className="text-muted"> </td>
|
|
||||||
<td className="indented-cell">{row.displayName || row.name}</td>
|
|
||||||
<td>{formatValue(row.phaseType ?? undefined, "phaseType")}</td>
|
|
||||||
<td>{row.connectionKind ?? "-"}</td>
|
|
||||||
<td>{row.costGroup ?? "-"}</td>
|
|
||||||
<td>{row.category ?? "-"}</td>
|
|
||||||
<td>{row.level ?? "-"}</td>
|
|
||||||
<td>{row.roomNumberSnapshot ?? "-"}</td>
|
|
||||||
<td>{row.roomNameSnapshot ?? "-"}</td>
|
|
||||||
<td className="text-end">{formatCellValue(row.quantity, "quantity")}</td>
|
|
||||||
<td className="text-end">{formatCellValue(row.powerPerUnit, "powerPerUnit")}</td>
|
|
||||||
<td className="text-end">
|
|
||||||
{formatValue(row.simultaneityFactor, "simultaneityFactor")}
|
|
||||||
</td>
|
|
||||||
<td className="text-end">{formatValue(row.cosPhi, "cosPhi")}</td>
|
|
||||||
<td className="text-end">{formatCellValue(row.rowTotalPower, "rowTotalPower")}</td>
|
|
||||||
<td>-</td>
|
|
||||||
<td className="text-end">-</td>
|
|
||||||
<td>-</td>
|
|
||||||
<td>-</td>
|
|
||||||
<td>-</td>
|
|
||||||
<td className="text-end">-</td>
|
|
||||||
<td>{row.remark ?? "-"}</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<tr className="placeholder-row">
|
|
||||||
<td>-frei-</td>
|
|
||||||
<td colSpan={20}>Freie Zeile</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user