Develop - #82
Merged
Merged
Conversation
Add minDate/maxDate props to shared DatePicker component and apply constraints to all 12 date range instances: "to" date cannot precede "from" date, and "to" auto-resets when "from" moves past it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… filters - Filters collapsed by default on time entries page (open on click) - Manual time entry form requires project, date, start/end time with inline error messages (manual validation replaces zodResolver) - Clicking a table row opens view modal with disabled fields - View modal has Edit button to switch to editable mode - Cancel in edit mode returns to view without closing dialog - Added useUpdateManualEntry hook for editing existing entries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… footer - Checkboxes on every row for users with delete or approve permissions - Header checkbox selects/deselects all visible entries - Delete button (destructive) appears when entries are selected - Approve button only shows count of selected pending entries - Edit button moved from dialog header to footer next to Close Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Date pickers default to empty (show all entries) - Date filtering only applied when user explicitly picks dates - Clear filters button also resets date range - Date range counts toward active filter badge Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Removed Late column (header + cell) from attendance table - Removed Late Days stats card from summary strip - Cleaned up unused Clock icon and formatMinutes imports Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Give Status column 40% width to absorb the extra space left by the removed Late column, keeping the remaining columns compact. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single w-[40%] on Status with explicit percentage widths on all columns so gaps are uniform after removing the Late column. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b5092e3 removed the Late column and the Late Days tile outright, so the owner and HR lost them too. Put both back behind a `canSeeLate` role check (`owner` / `hr_manager`) instead, so the people who need the signal keep it and employees do not see their own lateness. Also closes a gap the removal left open: the Late badge on the Status cell still rendered "Late 15m" to everyone, one cell over from the column that had just been taken away. It now rides the same gate, as does the Late Days stat tile. All three late surfaces are gated together — hiding one alone leaks the same number from the others. Details: - The stat strip's column count follows the tile count (lg:grid-cols-5 -> lg:grid-cols-4) so the grid does not leave a hole; the skeleton count matches so the strip does not reflow on load. - 1c0ae90's `w-[40%]` on Status exists only to absorb the space the Late column would occupy, so it now applies only when that column is absent. - Restores the `Clock` and `formatMinutes` imports, and puts the `Tooltip` imports back to use — they were left unused by the removal and were raising three no-unused-vars warnings. Deliberately a role check rather than the `attendance.view_all` permission: that permission is also held by org_manager and finance_manager, who must not see it. Trade-off — a custom org role will not match; a dedicated `attendance.view_late` permission is the configurable version if wanted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drops hr_manager from `canSeeLate`, so the Late column, the Late badge on the Status cell and the Late Days stat tile are now visible to the owner and to no one else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-only feat(hr): show attendance lateness to the owner only
…provements - Add week navigation (prev/next arrows) to Weekly Progress card and chart - Smooth chart transitions with keepPreviousData instead of flash on refetch - Fix task names not displaying in time entries listing (task.title → task.name) - Replace task dropdown with free-text input for employee-defined tasks - Add text truncation with ellipsis for long task names - Fix task not updating when editing manual time entry (task_name support in update) - Only reset approval status on time changes, not task/notes edits - Support overnight (cross-midnight) time entries in manual entry form Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Restrict employee to only see their own department (not full org tree) - Allow employees to delete own pending/rejected manual time entries - Allow leave applications up to 7 days in the past - Simplify leave balance display to show only remaining days - Show "Half day" instead of 0.5 in leave listings - Fix attendance month filter showing number instead of month name - Add calendar icon to attendance month filter - Fix Docker dev server performance (health check interval, .env corrections) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Conflict: the attendance table header. This branch gave every column an explicit width; develop restored the Late column behind the owner-only `canSeeLate` gate. Kept both — Late is back and still gated, and it carries a width like every other column. Dropped develop's 40%-on-Status hack, which only existed to absorb the missing Late column's space and is redundant now that all columns are sized.
`tasks` has only ever had a `name` column, and TimeEntryController serializes the model directly, so `task.title` was always undefined. Three files declared it anyway: time/page.tsx typed `title` while reading `name`, which failed the build, and dashboard/page.tsx read `title` alone, so the timesheet rendered "No task" for every entry that had one.
Qa dashboard UI fixes
fix: employee role restrictions, leave/attendance UI improvements
… local one Screenshots stopped reaching the dashboard while time sync stayed healthy. On 2026-08-20 seventeen users tracked 5-8 hours each and three had any screenshot at all. Live uploads (arrival within 60s of capture) went 1627/1639 on Aug 12 to 0/835 on Aug 18 -- the offline-first rollout landed on Aug 13. `startTimer()` makes no network call any more, so `currentEntry.id` is the local SQLite id `local-<ts>-<rand>`, and it was passed straight to `screenshotService.start()`. `POST /screenshots/presign` validates `time_entry_id` as a uuid and looks it up in `time_entries`, so every live shot 422'd, exhausted its retries and fell into the offline queue. `rebindEntryId()` was written for exactly this case and survived the refactor, but its only caller -- `reconcileTimerState()` -- was deleted with it. The queued fallback then lost them for good. Resolution reads `timer_sessions.server_entry_id`, but the 05:00 purge and `clearForLogout()` delete that row with no knowledge of the queue's separate database, and with a 15-42 hour backlog lag shots routinely outlived their own session. The `idempotency_key` fallback could not help: the queued key is the shot's dedupe key, never the session's. Unresolvable items are held rather than dropped, so they piled up behind `LIMIT 500` and were finally deleted -- silently, with their image files -- by the 7-day TTL sweep. Heartbeats were unaffected because they are priority 1 and carry the session uuid, which is what isolated the fault. - `SessionSyncWorker` fires `onSessionConfirmed(localId, serverEntryId)` once per session, on the transition to a known server id; index.js rebinds capture to it - `liveCaptureEntryId()` seeds `start()` from an already-known server id, covering restore-after-restart and project switch - queued screenshots record `session_uuid`; `add()` persists it and `_resolveEntryId()` resolves through it first - `purgeConfirmed()` takes a keep-list fed by `offlineQueue.referencedSessionKeys()` - a flush that holds screenshots now logs it, escalating past 50 12 regression tests in desktop/test/screenshot-entry-id-binding.test.js (46 suites / 796 tests pass). Full write-up in bugs/desktop-screenshots-bound-to-local-entry-id.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Employees came back from a break, saw nothing, and carried on working after the idle watchdog had auto-stopped the timer -- so the work after their return was never recorded either. It takes one completely ordinary setup: a machine that never sleeps and never locks (on charger, external display, screensaver off). There, every existing path misses the user. - the idle alert beeps into an empty room, and the stop then dismisses it - the "Timer auto-stopped" toast fires at the moment of the stop, long before anyone is back at the desk - `notifyTrackingState()` -- whose entire job is telling the user their current state -- only runs on wake/unlock/startup, and such a machine emits none of those events - the idle watchdog self-gates on `isTimerRunning`, so the instant it stops the timer it also stops looking Nothing was watching for the user coming BACK. Adds a return-from-break watcher: the mirror image of the watchdog, running while the timer is STOPPED. It polls `getSystemIdleTime()` every 15s and fires when the user has been away past the org idle threshold and is active again. Absence is peak-tracked, because the poll that catches the return reads 0 -- the OS counter resets on the first keystroke -- so a last-reading model would make every absence invisible. An unreadable counter fails silent rather than inventing an absence. Three cues, because each one alone is routinely swallowed: - a `silent:false` notification with a unique id, so Action Center cannot dedup it against the auto-stop toast from hours earlier - an in-renderer WebAudio beep -- macOS Focus and Windows Action Center drop notification sound with no fallback, the same reason the idle alert carries its own. Three descending tones, distinct from the idle alert's two rising ones, and no external resource so the strict CSP is unchanged - the window itself, with a red banner that clears when tracking resumes Decision logic is pure in desktop/src/main/return-to-work.js. 24 regression tests in desktop/test/return-to-work.test.js (46 suites / 808 tests pass). Full write-up in bugs/desktop-no-notification-on-return-from-break.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-to-local-entry-id fix(desktop): bind screenshot capture to the server entry id, not the local one
…from-break fix(desktop): notify with sound when a user returns to a stopped timer
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.
No description provided.