feat(web): a11y wiring - label association, machine-readable time, links #473

Merged
nrupard merged 1 commit from fix/BUNYIP-466-a11y-wiring into main 2026-08-05 15:26:08 +02:00
Owner

Implements the BUNYIP-466 slice of the 2026-08-04 bunyip UI audit: three a11y-wiring findings (F22, F23, F4).

F22: associate form labels with their inputs

Admin and settings forms rendered <label> and <input> as siblings with no for/id, so screen readers could not tie them together. Every hand-written label+control pair now carries for/id using the input's name as the id (matching the existing auth-helper pattern): 87 pairs across onboarding, dashboard settings, and the admin config/list pages.

Same-page id collisions are disambiguated with a form-scoped prefix while the submitted name stays unchanged, so form semantics are untouched: the settings page renders four forms together, so current_password/totp_code/password become email-/password-/disable-2fa-/delete-account- prefixed ids, and the rate-limits per-action rows suffix the id with the action key. Controls that were already associated (the auth helpers, the contact form, and the docs-editor labels that wrap their input) are left untouched; the one genuinely label-less control (the application_groups group_id select, associated by its card title) is noted for a later pass.

F23: machine-readable timestamps, one humanizer

Two relative-time humanizers existed (util::relative_time and a local time_ago in the dashboard). time_ago is deleted and its callers routed through relative_time, leaving one humanizer. A new util::rel_time(iso) -> Markup wraps the relative string in <time datetime=(iso) title=(absolute)> so the value is machine-readable and carries an absolute-time tooltip; the absolute formatter (abs_time) moved into util alongside it. 17 render sites across users, feedback, entitlements, audit, error-log, ip-bans, rate-limits, the admin dashboard, and the settings sessions/devices lists now use it. Every site had a reachable raw ISO timestamp.

The "Back to users" (entitlements) and "Documentation" (docs footer) links were styled as body text; both now carry text-primary hover:underline like every other content link.

Verification

just check-container (dockerized fmt + clippy + workspace tests) green.

#BUNYIP-466

Implements the BUNYIP-466 slice of the 2026-08-04 bunyip UI audit: three a11y-wiring findings (F22, F23, F4). ## F22: associate form labels with their inputs Admin and settings forms rendered `<label>` and `<input>` as siblings with no `for`/`id`, so screen readers could not tie them together. Every hand-written label+control pair now carries `for`/`id` using the input's `name` as the id (matching the existing auth-helper pattern): 87 pairs across onboarding, dashboard settings, and the admin config/list pages. Same-page id collisions are disambiguated with a form-scoped prefix while the submitted `name` stays unchanged, so form semantics are untouched: the settings page renders four forms together, so `current_password`/`totp_code`/`password` become `email-`/`password-`/`disable-2fa-`/`delete-account-` prefixed ids, and the rate-limits per-action rows suffix the id with the action key. Controls that were already associated (the auth helpers, the contact form, and the docs-editor labels that wrap their input) are left untouched; the one genuinely label-less control (the application_groups group_id select, associated by its card title) is noted for a later pass. ## F23: machine-readable timestamps, one humanizer Two relative-time humanizers existed (`util::relative_time` and a local `time_ago` in the dashboard). `time_ago` is deleted and its callers routed through `relative_time`, leaving one humanizer. A new `util::rel_time(iso) -> Markup` wraps the relative string in `<time datetime=(iso) title=(absolute)>` so the value is machine-readable and carries an absolute-time tooltip; the absolute formatter (`abs_time`) moved into util alongside it. 17 render sites across users, feedback, entitlements, audit, error-log, ip-bans, rate-limits, the admin dashboard, and the settings sessions/devices lists now use it. Every site had a reachable raw ISO timestamp. ## F4: two nav links read as links The "Back to users" (entitlements) and "Documentation" (docs footer) links were styled as body text; both now carry `text-primary hover:underline` like every other content link. ## Verification `just check-container` (dockerized fmt + clippy + workspace tests) green. #BUNYIP-466
feat(web): a11y wiring - label association, machine-readable time, links
All checks were successful
E2E PR gate / Install + reachability (no deployment secrets) (pull_request) Successful in 25s
Check / fmt + clippy + build + tests (pull_request) Successful in 4m33s
Create release / Create release from merged PR (pull_request) Has been skipped
375bde4cc9
Implements the BUNYIP-466 slice of the 2026-08-04 UI audit (F22, F23, F4). Associates 87 hand-written admin/settings label+control pairs via for/id (id = the input's name, matching the auth helpers), disambiguating same-page id collisions with a form-scoped prefix while leaving the submitted name unchanged. Collapses the two relative-time humanizers into one (deletes the dashboard-local time_ago, routes its callers through util::relative_time) and adds util::rel_time, which wraps 17 render sites in a <time datetime title> element for machine-readable timestamps with an absolute-time tooltip. Restyles the two "Back to X" nav links as text-primary hover:underline.

#BUNYIP-466
nrupard deleted branch fix/BUNYIP-466-a11y-wiring 2026-08-05 15:26:09 +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/bunyip!473
No description provided.