Skip to content

Conversation

Lokowitz
Copy link
Owner

@Lokowitz Lokowitz commented Sep 22, 2025

Community Contribution License Agreement

By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.

Description

How to test?

Summary by CodeRabbit

  • Chores

    • Updated form resolver dependency to a newer version for compatibility and stability.
  • New Features

    • Added a subnet field to organization general settings.
  • Bug Fixes / Minor Changes

    • Minor form initialization and typing adjustments across settings and auth flows; runtime behavior preserved.
    • OTP submission form now includes an OTP field in its default state.

Copy link

coderabbitai bot commented Sep 22, 2025

Walkthrough

Removed explicit generic type parameters from many react-hook-form useForm(...) calls across app pages and components and bumped @hookform/resolvers from 4.1.3 → 5.2.2; one form default gained an otp field and one explicit default-values type assertion was removed.

Changes

Cohort / File(s) Summary
Dependency version bump
package.json
Updated dependency @hookform/resolvers from 4.1.35.2.2.
App pages — assorted form hooks
src/app/... (e.g. src/app/admin/idp/.../general/page.tsx, src/app/admin/idp/create/page.tsx, src/app/admin/idp/.../policies/page.tsx, src/app/admin/api-keys/create/page.tsx, src/app/auth/*, src/app/setup/page.tsx, src/app/[orgId]/settings/..., src/app/[orgId]/settings/resources/*, src/app/[orgId]/settings/sites/*, src/app/[orgId]/settings/clients/*, src/app/[orgId]/settings/api-keys/*, src/app/[orgId]/settings/general/page.tsx)
Removed explicit generic type parameters from useForm<...>(...) calls (now useForm(...)) while keeping resolvers/defaultValues. Notable small changes: subnet/defaults expanded in src/app/[orgId]/settings/general/page.tsx; removed as z.infer<...> assertion on addTargetForm defaultValues in src/app/[orgId]/settings/resources/create/page.tsx.
Components — form hooks & minor defaults
src/components/* (e.g. src/components/IdpCreateWizard.tsx, src/components/LoginForm.tsx, src/components/ResetPasswordForm.tsx, src/components/ResourceAuthPortal.tsx, src/components/SecurityKeyForm.tsx, src/components/SetResourcePasswordForm.tsx, src/components/SetResourcePincodeForm.tsx, src/components/SignupForm.tsx, src/components/SupporterStatus.tsx, src/components/TwoFactorSetupForm.tsx, src/components/VerifyEmailForm.tsx)
Removed explicit generic type parameters from many useForm<...>(...) calls (now useForm(...)). In src/components/ResourceAuthPortal.tsx the submitOtpForm defaultValues were expanded to include otp: "". No control-flow or runtime behavior changes otherwise.

Sequence Diagram(s)

(No sequence diagram — changes are type/initializer updates and a dependency bump; control flow is unchanged.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

Poem

I hop through code with ears held high,
I nudge one type and watch it fly.
Resolvers updated, generics set free,
I groom the defaults beneath a tree.
A tiny nibble, a joyful byte—🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title "bbbv" is vague and does not describe the primary changes in this pull request (which include a dependency bump of @hookform/resolvers and removing explicit useForm generics across many files), so it does not provide a useful summary for reviewers or future history. Please rename the title to a concise, descriptive sentence (for example: "Bump @hookform/resolvers to 5.2.2 and remove explicit useForm generics") and update the PR body with a short description and testing steps so reviewers can understand intent and verify changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Resolver

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4cc38d4 and 1e066cb.

📒 Files selected for processing (2)
  • src/components/SetResourcePasswordForm.tsx (1 hunks)
  • src/components/SetResourcePincodeForm.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/SetResourcePasswordForm.tsx
  • src/components/SetResourcePincodeForm.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/app/admin/idp/[idpId]/general/page.tsx (1)

77-91: Restore type-safety for react-hook-form.

Dropping the generic erases field typing, weakening validation and making FormField names untyped while onSubmit still expects GeneralFormValues.

Apply:

-const form = useForm({
+const form = useForm<GeneralFormValues>({
   resolver: zodResolver(GeneralFormSchema),
   defaultValues: {
     ...
   }
});
🧹 Nitpick comments (2)
src/app/admin/idp/[idpId]/general/page.tsx (2)

203-207: Duplicate form IDs and multiple form tags.

Three <form id="general-settings-form"> instances violate HTML uniqueness and can confuse UA/accessibility. Since all sections share one RHF instance, prefer a single form or at least unique IDs.

Low‑impact fix (remove duplicate IDs):

-<form
-  onSubmit={form.handleSubmit(onSubmit)}
-  className="space-y-4"
-  id="general-settings-form"
->
+<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">

Do this for the second and third forms. Keep the ID only on the primary form referenced by the bottom Save button.

Also applies to: 262-266, 363-367


72-73: Align default for autoProvision.

Schema default(false) conflicts with RHF defaultValues(true). Pick one source of truth to avoid confusion during resets.

Suggested:

- autoProvision: z.boolean().default(false)
+ autoProvision: z.boolean()

(or set both defaults to the same value).

Also applies to: 89-90

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61ecebf and 2bd4ad5.

📒 Files selected for processing (1)
  • src/app/admin/idp/[idpId]/general/page.tsx (2 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
src/app/admin/idp/[idpId]/general/page.tsx

[error] 1-1: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)

🪛 GitHub Actions: ESLint
src/app/admin/idp/[idpId]/general/page.tsx

[error] 1-1: ESLint parsing error: Unexpected keyword or identifier. Command 'npx eslint . --ext .js,.jsx,.ts,.tsx' failed.

🪛 GitHub Actions: Run Tests
src/app/admin/idp/[idpId]/general/page.tsx

[error] 1-1: Next.js build failed due to syntax error in page.tsx: 'w"use client";' -> Expected ';', '}' or .

🔇 Additional comments (1)
src/app/admin/idp/[idpId]/general/page.tsx (1)

3-3: Resolver/RHF/Zod compatibility — partial verification

package.json shows [email protected], @hookform/[email protected], [email protected] — these versions are compatible: @hookform/resolvers v5 targets RHF v7 and supports zod v3 (use zodResolver from '@hookform/resolvers/zod'). (npmjs.com)

Zod v4 is supported via a separate resolver (zodResolverV4) added in PR fosrl#776; only switch if you upgrade to zod v4. (github.com)

Sandbox ripgrep failed with "unrecognized file type: tsx" so I could not verify typed vs untyped useForm across the repo — re-run a local scan without --type flags, e.g.: rg -nP -C1 '\buseForm\s*(?:<[^>]+>)?\s*(' --hidden -g '!node_modules'.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (3)
src/app/[orgId]/settings/clients/create/page.tsx (3)

91-110: CIDR validation likely broken: z.string().ip() rejects “10.0.0.0/24”

Elsewhere you treat subnets as CIDR (e.g., remoteSubnets). Use a CIDR regex or a dedicated validator; ip() only accepts plain IPs.

-        subnet: z.string().ip().min(1, {
-            message: t("subnetRequired")
-        })
+        subnet: z
+            .string()
+            .regex(
+                /^(?:\d{1,3}\.){3}\d{1,3}\/(?:[0-9]|[12][0-9]|3[0-2])$/,
+                { message: t("subnetRequired") }
+            )

339-376: “latest” fallback breaks download URLs; fix asset URL building (and Windows flow)

When the GitHub API call times out/fails, you set version="latest" but still build links as /releases/download/latest/..., which 404s. Also, the Windows sequence downloads the installer then immediately runs “olm.exe” without installing.

Apply these changes to (1) compute a correct assetBaseUrl and (2) use it inside hydrateCommands; also adjust Windows commands to run the installer first.

-    const hydrateCommands = (
-        id: string,
-        secret: string,
-        endpoint: string,
-        version: string
-    ) => {
+    const hydrateCommands = (
+        id: string,
+        secret: string,
+        endpoint: string,
+        assetBaseUrl: string
+    ) => {
         const commands = {
             mac: {
                 "Apple Silicon (arm64)": [
-                    `curl -L -o olm "https://github.com/fosrl/olm/releases/download/${version}/olm_darwin_arm64" && chmod +x ./olm`,
+                    `curl -L -o olm "${assetBaseUrl}/olm_darwin_arm64" && chmod +x ./olm`,
                     `sudo ./olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ],
                 "Intel x64 (amd64)": [
-                    `curl -L -o olm "https://github.com/fosrl/olm/releases/download/${version}/olm_darwin_amd64" && chmod +x ./olm`,
+                    `curl -L -o olm "${assetBaseUrl}/olm_darwin_amd64" && chmod +x ./olm`,
                     `sudo ./olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ]
             },
             linux: {
                 amd64: [
-                    `wget -O olm "https://github.com/fosrl/olm/releases/download/${version}/olm_linux_amd64" && chmod +x ./olm`,
+                    `wget -O olm "${assetBaseUrl}/olm_linux_amd64" && chmod +x ./olm`,
                     `sudo ./olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ],
                 arm64: [
-                    `wget -O olm "https://github.com/fosrl/olm/releases/download/${version}/olm_linux_arm64" && chmod +x ./olm`,
+                    `wget -O olm "${assetBaseUrl}/olm_linux_arm64" && chmod +x ./olm`,
                     `sudo ./olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ],
                 arm32: [
-                    `wget -O olm "https://github.com/fosrl/olm/releases/download/${version}/olm_linux_arm32" && chmod +x ./olm`,
+                    `wget -O olm "${assetBaseUrl}/olm_linux_arm32" && chmod +x ./olm`,
                     `sudo ./olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ],
                 arm32v6: [
-                    `wget -O olm "https://github.com/fosrl/olm/releases/download/${version}/olm_linux_arm32v6" && chmod +x ./olm`,
+                    `wget -O olm "${assetBaseUrl}/olm_linux_arm32v6" && chmod +x ./olm`,
                     `sudo ./olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ],
                 riscv64: [
-                    `wget -O olm "https://github.com/fosrl/olm/releases/download/${version}/olm_linux_riscv64" && chmod +x ./olm`,
+                    `wget -O olm "${assetBaseUrl}/olm_linux_riscv64" && chmod +x ./olm`,
                     `sudo ./olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ]
             },
             windows: {
                 x64: [
-                    `curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/olm_windows_installer.exe"`,
-                    `# Run the installer to install olm and wintun`,
+                    `curl -L -o olm_windows_installer.exe "${assetBaseUrl}/olm_windows_installer.exe"`,
+                    `start /wait "" olm_windows_installer.exe`,
                     `olm.exe --id ${id} --secret ${secret} --endpoint ${endpoint}`
                 ]
             }
         };
         setCommands(commands);
     };
@@
-            let olmVersion = "latest";
+            let assetBaseUrl = "https://github.com/fosrl/olm/releases/latest/download";
@@
-                const latestVersion = data.tag_name;
-                olmVersion = latestVersion;
+                const latestVersion = data.tag_name;
+                if (typeof latestVersion === "string" && latestVersion.trim()) {
+                    assetBaseUrl = `https://github.com/fosrl/olm/releases/download/${latestVersion}`;
+                }
@@
-                        hydrateCommands(
-                            olmId,
-                            olmSecret,
-                            env.app.dashboardUrl,
-                            olmVersion
-                        );
+                        hydrateCommands(
+                            olmId,
+                            olmSecret,
+                            env.app.dashboardUrl,
+                            assetBaseUrl
+                        );

300-311: Fix inverted Axios generics — use the response data type (T), not AxiosResponse

You're passing AxiosResponse as the axios generic; change to T because axios methods return AxiosResponse (the generic should describe the response data shape).

Location: src/app/[orgId]/settings/clients/create/page.tsx (around lines 300–328)

Suggested fixes:

-            .put<
-                AxiosResponse<CreateClientResponse>
-            >(`/org/${orgId}/client`, payload)
+            .put<CreateClientResponse>(`/org/${orgId}/client`, payload)
-            const res = await api.get<AxiosResponse<ListSitesResponse>>(
-                `/org/${orgId}/sites/`
-            );
+            const res = await api.get<ListSitesResponse>(
+                `/org/${orgId}/sites/`
+            );

Search & fix across the repo:

rg -nP '\b(?:get|post|put|patch|delete)\s*<\sAxiosResponse<' -g '.ts' -g '*.tsx' -C2

🧹 Nitpick comments (24)
src/app/[orgId]/settings/clients/create/page.tsx (1)

268-276: Restore strong typing on useForm to keep field names/types checked

Dropping the generic degrades type safety and IntelliSense on form methods/fields.

-    const form = useForm({
+    const form = useForm<CreateClientFormValues>({
       resolver: zodResolver(createClientFormSchema),
       defaultValues: {
         name: "",
         method: "olm",
         siteIds: [],
         subnet: ""
       }
     });
src/app/[orgId]/settings/sites/[niceId]/general/page.tsx (1)

67-80: Keep form types explicit for GeneralFormValues

Un-typed useForm weakens compile-time guarantees (e.g., name/remoteSubnets keys).

-    const form = useForm({
+    const form = useForm<GeneralFormValues>({
       resolver: zodResolver(GeneralFormSchema),
       defaultValues: {
         name: site?.name,
         dockerSocketEnabled: site?.dockerSocketEnabled ?? false,
         remoteSubnets: site?.remoteSubnets
           ? site.remoteSubnets.split(",").map((subnet, index) => ({
               id: subnet.trim(),
               text: subnet.trim()
             }))
           : []
       },
       mode: "onChange"
     });

Also double-check Line 58: createApiClient(useEnvContext()) vs other files’ pattern createApiClient({ env }). Ensure the function signature matches to avoid subtle runtime issues.

src/app/auth/initial-setup/page.tsx (1)

54-62: Preserve typed form values

Re-introduce the schema-driven generic to avoid any-typed form fields.

-    const form = useForm({
+    const form = useForm<z.infer<typeof formSchema>>({
       resolver: zodResolver(formSchema),
       defaultValues: {
         setupToken: "",
         email: "",
         password: "",
         confirmPassword: ""
       }
     });
src/components/VerifyEmailForm.tsx (1)

83-89: Type the form instance to FormSchema

Keeps field names and handlers aligned with Zod.

-    const form = useForm({
+    const form = useForm<z.infer<typeof FormSchema>>({
       resolver: zodResolver(FormSchema),
       defaultValues: {
         email: email,
         pin: ""
       }
     });
src/app/admin/idp/create/page.tsx (1)

82-97: Re-add CreateIdpFormValues typing to form

Avoids accidental key typos and keeps setValue/getValues typed.

-    const form = useForm({
+    const form = useForm<CreateIdpFormValues>({
       resolver: zodResolver(createIdpFormSchema),
       defaultValues: {
         name: "",
         type: "oidc",
         clientId: "",
         clientSecret: "",
         authUrl: "",
         tokenUrl: "",
         identifierPath: "sub",
         namePath: "name",
         emailPath: "email",
         scopes: "openid profile email",
         autoProvision: false
       }
     });

There are multiple forms in this file sharing id="create-idp-form". Please verify DOM id uniqueness to avoid unintended submissions.

src/app/[orgId]/settings/access/users/create/page.tsx (3)

164-171: Type internalForm with its schema

-    const internalForm = useForm({
+    const internalForm = useForm<z.infer<typeof internalFormSchema>>({
       resolver: zodResolver(internalFormSchema),
       defaultValues: {
         email: "",
         validForHours: "72",
         roleId: ""
       }
     });

173-180: Type googleAzureForm with its schema

-    const googleAzureForm = useForm({
+    const googleAzureForm = useForm<z.infer<typeof googleAzureFormSchema>>({
       resolver: zodResolver(googleAzureFormSchema),
       defaultValues: {
         email: "",
         name: "",
         roleId: ""
       }
     });

182-190: Type genericOidcForm with its schema

-    const genericOidcForm = useForm({
+    const genericOidcForm = useForm<z.infer<typeof genericOidcFormSchema>>({
       resolver: zodResolver(genericOidcFormSchema),
       defaultValues: {
         username: "",
         email: "",
         name: "",
         roleId: ""
       }
     });
src/components/SetResourcePincodeForm.tsx (1)

68-71: Retain SetPincodeFormValues typing

-    const form = useForm({
+    const form = useForm<SetPincodeFormValues>({
       resolver: zodResolver(setPincodeFormSchema),
       defaultValues
     });

Line 145: autoComplete="false" isn’t a valid value; consider "one-time-code" or "off" for better UX/autofill behavior.

src/app/setup/page.tsx (1)

53-60: Type orgForm to z.infer

-    const orgForm = useForm({
+    const orgForm = useForm<z.infer<typeof orgSchema>>({
       resolver: zodResolver(orgSchema),
       defaultValues: {
         orgName: "",
         orgId: "",
         subnet: ""
       }
     });
src/components/SupporterStatus.tsx (2)

81-87: Dropping useForm generics reduces type-safety

Runtime is unchanged, but you lose compile-time checks that form field names match schema. Consider keeping the generic or annotating the return type to preserve safety.

Suggested pattern:

-const form = useForm({
+const form = useForm<z.infer<typeof formSchema>>({
   resolver: zodResolver(formSchema),
   defaultValues: { githubUsername: "", key: "" }
})

238-239: Fix i18n key typo ('supportKetOptionFull')

Likely meant 'supportKeyOptionFull'. This will render a missing translation.

Apply:

-<CardTitle>{t('supportKetOptionFull')}</CardTitle>
+<CardTitle>{t('supportKeyOptionFull')}</CardTitle>
src/app/admin/idp/[idpId]/policies/page.tsx (1)

105-112: Un-typed useForm weakens compile-time guarantees

Forms now accept any shape. Given onSubmit handlers are typed, consider retaining generics to ensure field-name drift is caught during builds.

For example:

-const form = useForm({
+const form = useForm<PolicyFormValues>({
   resolver: zodResolver(policyFormSchema),
   defaultValues: { orgId: "", roleMapping: "", orgMapping: "" }
})

-const defaultMappingsForm = useForm({
+const defaultMappingsForm = useForm<DefaultMappingsValues>({
   resolver: zodResolver(defaultMappingsSchema),
   defaultValues: { defaultRoleMapping: "", defaultOrgMapping: "" }
})

Also applies to: 114-120

src/app/[orgId]/settings/general/page.tsx (2)

62-69: useForm without generics removes helpful type checks

If intentional across the repo, fine; otherwise keep the inferred type to prevent silent field-name mismatches.

-const form = useForm({
+const form = useForm<GeneralFormValues>({
   resolver: zodResolver(GeneralFormSchema),
   defaultValues: { name: org?.org.name, subnet: org?.org.subnet || "" },
   mode: "onChange"
})

54-58: Avoid double useEnvContext() and standardize api client init

You call useEnvContext() twice and pass the hook result directly to createApiClient here, while other files pass { env }. Normalize and remove the extra hook call.

Apply:

-const api = createApiClient(useEnvContext());
+const { env } = useEnvContext();
+const api = createApiClient({ env });
 const { user } = useUserContext();
 const t = useTranslations();
-const { env } = useEnvContext();
src/app/admin/license/page.tsx (2)

100-106: Untyped form instance

Same note: removing generics trades off type safety. Consider keeping them.

-const form = useForm({
+const form = useForm<z.infer<typeof formSchema>>({
   resolver: zodResolver(formSchema),
   defaultValues: { licenseKey: "", agreeToTerms: false }
})

438-439: Fix i18n key typos

These look misspelled and will likely fail at runtime.

-{t('licenseReckeckAll')}
+{t('licenseRecheckAll')}
-{t('licenseSiteUsageDecsription')}
+{t('licenseSiteUsageDescription')}

Also applies to: 446-447

src/components/SignupForm.tsx (1)

120-129: Type-safety regression on form

Keeping the generic helps catch schema/field mismatches early.

-const form = useForm({
+const form = useForm<z.infer<typeof formSchema>>({
   resolver: zodResolver(formSchema),
   defaultValues: {
     email: emailParam || "",
     password: "",
     confirmPassword: "",
     agreeToTerms: false
   },
   mode: "onChange"
})
src/app/[orgId]/settings/api-keys/create/page.tsx (1)

94-99: Both forms lost their value types

Recommend keeping generics so refactors don’t silently break fields.

-const form = useForm({
+const form = useForm<CreateFormValues>({
   resolver: zodResolver(createFormSchema),
   defaultValues: { name: "" }
})

-const copiedForm = useForm({
+const copiedForm = useForm<CopiedFormValues>({
   resolver: zodResolver(copiedFormSchema),
   defaultValues: { copied: true }
})

Also applies to: 101-106

src/app/[orgId]/settings/resources/[niceId]/authentication/page.tsx (1)

141-144: Preserve generics to avoid TagInput typing gaps

Given Tag arrays and the existing ts-ignore for TagInput elsewhere in this file, keeping form generics helps reduce casts/ignores.

-const usersRolesForm = useForm({
+const usersRolesForm = useForm<z.infer<typeof UsersRolesFormSchema>>({
   resolver: zodResolver(UsersRolesFormSchema),
   defaultValues: { roles: [], users: [] }
})

-const whitelistForm = useForm({
+const whitelistForm = useForm<z.infer<typeof whitelistSchema>>({
   resolver: zodResolver(whitelistSchema),
   defaultValues: { emails: [] }
})

Also applies to: 146-149

src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx (1)

277-283: Typed forms recommended for settings groups

Keeping generics on these three forms protects settings payloads during refactors.

-const tlsSettingsForm = useForm({
+const tlsSettingsForm = useForm<TlsSettingsValues>({
   resolver: zodResolver(tlsSettingsSchema),
   defaultValues: { ssl: resource.ssl, tlsServerName: resource.tlsServerName || "" }
})

-const proxySettingsForm = useForm({
+const proxySettingsForm = useForm<ProxySettingsValues>({
   resolver: zodResolver(proxySettingsSchema),
   defaultValues: { setHostHeader: resource.setHostHeader || "", headers: resource.headers }
})

-const targetsSettingsForm = useForm({
+const targetsSettingsForm = useForm<TargetsSettingsValues>({
   resolver: zodResolver(targetsSettingsSchema),
   defaultValues: { stickySession: resource.stickySession }
})

Also applies to: 285-292, 293-299

src/app/[orgId]/settings/resources/create/page.tsx (2)

214-220: Keep schema-derived generics on useForm (base/http/tcpUdp).

The change weakens type safety across form fields and consumers.

-    const baseForm = useForm({
+    const baseForm = useForm<BaseResourceFormValues>({
       resolver: zodResolver(baseResourceFormSchema),
       defaultValues: {
         name: "",
         http: true
       }
     });

-    const httpForm = useForm({
+    const httpForm = useForm<HttpResourceFormValues>({
       resolver: zodResolver(httpResourceFormSchema),
       defaultValues: {}
     });

-    const tcpUdpForm = useForm({
+    const tcpUdpForm = useForm<TcpUdpResourceFormValues>({
       resolver: zodResolver(tcpUdpResourceFormSchema),
       defaultValues: {
         protocol: "tcp",
         proxyPort: undefined
         // enableProxy: false
       }
     });

Also applies to: 222-226, 227-234


236-245: Avoid the as any as number default; use a controlled numeric field.

The double cast hides errors and may introduce "" into numeric flows.

Prefer undefined default and mirror the controlled pattern used for proxyPort:

 const addTargetForm = useForm({
   resolver: zodResolver(addTargetSchema),
   defaultValues: {
     ip: "",
     method: baseForm.watch("http") ? "http" : null,
-    port: "" as any as number,
+    port: undefined,
     path: null,
     pathMatchType: null
   }
 });

And update the port field to control value/parse (outside the hunk, shown for completeness):

-<Input
-  id="port"
-  type="number"
-  {...field}
-  required
-/>
+<Input
+  id="port"
+  type="number"
+  value={field.value ?? ""}
+  onChange={(e) =>
+    field.onChange(
+      e.target.value ? parseInt(e.target.value, 10) : undefined
+    )
+  }
+  required
+/>
src/components/ResourceAuthPortal.tsx (1)

138-144: Preserve strong typing on all four useForm instances.

Re‑add generics to retain field‑level type safety and better DX.

-const pinForm = useForm({
+const pinForm = useForm<z.infer<typeof pinSchema>>({
   resolver: zodResolver(pinSchema),
   defaultValues: { pin: "" }
 });

-const passwordForm = useForm({
+const passwordForm = useForm<z.infer<typeof passwordSchema>>({
   resolver: zodResolver(passwordSchema),
   defaultValues: { password: "" }
 });

-const requestOtpForm = useForm({
+const requestOtpForm = useForm<z.infer<typeof requestOtpSchema>>({
   resolver: zodResolver(requestOtpSchema),
   defaultValues: { email: "" }
 });

-const submitOtpForm = useForm({
+const submitOtpForm = useForm<z.infer<typeof submitOtpSchema>>({
   resolver: zodResolver(submitOtpSchema),
   defaultValues: { email: "", otp: "" }
 });

Also applies to: 145-151, 152-158, 159-165

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bab070b and 4cc38d4.

📒 Files selected for processing (31)
  • src/app/[orgId]/settings/access/users/[userId]/access-controls/page.tsx (1 hunks)
  • src/app/[orgId]/settings/access/users/create/page.tsx (3 hunks)
  • src/app/[orgId]/settings/api-keys/create/page.tsx (1 hunks)
  • src/app/[orgId]/settings/clients/[clientId]/general/page.tsx (1 hunks)
  • src/app/[orgId]/settings/clients/create/page.tsx (1 hunks)
  • src/app/[orgId]/settings/general/page.tsx (1 hunks)
  • src/app/[orgId]/settings/resources/[niceId]/authentication/page.tsx (1 hunks)
  • src/app/[orgId]/settings/resources/[niceId]/general/page.tsx (1 hunks)
  • src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx (2 hunks)
  • src/app/[orgId]/settings/resources/[niceId]/rules/page.tsx (1 hunks)
  • src/app/[orgId]/settings/resources/create/page.tsx (2 hunks)
  • src/app/[orgId]/settings/sites/[niceId]/general/page.tsx (1 hunks)
  • src/app/[orgId]/settings/sites/create/page.tsx (1 hunks)
  • src/app/admin/api-keys/create/page.tsx (1 hunks)
  • src/app/admin/idp/[idpId]/policies/page.tsx (2 hunks)
  • src/app/admin/idp/create/page.tsx (1 hunks)
  • src/app/admin/license/page.tsx (1 hunks)
  • src/app/auth/initial-setup/page.tsx (1 hunks)
  • src/app/auth/reset-password/ResetPasswordForm.tsx (2 hunks)
  • src/app/setup/page.tsx (1 hunks)
  • src/components/IdpCreateWizard.tsx (1 hunks)
  • src/components/LoginForm.tsx (1 hunks)
  • src/components/ResetPasswordForm.tsx (2 hunks)
  • src/components/ResourceAuthPortal.tsx (1 hunks)
  • src/components/SecurityKeyForm.tsx (2 hunks)
  • src/components/SetResourcePasswordForm.tsx (1 hunks)
  • src/components/SetResourcePincodeForm.tsx (1 hunks)
  • src/components/SignupForm.tsx (1 hunks)
  • src/components/SupporterStatus.tsx (1 hunks)
  • src/components/TwoFactorSetupForm.tsx (1 hunks)
  • src/components/VerifyEmailForm.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • src/app/[orgId]/settings/resources/[niceId]/general/page.tsx
  • src/components/SecurityKeyForm.tsx
  • src/app/auth/reset-password/ResetPasswordForm.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/ResourceAuthPortal.tsx (1)
server/auth/passwordSchema.ts (1)
  • passwordSchema (3-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (11)
src/components/IdpCreateWizard.tsx (1)

87-103: Restore form generic: useForm

useForm currently lacks a generic which removes form type-safety — add and search the repo for other untyped useForm calls.

Apply:

-    const form = useForm({
+    const form = useForm<CreateIdpFormValues>({
       resolver: zodResolver(createIdpFormSchema),
       defaultValues: {
         name: "",
         type: "oidc",
         clientId: "",
         clientSecret: "",
         authUrl: "",
         tokenUrl: "",
         identifierPath: "sub",
         namePath: "name",
         emailPath: "email",
         scopes: "openid profile email",
         autoProvision: false,
         ...defaultValues
       }
     });

Quick repo check (run locally):

rg -n --hidden --glob '!**/node_modules/**' -g '*.{ts,tsx}' "useForm(" -S || true
rg -n --hidden --glob '!**/node_modules/**' -g '*.{ts,tsx}' "useForm<" -S || true
src/app/[orgId]/settings/access/users/[userId]/access-controls/page.tsx (1)

66-73: Consistent with library upgrade to rely on type inference.

The change from explicit generic types to inference aligns with the broader upgrade to @hookform/resolvers 5.2.2 and follows the pattern established across the codebase. Most resolvers can infer the output type from the schema automatically, making explicit type annotations redundant.

src/app/[orgId]/settings/resources/[niceId]/rules/page.tsx (1)

117-124: Type inference works correctly with zodResolver.

The removal of explicit generic type parameters is appropriate here. The zodResolver automatically infers the output type from the schema, maintaining the same runtime validation behavior while simplifying the type annotations.

src/app/admin/api-keys/create/page.tsx (1)

92-97: Multiple form instances updated consistently.

Both form instances (main form and copied form) have been updated to use type inference instead of explicit generics. The resolver configuration and defaultValues remain unchanged, ensuring runtime behavior is preserved while benefiting from the improved type inference capabilities of the newer resolver version.

Also applies to: 99-104

src/components/TwoFactorSetupForm.tsx (1)

94-99: Form typing modernization maintains functionality.

Both enableForm and confirmForm have been updated to use type inference. The resolver configuration using zodResolver and defaultValues remain intact, preserving the component's validation logic while following the modern pattern enabled by the resolver library upgrade.

Also applies to: 101-106

src/components/LoginForm.tsx (1)

83-89: Authentication forms updated properly.

Both the main login form and MFA form have been consistently updated to use type inference. The zodResolver configuration ensures type safety is maintained through schema inference rather than explicit generic parameters.

Also applies to: 91-96

src/app/[orgId]/settings/sites/create/page.tsx (1)

428-437: Large form with complex defaultValues handled correctly.

The site creation form maintains all its resolver configuration and complex defaultValues structure while benefiting from the simplified type annotation approach. The createSiteFormSchema provides strong typing through inference.

src/components/SetResourcePasswordForm.tsx (1)

64-67: Password form maintains type safety.

The form configuration preserves the resolver and defaultValues while using the modern inference approach. The onSubmit function signature still uses the explicit SetPasswordFormValues type, ensuring proper typing for the handler.

src/app/[orgId]/settings/clients/[clientId]/general/page.tsx (1)

61-68: Client settings form updated consistently.

The general settings form follows the same pattern as other forms in the PR, removing explicit generic types while maintaining resolver configuration. The form's complex Tag array handling in defaultValues continues to work with inferred types.

src/components/ResourceAuthPortal.tsx (1)

159-165: LGTM: added otp to defaultValues.

This aligns the form state with the OTP input and avoids undefined reads.

src/components/ResetPasswordForm.tsx (1)

105-113: Restore strong typing for all useForm instances.

Dropping generics removes compile-time checks on field names/values — keep schema-derived types or confirm resolver-driven inference is supported by your dependency versions.

File: src/components/ResetPasswordForm.tsx (lines 105–113, 115–121, 122–128)

-    const form = useForm({
+    const form = useForm<z.infer<typeof formSchema>>({
       resolver: zodResolver(formSchema),
       defaultValues: {
         email: emailParam || "",
         token: tokenParam || "",
         password: "",
         confirmPassword: ""
       }
     });

-    const mfaForm = useForm({
+    const mfaForm = useForm<z.infer<typeof mfaSchema>>({
       resolver: zodResolver(mfaSchema),
       defaultValues: {
         code: ""
       }
     });

-    const requestForm = useForm({
+    const requestForm = useForm<z.infer<typeof requestSchema>>({
       resolver: zodResolver(requestSchema),
       defaultValues: {
         email: emailParam || ""
       }
     });

If relying on resolver-driven inference, confirm the project uses react-hook-form v7 + @hookform/resolvers v5 (or newer).

@Lokowitz Lokowitz closed this Sep 23, 2025
@Lokowitz Lokowitz deleted the Resolver branch September 26, 2025 10:43
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.

1 participant