refactor(ui): migrate console forms to react-hook-form (team#152)#6619
refactor(ui): migrate console forms to react-hook-form (team#152)#6619luannmoreira wants to merge 12 commits into
Conversation
|
Claude finished @luannmoreira's task in 8m 26s —— View job Code Review CompleteReviewed 17 files across code quality, security, testing, language patterns, and architecture. 1 inline issue posted (1 medium). Additional notes
Otherwise the migration is solid: the resolver If you've addressed the feedback and want a new review, tag |
70c7ed4 to
443179b
Compare
|
/review |
|
Claude finished @otavio's task in 19m 54s —— View job Code Review CompleteReviewed the current PR head (
Findings posted inline:
Additional notes
If you've addressed the feedback and want a new review, tag |
c9b603e to
34f31d7
Compare
- Restore the positive-integer rule for firewall priority (reject 0 and negatives), matching the field hint and pre-migration behavior. - Validate on clearing the secure-vault passphrase so isValid/errors stay in sync when swapping in a different encrypted key. - Rework the firewall tags test to verify the 3-tag selector cap instead of passing on a valid 3-tag selection.
34f31d7 to
797df19
Compare
|
/review |
|
Claude finished @otavio's task in 12m 43s —— View job Code Review CompleteReviewed 69 files across code quality, security, testing, TypeScript/React patterns, and architecture/cross-repo — no new issues found. The code looks good as-is. The four issues from the previous review rounds are all confirmed fixed in
Spot-checks that came back clean: removed symbols ( If you push additional changes and want a new review, tag |
797df19 to
3aafeb6
Compare
|
/review |
|
Claude finished @otavio's task in 6m 39s —— View job Code Review CompleteReviewed 69 files across code quality, security, testing, TypeScript/React patterns, and architecture/cross-repo — no new issues found. The code looks good as-is. All four issues from previous review rounds remain resolved at the current head (
Spot-checks that came back clean:
If you push additional changes and want a new review, tag |
3aafeb6 to
5a16b59
Compare
5a16b59 to
da33d37
Compare
…rimitives Introduce the shared foundation for the console form standardization (shellhub-io/team#152): FormDrawer owns the Drawer, form element, and Cancel/Submit footer; useDrawerForm wraps useForm with zodResolver and reset-on-open; FormRootError renders form-level server errors; and the react-hook-form field wrappers (FormNumericInput, FormRadioGroupField, FormTagsSelector, FormTextareaField, FormToggleField) bridge useController over the design-system inputs. Adds the react-hook-form and zod dependencies.
da33d37 to
9aef980
Compare
|
/review |
|
Claude finished @otavio's task in 16m 4s —— View job Code Review CompleteReviewed 66 files across code quality, security, testing, TypeScript/React patterns, and architecture/cross-repo. 1 inline issue posted (1 low).
Additional notesOtherwise the migration is clean at the current head:
If you've addressed the feedback and want a new review, tag |
9aef980 to
dcb6183
Compare
|
/review |
|
Claude finished @otavio's task in 8m 47s —— View job Code Review CompleteReviewed 66 files across code quality, security, testing, TypeScript/React patterns, and architecture/cross-repo. 1 inline issue posted (1 low).
Additional notesOtherwise the migration remains clean at the current head:
If you've addressed the feedback and want a new review, tag |
Migrate the edit-profile and change-password drawers to the shared react-hook-form + zod architecture (shellhub-io/team#152). Validation moves into editProfileSchema.ts and changePasswordSchema.ts as the single source of truth; required fields validate unconditionally and the recovery email stays optional with its cross-field rule re-running when the primary email changes. Form-level server errors use RHF root errors.
Migrate the Settings rename-namespace drawer to react-hook-form + zod (shellhub-io/team#152). The namespace-name rule lives in namespaceRenameSchema.ts and the rename error surfaces through an RHF root error. The session-recording and device-auto-accept toggles and the delete/leave dialogs are left as-is.
Migrate the admin SAML configuration drawer to react-hook-form + zod (shellhub-io/team#152). All business logic (certificate normalization, payload shaping) moves into samlSchema.ts, with the drawer reduced to field wrappers over the schema.
Migrate the firewall rule drawer to react-hook-form + zod (shellhub-io/team#152). ruleSchema.ts replaces the hand-rolled resolver as the single source of truth, and the drawer composes FormDrawer with the shared field wrappers.
Migrate the public key drawer to react-hook-form + zod (shellhub-io/team#152). keySchema.ts owns validation and payload shaping; the drawer composes FormDrawer with the shared field wrappers.
Migrate the secure vault key drawer to react-hook-form + zod (shellhub-io/team#152). vaultKeySchema.ts owns validation, and the drawer composes FormDrawer with the shared field wrappers.
Migrate the admin create/edit user drawers to react-hook-form + zod (shellhub-io/team#152). userSchema.ts becomes the single source of truth and the bespoke useUserForm hook is removed; the drawers compose FormDrawer with the shared field wrappers.
…m + zod Migrate the admin edit-namespace drawer to react-hook-form + zod (shellhub-io/team#152). editNamespaceSchema.ts owns validation; the drawer composes FormDrawer with the shared field wrappers.
…+ zod Migrate the New / Edit announcement full-page forms to react-hook-form + zod (shellhub-io/team#152). announcementSchema.ts owns validation; the pages use useForm with zodResolver directly rather than FormDrawer.
…+ zod Migrate the add-member and edit-member-role drawers to react-hook-form + zod (shellhub-io/team#152). The add-member and edit-role schemas live in team/schemas.ts, and constants.tsx gains FormRoleSelector — a react-hook-form binding over the shared RoleSelector used across the team drawers.
…-form + zod Migrate the generate-key and edit-key drawers to react-hook-form + zod (shellhub-io/team#152). The generate-key and edit-key schemas live in team/schemas.ts, including the string-bound expiry that is converted to the numeric API value in buildGenerateKeyBody. The generate-key drawer swaps to a result view after submit, so it composes useDrawerForm + field wrappers + FormRootError under a raw Drawer rather than FormDrawer.
dcb6183 to
69657da
Compare
|
/review |
|
Claude finished @otavio's task in 9m 9s —— View job Code Review CompleteReviewed 66 files across code quality, security, testing, TypeScript/React patterns, and architecture/cross-repo — no new issues found. The code looks good as-is. All prior-round issues remain resolved at the current head (
Spot-checks that came back clean:
If you push additional changes and want a new review, tag |
Summary
Migrates every console drawer and page form to a single react-hook-form + Zod architecture (tracked in shellhub-io/team#152). All in-scope forms now share one validation, submit, reset, and error-handling model, and the legacy
makeRhfResolveradapter is removed.The pilot (SignUp) and the auth/onboarding forms were merged separately and are intentionally left on their existing resolvers (converted in a later PR).
Architecture — four layers
components/common/fields/rhf/*) — thinuseControllerbridges over the design-system inputs (FormInputField,FormPasswordField,FormNumericInput,FormCheckboxField,FormRadioGroupField,FormTextareaField,FormToggleField).FormToggleFieldnow renders its validation error like the other fields and uses the design-systemToggleprimitive.*Schema.tsper form as the single source of truth: a Zod schema (aschema(mode)factory where rules are mode-dependent),type X = z.infer<...>,buildXDefaults, andbuildXBody. All business logic (trimming,parseInt, payload shaping, SAML cert normalization) lives here, not in components.useDrawerForm(open, schema, defaults)wrapsuseForm({ resolver: zodResolver(schema), mode: "onChange" })and standardizes reset-on-open. The resolver uses a ref-based wrapper to avoid the stale-resolver bug when the schema changes between renders.FormDrawerowns theDrawer,<form>, Cancel/Submit footer (disabled on!isValid || isSubmitting, optionalrequireDirty), and the sharedFormRootError.A new form = write
xSchema.ts+ a drawer that callsuseDrawerFormand renders<FormDrawer>with field wrappers. No hand-rolled resolver, reset, submit, or root-error code.Migrated forms
Account & settings: profile (edit-profile + change-password), namespace rename, SAML config.
Resources: firewall rule, public key, secure vault key.
Admin: create/edit user (bespoke
useUserFormhook removed), edit namespace, announcements — new/edit (full-page forms usinguseForm+zodResolverdirectly, noFormDrawer).Team: add/edit member, generate/edit API key.
Two dual-mode drawers (Add Member, Generate Key) swap to a result view after submit, so they compose
useDrawerForm+ field wrappers +FormRootErrorunder a rawDrawerrather thanFormDrawer.Cleanup
makeRhfResolverand its test, and the per-form resolver adapters —zodResolver(schema)insideuseDrawerFormis now the only resolver.schema.safeParsetests with equivalent coverage.Behavior change
FormDrawergates the submit button onisValid, so an invalid form now keeps submit disabled rather than enabled-but-blocked-on-click. A few drawer/page assertions were updated accordingly (async enable viawaitFor; the invitation email field flags itself invalid inline as typed).Test plan
npm run build(tsc + vite) passesnpm run lintpasses (0 errors)