diff --git a/changes/25264-sso-form-validation b/changes/25264-sso-form-validation new file mode 100644 index 0000000000..b0fdf4435e --- /dev/null +++ b/changes/25264-sso-form-validation @@ -0,0 +1,2 @@ +- Fix form validation behavior on the SSO settings form. +- diff --git a/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx b/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx index 8c9d959358..5b0fc667d3 100644 --- a/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx +++ b/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx @@ -32,6 +32,50 @@ interface ISsoFormErrors { idp_name?: string | null; } +const validate = (formData: ISsoFormData) => { + const errors: ISsoFormErrors = {}; + + const { + enableSso, + idpImageUrl, + metadata, + metadataUrl, + entityId, + idpName, + } = formData; + + if (enableSso) { + if (idpImageUrl && !validUrl({ url: idpImageUrl })) { + errors.idp_image_url = `${idpImageUrl} is not a valid URL`; + } + + if (!metadata) { + if (!metadataUrl) { + errors.metadata_url = "Metadata or Metadata URL must be present"; + errors.metadata = "Metadata or Metadata URL must be present"; + } else if ( + !validUrl({ url: metadataUrl, protocols: ["http", "https"] }) + ) { + errors.metadata_url = `${metadataUrl} is not a valid URL`; + } + } + + if (!entityId) { + errors.entity_id = "Entity ID must be present"; + } + + if (typeof entityId === "string" && entityId.length < 5) { + errors.entity_id = "Entity ID must be 5 or more characters"; + } + + if (!idpName) { + errors.idp_name = "Identity provider name must be present"; + } + } + + return errors; +}; + const Sso = ({ appConfig, handleSubmit, @@ -64,51 +108,35 @@ const Sso = ({ const [formErrors, setFormErrors] = useState({}); const onInputChange = ({ name, value }: IFormField) => { - setFormData({ ...formData, [name]: value }); + const newFormData = { ...formData, [name]: value }; + setFormData(newFormData); + const newErrs = validate(newFormData); + // only set errors that are updates of existing errors + // new errors are only set onBlur or submit + const errsToSet: Record = {}; + Object.keys(formErrors).forEach((k) => { + // @ts-ignore + if (newErrs[k]) { + // @ts-ignore + errsToSet[k] = newErrs[k]; + } + }); + setFormErrors(errsToSet); }; - const validateForm = () => { - const errors: ISsoFormErrors = {}; - - if (enableSso) { - if (idpImageUrl && !validUrl({ url: idpImageUrl })) { - errors.idp_image_url = `${idpImageUrl} is not a valid URL`; - } - - if (!metadata) { - if (!metadataUrl) { - errors.metadata_url = "Metadata or Metadata URL must be present"; - errors.metadata = "Metadata or Metadata URL must be present"; - } else if ( - !validUrl({ url: metadataUrl, protocols: ["http", "https"] }) - ) { - errors.metadata_url = `${metadataUrl} is not a valid URL`; - } - } - - if (!entityId) { - errors.entity_id = "Entity ID must be present"; - } - - if (typeof entityId === "string" && entityId.length < 5) { - errors.entity_id = "Entity ID must be 5 or more characters"; - } - - if (!idpName) { - errors.idp_name = "Identity provider name must be present"; - } - } - - setFormErrors(errors); + const onInputBlur = () => { + setFormErrors(validate(formData)); }; - useEffect(() => { - validateForm(); - }, [idpImageUrl, metadata, metadataUrl, entityId, idpName]); - const onFormSubmit = (evt: React.MouseEvent) => { evt.preventDefault(); + const errs = validate(formData); + if (Object.keys(errs).length > 0) { + setFormErrors(errs); + return; + } + // Formatting of API not UI const formDataToSubmit = { sso_settings: { @@ -135,6 +163,7 @@ const Sso = ({
@@ -158,7 +187,7 @@ const Sso = ({ name="entityId" value={entityId} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.entity_id} tooltip="The required entity ID is a URI that you use to identify Fleet when configuring the identity provider." /> @@ -168,7 +197,7 @@ const Sso = ({ name="idpImageUrl" value={idpImageUrl} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.idp_image_url} tooltip={`An optional link to an image such as a logo for the identity provider.`} @@ -180,7 +209,7 @@ const Sso = ({ name="metadata" value={metadata} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.metadata} tooltip="Metadata XML provided by the identity provider." /> @@ -196,12 +225,13 @@ const Sso = ({ name="metadataUrl" value={metadataUrl} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.metadata_url} tooltip="Metadata URL provided by the identity provider." />