Rapport: voet met legenda op elke pagina (#113, nabespreking) - #135
Merged
Merged
Conversation
De Gantt-afdruk tekent één voetstrook (projectnaam, afdrukdatum, legenda, merk) onder de laatste rij; de pagineerder herhaalde alleen de kop, dus bij een meerpagina-afdruk stond de legenda uitsluitend op de laatste pagina. Met "een blad per persoon" (#132) is dat geen randgeval meer: een uitgedeeld vel zonder legenda is onleesbaar (hyperkritische review op #132, bevinding 5). De voet is nu, net als de kop, een herhaalbaar blok: - `RenderReportResult.footerHeight` (de render meldt zijn voethoogte, schaalt mee met de rapport-lettergrootte; tabelrenders en de lege staat hebben er geen); - `tileLayout.computeTileLayout` kent `repeatFooterHeightPx`: de body loopt van onder de kop tot boven de voet (`repeatFooterSrcY`), elke pagina houdt onderaan het printgebied `footerTopPt` vrij; zonder de optie byte-identiek, met dezelfde degeneratievangnetten als de kop; - raster-pagineerder, vector-pagineerder én preview tekenen de strook per pagina uit hetzelfde bronvenster (in de vector-tak komt de voettekst daardoor per pagina mee, zoals de koptekst); - instelling `repeatFooter` (standaard aan, zoals de kop) in ops-reportSettings, checkbox naast "Kop op elke pagina herhalen", 14 locales, gids nl+en. Het vaste "Pagina 1 van 1" in de voet is weg: de render kent het paginatotaal niet en het zou nu op elke pagina zo staan; het echte "n / totaal" drukken de pagineerders al in de ondermarge. Regressie: check-print-report.ts (voethoogte, tegeling met/zonder voet byte-identiek, laatste body-tegel eindigt boven de voet, rijgrenzen blijven, degeneratie, zonder kop en in 'actual', samen met blad-per-resource, geen nep-paginanummer), nieuw check-report-footer-setting.ts, browserspec report-footer.spec.ts (telt per PDF-pagina de XObject-tekeningen: 3 mét voet, 2 zonder; preview rastert opnieuw). report-preview-performance.spec.ts: fixture 260 → 240 rijen, want het paginatotaal stond precies op de previewcachegrens en de voet kost per pagina één strook body. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014zosxbSXvi3YSGmeN1MsQq
Nozzit
pushed a commit
that referenced
this pull request
Sep 14, 2026
…ollator, één relatiepredicaat (review ronde 2) Tweede hyperkritische review op #132 ("ja, mits"), verwerkt: N1 De bandvolgorde hing aan de host-locale (`localeCompare(b, undefined, …)`): dezelfde planning gaf op een Zweedse machine een andere bladnummering dan op een Nederlandse. `computeResourceGanttRows` krijgt nu `opts.locale` (de app-taal, `i18n.language`); één `Intl.Collator` voor sortering én gelijknaamdetectie. Test: en ⇒ Älg vóór Zorg, sv ⇒ erna. N5 `Jan`/`jan`/` Jan ` kregen geen volgnummer maar sorteerden wél als gelijk. Duplicaten worden nu met dezelfde collator (sensitivity base) gegroepeerd ⇒ `Jan #1`, `jan #2`, `Jan #3`. N4 Het surrogaat `#n` voor een naamloze resource deelt de naamruimte met een resource die letterlijk "#2" heet; surrogaten gaan nu door dezelfde duplicaatpas (`#2 #1`, `#2 #2`). N6 `showDeps`-forcering en verborgen vinkje hangen aan één predicaat, `reportTypeDrawsRelations()` in reportSettings, headless bewaakt (plus: showDeps staat standaard aan, dus de forcering is dragend). N8 `counts.assignments` telt records i.p.v. rijen — dezelfde telling als Resourcetoewijzingen. N9 `startOf` weg; `taskStart` uit reportCommon. N7 `RESOURCE_GANTT_NONE_KEY` niet meer geëxporteerd; `resourceBandLabels` blijft publiek en wordt nu rechtstreeks getest. N2 Gids (14 talen): "verzameltaken worden nooit toegewezen" was onwaar — MSPDI/MPP-importeurs maken zulke toewijzingen wél; nu: "een toewijzing op een verzameltaak (uit een import) wordt hier niet getoond". Module-commentaar idem. N10 ja/ko: dubbele zin over "rijen niet van het scherm" weg. N11 nl/en: de reden voor "geen relaties" eerlijker geformuleerd (kan onder meerdere banden staan; pijlen zouden bij blad per resource van het vel lopen). N3 (het vaste "Pagina 1 van 1" in de voet) zit in #135, samen met de voet op elke pagina. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014zosxbSXvi3YSGmeN1MsQq
Merged
5 tasks
…gina's (review op #135) Hyperkritische review op #135 ("nee, nog niet"), verwerkt: 1. De voet werd per KOLOMvenster gesneden: met de tijdlijn over N pagina's (of een horizontaal getegelde 'actual'-export) stond de legenda in één kolom en kregen de andere pagina's een lege grijze strook — terwijl de gids "elk vel zijn eigen legenda" beloofde. Nu: de render legt de voetinhoud binnen `PrintOptions.footerLayoutWidth` (= `TileLayout.footerLayoutWidthPx`, één paginabreedte; achtergrondstrook blijft canvasbreed), en raster-pagineerder, vector- pagineerder én preview tekenen de voet één keer per pagina uit het vaste `footerWindow` (x vanaf 0, één paginabreedte, op de linkermarge). De vector-tak doet daarvoor bij meer dan één kolom één extra render-pass met die breedte (zoals de CJK-pass); raster en preview kennen de layout al vóór hun render. 4. Eénpagina-afdruk: de voet sprong van onder de laatste rij naar de onderrand van het papier (≈20 cm wit). Past de bron (kop meegerekend) op één pagina en dwingt geen gedwongen breekpositie een tweede af, dan wordt de voet niet herhaald — byte-identiek aan zonder optie. 5. `RenderReportResult.footerHeight` is verplicht (zoals `headerHeight`): 0 in pdfTable (2×) en in de lege render; de `?? 0`-terugvallen zijn weg. 6. `labels.page`/`labels.of` waren dood sinds het nepnummer uit de voet is: uit `PrintOptions`, `ReportPanel`, vier testfixtures en de 14 `report.json`-locales (28 weessleutels). 7. Browsertest bewaakt nu inhoud i.p.v. venstertelling: per PDF-pagina één clip-rechthoek op de onderrand van het printgebied, laag, vanaf x = 24 en één volle printbreedte breed — ook met de tijdlijn over 2 pagina's (kolom 2 krijgt dus niet de kolomsnede); zonder optie op geen enkele pagina; vacuüm-`every` uitgesloten. 3. Gids nl/en: de kosten (±2 rijen minder per vel, soms een pagina meer, een resource die net op één vel paste kan bij "blad per resource" over twee gaan) en het éénpagina-geval. 8. report-preview-performance: fixture 240 → 200 rijen (6 pagina's bij maxPages 7, met marge). 9. tileLayout-moduledoc bijgewerkt (drie assen, "oude gedrag"-defaults, TileBodyRow); `FOOTER_PT` → `PAGE_NUMBER_PT` zodat het niet met `repeatFooter*` verwart. Headless: footerWindow = één paginabreedte vanaf x=0 bij twee kolommen; met `footerLayoutWidth` staat alle voettekst (merk incl.) binnen die breedte en veranderen de canvasmaten niet; éénpagina ⇒ voet niet herhaald, tegeling identiek; blad-per-resource (gedwongen posities) ⇒ wél. Niet gedaan (bevinding 2): de preview rendert per pagina een derde volledige pass voor de voetstrook, zoals dat voor de kop al gold — een offscreen-cache voor kop én voet is een aparte klus. De previewkosten zijn niet gemeten. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014zosxbSXvi3YSGmeN1MsQq
… claude/report-footer-per-page
…een bij herhaling (review #135 ronde 2) B1 `multiPage` keek alleen omlaag: één rij hoog maar horizontaal over N vellen getegeld gold als "past op één pagina" ⇒ voet niet herhaald, en — omdat de voetbreedte tóch meeging — in kolom 1 geperst terwijl hij per kolom gesneden werd: lege grijze strook op kolom 2..N (omslagpunt ±36 taken op A3 liggend). Nu: `cols > 1` telt als meerdere vellen. B2 `footerLayoutWidth` ging in preview en raster-export onvoorwaardelijk mee (vector niet) ⇒ de UIT-stand week af van vóór de optie en de drie paden gaven drie uitkomsten. Eén helper `footerLayoutWidthFor(layout)` in tileLayout (undefined zonder herhaling) voor alle drie. B3 Browsertest bewaakt nu inhoud: per pagina het voetvenster (`q … re … Q`) met ≥ 4 tekstoperatoren (naam, datum, merk, legenda), x = marge, volle printbreedte — plus een tweede scenario: 6 taken × "tijdlijn over 2 pagina's" (één rij hoog, twee vellen breed), waar de voet op beide vellen compleet moet zijn en zonder kolommen juist aan de body blijft. B4 Hoogtefilter in de browsertest ruimer (tot 80 pt) zodat lettergrootte 125 % ook past; een body-tegel op de onderrand is een volle pagina en dus honderden punten hoog. B5 `forcesSecondPage` toetst gedwongen posities tegen `ch - voet` (zelfde bovengrens als `inBody` ná de beslissing), met commentaar over de circulariteit; headless bewaakt. B6 Laatste fixture met `page`/`of` opgeschoond. Headless: één rij × twee kolommen ⇒ voet herhaald en body-tegel eindigt boven de voet; 'actual' met meerdere kolommen idem; `footerLayoutWidthFor` undefined zonder herhaling. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014zosxbSXvi3YSGmeN1MsQq
… testparser met q/Q-stack (review #135 ronde 3) F1 De extra render-pass voor de voetbreedte draaide bij een kale float-`<` in ~5 % van de breedtes voor niets (col0Bodypx en cw analytisch gelijk, als float 1e-13 uit elkaar): nu alleen bij `footerLayoutWidth < dims.width - 0.5`, met commentaar dat zegt wat er getoetst wordt. F2 Na die pass wordt de coverage-poort herhaald: een smallere voet kan alleen legenda-items weglaten, maar dat is nu geen ongeschreven aanname meer. F3 Browsertestparser: tegelvensters met een stack voor geneste q/Q (halfdoorzichtige tekst) i.p.v. "tot de eerste Q"; de voethoogte getoetst tegen de halve papierhoogte i.p.v. een vaste band, zodat een smal rapport (schaal > 0,75) de UIT-assertie niet vals groen maakt. F4 Gids nl/en: het paginanummer staat altijd in de ondermarge, de voet draagt er geen meer — ook met de optie uit is dat anders dan vóór deze PR. F5 CLAUDE.md: de preview rendert per pagina één volledige pass extra voor de voetstrook. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014zosxbSXvi3YSGmeN1MsQq
Nozzit
pushed a commit
that referenced
this pull request
Sep 14, 2026
, rapportvoet #135) Conflicten in `reportSettings.ts` (periode-sleutels naast de resourcediagram-opties) en de import van `check-reports.ts` (periodehulpen naast `computeResourceGanttRows`); beide additief samengevoegd. Alle poorten groen op het resultaat. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JoVB3BSFPZoKLvL6NmWRKy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Vervolg op #132 (issue #113) — gestapeld op die branch (bevat de laatste #132-commit
1cf581bvia merge); de base kan na de merge van #132 naarmainworden gezet. Refs #113. Let op:ci.ymltriggert alleen op PR's naarmain, dus op deze PR draait geen CI zolang de base de #132-branch is; tot de retarget zijn de lokale suites hieronder de poort.De Gantt-afdruk tekent één voetstrook (projectnaam, afdrukdatum, legenda, merk) onder de laatste rij, en de pagineerders herhaalden alleen de kop: bij elke meerpagina-afdruk stond de legenda dus alleen op de laatste pagina. Dat bestond al, maar "een blad per persoon" (#132) maakt het onhoudbaar — een uitgedeeld vel met rode en blauwe balken zonder legenda (bevinding 5 van de hyperkritische review op #132).
De voet is nu, net als de kop, een herhaalbaar blok:
RenderReportResult.footerHeight(verplicht, zoalsheaderHeight): de render meldt zijn voethoogte (schaalt mee met de rapport-lettergrootte; tabelrenders en de lege staat melden 0).tileLayout.computeTileLayoutkentrepeatFooterHeightPx: de body loopt van onder de kop tot boven de voet (repeatFooterSrcY); elke pagina houdt onderaan het printgebiedfooterTopPtvrij (boven de paginanummer-marge, nuPAGE_NUMBER_PT). De voet wordt uit één vast bronvenster getekend,footerWindow(x vanaf 0, één paginabreedte, op de linkermarge) — níét per kolomvenster gesneden — en de render legt de voetinhoud binnenPrintOptions.footerLayoutWidth(=footerLayoutWidthFor(layout): één paginabreedte zodra de voet herhaald wordt, andersundefined= de oude render), zodat naam, legenda en merk op élk vel compleet zijn, ook met de tijdlijn over meerdere pagina's. Herhaald wordt er alleen als er meer dan één vel is: meer dan één rij, of meer dan één kolom, of een gedwongen paginaovergang (blad per resource); past alles op één vel, dan blijft de voet onder de laatste rij. Zonder de optie is de tegeling én de render byte-identiek (op het weggehaalde nepnummer na, zie onder); dezelfde degeneratievangnetten als de kop.paginate.ts), vector-pagineerder (paginateVector.ts) én de preview (renderPrintPreviewPage) tekenen de strook één keer per pagina uit dat venster, alle drie via dezelfdefooterLayoutWidthFor. De vector-tak doet bij meer dan één kolom één extra render-pass met de voetbreedte (zoals de CJK-pass; alleen als die breedte écht kleiner is dan het canvas, met herhaalde coverage-poort); raster-export en preview kennen de layout al vóór hun render. De preview rendert per pagina één volledige pass extra voor de strook, net als voor de kop (staat inCLAUDE.md; een offscreen-cache voor kop én voet is een aparte klus).repeatFooter, standaard aan zoals de kop) inops-reportSettings, checkbox naast "Kop op elke pagina herhalen"; 14 locales; gids nl+en (optiebullet met de kosten, het éénpagina-geval en het paginanummer; in de resourcediagram-sectie vervangt "elk uitgedeeld vel zijn eigen legenda" de zin dat de voet op het laatste vel staat).labels.page/labels.ofzijn uitPrintOptions,ReportPanel, vijf testfixtures en de 14report.json-locales.Schermbewijs:
artifacts/resourcediagram/03-voet-op-elke-pagina-pagina-2.png— pagina 2 van het resourcediagram met blad per resource, mét voet.Hyperkritische reviews (subagent, Opus), drie rondes. Ronde 1 ("nee, nog niet", verwerkt in
59ab7a1): voet per kolom gesneden ⇒ legenda in één kolom; éénpagina-afdruk kreeg de voet aan de onderrand;footerHeightoptioneel; dode labels + weessleutels; browsertest telde vensters i.p.v. inhoud; kosten ongedocumenteerd; fixture op de cachegrens; moduledoc/naam. Ronde 2 ("nee", verwerkt in99d6107): één rij × N kolommen kreeg geen herhaling én een in kolom 1 geperste, gesneden voet; voetbreedte ging onvoorwaardelijk mee ⇒ UIT-stand ≠ oude render, drie paden uiteen; browsertest bewees geometrie, geen inhoud; hoogtefilter aan lettergrootte 100 % geklonken; twee bovengrenzen voor gedwongen posities; één fixture over het hoofd gezien. Ronde 3 ("ja — mag door", restpunten verwerkt in de laatste commit): loze extra vector-pass door float-<(~5 % van de breedtes); coverage-poort na die pass; testparser met q/Q-stack en hoogte t.o.v. de papierhoogte; gids over het paginanummer; previewkosten inCLAUDE.md. De reviewer mat de PDF-vorm zelf na met een eigen headless vector-export in acht configuraties en vond geen tekstlek tussen body en voet.How it was verified
npm run verifygreen — lokaal op de Rapport: voet met legenda op elke pagina (#113, nabespreking) #135-branch: typecheck, lint, cycles, verify:docs (34 × 14), verify:i18n, de rapportbatterijen (check-print-report,check-reports, beide settings-checks, pluscheck-today-label,check-split-bar-render,check-print-working-exceptions,check-print-raster-export-streaming,check-dependency-stylevoor de labelverwijdering), de volledige planningssuite (exit 0, incl. tijdzone-matrix) en de volledige browsersuite (142/144 — de twee bekende sandbox-fouten injust-updated-dialog.spec.tsop de proxy-CA, niet op CI; zie Rapport: resourcediagram — de Gantt-afdruk per resource, met een blad per persoon (#113) #132). Na de laatste commit opnieuw: typecheck, lint, docs,check-print-reportenreport-footer.spec.ts(2/2).tests/planning/check-print-report.ts(voethoogte gemeld en geschaald; voet = precies het stuk onder de laatste rijgrens; tegeling zonder optie byte-identiek en de voet hangt dan aan de laatste tegel; met optie eindigt de laatste body-tegel boven de voet, pagina's eindigen nog op rijgrenzen, kop + body + voet passen in het printgebied; te hoge voet ⇒ niet herhaald; zonder kop en inactual; twee kolommen:footerWindow= één paginabreedte vanaf x=0, en metfooterLayoutWidthstaat alle voettekst incl. het merk binnen die breedte zonder dat de canvasmaten veranderen; éénpagina ⇒ voet niet herhaald, tegeling identiek; één rij × twee kolommen ⇒ wél herhaald, ook inactual; blad-per-resource ⇒ wél; gedwongen positie in de voetstrook zet de herhaling niet aan;footerLayoutWidthForundefined zonder herhaling; geen nep-paginanummer), nieuwtests/planning/check-report-footer-setting.ts(default aan, opslag van vóór de optie, rommel, round-trip; bedraad inrun.sh),tests/browser/report-footer.spec.ts(parseert per PDF-pagina de tegelvensters met een q/Q-stack: precies één voetvenster op de onderrand van het printgebied, vanaf x = 24, één volle printbreedte breed en met ≥ 4 tekstoperatoren — mét voet op elke pagina, óók met "Tijdlijn over 2 pagina's"; zonder voet nergens; tweede scenario: 6 taken ⇒ één vel zonder los voetvenster, met de tijdlijn over 2 pagina's ⇒ twee vellen die elk de volle voet mét tekst dragen).tests/browser/report-preview-performance.spec.ts: fixture 260 → 200 rijen (6 vanmaxPages7, met marge). Die test materialiseert bewust de hele preview; met 260 rijen stond het paginatotaal precies op de grens en kost de voet per pagina één strook body.Does this touch
ops-reportSettings).repeatFooterviat(...)in alle 14report.json-locales (+page/ofverwijderd);verify:i18ngroen.@tauri-apps/*— n.v.t.Documentation
public/docs/{nl,en}/gids-rapporten-printen.md: bullet Voet op elke pagina herhalen (incl. meerdere kolommen, éénpagina-geval, de kosten, de botsing met blad-per-resource en het paginanummer in de ondermarge); resourcediagram-sectie aangepast.CLAUDE.md: rapportparagraaf (voet als herhaalbaar blok, de ketenfooterHeight→repeatFooterHeightPx/repeatFooter, de previewkosten).docs/CHANGELOG.mdbewust niet (alleen bij een release).🤖 Generated with Claude Code
https://claude.ai/code/session_014zosxbSXvi3YSGmeN1MsQq