Compare commits

..

3 commits

Author SHA1 Message Date
Grovy311
7b2419b347 Polish the printed rough power balance
The printed page kept the dark app background in the page margins, the
consumer column wrapped while the empty remark column took the space, an
empty "bearbeitet von" label was printed, and numbers were printed as
typed (11200). Print margins are white now, the consumer column is wider,
empty editors are omitted and numbers print with thousands separators
(11.200) like the template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 18:04:54 +02:00
Grovy311
72189d23a5 Offer supply suggestions, drop the circuit column, center cells
The Versorgung field suggests ELT and MSR (plus values already used in
the balance) through a datalist and still accepts free text. The circuit
number column is not needed in early design phases; it is removed from
the data model, the regenerated migration 0010, the editor and the
print. All cells are centered except "Verbraucher / Flächen", group
titles and total labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:56:53 +02:00
Grovy311
e06c7d91e2 Print the rough power balance in the kbp design
The print of the rough power balance was plain grey. It now follows the
kbp design of the print view: a title block with office logo, stand,
project, number, owner, address, work stage, date, editor and office;
header row in kbp blue, cost-group rows tinted with a lilac rule, bold
subtotals, the total including reserve as a blue band, colored
deviations in the comparison, Arial, exact print colors, and a footer
with project, stand and "Seite x von y" on every page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:48:37 +02:00
15 changed files with 394 additions and 69 deletions

View file

@ -34,7 +34,7 @@ das Frontend sie direkt nutzt (Turbopack löst die `.js`-Suffixe der API nicht a
|---|---|
| `estimate_balances` | ein **Stand** je Projekt (z. B. Vorplanung, Entwurfsplanung): Name, LPH, Datum, Reserve AV/SV in %, Sortierung |
| `estimate_groups` | Kostengruppe (`"410"` … `"480"`, `""` für „Allgemein“), Titel, „bearbeitet von“, Sortierung |
| `estimate_rows` | Versorgung, Stromkreis-Nr. (Freitext), Verbraucher/Fläche, Anzahl bzw. Fläche, Einheit (`piece` = St., `area` = m²), Anschluss (fest/Steckdose), Einzelleistung in W bzw. W/m², GLF, cos φ, SV ja/nein, Anmerkung |
| `estimate_rows` | Versorgung (Auswahl ELT/MSR oder Freitext), Verbraucher/Fläche, Anzahl bzw. Fläche, Einheit (`piece` = St., `area` = m²), Anschluss (fest/Steckdose), Einzelleistung in W bzw. W/m², GLF, cos φ, SV ja/nein, Anmerkung |
Neue Stände entstehen aus der Vorlage KG 400 (410 Sanitär, 420 Wärme, 430 Luft,
434 Kälte, 440 Starkstrom, 450 Schwachstrom, 460 Förder, 470 Nutzungsspezifisch,

View file

@ -1731,7 +1731,6 @@ button.structure-entry-main:focus-visible {
.estimate-col-kg { width: 3rem; }
.estimate-col-supply { width: 4rem; }
.estimate-col-circuit { width: 4.6rem; }
.estimate-col-name { width: auto; }
.estimate-col-quantity { width: 4.8rem; }
.estimate-col-unit { width: 3.8rem; }
@ -1965,14 +1964,53 @@ button.structure-entry-main:focus-visible {
display: none;
}
/* Ausrichtung: alle Zellen zentriert, nur „Verbraucher / Flächen“, die
Gruppentitel und die Summenbeschriftungen stehen links bzw. rechts. */
.estimate-sheet td,
.estimate-sheet td.estimate-number,
.estimate-sheet .estimate-cell-input,
.estimate-sheet .estimate-cell-input.is-numeric {
text-align: center;
}
.estimate-sheet .estimate-cell-select {
text-align: center;
text-align-last: center;
}
.estimate-sheet .estimate-unit-input,
.estimate-sheet .estimate-gzf-input {
justify-content: center;
}
.estimate-sheet td.estimate-name-cell,
.estimate-sheet td.estimate-name-cell .estimate-cell-input,
.estimate-sheet .estimate-group-title-row td:not(.estimate-cost-group-cell),
.estimate-comparison td:nth-child(2) {
text-align: left;
}
.estimate-sheet td.estimate-total-label {
text-align: right;
}
/* Druck im kbp-CD der Seitenansicht (src/frontend/print/print-document.css):
gleiche Farben, Schrift, Titelblock und Fußzeile. Die Fußzeile mit
Seitenzahlen setzt EstimatePrintHeader als @page-Regel mit Projektdaten. */
.estimate-print-titleblock {
display: none;
}
@page estimate-balance {
size: A4 landscape;
margin: 10mm;
margin: 10mm 10mm 13mm;
}
@media print {
body:has(.estimate-print-root) .sidebar,
.estimate-print-root .estimate-no-print,
.estimate-print-root .estimate-page-header,
.estimate-print-root .estimate-header-fields,
.estimate-print-root .alert,
.estimate-print-root input,
.estimate-print-root select,
@ -1980,37 +2018,157 @@ button.structure-entry-main:focus-visible {
display: none !important;
}
body:has(.estimate-print-root) {
html:has(.estimate-print-root),
body:has(.estimate-print-root),
body:has(.estimate-print-root) .app-shell,
body:has(.estimate-print-root) .app-shell-content {
background: #fff !important;
}
/* Der Dunkelmodus setzt color-scheme: dark; Chrome färbt damit auch den
Seitenrand dunkel. Im Druck gilt immer das helle Schema. */
html:has(.estimate-print-root) {
color-scheme: light !important;
}
.estimate-print-root .estimate-group-editor.is-empty {
display: none;
}
/* Verbraucher bekommt den Platz; Anmerkungen bleiben schmal. */
.estimate-sheet .estimate-col-name {
width: 52mm;
}
.estimate-sheet .estimate-col-remark {
width: 24mm;
}
.estimate-sheet .estimate-col-supply {
width: 13mm;
}
body:has(.estimate-print-root) .app-shell {
display: block;
}
.estimate-print-root {
--ep-blue: #476088;
--ep-lilac: #9198c4;
--ep-line: #d6dae5;
--ep-tint: #f5f6fa;
--ep-text: #2b2b2b;
--ep-muted: #6b7280;
--ep-accent: #c9782a;
page: estimate-balance;
padding: 0 !important;
max-width: none;
color: #000;
color: var(--ep-text);
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
color-scheme: light;
}
.estimate-print-root * {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.estimate-print-root .estimate-print-value {
display: inline;
}
.estimate-print-root .page-header {
/* Titelblock wie der Plankopf der Seitenansicht */
.estimate-print-titleblock {
display: grid;
grid-template-columns: 30mm 1fr auto auto;
margin-bottom: 4mm;
border: 1.5px solid var(--ep-blue);
background: #fff;
font-size: 8.5pt;
break-inside: avoid;
}
.estimate-print-root .page-header h1 {
font-size: 14pt;
color: #000;
.estimate-print-titleblock > * {
padding: 2.5mm 3.5mm;
border-left: 1px solid var(--ep-line);
}
.estimate-print-titleblock > :first-child {
border-left: none;
}
.estimate-print-logo {
display: flex;
align-items: center;
justify-content: center;
min-height: 16mm;
color: var(--ep-blue);
font-weight: bold;
text-align: center;
}
.estimate-print-logo img {
max-width: 100%;
max-height: 10mm;
}
.estimate-print-kicker {
color: var(--ep-muted);
font-size: 7pt;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.estimate-print-heading {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 1mm 4mm;
margin-top: 1mm;
}
.estimate-print-stand {
color: var(--ep-blue);
font-size: 16pt;
font-weight: bold;
}
.estimate-print-project {
font-size: 12pt;
font-weight: bold;
}
.estimate-print-meta {
display: grid;
grid-template-columns: auto auto;
gap: 0.8mm 4mm;
align-content: center;
margin: 0;
font-size: 7.5pt;
}
.estimate-print-meta div {
display: contents;
}
.estimate-print-meta dt {
color: var(--ep-muted);
font-weight: normal;
}
.estimate-print-meta dd {
margin: 0;
font-weight: bold;
}
.estimate-print-meta.is-tinted {
background: var(--ep-tint);
}
/* Karten und Ränder der Bildschirmansicht entfallen */
.estimate-print-root .card {
border: 0;
box-shadow: none;
box-shadow: none !important;
background: transparent;
}
@ -2026,54 +2184,117 @@ button.structure-entry-main:focus-visible {
break-inside: avoid;
}
.estimate-print-root .estimate-comparison-card .card-header {
margin-bottom: 2mm;
color: var(--ep-blue);
font-size: 10pt;
font-weight: bold;
}
.estimate-sheet-wrap {
overflow: visible;
}
/* Tabelle */
.estimate-sheet {
min-width: 0;
table-layout: auto;
font-size: 7.5pt;
font-size: 7.4pt;
line-height: 1.2;
background: #fff;
color: #000;
color: var(--ep-text);
}
.estimate-sheet th,
.estimate-sheet td {
border-color: #999;
padding: 1px 3px;
border: 1px solid var(--ep-line) !important;
padding: 0.7mm 1.5mm;
background: #fff;
color: var(--ep-text);
}
.estimate-sheet thead {
display: table-header-group;
}
.estimate-sheet thead th,
.estimate-total-row td {
background: #e8e8e8 !important;
.estimate-sheet thead th {
background: var(--ep-blue) !important;
border-color: var(--ep-blue) !important;
color: #fff !important;
font-weight: bold;
vertical-align: bottom;
}
.estimate-sheet thead .estimate-th-hint {
color: #dfe3f0 !important;
}
.estimate-group-title-row td {
background: #d9d9d9 !important;
background: var(--ep-tint) !important;
border-top: 1.5px solid var(--ep-lilac) !important;
font-weight: bold;
}
.estimate-group-title-row .estimate-cost-group-cell {
color: var(--ep-blue) !important;
}
.estimate-group-title-row .estimate-group-editor {
color: var(--ep-muted);
font-weight: normal;
}
.estimate-subtotal-row td {
background: #f2f2f2 !important;
border-bottom: 1.5px solid var(--ep-line) !important;
font-weight: bold;
}
.estimate-subtotal-row .estimate-total-label {
color: var(--ep-muted);
}
.estimate-total-row td {
background: var(--ep-tint) !important;
font-weight: bold;
}
.estimate-total-row.is-strong td {
background: var(--ep-blue) !important;
border-color: var(--ep-blue) !important;
color: #fff !important;
}
.estimate-total-row .estimate-total-hint {
color: var(--ep-muted);
font-weight: normal;
}
.estimate-total-row.is-strong .estimate-total-hint {
color: #dfe3f0;
}
.estimate-comparison .is-over {
color: var(--ep-accent) !important;
font-weight: bold;
}
.estimate-comparison .is-under {
color: var(--ep-blue) !important;
font-weight: bold;
}
.estimate-group-title-row,
.estimate-subtotal-row,
.estimate-total-row {
.estimate-total-row,
.estimate-row {
break-inside: avoid;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.estimate-group-title-row {
break-after: avoid;
}
/* Totals print once at the end, not repeated on every page. */
/* Summen einmal am Ende, nicht auf jeder Seite */
.estimate-sheet tfoot {
display: table-row-group;
break-inside: avoid;
@ -2085,10 +2306,6 @@ button.structure-entry-main:focus-visible {
.estimate-unit-input,
.estimate-gzf-input {
justify-content: flex-end;
}
.estimate-header-fields {
margin-bottom: 3mm;
justify-content: center;
}
}

View file

@ -48,6 +48,7 @@ import {
} from "../../../../../frontend/estimate-balance/estimate-balance-sheet";
import { EstimateComparisonTable } from "../../../../../frontend/estimate-balance/estimate-comparison-table";
import { DraftInput } from "../../../../../frontend/estimate-balance/estimate-draft-input";
import { EstimatePrintHeader } from "../../../../../frontend/estimate-balance/estimate-print-header";
import {
EstimateGroupModal,
type EstimateGroupFormValues,
@ -461,6 +462,7 @@ export default function EstimateBalanceEditorPage() {
return (
<main className="container-fluid py-4 estimate-print-root">
{project && draft ? <EstimatePrintHeader balance={draft} project={project} /> : null}
<div className="page-header estimate-page-header">
<div className="d-flex align-items-start gap-3">
<Link

View file

@ -27,7 +27,6 @@ CREATE TABLE `estimate_rows` (
`group_id` text NOT NULL,
`sort_order` integer DEFAULT 0 NOT NULL,
`supply` text,
`circuit_ref` text,
`name` text DEFAULT '' NOT NULL,
`quantity` real DEFAULT 0 NOT NULL,
`unit` text DEFAULT 'piece' NOT NULL,

View file

@ -1,7 +1,7 @@
{
"version": "6",
"dialect": "sqlite",
"id": "6df688bd-a78a-46a1-ba7a-4068119bf8bd",
"id": "5376ae9f-67c7-4603-b3d2-8527136436f9",
"prevId": "2cd9adef-2f08-4635-b3d9-ecf71f624c7f",
"tables": {
"buildings": {
@ -1322,13 +1322,6 @@
"notNull": false,
"autoincrement": false
},
"circuit_ref": {
"name": "circuit_ref",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",

View file

@ -75,7 +75,7 @@
{
"idx": 10,
"version": "6",
"when": 1790425784626,
"when": 1790438092269,
"tag": "0010_estimate_balances",
"breakpoints": true
}

View file

@ -44,7 +44,6 @@ export const estimateRows = sqliteTable(
.references(() => estimateGroups.id, { onDelete: "cascade" }),
sortOrder: integer("sort_order").notNull().default(0),
supply: text("supply"),
circuitRef: text("circuit_ref"),
name: text("name").notNull().default(""),
quantity: real("quantity").notNull().default(0),
unit: text("unit", { enum: ["piece", "area"] }).notNull().default("piece"),

View file

@ -28,7 +28,6 @@ export const estimateRowSnapshotSchema = z
id: idSchema,
sortOrder: z.number().int().min(0),
supply: nullableText(50),
circuitRef: nullableText(50),
name: trimmed(200),
quantity: finite.min(0),
unit: z.enum(["piece", "area"]),
@ -158,7 +157,6 @@ export function canonicalEstimateBalance(balance: EstimateBalanceSnapshot): stri
id: row.id,
sortOrder: row.sortOrder,
supply: row.supply,
circuitRef: row.circuitRef,
name: row.name,
quantity: row.quantity,
unit: row.unit,

View file

@ -18,7 +18,6 @@ export const estimateTextLimits = {
groupTitle: 200,
groupEditor: 100,
supply: 50,
circuitRef: 50,
rowName: 200,
remark: 500,
} as const;
@ -34,7 +33,6 @@ export function createEstimateRow(
id: createId(),
sortOrder,
supply: null,
circuitRef: null,
name: "",
quantity: 1,
unit: "piece",
@ -257,7 +255,6 @@ export function toSaveableEstimateBalance(
id: row.id,
sortOrder: row.sortOrder,
supply: optionalText(row.supply),
circuitRef: optionalText(row.circuitRef),
name: requiredText(row.name),
quantity: row.quantity,
unit: row.unit,

View file

@ -31,6 +31,7 @@ import {
formatKw,
parseGermanDecimal,
type DecimalRange,
formatGermanNumber,
} from "./estimate-balance-format";
import { DraftInput } from "./estimate-draft-input";
@ -50,8 +51,12 @@ interface EstimateBalanceSheetProps {
}
// Leading columns up to cos φ; the power columns follow.
const LEADING_COLUMN_COUNT = 10;
const COLUMN_COUNT = 17;
const LEADING_COLUMN_COUNT = 9;
const COLUMN_COUNT = 16;
/** Suggested supply values; free text stays possible. */
const SUPPLY_SUGGESTIONS = ["ELT", "MSR"];
const SUPPLY_LIST_ID = "estimate-supply-options";
function NumberInput({
ariaLabel,
@ -77,6 +82,7 @@ function NumberInput({
disabled={disabled}
format={(current: number) => formatDecimalInput(current)}
inputMode="decimal"
printFormat={(current: number) => formatGermanNumber(current, 0, 3)}
onCommit={onCommit}
onValidityChange={(isValid) => onValidityChange(fieldKey, isValid)}
parse={(text) => parseGermanDecimal(text, range)}
@ -85,9 +91,17 @@ function NumberInput({
);
}
function supplyOptions(balance: EstimateBalanceSnapshot): string[] {
const used = balance.groups.flatMap((group) =>
group.rows.map((row) => row.supply?.trim() ?? "")
);
return [...new Set([...SUPPLY_SUGGESTIONS, ...used.filter(Boolean)])];
}
function TextInput({
ariaLabel,
disabled,
list,
maxLength,
onChange,
placeholder,
@ -95,6 +109,7 @@ function TextInput({
}: {
ariaLabel: string;
disabled: boolean;
list?: string;
maxLength: number;
onChange: (value: string) => void;
placeholder?: string;
@ -106,6 +121,7 @@ function TextInput({
aria-label={ariaLabel}
className="estimate-cell-input"
disabled={disabled}
list={list}
maxLength={maxLength}
onChange={(event) => onChange(event.target.value)}
placeholder={placeholder}
@ -189,22 +205,14 @@ function EstimateRowLine({
<TextInput
ariaLabel={`Versorgung (${rowLabel})`}
disabled={disabled}
list={SUPPLY_LIST_ID}
maxLength={estimateTextLimits.supply}
onChange={(supply) => patch({ supply })}
placeholder="ELT"
value={row.supply}
/>
</td>
<td>
<TextInput
ariaLabel={`Stromkreis-Nr. (${rowLabel})`}
disabled={disabled}
maxLength={estimateTextLimits.circuitRef}
onChange={(circuitRef) => patch({ circuitRef })}
value={row.circuitRef}
/>
</td>
<td>
<td className="estimate-name-cell">
<TextInput
ariaLabel={`Verbraucher / Fläche (${rowLabel})`}
disabled={disabled}
@ -384,11 +392,15 @@ export function EstimateBalanceSheet({
return (
<div className="estimate-sheet-wrap">
<datalist id={SUPPLY_LIST_ID}>
{supplyOptions(balance).map((supply) => (
<option key={supply} value={supply} />
))}
</datalist>
<table className="estimate-sheet">
<colgroup>
<col className="estimate-col-kg" />
<col className="estimate-col-supply" />
<col className="estimate-col-circuit" />
<col className="estimate-col-name" />
<col className="estimate-col-quantity" />
<col className="estimate-col-unit" />
@ -409,9 +421,8 @@ export function EstimateBalanceSheet({
<th rowSpan={2}>KG</th>
<th rowSpan={2}>
Versorgung
<span className="estimate-th-hint">ELT/ISP …</span>
<span className="estimate-th-hint">ELT/MSR …</span>
</th>
<th rowSpan={2}>Stromkreis-Nr.</th>
<th rowSpan={2}>Verbraucher / Flächen</th>
<th colSpan={2}>
Anzahl / Fläche
@ -452,7 +463,13 @@ export function EstimateBalanceSheet({
<td colSpan={COLUMN_COUNT - 2}>
<div className="estimate-group-title">
<span className="estimate-group-name">{group.title}</span>
<label className="estimate-group-editor">
<label
className={
group.editor?.trim()
? "estimate-group-editor"
: "estimate-group-editor is-empty"
}
>
<span>bearbeitet von</span>
<input
aria-label={`Bearbeitet von (${label})`}

View file

@ -9,6 +9,8 @@ interface DraftInputProps<T> {
className?: string;
disabled?: boolean;
format: (value: T) => string;
/** Printed text; defaults to the input text. */
printFormat?: (value: T) => string;
inputMode?: "decimal" | "text";
maxLength?: number;
onCommit: (value: T) => void;
@ -30,6 +32,7 @@ export function DraftInput<T>({
className = "estimate-cell-input",
disabled,
format,
printFormat,
inputMode = "text",
maxLength,
onCommit,
@ -101,7 +104,9 @@ export function DraftInput<T>({
type="text"
value={text}
/>
<span className="estimate-print-value">{error ? format(value) : text}</span>
<span className="estimate-print-value">
{printFormat ? printFormat(value) : error ? format(value) : text}
</span>
</>
);
}

View file

@ -0,0 +1,104 @@
"use client";
import { useEffect, useState } from "react";
import { documentLogoUrl, getDocumentBranding } from "../utils/api";
import type { EstimateBalanceDto, OfficeProfileDto, ProjectDto } from "../types";
import { formatIsoDateGerman } from "./estimate-balance-format";
interface EstimatePrintHeaderProps {
project: ProjectDto;
balance: EstimateBalanceDto;
}
function cssString(value: string) {
return JSON.stringify(value.replace(/[<>\r\n]/g, " "));
}
/**
* Print-only title block and page footer of the rough power balance in the
* kbp corporate design of the print view (Seitenansicht): logo, blue title,
* meta data, "Seite x von y". Hidden on screen.
*/
export function EstimatePrintHeader({ project, balance }: EstimatePrintHeaderProps) {
const [office, setOffice] = useState<OfficeProfileDto | null>(null);
const [hasLogo, setHasLogo] = useState(false);
const [logoVersion, setLogoVersion] = useState("");
useEffect(() => {
getDocumentBranding()
.then((branding) => {
setOffice(branding.office);
setHasLogo(Boolean(branding.logo));
setLogoVersion(branding.logo ? branding.logo.updatedAtIso : "");
})
.catch(() => {
setOffice(null);
setHasLogo(false);
});
}, []);
const stand = [balance.name, balance.workStage].filter(Boolean).join(" · ");
const date = balance.dateIso ? formatIsoDateGerman(balance.dateIso) : null;
const footer = `
@page estimate-balance {
size: A4 landscape;
margin: 10mm 10mm 13mm;
@bottom-left { content: ${cssString(`${project.name} · Grobe Leistungsbilanz`)}; font: 7.5pt Arial, sans-serif; color: #6b7280; }
@bottom-center { content: ${cssString(`Stand ${stand}${date ? ` · ${date}` : ""}`)}; font: 7.5pt Arial, sans-serif; color: #6b7280; }
@bottom-right { content: "Seite " counter(page) " von " counter(pages); font: 7.5pt Arial, sans-serif; color: #6b7280; }
}`;
return (
<>
<style>{footer}</style>
<header className="estimate-print-titleblock" aria-hidden="true">
<div className="estimate-print-logo">
{hasLogo ? (
<img alt="" src={`${documentLogoUrl}?v=${encodeURIComponent(logoVersion)}`} />
) : (
<span>{office?.officeName ?? ""}</span>
)}
</div>
<div className="estimate-print-title">
<div className="estimate-print-kicker">Grobe Leistungsbilanz · KG 400</div>
<div className="estimate-print-heading">
<span className="estimate-print-stand">{balance.name}</span>
<span className="estimate-print-project">{project.name}</span>
</div>
</div>
<dl className="estimate-print-meta">
<div>
<dt>Projekt-Nr.</dt>
<dd>{project.internalProjectNumber ?? "–"}</dd>
</div>
<div>
<dt>Bauherr</dt>
<dd>{project.buildingOwner ?? "–"}</dd>
</div>
<div>
<dt>Anschrift</dt>
<dd>{project.siteAddress?.split("\n").join(", ") ?? "–"}</dd>
</div>
</dl>
<dl className="estimate-print-meta is-tinted">
<div>
<dt>Leistungsphase</dt>
<dd>{balance.workStage ?? "–"}</dd>
</div>
<div>
<dt>Datum</dt>
<dd>{date ?? "–"}</dd>
</div>
<div>
<dt>Bearbeitung</dt>
<dd>{project.projectEditor ?? "–"}</dd>
</div>
<div>
<dt>Büro</dt>
<dd>{office?.officeName ?? "–"}</dd>
</div>
</dl>
</header>
</>
);
}

View file

@ -12,10 +12,8 @@ export type EstimateRowConnection = "fixed" | "socket";
export interface EstimateRowSnapshot {
id: string;
sortOrder: number;
/** Versorgung, e.g. "ELT" or "ISP". */
/** Versorgung, e.g. "ELT" or "MSR" (free text). */
supply: string | null;
/** Optional circuit reference, free text. */
circuitRef: string | null;
/** Verbraucher / Fläche. May be empty while a row is being typed. */
name: string;
/** Anzahl (unit "piece") or area in m² (unit "area"). */

View file

@ -165,7 +165,6 @@ describe("estimate balance document editing", () => {
id: "row-x",
sortOrder: 3,
supply: null,
circuitRef: null,
name: "",
quantity: 1,
unit: "piece",
@ -273,7 +272,6 @@ describe("estimate balance saving", () => {
balance = updateEstimateRow(balance, "group-410", "row-a", {
name: " Hebeanlage ",
supply: " ELT ",
circuitRef: "",
remark: " ",
});
const saveable = toSaveableEstimateBalance(balance);
@ -286,10 +284,9 @@ describe("estimate balance saving", () => {
{
name: saveable.groups[0]!.rows[0]!.name,
supply: saveable.groups[0]!.rows[0]!.supply,
circuitRef: saveable.groups[0]!.rows[0]!.circuitRef,
remark: saveable.groups[0]!.rows[0]!.remark,
},
{ name: "Hebeanlage", supply: "ELT", circuitRef: null, remark: null }
{ name: "Hebeanlage", supply: "ELT", remark: null }
);
});

View file

@ -52,7 +52,6 @@ function row(
id: id(),
sortOrder: 0,
supply: "ELT",
circuitRef: null,
name,
quantity,
unit: "piece",