fix(worklog): derive row cues on the client + distinguish future entries#576
Conversation
There was a problem hiding this comment.
Code Review
This pull request shifts the derivation of worklog row cues (day-break, pause, and overlap) to the client side and introduces support for displaying future-dated entries separated by a labeled divider band. Additionally, it adds E2E screenshot clock-freezing capabilities and corresponding unit tests. The review feedback suggests optimizing the client-side sorting performance in deriveRowCues by pre-mapping the entries to avoid redundant date parsing, and improving accessibility by using em instead of rem for the divider band's typography and padding to support user-configurable text scaling.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #576 +/- ##
=========================================
Coverage 82.14% 82.14%
Complexity 3378 3378
=========================================
Files 241 241
Lines 9210 9210
=========================================
Hits 7566 7566
Misses 1644 1644
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The day-break/pause/overlap row borders were read from the persisted entries.class column, which is only (re)computed server-side on save. Seed, imported or otherwise-unsaved entries therefore rendered with wrong/absent cues — most visibly, a multi-day worklog showed day-break borders only for the day that happened to be classified. Derive the cues on the client from the (day, start, end) ordering of the rows actually displayed (deriveRowCues), so they are correct for any data. Also distinguish future entries (day > local today, when show_future is on) with a cool row tint and a labeled 'Zukunft' divider band between the future block and today/past — a non-colour cue paired with the tint. The grid skips the band in keyboard navigation via the generalized non-data-row helper. Fixes #575. Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
…mages Freeze the browser clock so client-clock features (the worklog future-entry cue) render deterministically against the e2e stack's frozen server time. Adds the docs/images/pr-575 captures used in the PR. Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
01a25db to
5ee06b2
Compare
…ivider - deriveRowCues: pre-parse each row's id/day/start/end once and sort by a precomputed key, instead of re-running dmyToIso/str inside the comparator. - Future divider band uses em (not rem) for padding/font-size so it tracks the --font-scale text-size preference (ADR-014). Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
There was a problem hiding this comment.
Pull request overview
This PR fixes incorrect worklog row cues by deriving day break / pause / overlap on the client from the rendered row ordering (instead of relying on the persisted entries.class), and adds a clear UI distinction for future-dated entries (tint + “Future/Zukunft” divider).
Changes:
- Derive row cues client-side (
deriveRowCues) and use them for styling + non-color labels. - Add future-entry styling and insert a labeled divider band between future and today/past rows; update grid keyboard navigation to skip non-data divider rows.
- Add i18n string
tracking_future_dividerto all catalogs and make screenshot capture deterministic via--clock.
Reviewed changes
Copilot reviewed 10 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/styles/app.css | Adds theme tokens and styles for future row tint + future divider band. |
| frontend/src/pages/Tracking.tsx | Replaces persisted class-based styling with client-derived cues; adds future detection + divider row. |
| frontend/src/pages/Tracking.test.tsx | Updates/extends Vitest coverage for derived cues and future divider behavior. |
| frontend/src/lib/gridNavigation.ts | Generalizes non-data-row skipping to include divider rows during keyboard navigation. |
| frontend/messages/en.json | Adds tracking_future_divider translation key. |
| frontend/messages/de.json | Adds tracking_future_divider translation key. |
| frontend/messages/es.json | Adds tracking_future_divider translation key. |
| frontend/messages/fr.json | Adds tracking_future_divider translation key. |
| frontend/messages/ru.json | Adds tracking_future_divider translation key. |
| e2e/tools/capture-screenshots.mjs | Adds --clock option to freeze browser time for deterministic screenshots. |
- Keep the future divider band in the a11y tree (drop aria-hidden) so its label reaches screen readers — consistent with the grid non-data-row model. - toIsoDay() normalizes both dd/mm/YYYY and already-ISO dates; isFutureDay and deriveRowCues use it, so future detection works for imported/ISO rows. - deriveRowCues only derives pause/overlap from a fully-timed pair (mirrors the backend), so a blank end no longer marks every later same-day row a pause. - capture-screenshots.mjs validates --clock and fails with a clear message. - Add specs for the blank-time guard and ISO-date future detection. Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
|



Related issues
Fixes #575
Problem
The worklog row cues — Tageswechsel (day break), Pause, Zeitüberschneidung (overlap) — were read from the persisted
entries.classcolumn, which is (re)computed only server-side at save time (BaseTrackingController::calculateClasses), per day. Any entry not written through the save flow (seed, import, future-dated) rendered with wrong/absent cues. Concretely, a multi-day worklog showed day-break borders only for the one classified day. See #575 for the full analysis.Change (client-side, no backend change)
(day, start, end)ordering of the rows actually displayed (deriveRowCues), replacing theCLASS_ROW[entry.class]lookup. Correct for any data; the persisted column is no longer read for rendering.show_futureis on): a cool row tint plus a labeled Zukunft divider band between the future block and today/past — a non-colour cue (WCAG 1.4.1) paired with the tint. "Today" uses the client clock (same convention asMonth.tsx).gridNavigation.ts(the existing.row-errorskip, now covering.grid-divider).tracking_future_dividerin all five catalogs.capture-screenshots.mjsgains--clockso the future cue renders deterministically against the frozen e2e server time.Screenshots
Real
/ui/trackingfrom the e2e stack, browser clock frozen to2024-01-15(matching the server) so the 2026 seed entries are "future".Note the day-break border now appears on every day's first entry (4 days, incl. the 2026 future days), and the future block is tinted + capped by the Zukunft band. In the reduced view this is what tells the future
15.01.(2026) apart from today's15.01.(2024), which the year-less compact date cannot.Validation
bun run test: 421/421 (incl. new derive-cues + future-divider specs and gridNavigation).bun run lintandbun run typecheck: clean.