feat(overrides): fold past date overrides into a collapsed section - #176
Merged
Conversation
GH #168: the page listed every override ever created in one flat list, so a host with many of them could not find the ones that still matter. Split on today in the owner's timezone; past ones move into a folded section instead of being deleted. Card markup extracted to a partial so it exists once.
Final-review wave. Restores meetingTypeId as the ORDER BY tiebreaker (a global and a per-type override can share a date, and Postgres's sort is unstable, so their cards could swap between page loads); records why ownerZoneId() does not reuse OwnerSettings.coerceZone; restores the pre-branch gap below the upcoming list when no past section renders; and pins the "Past overrides (N)" summary label in a test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
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.



Closes #168.
What
/me/date-overrideslisted every override the owner had ever created in one flat list, ordered global-first-then-by-date, so a host with many of them could not find the ones that still matter. The page now leads with upcoming overrides (soonest first) and folds everything dated before today into a collapsedPast overrides (N)section (most recent first).Nothing is deleted — that was the reporter's actual ask: "hide them, rather than delete them, as they may still be useful to someone."
<details>, so it works with JavaScript off. This is the codebase's first<details>-form daisyUI collapse; the checkbox form used inmeetingTypeDetail.htmlis the other valid form, not a correction.The request path
One owner-scoped query, split in memory. All three handlers (GET, create-POST, delete-POST) now render through the same method, so the
owner_idpredicate lives in one place instead of three.flowchart TD GET["GET /me/date-overrides"] --> INST POST["POST /me/date-overrides<br/>(create)"] --> INST DEL["POST /me/date-overrides/{id}/delete"] --> INST INST["dateOverridesInstance()"] --> Q Q["ownerId = ?1<br/>order by overrideDate, meetingTypeId nulls first"] --> W W["withWindows(...)<br/>one extra query, no N+1"] --> T T{"overrideDate.isBefore(today)?<br/>today = LocalDate.now(ownerZoneId())"} T -- "no (incl. today)" --> UP["upcoming — ascending"] T -- "yes" --> PAST["past — re-sorted descending"] UP --> TPL["dateOverrides.html"] PAST --> TPLThe two predicates are exact complements over a
NOT NULLcolumn, so no override can be dropped or shown twice. The secondary sort onmeetingTypeIdmatters: a global and a per-type override may share a date, and Postgres's sort is not stable, so without it those two cards could swap places between page loads.The page structure
The card body moved into
_dateOverrideCard.htmlso it is written once rather than duplicated across the two loops — same_name.html+{#include AdminResource/_name p=v /}convention as_workplanGrid.htmland_meetingtypecard.html. It carries its own CSRF token, which is whatCsrfFormCoverageTestcounts per file.Out of scope
The per-meeting-type override list on the meeting-type detail page is left unsplit. It already sits inside a closed accordion and is scoped to a single type, so it cannot produce the flat wall the reporter described. Tracked as a follow-up — note that
_dateOverrideCard.htmlis not directly reusable there (different card class, no scope label, different delete action, different message-key family).Testing
mvn testgreen: 1047 tests, 0 failures, 0 errors.Four tests in
AdminDateOverridesTestassert placement relative to theid="past-overrides"marker, plus the renderedPast overrides (1)label — not substring presence.<details>keeps its content in the response body, so a naivecontainsStringwould pass even with the split completely broken. A mutation check confirmed the tests fail when theupcomingpredicate is neutered.Also verified by hand against a running dev server: ordering, the count, expansion, delete-from-inside-the-collapse, and the bar disappearing once no past overrides remain.
i18n
New
adm_dateOverrides_past_summary(int count)ships with German and Hebrew values, identical{count}placeholder in all three.Docs
Changelog
## Unreleasedbullet and ausage/availability.mdparagraph are on thedocs-sitebranch. The embeddeddate-overrides.pngscreenshot now predates this layout; refreshing it is filed separately, to keep binary assets out of this diff.🤖 Generated with Claude Code