Repository navigation
fix(frontend): rename filter Clear to Select none, inline user errors - #1368
Merged
Merged
Conversation
In a categorical column-filter popover the footer button sets an explicit empty allow-list, which hides every row. Labelled "Clear", it reads as "remove this filter", so a user resetting a filter got an empty table instead (UX-28). The empty allow-list is deliberate (it lets you start from nothing and tick one value), so keep the behavior and name it for what it does. Numeric filters keep "Clear", which does remove the filter; (All) is how a categorical filter is removed. Applied to every popover that shares the pattern: Purchase History, the two RI Exchange tables, Plans' planned purchases and Opportunities. Refs LeanerCloud#727 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A refused user save was reported only through a toast (UX-33): it fades, sits away from the field, and gives screen-reader users no cue on the control. The email, required-groups and minlength checks were native bubbles that vanish on the next click, and they pre-empted the app's own group checks, so the admin met problems one at a time. New lib/field-errors.ts puts a .field-error message under the field, sets aria-invalid and appends the message to aria-describedby (existing help text stays announced), and clears it on the next edit of that field. #user-form is now novalidate; saveUser collects every problem at once (blank or malformed email, password requirements on create, no group or a contradictory group combination), marks each field and focuses the first. The group and password messages still toast as before. Opening the modal clears old messages. A forms.css rule lets the red border show on unfocused fields, since .form-group's border rule outranks the global [aria-invalid] one. Refs LeanerCloud#727 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e label Jest: the field-errors helper (placement after an anchor row, aria-describedby kept and restored, clear on edit), the user form (all problems at once with focus on the first, blank email, contradictory groups inline and toasted, clear then save, hidden password ignored on edit, reset on reopen) and the history popover footer label and commit for categorical vs numeric filters. Playwright: the Opportunities provider filter reads "Select none", and the user form flags fields in a real browser. Refs LeanerCloud#727 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Conflicts: - frontend/src/plans.ts, frontend/src/riexchange.ts: took main. LeanerCloud#1315 replaced the per-table Plans, Active RI and RI Exchange popover builders this branch had relabelled with the shared lib/column-filter-popover.ts, so those local edits have nothing left to apply to. - frontend/src/lib/column-filter-popover.ts (merged cleanly, edited here): the shared popover's footer button now reads "Select none" on categorical filters and "Clear" on numeric ones, carrying this branch's LeanerCloud#727 label over to Plans and both RI Exchange tables. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…red filter popovers main's LeanerCloud#1342 made `scope` a required field of the history popover config, so the LeanerCloud#727 footer-label test no longer typechecked; pass scope 'history'. Also assert the "Select none" / "Clear" labels in main's shared column-filter-popover tests, which now carry the label for Plans and RI Exchange. Refs LeanerCloud#727 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): APPROVE Blocking:
|
Collaborator
Author
|
Local verification at
|
IAmJSD
marked this pull request as ready for review
October 24, 2026 19:06
Collaborator
Author
|
Marked ready and merged by IAmJSD's agent, at IAmJSD's request (IAmJSD reviewed the before/after screenshots; cristim is traveling), after the independent review and local verification above, all at |
IAmJSD
added a commit
to IAmJSD/cloud-commitments-platform
that referenced
this pull request
Oct 24, 2026
Conflicts: - frontend/src/styles/forms.css: both sides inserted text before .form-help. Kept main's .form-group [aria-invalid="true"] border rule (LeanerCloud#1368) and then this branch's comment and display: block on .form-help; the two rules are independent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IAmJSD
added a commit
to IAmJSD/cloud-commitments-platform
that referenced
this pull request
Oct 24, 2026
Conflicts: - frontend/src/app.ts: import block only. This branch imports setOpenAccountsHandler (first-run card's Admin > Accounts navigation); main's LeanerCloud#1336 imports initPurchasingNav. Kept both imports; both call sites merged cleanly and are unchanged. Also checked: main's LeanerCloud#1397 envelope typing for getUpcomingPurchases sits next to this branch's 4th allSettled entry (listAccountsMinimal) in loadDashboard and merged cleanly. LeanerCloud#1368's "Select none" rename is the per-column popover button, separate from this branch's "Clear filters" (clearAllColumnFilters) action. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
In a categorical column filter, the footer button labelled "Clear" selects nothing, so a user trying to reset the filter got an empty table (UX-28). A refused user-form save was reported only through a fading toast or a native bubble that showed one problem at a time, with no field-level cue for screen readers (UX-33). This PR renames the categorical button to "Select none" and shows user-form errors inline under each field.
Refs #727
Partial: this PR does not change the group form. Main's #1339 already shows inline notes there for a blank name or permission row (
groups/groupFormValidation.ts); its Max Amount, unrepresentable-constraint and empty-permission refusals stay toast-only.What changed
994a233a, re-applied in the merge): the categorical footer button reads "Select none" (behavior unchanged); numeric filters keep "Clear". Applied in the sharedfrontend/src/lib/column-filter-popover.ts(Plans and both RI Exchange tables),frontend/src/lib/history-filter-popover.ts(Purchase History) andrecommendations.ts(Opportunities).89a109a5):frontend/src/lib/field-errors.ts(showFieldError,clearFieldError,clearFieldErrors): a.field-errormessage under the field or after a given anchor row,aria-invalid, the message appended toaria-describedby(existing help text stays announced), cleared on the nextinput/change.users/userModals.ts:saveUsercollects every problem at once (blank or malformed email, password rules on create, no group, contradictory groups), marks each field and focuses the first. The existing group and password toasts are kept. Opening the modal clears old messages.index.html:#user-formisnovalidate.styles/forms.css: lets the red border show on unfocused fields, since the.form-groupborder rule outranks the global[aria-invalid]one.4968c82c,24fc242c): newsrc/__tests__/form-validation-727.test.tsandtests-e2e/filter-select-none-and-user-form.spec.ts; main'scolumn-filter-popover.test.tsnow also asserts the "Select none" and "Clear" labels.994a233a,89a109a5,4968c82c, the merge with main9ab53a9a, and24fc242c(tests updated for main's scoped and shared filter popovers).Why this approach
novalidateplus app checks so every problem shows at once in the app's style; native bubbles would otherwise pre-empt the app's own group checks. Toasts stay for the messages that had them, so nothing existing regresses. The helper is inlib/so other forms can reuse it.Screenshots
Screenshots were taken before this branch was merged with main; before = main at a14dc8f. After is this branch at that point. Both are headless Chromium at 1440x900 against the repo's mocked e2e API.
Verification
Run on this branch's head
24fc242c.npm run lint: 0 errors. Typecheck and build pass.form-validation-727.test.ts(11 tests: helper placement,aria-describedbykept and restored, clear on edit; user form shows all problems with focus on the first, blank email, contradictory groups inline plus toast, clear then save, hidden password ignored on edit, reopen resets; history popover "Select none" commits an empty set and numeric "Clear" commitsnull).column-filter-popover.test.tschecks both labels on the shared popover.filter-select-none-and-user-form.spec.ts(2 tests). Full suite viae2e-local.sh: 203 passed.test-git-secrets-allowlist: 137 PASS.frontend/src/plans.tsandfrontend/src/riexchange.tsresolved, see the merge commit.Notes for review
lib/field-errorsand main'sgroups/groupFormValidation.ts). They differ onaria-describedby: this one appends to it, main's replaces it. They could be unified in a follow-up, which could also move group Max Amount onto inline errors.Overlaps
styles/forms.css(both add a block just above.form-help); keep both.Note for the UI owner
This changes UI code that @cristim owns. IAmJSD reviewed the before/after screenshots and asked for it to be merged; any design point you disagree with can be a follow-up.
🤖 Generated with Claude Code