Fix verified UI defects (dialogs, keyboard access, upload errors, duplicate toasts) #593
Labels
No labels
bug
duplicate
enhancement
help wanted
high priority
invalid
L
low priority
M
medium priority
needs refinement
optional
question
S
security
technical improvement
UX Improvement
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
local-it/mitgliederverwaltung#593
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
The UI audit for #402 found 13 defects plus 4 incidental ones and verified them in a headless browser against
main@d9093a1f. They hurt users today (a LiveView crash, Escape closing the wrong dialog, uploads failing silently, controls that only work with a mouse) and must not wait for the UI standard. Each gets a minimal, tested fix here. Where a later pattern issue (dialogs, combobox, sortable list) replaces the code structurally, the minimal fix still lands now so users do not wait.Visible improvement
Dialogs close with Escape and return focus; upload errors are shown; no duplicate toasts; every control on the affected pages works with the keyboard and shows focus.
Scope (ordered steps,
just ci-devgreen after each)Each item: browser finding · minimal fix · regression test.
phx-keydown="dialog_keydown"withoutphx-target;DatafieldsLivehas no matching clause. Browser: confirmed with a precondition: the crash (FunctionClauseErrorinDatafieldsLive.handle_event/3, remount, dialog gone) happens only when the<dialog>element itself has focus (e.g. after clicking its heading); typing in the slug input is harmless because LiveView only firesphx-keydownwhene.targetcarries the attribute. Fix: addphx-target={@myself}and the handler in the component. Test:render_keydownon the dialog with Escape closes it and the LiveView stays alive.phx-targeton the fee dialogs; the event reachesMemberLive.Show.dialog_keydown. Browser: confirmed: Escape never closes a fee dialog; with the dialog focused, focus jumps to#delete-member-trigger. Fix: target the fees component and handle Escape there. Test: Escape on each fee dialog closes that dialog and leaves the delete dialog closed.BODY(4 fee dialogs + deactivate, there also after Escape). Fix: stable trigger ids +FocusRestorepush on close (legacy pattern, CODE_GUIDELINES §8.11). Test: closing pushes thefocus_restoreevent with the trigger id.div[role=option] tabindex=0without key handling (WCAG 2.1.1). Browser: confirmed: Enter/Space/ArrowDown do nothing. Fix: render the options as<button type="button">items (the menu-button pattern comes in U7). Test: the options are buttons with accessible names and trigger the add event.<span>. Browser: confirmed: not reachable with Tab. Fix: render it as a<button>with an accessible name (“Edit amount for ‹cycle›”). Test: the element is a button and opens the edit dialog.focus:outline-nonewithout replacement (WCAG 2.4.7). Browser: confirmed::focus-visibleapplies but outline and box-shadow are none. Fix: use the sharedbutton_focus_classes/0. Test: the rendered button carries the shared focus classes and nooutline-none.upload_errors/2is never rendered;<label for="csv_file">points at an id thatlive_file_inputoverrides. Browser: confirmed: a.txtfile and an 11 MB.csv(limit 10 MB) give no message, only a disabled submit and a reset file selection. Fix: render upload errors below the field witharia-invalid; bind the label to the real input id. Test: uploading a wrong type and an oversized file renders the translated error; the label'sformatches the input id.phx-window-keydownwithoutphx-key;validatereloads members on every change becauseMap.has_key?(user_params, "email")is always true; debounce also swallows fast arrow keys. Browser: confirmed:member_dropdown_keydownfires from the email field and frombody; everyvalidatereloads members; fast arrow presses get lost. Fix: bind keydown on the picker input only, without debounce on arrow keys; reload members only when the search text changes. Test: avalidatewithout a search change performs no member read; keydown outside the picker sends no event.avatar placeholder. Browser: confirmed: the initial sits 4 px too high. Fix:avatar-placeholder. Test: the rendered avatar usesavatar-placeholder.text-branddoes not exist. Browser: the page is unreachable without SSO;text-brandoccurs 0× in the compiled CSS. Fix:link link-primary. Test: the link renders the link classes.locked_idsis missing; live-region texts are hard-coded English. Browser: confirmed: the email row moves by keyboard and drag, and the new order is saved. Fix: lock the email row (client and server) and translate the announcements via gettext. Test: a move request for the email row is rejected; announcements come from gettext.flash-group-root+flash-group) and two live regions; a LiveView save shows one. Fix: render exactly one flash group (DESIGN_GUIDELINES §9.4). Test: a controller-rendered page with a flash contains exactly one flash group.Out of scope
<.modal>,<.combobox>,<.file_input>, menu button): U4, U7.Acceptance criteria
just ci-devgreen after every step.Dependencies
membership_fees_component.ex, which #536 (merged) changed: re-check their anchors before these steps.Anchors (verified against
main@d9093a1f, re-check before filing)lib/mv_web/live/custom_field_live/index_component.ex:112,lib/mv_web/live/datafields_live.ex:27lib/mv_web/live/member_live/show/membership_fees_component.ex:306,353,395,458,lib/mv_web/live/member_live/show.ex:524lib/mv_web/live/member_live/show/deactivate_component.ex:77lib/mv_web/live/import_live/components.ex:79,90lib/mv_web/live/user_live/form.ex:113,166,174,192,213lib/mv_web/live/global_settings_live.ex:226lib/mv_web/live/member_live/show/membership_fees_component.ex:209lib/mv_web/components/table_components.ex:24lib/mv_web/components/layouts/sidebar.ex:318lib/mv_web/live/user_live/form.ex:232,482,816lib/mv_web/live/global_settings_live.ex:270,assets/js/app.js(sortable hook)lib/mv_web/live/auth/link_oidc_account_live.ex:293lib/mv_web/components/layouts/root.html.heex:72,lib/mv_web/components/layouts.ex:263Caution