From 495fddc4e6d382637ef372266aca8f8abfa8b3c4 Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Thu, 2 Jan 2025 10:30:41 -0800 Subject: [PATCH] UI - Improve validation of SMTP settings form (#25051) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## #25009 - Update validation to match pattern defined in `frontend/docs/patterns.md` - Validate email even when not enabling the feature, since we allow setting it - Remove "CONFIGURED" and "NOT CONFIGURED" copy Screenshot 2024-12-30 at 11 27 08 AM Screenshot 2024-12-30 at 11 27 16 AM Screenshot 2024-12-30 at 11 27 24 AM Screenshot 2024-12-30 at 11 44 10 AM - [x] Changes file added for user-visible changes in `changes/` - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling --- changes/25009-smtp-page-validation | 1 + .../pages/admin/OrgSettingsPage/_styles.scss | 12 -- .../admin/OrgSettingsPage/cards/Smtp/Smtp.tsx | 146 ++++++++++-------- 3 files changed, 82 insertions(+), 77 deletions(-) create mode 100644 changes/25009-smtp-page-validation diff --git a/changes/25009-smtp-page-validation b/changes/25009-smtp-page-validation new file mode 100644 index 0000000000..4dee1c5ab9 --- /dev/null +++ b/changes/25009-smtp-page-validation @@ -0,0 +1 @@ +- Improve validation workflow on SMTP settings page diff --git a/frontend/pages/admin/OrgSettingsPage/_styles.scss b/frontend/pages/admin/OrgSettingsPage/_styles.scss index 9919e5865f..10d7a76b4a 100644 --- a/frontend/pages/admin/OrgSettingsPage/_styles.scss +++ b/frontend/pages/admin/OrgSettingsPage/_styles.scss @@ -58,18 +58,6 @@ em { font-style: normal; } - - &--configured { - em { - color: $ui-success; - } - } - - &--notconfigured { - em { - color: $ui-error; - } - } } } diff --git a/frontend/pages/admin/OrgSettingsPage/cards/Smtp/Smtp.tsx b/frontend/pages/admin/OrgSettingsPage/cards/Smtp/Smtp.tsx index d1f6160a5b..eaef7914de 100644 --- a/frontend/pages/admin/OrgSettingsPage/cards/Smtp/Smtp.tsx +++ b/frontend/pages/admin/OrgSettingsPage/cards/Smtp/Smtp.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useContext } from "react"; +import React, { useState, useContext } from "react"; import { AppContext } from "context/app"; @@ -43,6 +43,54 @@ interface ISmtpConfigFormErrors { password?: string | null; } +const validateFormData = (newData: ISmtpConfigFormData) => { + const errors: ISmtpConfigFormErrors = {}; + + const { + enableSMTP, + smtpSenderAddress, + smtpServer, + smtpPort, + smtpAuthenticationType, + smtpUsername, + smtpPassword, + } = newData; + + if (enableSMTP) { + if (!smtpSenderAddress) { + errors.sender_address = "SMTP sender address must be present"; + } else if (!validEmail(smtpSenderAddress)) { + errors.sender_address = `${smtpSenderAddress} is not a valid email`; + } + + if (!smtpServer) { + errors.server = "SMTP server must be present"; + } + if (!smtpPort) { + errors.server = "SMTP server port must be present"; + errors.server_port = "Port"; + } + if (!smtpServer && !smtpPort) { + errors.server = "SMTP server and server port must be present"; + errors.server_port = "Port"; + } + if (smtpAuthenticationType === "authtype_username_password") { + if (smtpUsername === "") { + errors.user_name = "SMTP username must be present"; + } + if (smtpPassword === "") { + errors.password = "SMTP password must be present"; + } + } + } else if (smtpSenderAddress && !validEmail(smtpSenderAddress)) { + // validations for valid submissions even when smtp not enabled, i.e., updating what will be + // used once it IS enabled + errors.sender_address = `${smtpSenderAddress} is not a valid email`; + } + + return errors; +}; + const baseClass = "app-config-form"; const Smtp = ({ @@ -82,50 +130,35 @@ const Smtp = ({ const sesConfigured = appConfig.email?.backend === "ses" || false; const onInputChange = ({ name, value }: IFormField) => { - setFormData({ ...formData, [name]: value }); + const newFormData = { ...formData, [name]: value }; + setFormData(newFormData); + const newErrs = validateFormData(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: ISmtpConfigFormErrors = {}; - - if (enableSMTP) { - if (!smtpSenderAddress) { - errors.sender_address = "SMTP sender address must be present"; - } else if (!validEmail(smtpSenderAddress)) { - errors.sender_address = `${smtpSenderAddress} is not a valid email`; - } - - if (!smtpServer) { - errors.server = "SMTP server must be present"; - } - if (!smtpPort) { - errors.server = "SMTP server port must be present"; - errors.server_port = "Port"; - } - if (!smtpServer && !smtpPort) { - errors.server = "SMTP server and server port must be present"; - errors.server_port = "Port"; - } - if (smtpAuthenticationType === "authtype_username_password") { - if (smtpUsername === "") { - errors.user_name = "SMTP username must be present"; - } - if (smtpPassword === "") { - errors.password = "SMTP password must be present"; - } - } - } - - setFormErrors(errors); + const onInputBlur = () => { + setFormErrors(validateFormData(formData)); }; - useEffect(() => { - validateForm(); - }, [smtpAuthenticationType]); - const onFormSubmit = (evt: React.MouseEvent) => { evt.preventDefault(); + const errs = validateFormData(formData); + if (Object.keys(errs).length > 0) { + setFormErrors(errs); + return; + } + // Formatting of API not UI const formDataToSubmit = { smtp_settings: { @@ -157,7 +190,7 @@ const Smtp = ({ name="smtpUsername" value={smtpUsername} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.user_name} blockAutoComplete /> @@ -168,7 +201,7 @@ const Smtp = ({ name="smtpPassword" value={smtpPassword} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.password} blockAutoComplete /> @@ -177,6 +210,7 @@ const Smtp = ({ options={authMethodOptions} placeholder="" onChange={onInputChange} + onBlur={onInputBlur} name="smtpAuthenticationMethod" value={smtpAuthenticationMethod} parseTarget @@ -205,6 +239,7 @@ const Smtp = ({
@@ -228,7 +263,7 @@ const Smtp = ({ name="smtpServer" value={smtpServer} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.server} tooltip="The hostname / private IP address and corresponding port of your organization's SMTP server." /> @@ -239,12 +274,13 @@ const Smtp = ({ name="smtpPort" value={smtpPort} parseTarget - onBlur={validateForm} + onBlur={onInputBlur} error={formErrors.server_port} />
- - - {appConfig.smtp_settings?.configured - ? "CONFIGURED" - : "NOT CONFIGURED"} - - - ) : ( - <> - ) - } - /> + {sesConfigured ? renderSesEnabled() : renderSmtpForm()}