Skip to content

Add useFormValidation hook and migrate the user forms onto it - #50435

Draft
nulmete wants to merge 2 commits into
mainfrom
useFormValidationHook
Draft

Add useFormValidation hook and migrate the user forms onto it#50435
nulmete wants to merge 2 commits into
mainfrom
useFormValidationHook

Conversation

@nulmete

@nulmete nulmete commented Aug 3, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #48220, resolves #48269

Every Fleet form re-implements validation state by hand, so behavior drifts between them: errors appear on untouched fields, submit buttons disable while a field is invalid, and error copy is inconsistent. #49041 documented the target behavior but nothing implements it yet.

This adds a useFormValidation hook as the single source of truth for those rules and migrates the new/edit user and API-only user forms onto it as the reference implementations. The remaining forms migrate in follow-ups.

Checklist for submitter

If some of the following don't apply, delete the relevant line.

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    See Changes files for more information.

  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.

  • Timeouts are implemented and retries are limited to avoid infinite loops

  • If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes

Testing

For unreleased bug fixes in a release candidate, one of:

  • Confirmed that the fix is not expected to adversely impact load test results
  • Alerted the release DRI if additional load testing is needed

Database migrations

  • Checked schema for all modified table for columns that will auto-update timestamps during migration.
  • Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects.
  • Ensured the correct collation is explicitly set for character columns (COLLATE utf8mb4_unicode_ci).

New Fleet configuration settings

  • Setting(s) is/are explicitly excluded from GitOps

If you didn't check the box above, follow this checklist for GitOps-enabled settings:

  • Verified that the setting is exported via fleetctl generate-gitops
  • Verified the setting is documented in a separate PR to the GitOps documentation
  • Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional)
  • Verified that any relevant UI is disabled when GitOps mode is enabled

fleetd/orbit/Fleet Desktop

  • Verified compatibility with the latest released version of Fleet (see Must rule)
  • If the change applies to only one platform, confirmed that runtime.GOOS is used as needed to isolate changes
  • Verified that fleetd runs on macOS, Linux and Windows
  • Verified auto-update works from the released version of component to the new version (see tools/tuf/test)

Summary by CodeRabbit

  • New Features

    • Added consistent validation across new user, edited user, and API user forms.
    • Validation errors appear after editing or submitting, clear when fields regain focus, and display inline.
    • Fleet-selection errors now appear directly on the selector.
    • Forms remain responsive during submission and support modal-footer submission.
  • Bug Fixes

    • Standardized email and password validation messages.
    • Improved handling and display of server-side field errors.
    • Prevented duplicate form submissions.

Adds frontend/hooks/useFormValidation.ts as the single source of truth for
the form validation behavior documented in frontend/docs/patterns.md, and
migrates UserForm and ApiUserForm onto it as the reference implementations.
Copilot AI review requested due to automatic review settings August 3, 2026 14:19
@nulmete

nulmete commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.50951% with 46 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.22%. Comparing base (1dc1a51) to head (8c904b6).
⚠️ Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
...n/ManageUsersPage/components/UserForm/UserForm.tsx 66.66% 25 Missing ⚠️
...n/ManageUsersPage/helpers/userManagementHelpers.ts 7.14% 13 Missing ⚠️
...geUsersPage/components/ApiUserForm/ApiUserForm.tsx 86.04% 5 Missing and 1 partial ⚠️
frontend/hooks/useFormValidation.ts 98.47% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #50435      +/-   ##
==========================================
+ Coverage   68.20%   68.22%   +0.01%     
==========================================
  Files        3943     3948       +5     
  Lines      251273   251465     +192     
  Branches    13406    13302     -104     
==========================================
+ Hits       171390   171562     +172     
- Misses      64532    64552      +20     
  Partials    15351    15351              
Flag Coverage Δ
frontend 61.44% <82.50%> (+0.14%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR adds the shared useFormValidation hook with dirty-field tracking, client and server errors, trimming, reset, and asynchronous submission handling. UserForm and ApiUserForm use the hook for validation and form state. Fleet errors render inline on selectors. Modal footer buttons can submit external forms through a native form identifier. User form error types and server-error prop names are standardized.

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR fixes the user-form behavior in #48269, but it does not satisfy major #48220 requirements such as documentation, Storybook coverage, and continuous on-change validation. Add the required documentation, Storybook state-transition example, reference component migration, and full-form on-change validation before merging.
Out of Scope Changes check ⚠️ Warning The API-only user form migration is outside #48220 and #48269, which focus on the shared hook and add/edit user form behavior. Move the API-only user form migration to a follow-up PR, or link an issue that explicitly includes this scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the new hook and the migration of user forms, which are the primary changes.
Description check ✅ Passed The description includes the related issues, implementation summary, testing section, and repository checklist, although checklist items remain unchecked.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch useFormValidationHook

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
frontend/pages/admin/ManageUsersPage/components/ApiUserForm/ApiUserForm.tsx (1)

139-144: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify onAccessTypeChange and confirm the intended endpoint-selection behavior.

On the isSpecific === true branch, api_endpoints: formData.api_endpoints re-assigns the current value. It adds no change but marks api_endpoints dirty. It also reads formData from the render closure rather than the hook's internal current value.

A user who selects "All API endpoints" and then returns to "Specific API endpoints" loses the previous endpoint list, because the first change sets it to []. Confirm that this reset is intended.

♻️ Proposed simplification
   const onAccessTypeChange = (isSpecific: boolean) => {
-    commitFields({
-      isSpecificEndpoints: isSpecific,
-      api_endpoints: isSpecific ? formData.api_endpoints : [],
-    });
+    commitFields(
+      isSpecific
+        ? { isSpecificEndpoints: true }
+        : { isSpecificEndpoints: false, api_endpoints: [] }
+    );
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/pages/admin/ManageUsersPage/components/ApiUserForm/ApiUserForm.tsx`
around lines 139 - 144, Update onAccessTypeChange to avoid reassigning
api_endpoints when isSpecific is true, and use the hook’s current field value
rather than the render-closure formData where needed. Preserve the existing
reset-to-empty behavior for the false branch only; confirm that switching back
to specific endpoints should not restore the previously cleared selections.
frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx (1)

672-703: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Use a per-instance id for the submit-form association.

FORM_ID is module-scoped, so multiple UserForm instances would render duplicate form ids. The modal submit button passes this through Button.formId as button.form, which can target the first matching form in this edge case. Derive formId per instance with useId and use it in both the <form id=...> and footer submit button.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx` around
lines 672 - 703, The module-scoped FORM_ID causes duplicate form identifiers
across UserForm instances. In the UserForm component, derive a per-instance
formId with useId and replace FORM_ID in both the form id attribute and the
footer submit Button’s formId prop, preserving the existing submit behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/hooks/useFormValidation.ts`:
- Around line 122-123: Implement the form-level isValid contract in
frontend/hooks/useFormValidation.ts: add isValid to the returned API without
using it to disable submission, recompute it after setField and commitFields
update form data, and recompute it during reset. Add coverage in
frontend/hooks/useFormValidation.tests.ts for invalid initial data,
valid/invalid transitions for text fields and committed controls, and reset
behavior.
- Around line 174-176: Remove the render-time assignments to validateRef,
skipTrimRef, and isSubmittingRef in the useFormValidation hook. Update these
refs from an effect or other non-render path, or refactor the stable callbacks
to avoid mutable latest-value refs while preserving access to the current
validator, trim setting, and submitting state.

---

Nitpick comments:
In `@frontend/pages/admin/ManageUsersPage/components/ApiUserForm/ApiUserForm.tsx`:
- Around line 139-144: Update onAccessTypeChange to avoid reassigning
api_endpoints when isSpecific is true, and use the hook’s current field value
rather than the render-closure formData where needed. Preserve the existing
reset-to-empty behavior for the false branch only; confirm that switching back
to specific endpoints should not restore the previously cleared selections.

In `@frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx`:
- Around line 672-703: The module-scoped FORM_ID causes duplicate form
identifiers across UserForm instances. In the UserForm component, derive a
per-instance formId with useId and replace FORM_ID in both the form id attribute
and the footer submit Button’s formId prop, preserving the existing submit
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2d1368eb-1ca2-4e7c-a79c-83d34df78d5b

📥 Commits

Reviewing files that changed from the base of the PR and between fd3da2f and 4b90627.

⛔ Files ignored due to path filters (2)
  • .claude/rules/fleet-frontend.md is excluded by !**/*.md
  • frontend/docs/patterns.md is excluded by !**/*.md
📒 Files selected for processing (13)
  • changes/use-form-validation-hook
  • frontend/components/buttons/Button/Button.tsx
  • frontend/hooks/useFormValidation.tests.ts
  • frontend/hooks/useFormValidation.ts
  • frontend/interfaces/user.ts
  • frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/UsersPage/UsersPage.tsx
  • frontend/pages/admin/ManageUsersPage/CreateUserPage/CreateUserPage.tsx
  • frontend/pages/admin/ManageUsersPage/EditUserPage/EditUserPage.tsx
  • frontend/pages/admin/ManageUsersPage/components/AddUserModal/AddUserModal.tsx
  • frontend/pages/admin/ManageUsersPage/components/ApiUserForm/ApiUserForm.tsx
  • frontend/pages/admin/ManageUsersPage/components/EditUserModal/EditUserModal.tsx
  • frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tests.tsx
  • frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx
💤 Files with no reviewable changes (1)
  • frontend/interfaces/user.ts

Comment thread frontend/hooks/useFormValidation.ts
Comment thread frontend/hooks/useFormValidation.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.

Pull request overview

This PR introduces a shared useFormValidation hook to standardize Fleet’s form validation behavior (error timing, clearing rules, submit checkpoint behavior, trimming, and in-flight guarding) and migrates the user-management forms to use it, along with updated docs and a small Button enhancement to support submit buttons rendered outside a <form>.

Changes:

  • Added frontend/hooks/useFormValidation.ts with unit tests, and documented it in frontend/docs/patterns.md and .claude/rules/fleet-frontend.md.
  • Migrated UserForm and ApiUserForm to the hook, including inline “select at least one fleet” errors and updated validation copy.
  • Updated user create/edit pages/modals to pass field-level API errors as serverErrors, and added Button support for submitting an external form via form attribute.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
frontend/pages/admin/ManageUsersPage/EditUserPage/EditUserPage.tsx Switches page-level error state to IFormErrors, updates server error copy, and passes serverErrors into UserForm.
frontend/pages/admin/ManageUsersPage/CreateUserPage/CreateUserPage.tsx Adds getFieldErrors helper for mapping API failures to inline errors; switches to IFormErrors and passes serverErrors.
frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx Refactors the core user add/edit form to useFormValidation, adds inline fleets error, and moves submission to <form onSubmit>.
frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tests.tsx Updates/extends tests for new validation behavior and copy; adds new test cases for submit/inline fleets error.
frontend/pages/admin/ManageUsersPage/components/EditUserModal/EditUserModal.tsx Updates prop types and passes serverErrors into UserForm.
frontend/pages/admin/ManageUsersPage/components/ApiUserForm/ApiUserForm.tsx Refactors API-only user form to useFormValidation, consolidating validation and submit flow.
frontend/pages/admin/ManageUsersPage/components/AddUserModal/AddUserModal.tsx Updates prop types and passes serverErrors into UserForm.
frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/UsersPage/UsersPage.tsx Updates local state types from IUserFormErrors to IFormErrors.
frontend/interfaces/user.ts Removes IUserFormErrors (no longer used after migration).
frontend/hooks/useFormValidation.ts Adds the new reusable form validation hook (dirty-gating, clear-on-focus, submit checkpoint, trimming, server error merge + toasts).
frontend/hooks/useFormValidation.tests.ts Adds unit tests for hook behavior (dirty gating, submit checkpoint, trimming, server errors, in-flight guarding).
frontend/docs/patterns.md Documents that useFormValidation implements the canonical validation rules and points to reference migrations.
frontend/components/buttons/Button/Button.tsx Adds formId prop to support submitting a sibling <form> via the HTML form attribute.
.claude/rules/fleet-frontend.md Updates validation guidance to prefer useFormValidation and references migrated forms.
Files excluded by content exclusion policy (1)
  • changes/use-form-validation-hook

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +213 to +235
const commitFields = useCallback((changes: Partial<TFormData>) => {
const next = { ...formDataRef.current, ...changes };
formDataRef.current = next;
setFormData(next);
Object.keys(changes).forEach((key) => dirtyFieldsRef.current.add(key));
setIsDirty(true);

const currentErrors = validateRef.current(next);
setErrors((prev) => {
const kept: IFormErrors = {};
let dropped = false;
Object.keys(prev).forEach((key) => {
if (currentErrors[key]) {
// Keep the message already on screen rather than the freshly computed
// one — a server error must not be overwritten by a client rule.
kept[key] = prev[key];
} else {
dropped = true;
}
});
return dropped ? kept : prev;
});
}, []);
Comment thread frontend/docs/patterns.md
…ApiUserForm

- Return the request promise from onSubmit so the hook's double-submit guard
  actually engages; the reference migrations were swallowing it.
- Extract getUserFieldErrors into userManagementHelpers so the same server
  reason reads identically from every screen that creates or edits a user.
  UsersPage still had pre-register copy, including a trailing period on a
  field error.
- Add ApiUserForm tests: dirty gate, clear-on-focus, inline "at least one"
  errors, conditional clearing, trimming, free-tier rules, in-flight disabling.
- Fix server errors being dropped by an unrelated commitFields, and the
  serverErrors effect looping on an inline object literal.
- Keep every returned callback identity stable, enforced by a test.
Copilot AI review requested due to automatic review settings August 3, 2026 16:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.

Pull request overview

Copilot reviewed 17 out of 18 changed files in this pull request and generated no new comments.

Files excluded by content exclusion policy (1)
  • changes/use-form-validation-hook
Suppressed comments (1)

frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx:251

  • For invite edits (isInvitePending), IEditInviteFormData requires password: null, but buildSubmitData currently always sets password to the local state string even when the password field is hidden. This can send password: "" to the invites API and break the request (and it’s inconsistent with the “hidden fields aren’t validated” rule above). Set password to null whenever the password section isn’t shown.
      email: data.email,
      name: data.name,
      newUserType: data.newUserType,
      password: data.password,
      sso_enabled: data.sso_enabled,

@nulmete
nulmete requested a review from Copilot August 3, 2026 16:23
@nulmete

nulmete commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/hooks/useFormValidation.ts (1)

242-264: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear the server-error exemption for fields updated through commitFields.

validateField (Line 295) and clearFieldError (Line 278) both remove a field from serverErrorFieldsRef when the user interacts with it, so a stale server verdict does not outlive the field it was reported on. commitFields marks the changed keys dirty (Line 246) but never removes them from serverErrorFieldsRef.

Text-input fields avoid the gap because their onFocus handler calls clearFieldError before any edit happens. Committed-control fields (radios, dropdowns, multi-selects) have no equivalent step: commitFields is the only interaction point. If a server error is ever mapped onto a field driven by commitFields, changing that field's value would not clear the exemption, so the stale server message would stay on screen until submit, reset, or an explicit clearFieldError/clearErrors call.

No current consumer (UserForm, ApiUserForm) maps a server error onto a commitFields-driven field, so this has no active impact today. Since this hook is the shared source of truth for future form migrations, fix it now to prevent this from surfacing as a real bug later.

🐛 Proposed fix
   const commitFields = useCallback((changes: Partial<TFormData>) => {
     const next = { ...formDataRef.current, ...changes };
     formDataRef.current = next;
     setFormData(next);
-    Object.keys(changes).forEach((key) => dirtyFieldsRef.current.add(key));
+    Object.keys(changes).forEach((key) => {
+      dirtyFieldsRef.current.add(key);
+      serverErrorFieldsRef.current.delete(key);
+    });
     setIsDirty(true);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/hooks/useFormValidation.ts` around lines 242 - 264, Update
commitFields to remove every key in changes from serverErrorFieldsRef.current
before recalculating errors, matching the cleanup behavior of validateField and
clearFieldError while preserving the existing dirty-state and validation flow.
frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/UsersPage/UsersPage.tsx (1)

66-75: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reset addUserErrors when the Add User modal toggles.

toggleEditUserModal clears editUserErrors on every toggle (Line 129), but toggleAddUserModal and toggleCreateUserModal never clear addUserErrors. AddUserModal fully unmounts when showCreateUserModal becomes false (Line 438) and remounts fresh when it becomes true again, so its internal useFormValidation state resets to {} on each reopen.

Because the server-error effect in useFormValidation shows and toasts any field in serverErrors that differs from its freshly-reset internal state, a stale addUserErrors value from a previous failed submission (set at Line 222 or Line 250) reappears immediately on the next "Add user" open, before the user types anything. This produces a false inline error and a false toast on a blank form.

Reset addUserErrors alongside the modal toggle, matching the pattern already used for editUserErrors.

🐛 Proposed fix
   const toggleCreateUserModal = useCallback(() => {
     setShowCreateUserModal(!showCreateUserModal);
     setShowAddUserModal(false);
+    setAddUserErrors({});
   }, [showCreateUserModal, setShowCreateUserModal, setShowAddUserModal]);

Also applies to: 134-137

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/UsersPage/UsersPage.tsx`
around lines 66 - 75, Update the add-user modal toggle handlers, specifically
toggleAddUserModal and toggleCreateUserModal, to clear addUserErrors whenever
the modal is toggled. Match the existing reset behavior in toggleEditUserModal
so reopening AddUserModal cannot reuse validation errors from a previous
submission.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@frontend/hooks/useFormValidation.ts`:
- Around line 242-264: Update commitFields to remove every key in changes from
serverErrorFieldsRef.current before recalculating errors, matching the cleanup
behavior of validateField and clearFieldError while preserving the existing
dirty-state and validation flow.

In
`@frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/UsersPage/UsersPage.tsx`:
- Around line 66-75: Update the add-user modal toggle handlers, specifically
toggleAddUserModal and toggleCreateUserModal, to clear addUserErrors whenever
the modal is toggled. Match the existing reset behavior in toggleEditUserModal
so reopening AddUserModal cannot reuse validation errors from a previous
submission.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 90edf46b-18b0-4e89-a3ff-ae6f16847da8

📥 Commits

Reviewing files that changed from the base of the PR and between 4b90627 and 8c904b6.

📒 Files selected for processing (11)
  • frontend/hooks/useFormValidation.tests.ts
  • frontend/hooks/useFormValidation.ts
  • frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/UsersPage/UsersPage.tsx
  • frontend/pages/admin/ManageUsersPage/CreateApiUserPage/CreateApiUserPage.tsx
  • frontend/pages/admin/ManageUsersPage/CreateUserPage/CreateUserPage.tsx
  • frontend/pages/admin/ManageUsersPage/EditUserPage/EditUserPage.tsx
  • frontend/pages/admin/ManageUsersPage/components/ApiUserForm/ApiUserForm.tests.tsx
  • frontend/pages/admin/ManageUsersPage/components/ApiUserForm/ApiUserForm.tsx
  • frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tests.tsx
  • frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx
  • frontend/pages/admin/ManageUsersPage/helpers/userManagementHelpers.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/pages/admin/ManageUsersPage/CreateUserPage/CreateUserPage.tsx
  • frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx
  • frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tests.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.

Pull request overview

Copilot reviewed 17 out of 18 changed files in this pull request and generated no new comments.

Files excluded by content exclusion policy (1)
  • changes/use-form-validation-hook
Suppressed comments (3)

frontend/pages/admin/ManageUsersPage/helpers/userManagementHelpers.ts:99

  • Doc comment grammar: “a users/invites API failure” reads incorrectly. Consider rephrasing to “a users or invites API failure” (or similar) for clarity.
/**
 * Maps a users/invites API failure to inline field errors, or null when the
 * failure isn't field-specific and belongs in a toast instead.
 */

frontend/hooks/useFormValidation.ts:297

  • validateField validates against the raw (untrimmed) form data, but handleSubmit validates against trimmed data. With validators like validEmail (no trimming), this can produce inconsistent UX (e.g., trailing spaces show an error on blur but submit succeeds). Consider validating blur against the same trimmed view (respecting skipTrim) to keep behavior consistent.
    // Blur hands the field back to client validation, so a server verdict on it
    // no longer applies.
    serverErrorFieldsRef.current.delete(name);
    const message = validateRef.current(formDataRef.current)[name];
    setErrors((prev) => {

frontend/pages/admin/ManageUsersPage/components/UserForm/UserForm.tsx:545

  • Password help text doesn’t mention the “at least 1 letter” requirement that the password validator enforces (and that the new invalid-format error copy mentions). This can confuse users who enter numbers+symbols only. Update the help text to match the actual rules.
        type="password"
        disabled={isSubmitting}
        helpText="12-48 characters, with at least 1 number (e.g. 0 - 9) and 1 symbol (e.g. &*#)."
        blockAutoComplete

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add/edit user form shows validation errors on untouched fields Frontend: Design useFormValidation hook with touched-tracking

2 participants