Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code b58a868b51 fix: wire fieldState.error to form inputs and remove noErrorHelper suppression
https://sonarly.com/issue/34230?type=bug

Over two-thirds of react-hook-form Controller instances in the frontend don't destructure or pass `fieldState.error` to their input components, causing validation messages from Zod schemas to be silently swallowed. Additionally, several forms explicitly suppress error helper text via `noErrorHelper={true}`.

Fix: Fixed validation feedback in three form components by wiring Zod validation errors through to the UI:

**1. SSO OIDC Form (`SettingsSSOOIDCForm.tsx`)**
Added `fieldState: { error }` destructuring and `error={error?.message}` prop to all 3 Controller inputs (clientID, clientSecret, issuer). These fields have `z.string().nonempty()` validation in `SSOIdentityProviderSchema.ts` but the errors were never surfaced — users could submit empty required fields with no feedback.

**2. SSO Identity Providers Form (`SettingsSSOIdentitiesProvidersForm.tsx`)**
Added the same error wiring to the "name" Controller input, which also has a `z.string().nonempty()` validation in the schema.

**3. Data Model Object About Form (`SettingsDataModelObjectAboutForm.tsx`)**
Removed `noErrorHelper={true}` from 3 SettingsTextInput instances (labelSingular, labelPlural, and API name fields). These inputs already correctly pass `error={errors.fieldName?.message}` — but the `noErrorHelper` prop was suppressing the error text display, leaving only red borders with no explanatory message. The associated TODO comments ("we should discuss on how to notify user about form validation schema issue, from now just displaying red borders") confirm this was tech debt, not a design choice. Removed those TODOs as they're now resolved.

All changes follow the identical pattern used in properly-wired forms throughout the codebase (PasswordReset.tsx, CreateProfile.tsx, CreateWorkspace.tsx, SettingsAccountsConnectionForm.tsx, etc.).

Note: This PR addresses the most impactful subset of the reported issue. Additional forms (NameField.tsx, NameFields.tsx, ApiKeyNameInput.tsx) still use raw `useState` instead of react-hook-form and would need larger refactors to add validation — those are tracked by existing TODO comments in the codebase.
2026-05-04 20:39:52 +00:00
3 changed files with 20 additions and 10 deletions
@@ -193,8 +193,6 @@ export const SettingsDataModelObjectAboutForm = ({
render={({ field: { onChange, value }, formState: { errors } }) => (
<SettingsTextInput
instanceId={labelSingularTextInputId}
// TODO we should discuss on how to notify user about form validation schema issue, from now just displaying red borders
noErrorHelper={true}
error={errors.labelSingular?.message}
label={t`Singular`}
placeholder={t`Listing`}
@@ -218,8 +216,6 @@ export const SettingsDataModelObjectAboutForm = ({
render={({ field: { onChange, value }, formState: { errors } }) => (
<SettingsTextInput
instanceId={labelPluralTextInputId}
// TODO we should discuss on how to notify user about form validation schema issue, from now just displaying red borders
noErrorHelper={true}
error={errors.labelPlural?.message}
label={t`Plural`}
placeholder={t`Listings`}
@@ -325,8 +321,6 @@ export const SettingsDataModelObjectAboutForm = ({
maxLength={OBJECT_NAME_MAXIMUM_LENGTH}
onBlur={() => onNewDirtyField?.()}
error={errors[fieldName]?.message}
// TODO we should discuss on how to notify user about form validation schema issue, from now just displaying red borders
noErrorHelper={true}
RightIcon={() =>
tooltip && (
<>
@@ -87,13 +87,17 @@ export const SettingsSSOIdentitiesProvidersForm = () => {
<Controller
name="name"
control={control}
render={({ field: { onChange, value } }) => (
render={({
field: { onChange, value },
fieldState: { error },
}) => (
<SettingsTextInput
instanceId="sso-identity-provider-name"
autoComplete="off"
label={t`Name`}
value={value}
onChange={onChange}
error={error?.message}
fullWidth
placeholder={t`Google OIDC`}
/>
@@ -109,13 +109,17 @@ export const SettingsSSOOIDCForm = () => {
<Controller
name="clientID"
control={control}
render={({ field: { onChange, value } }) => (
render={({
field: { onChange, value },
fieldState: { error },
}) => (
<SettingsTextInput
instanceId="sso-oidc-client-id"
autoComplete="off"
label={t`Client ID`}
value={value}
onChange={onChange}
error={error?.message}
fullWidth
placeholder="900960562328-36306ohbk8e3.apps.googleusercontent.com"
/>
@@ -124,7 +128,10 @@ export const SettingsSSOOIDCForm = () => {
<Controller
name="clientSecret"
control={control}
render={({ field: { onChange, value } }) => (
render={({
field: { onChange, value },
fieldState: { error },
}) => (
<SettingsTextInput
instanceId="sso-oidc-client-secret"
autoComplete="off"
@@ -132,6 +139,7 @@ export const SettingsSSOOIDCForm = () => {
label={t`Client Secret`}
value={value}
onChange={onChange}
error={error?.message}
fullWidth
placeholder="****************************"
/>
@@ -140,13 +148,17 @@ export const SettingsSSOOIDCForm = () => {
<Controller
name="issuer"
control={control}
render={({ field: { onChange, value } }) => (
render={({
field: { onChange, value },
fieldState: { error },
}) => (
<SettingsTextInput
instanceId="sso-oidc-issuer"
autoComplete="off"
label={t`Issuer URI`}
value={value}
onChange={onChange}
error={error?.message}
fullWidth
placeholder="https://accounts.google.com"
/>