@@ -331,7 +331,12 @@ function OrganizationSsoSettings({ organizationId }: SSOProps) {
331331 return out
332332 }
333333
334- const validateAll = ( data : typeof formData ) => {
334+ /**
335+ * `isReplacingSecret` is a parameter rather than a closure read: callers that
336+ * validate in the same tick as toggling it would otherwise see the previous
337+ * value and leave a stale "required" error on a field that is no longer an input.
338+ */
339+ const validateAll = ( data : typeof formData , isReplacingSecret = isReplacingClientSecret ) => {
335340 const newErrors : Record < string , string [ ] > = {
336341 providerType : [ ] ,
337342 providerId : validateProviderId ( data . providerId ) ,
@@ -354,7 +359,7 @@ function OrganizationSsoSettings({ organizationId }: SSOProps) {
354359 // clicked the field is a real input again, so a blank or whitespace-only
355360 // value has to fail rather than quietly overwrite a working secret.
356361 newErrors . clientSecret =
357- hasStoredClientSecret && ! isReplacingClientSecret
362+ hasStoredClientSecret && ! isReplacingSecret
358363 ? [ ]
359364 : validateRequired ( 'Client Secret' , data . clientSecret )
360365 if ( ! data . scopes || ! data . scopes . trim ( ) ) {
@@ -483,6 +488,18 @@ function OrganizationSsoSettings({ organizationId }: SSOProps) {
483488 validateAll ( next )
484489 }
485490
491+ /**
492+ * Backs out of a replacement: drops what was typed and revalidates as "keeping
493+ * the saved secret", so a required-error from a failed submit does not linger on
494+ * a row that is no longer an input.
495+ */
496+ const handleKeepSavedSecret = ( ) => {
497+ setIsReplacingClientSecret ( false )
498+ const next = { ...formData , clientSecret : '' }
499+ setFormData ( next )
500+ validateAll ( next , false )
501+ }
502+
486503 const isSaml = formData . providerType === 'saml'
487504 const mappingDefaults = isSaml ? SAML_DEFAULT_MAPPING : OIDC_DEFAULT_MAPPING
488505 const callbackUrl = `${ getBaseUrl ( ) } /api/auth/${ isSaml ? 'sso/saml2/callback' : 'sso/callback' } /${ formData . providerId || existingProvider ?. providerId || 'provider-id' } `
@@ -822,10 +839,7 @@ function OrganizationSsoSettings({ organizationId }: SSOProps) {
822839 storedHint = { storedClientSecretHint }
823840 isReplacing = { isReplacingClientSecret }
824841 onReplace = { ( ) => setIsReplacingClientSecret ( true ) }
825- onCancelReplace = { ( ) => {
826- setIsReplacingClientSecret ( false )
827- handleInputChange ( 'clientSecret' , '' )
828- } }
842+ onCancelReplace = { handleKeepSavedSecret }
829843 value = { formData . clientSecret }
830844 onChange = { ( next ) => handleInputChange ( 'clientSecret' , next ) }
831845 hasError = { showErrors && errors . clientSecret . length > 0 }
0 commit comments