fix(report): keep sport times chronological within each day

This commit is contained in:
fy59 2026-10-07 10:20:12 +02:00
parent bf5a06973d
commit e454c86354
6 changed files with 19 additions and 11 deletions

View file

@ -2,8 +2,9 @@
## Unreleased — 0.1.7
- Present Sleep PDF nights and the completed-sport appendix newest first while
preserving chronological timed content within each night. Add a restrained
- Present Sleep PDF nights and completed-sport days newest first while
preserving chronological timed content within each night and sport day.
Add a restrained
printable header, period and generation date, and pale row separation.
Remove unhelpful validation labels from agenda rows and PDF warnings; the
editor now names the exact-revision synchronization publication action and

View file

@ -263,8 +263,9 @@ full-width heart-rate detail; it performs no database mutation. PDF preview
and download instead share an explicit inclusive range over night start dates,
initialized to the loaded history bounds and independent of detail selection.
The vector PDF now presents selected nights newest first, while retaining
chronological timed content within each night; its sport appendix is also
newest first. A light header, period, generation date and pale alternating rows
chronological timed content within each night; its sport appendix shows newest
days first and chronological sessions within each day. A light header, period,
generation date and pale alternating rows
improve print hierarchy in color and grayscale. Agenda rows and PDF omit the
publication/validation labels. The editor still exposes the exact-revision
publication action and state required for synchronization; PDF selection and

View file

@ -66,8 +66,9 @@ on dated pages instead of truncating silently. Review the chosen range before
export; a PDF is a local copy of potentially sensitive information.
The PDF prints the newest selected night first and orders its sport appendix by
actual session start, newest first. Events and medication intakes within each
night keep their chronological order. A light, printable header shows the
actual session day, newest first, with sessions chronological within each day.
Events and medication intakes within each night keep their chronological order.
A light, printable header shows the
selected period and generation date; alternating pale rows and a restrained
accent distinguish nights. Publication status and global validation warnings
are omitted from the report. This presentation does not alter Sleep facts,

View file

@ -409,9 +409,10 @@ subset summaries cannot inherit facts from unselected nights. The same real
Firefox scenario exports a seven-night French PDF from the embedded production
bundle, extracts its text with `pdftotext` and rasterizes its A4 landscape page
with `pdftoppm` for retained visual inspection.
The 0.1.7 PDF polish tests also assert newest-first night and sport appendix
order, unchanged chronological intervals and medication intakes within a night,
7/14/21/28-night pagination, and absence of global validation warnings. Web
The 0.1.7 PDF polish tests also assert newest-first night and sport day order,
chronological sessions within each day, unchanged chronological intervals and
medication intakes within a night, 7/14/21/28-night pagination, and absence of
global validation warnings. Web
tests keep the exact-revision publication action and editing while excluding
publication labels from agenda rows.

View file

@ -332,6 +332,8 @@ describe("sleep diary PDF", () => {
it("prints factual sport bands and a separate legible listing without changing sleep totals", async () => {
const sessions = [
{ identity: "se_previous", session_type: "training", label: "Yoga",
started_at: "2026-09-20T19:00:00+02:00", ended_at: "2026-09-20T19:30:00+02:00" },
{ identity: "se_morning", session_type: "training", label: "Musculation",
started_at: "2026-09-21T05:00:00+02:00", ended_at: "2026-09-21T06:00:00+02:00" },
{ identity: "se_evening", session_type: "training", label: "Étirements",
@ -344,7 +346,8 @@ describe("sleep diary PDF", () => {
expect(content).toContain("Musculation");
expect(content).toContain("05:00");
expect(content).toContain("Étirements");
expect(content.indexOf("Étirements")).toBeLessThan(content.indexOf("Musculation"));
expect(content.indexOf("Musculation")).toBeLessThan(content.indexOf("Étirements"));
expect(content.indexOf("Étirements")).toBeLessThan(content.indexOf("Yoga"));
expect(content).toContain("sommeil non renseigné");
expect(content).toContain("1 nuit");
expect((source.match(/\/Type \/Page /g) ?? []).length).toBe(2);

View file

@ -527,7 +527,8 @@ export function buildSleepDiaryPdf(
right.night_start_date.localeCompare(left.night_start_date) ||
left.entry_id.localeCompare(right.entry_id));
const orderedSport = [...sport].sort((left, right) =>
Date.parse(right.started_at) - Date.parse(left.started_at) ||
right.started_at.slice(0, 10).localeCompare(left.started_at.slice(0, 10)) ||
Date.parse(left.started_at) - Date.parse(right.started_at) ||
left.identity.localeCompare(right.identity));
const first = reportStart ?? orderedEntries[orderedEntries.length - 1]?.night_start_date ?? "—";
const last = reportEnd ?? orderedEntries[0]?.night_start_date ?? "—";