Skip to content

Make the history say what actually changed - #45

Merged
karlitschek merged 3 commits into
mainfrom
feat/noid/history-shows-what-changed
Aug 12, 2026
Merged

Make the history say what actually changed#45
karlitschek merged 3 commits into
mainfrom
feat/noid/history-shows-what-changed

Conversation

@karlitschek

Copy link
Copy Markdown
Member

The History tab said "Adjusted by HR" and, underneath, what the request had become. It never said what changed — so "+2 days added for the wedding" was nowhere to be found. Two separate causes; one commit each.

1. Edits recorded the result, not the change

request_hr_edited wrote "HR adjusted to 2026-03-02 – 2026-03-06 (5 days)". That is the resulting state, which the request itself already shows. What a history is for is what somebody changed and by how much — and a day count means nothing without the number it replaced. request_updated was worse: "Changed to <start> – <end>" never mentioned working days at all, so a pure day-count correction produced a line implying nothing had happened.

Edits now report the difference, field by field:

Working days 3 → 5 (+2); Reason “Wedding” → “Wedding (extended)”

Both edit paths snapshot the request before mutating it, since afterwards the old values are gone. A save that changes nothing writes no detail at all, rather than a sentence implying it did.

Creation gained a real detail line too — type, dates, day count and the employee's reason. That reason previously went only to nextcloud.log, on the stated grounds that the Details tab shows it. But the Details tab shows the current reason, so once HR corrected the request, nothing could say what the leave had originally been booked for.

2. Entitlement changes had no history at all

absence_request_events is keyed on request_id, and an entitlement belongs to no request — so an adjustment left only a log line nobody reads and an activity entry reading "Leave balance of X was adjusted", with neither the amount nor the reason.

The sharpest part: the note HR is required to write when adjusting ('A note is required when adjusting an entitlement.') was stored on the entitlement row, displayed in no view whatsoever — it appeared in zero src/ files — and overwritten by the next adjustment. A mandatory field nobody could ever read.

New absence_entitlement_events table records one row per figure a save actually moved, carrying who, which figure, from what to what, and the note. One row per figure rather than per save, so "+2 days for the wedding" reads on its own instead of having to be diffed out of a blob. A save that moves nothing records nothing.

Surfaced where the question is asked — the entitlement editor in HR → Balances, next to the figure it explains — and over GET /api/entitlements/{id}/history. The activity entry now says what changed rather than only that something did.

Writes are best-effort, like the request timeline: an unwritable history must not cost HR the adjustment they just made. The events name the employee and describe their allowance, so UserDeletedListener purges them with the rest (§17).

Testing

PHP: 163 tests, 451 assertions, 0 failures (2 new — one that an adjustment records field, delta, actor and note; one that a no-op save records nothing). Frontend: eslint 0 errors, stylelint clean, 27/27 vitest, production build succeeds. Bundles recompiled in the last commit.

Schema changes are in Version1004Date20260812120000, guarded so a re-run is a no-op. Existing rows are unaffected — history starts accumulating from the first change after upgrade.

🤖 Generated with Claude Code

Frank Karlitschek and others added 3 commits August 12, 2026 15:30
The request timeline said "HR adjusted to 2 – 6 March (5 days)", which is the
resulting state — readable, and useless for the question anybody opens the
history to ask. The request itself already shows what it says now. What the
timeline is for is what somebody changed and by how much, and a day count means
nothing without the number it replaced.

Edits now report the difference, field by field: "Working days 3 → 5 (+2)",
"Dates 2–4 Mar → 2–6 Mar", "Reason “Wedding” → …", replacement added or removed.
Both edit paths snapshot the request before mutating it, since afterwards the old
values are gone. A save that changes nothing writes no detail rather than a
sentence implying it did.

Creation gained a real detail line too — type, dates, day count and the
employee's reason. That reason previously went only into the server log, on the
grounds that the Details tab shows it; but the Details tab shows the *current*
reason, so once HR corrected the request nothing could say what the leave had
been booked for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entitlement changes had nowhere to be recorded. The request timeline is keyed on
request_id and an entitlement belongs to no request, so an adjustment left a line
in nextcloud.log that nobody reads and an activity entry reading "Leave balance
of X was adjusted" — with neither the amount nor the reason.

The note HR is *required* to write when adjusting was the sharpest part: stored
on the entitlement row, displayed in no view at all, and overwritten by the next
adjustment. A mandatory field nobody could ever read.

Adds absence_entitlement_events: one row per figure a save actually moved,
carrying who, which figure, from what to what, and the note. One row per figure
rather than per save, so "+2 days for the wedding" is a fact that reads on its
own instead of something to be diffed out of a blob. A save that moves nothing
records nothing.

Surfaced where the question gets asked — the entitlement editor in HR → Balances,
next to the figure it explains — and over GET /api/entitlements/{id}/history.
The activity entry now says what changed rather than only that something did.

Writes are best-effort, like the request timeline: an unwritable history must not
cost HR the adjustment they just made. The events name the employee and describe
their allowance, so UserDeletedListener purges them with the rest (§17).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nextcloud-command nextcloud-command added the AI assisted This PR contains AI-assisted commits label Aug 12, 2026
@karlitschek
karlitschek merged commit d289000 into main Aug 12, 2026
26 of 30 checks passed
@karlitschek
karlitschek deleted the feat/noid/history-shows-what-changed branch August 12, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI assisted This PR contains AI-assisted commits

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants