feat(time): add H:MM duration display format option (PMS-265) #120

Merged
longjacksonle merged 1 commit from feat/pms-265-duration-format-option into main 2026-06-12 15:20:33 +02:00

What

Adds H:MM as an additional logged-time display format (90 min -> 1:30, 30 min -> 0:30), selectable per-device on Profile > Preferences. Decimal (1.5h) stays the default, so existing users see no change until they opt in. Closes PMS-265.

Why

Time entries are stored as whole duration_minutes but the SPA only ever rendered them as decimal hours. Many users read timesheets faster in clock style. This adds the option without removing the decimal shape.

How

  • New src/utils/duration.rs central formatter: fmt_hm, fmt_decimal, and fmt_duration (reads the mokosh_duration_format localStorage pref, default decimal, on each call so a change applies on the next render). Owns the pref key + default.
  • Profile > Preferences gains a "Duration format" radio fieldset (Decimal 1.5h / Hours:minutes 1:30) alongside Theme / Time format / First day of week, persisting via utils::prefs::set_str.
  • All logged-duration sites route through fmt_duration: Time Entries stat cards + Hours cells, Timesheets weekly grid (cells, row totals, daily totals, grand total), and the Dashboard recent-time table.
  • Project budget/actual hour figures are budgets in hours, not logged minutes, and are intentionally left as-is.

Testing

  • cargo test --lib: 74 pass (6 new for the formatter: zero, sub-hour padding, exact hours, mixed, negative clamp, decimal shape).
  • cargo check --target wasm32-unknown-unknown: clean.
  • cargo clippy --all-targets: clean except the pre-existing manual_checked_ops warning at projects.rs:930, which is a rust-1.95-only lint not present in CI's rust-1.94 image and unrelated to this change.

Relates to PMS-233.

🤖 Generated with Claude Code

## What Adds **H:MM** as an additional logged-time display format (90 min -> `1:30`, 30 min -> `0:30`), selectable per-device on Profile > Preferences. Decimal (`1.5h`) stays the default, so existing users see no change until they opt in. Closes PMS-265. ## Why Time entries are stored as whole `duration_minutes` but the SPA only ever rendered them as decimal hours. Many users read timesheets faster in clock style. This adds the option without removing the decimal shape. ## How - New `src/utils/duration.rs` central formatter: `fmt_hm`, `fmt_decimal`, and `fmt_duration` (reads the `mokosh_duration_format` localStorage pref, default `decimal`, on each call so a change applies on the next render). Owns the pref key + default. - Profile > Preferences gains a "Duration format" radio fieldset (Decimal 1.5h / Hours:minutes 1:30) alongside Theme / Time format / First day of week, persisting via `utils::prefs::set_str`. - All logged-duration sites route through `fmt_duration`: Time Entries stat cards + Hours cells, Timesheets weekly grid (cells, row totals, daily totals, grand total), and the Dashboard recent-time table. - Project budget/actual hour figures are budgets in hours, not logged minutes, and are intentionally left as-is. ## Testing - `cargo test --lib`: 74 pass (6 new for the formatter: zero, sub-hour padding, exact hours, mixed, negative clamp, decimal shape). - `cargo check --target wasm32-unknown-unknown`: clean. - `cargo clippy --all-targets`: clean except the pre-existing `manual_checked_ops` warning at `projects.rs:930`, which is a rust-1.95-only lint not present in CI's rust-1.94 image and unrelated to this change. Relates to PMS-233. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(time): add H:MM duration display format option (PMS-265)
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 59s
Create release / Create release from merged PR (pull_request) Has been skipped
5b1531265a
Logged time is stored as whole `duration_minutes` but the SPA only ever rendered it as decimal hours (90 min -> "1.5h"). Add H:MM clock style (90 min -> "1:30", 30 min -> "0:30") as an additional, opt-in display format. Decimal stays the default so existing users see no change until they pick the new option.

New `src/utils/duration.rs` central formatter owns the preference: `fmt_hm` (H:MM, zero-padded minutes, negative clamp), `fmt_decimal` (the legacy "Nh" shape), and `fmt_duration` which reads the per-device `mokosh_duration_format` localStorage pref (default `decimal`) on each call so a change applies on the next render. Ships with 6 unit tests covering zero, sub-hour padding, exact hours, mixed, negative clamp, and the decimal shape.

Profile > Preferences gains a "Duration format" radio fieldset (Decimal 1.5h / Hours:minutes 1:30) next to Theme / Time format / First day of week, persisting via `utils::prefs::set_str`. All logged-duration display sites now route through `fmt_duration`: the Time Entries stat cards and Hours cells, the Timesheets weekly grid (cells, row totals, daily totals, grand total), and the Dashboard recent-time table. Project budget/actual hour figures are budgets in hours (not logged minutes) and keep their existing rendering.

Relates to PMS-233.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/pms-265-duration-format-option 2026-06-12 15:20:33 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
psa-systems/mokosh-apps!120
No description provided.