From 639c7ad6adc1962b9da974bbcee59a49613132e8 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 19 Aug 2025 08:07:01 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=AC=20feat:=20Agent=20Support=20Email?= =?UTF-8?q?=20Address=20Validation=20(#9128)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: email-regex realtime updates and looser validation * feat: add zod validation to email address input * refactor: emailValidation to email --- .../SidePanel/Agents/AgentConfig.tsx | 7 ++--- .../SidePanel/Agents/AgentPanel.tsx | 1 + .../components/SidePanel/Agents/MCPPanel.tsx | 1 + client/src/utils/email.ts | 28 +++++++++++++++++++ client/src/utils/index.ts | 1 + 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 client/src/utils/email.ts diff --git a/client/src/components/SidePanel/Agents/AgentConfig.tsx b/client/src/components/SidePanel/Agents/AgentConfig.tsx index 5d6c9a7cf..886fba378 100644 --- a/client/src/components/SidePanel/Agents/AgentConfig.tsx +++ b/client/src/components/SidePanel/Agents/AgentConfig.tsx @@ -8,6 +8,7 @@ import { processAgentOption, getEndpointField, defaultTextProps, + validateEmail, getIconKey, cn, } from '~/utils'; @@ -445,10 +446,8 @@ export default function AgentConfig({ createMutation }: Pick + validateEmail(value ?? '', localize('com_ui_support_contact_email_invalid')), }} render={({ field, fieldState: { error } }) => ( <> diff --git a/client/src/components/SidePanel/Agents/AgentPanel.tsx b/client/src/components/SidePanel/Agents/AgentPanel.tsx index 6d9d643ba..96fc43d27 100644 --- a/client/src/components/SidePanel/Agents/AgentPanel.tsx +++ b/client/src/components/SidePanel/Agents/AgentPanel.tsx @@ -72,6 +72,7 @@ export default function AgentPanel() { const models = useMemo(() => modelsQuery.data ?? {}, [modelsQuery.data]); const methods = useForm({ defaultValues: getDefaultAgentFormValues(), + mode: 'onChange', }); const { control, handleSubmit, reset } = methods; diff --git a/client/src/components/SidePanel/Agents/MCPPanel.tsx b/client/src/components/SidePanel/Agents/MCPPanel.tsx index 6e793f13f..e207a1530 100644 --- a/client/src/components/SidePanel/Agents/MCPPanel.tsx +++ b/client/src/components/SidePanel/Agents/MCPPanel.tsx @@ -65,6 +65,7 @@ export default function MCPPanel() { const methods = useForm({ defaultValues: defaultMCPFormValues, + mode: 'onChange', }); const { reset } = methods; diff --git a/client/src/utils/email.ts b/client/src/utils/email.ts new file mode 100644 index 000000000..b1ad6d7d1 --- /dev/null +++ b/client/src/utils/email.ts @@ -0,0 +1,28 @@ +import { z } from 'zod'; + +/** + * Zod email validation schema + * Uses Zod's built-in email validation which is more robust than simple regex + * Based on: https://zod.dev/api?id=emails + */ +export const emailSchema = z.string().email(); + +/** + * Validates an email address using Zod + * @param email - The email address to validate + * @param errorMessage - Optional custom error message (defaults to Zod's message) + * @returns true if valid, error message if invalid + */ +export const validateEmail = (email: string, errorMessage?: string): true | string => { + if (!email || email.trim() === '') { + return true; + } + + const result = emailSchema.safeParse(email); + return ( + result.success || + errorMessage || + result.error.errors[0]?.message || + 'Please enter a valid email address' + ); +}; diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts index 6fc179f56..07a1caecb 100644 --- a/client/src/utils/index.ts +++ b/client/src/utils/index.ts @@ -18,6 +18,7 @@ export * from './resources'; export * from './roles'; export * from './localStorage'; export * from './promptGroups'; +export * from './email'; export { default as cn } from './cn'; export { default as logger } from './logger'; export { default as buildTree } from './buildTree';