From 06d532993020d2e16f7fe8dc07efad6acc99affb Mon Sep 17 00:00:00 2001 From: Lily Delalande <119957291+lily-de@users.noreply.github.com> Date: Mon, 31 Mar 2025 11:26:59 -0400 Subject: [PATCH] ui: add validation to provider form (#1932) --- .../modal/ProviderConfiguationModal.tsx | 27 +++++++ .../forms/DefaultProviderSetupForm.tsx | 6 +- .../handlers/DefaultSubmitHandler.tsx | 78 ------------------- 3 files changed, 32 insertions(+), 79 deletions(-) diff --git a/ui/desktop/src/components/settings_v2/providers/modal/ProviderConfiguationModal.tsx b/ui/desktop/src/components/settings_v2/providers/modal/ProviderConfiguationModal.tsx index 2a23d6b7..85fff361 100644 --- a/ui/desktop/src/components/settings_v2/providers/modal/ProviderConfiguationModal.tsx +++ b/ui/desktop/src/components/settings_v2/providers/modal/ProviderConfiguationModal.tsx @@ -21,6 +21,7 @@ const customFormsMap = { export default function ProviderConfigurationModal() { const { upsert } = useConfig(); + const [validationErrors, setValidationErrors] = useState({}); const { isOpen, currentProvider, modalProps, closeModal } = useProviderModal(); const [configValues, setConfigValues] = useState({}); @@ -36,6 +37,31 @@ export default function ProviderConfigurationModal() { e.preventDefault(); console.log('Form submitted for:', currentProvider.name); + // Reset previous validation errors + setValidationErrors({}); + + // Validation logic + const parameters = currentProvider.metadata.config_keys || []; + const errors = {}; + + // Check required fields + parameters.forEach((parameter) => { + if ( + parameter.required && + (configValues[parameter.name] === undefined || + configValues[parameter.name] === null || + configValues[parameter.name] === '') + ) { + errors[parameter.name] = `${parameter.name} is required`; + } + }); + + // If there are validation errors, stop the submission + if (Object.keys(errors).length > 0) { + setValidationErrors(errors); + return; // Stop the submission process + } + try { // Wait for the submission to complete await SubmitHandler(upsert, currentProvider, configValues); @@ -79,6 +105,7 @@ export default function ProviderConfigurationModal() { configValues={configValues} setConfigValues={setConfigValues} provider={currentProvider} + validationErrors={validationErrors} {...(modalProps.formProps || {})} // Spread any custom form props /> diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx index f9af1abc..06263089 100644 --- a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx @@ -6,12 +6,14 @@ interface DefaultProviderSetupFormProps { configValues: Record; setConfigValues: React.Dispatch>>; provider: any; + validationErrors: any; } export default function DefaultProviderSetupForm({ configValues, setConfigValues, provider, + validationErrors, }: DefaultProviderSetupFormProps) { const parameters = provider.metadata.config_keys || []; const [isLoading, setIsLoading] = useState(true); @@ -107,7 +109,9 @@ export default function DefaultProviderSetupForm({ })) } placeholder={getPlaceholder(parameter)} - className="w-full h-14 px-4 font-regular rounded-lg border shadow-none border-gray-300 bg-white text-lg placeholder:text-gray-400 font-regular text-gray-900" + className={`w-full h-14 px-4 font-regular rounded-lg border shadow-none ${ + validationErrors[parameter.name] ? 'border-red-500' : 'border-gray-300' + } bg-white text-lg placeholder:text-gray-400 font-regular text-gray-900`} required={true} /> diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx index 94a6a2d3..59fea347 100644 --- a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx @@ -1,81 +1,3 @@ -import { useConfig } from '../../../../../ConfigContext'; -import React from 'react'; - -/** - * Custom hook for provider configuration submission - * Returns a submit handler function and submission state - */ -export const useDefaultSubmit = () => { - const { upsert } = useConfig(); - const [isSubmitting, setIsSubmitting] = React.useState(false); - const [error, setError] = React.useState(null); - const [isSuccess, setIsSuccess] = React.useState(false); - - /** - * Submit handler for provider configuration - * @param {Object} provider - The provider object with metadata - * @param {Object} configValues - The form values to be submitted - * @param {Function} onSuccess - Optional callback for successful submission - */ - const handleSubmit = async (provider, configValues, onSuccess) => { - setIsSubmitting(true); - setError(null); - setIsSuccess(false); - - try { - const parameters = provider.metadata.config_keys || []; - - // Create an array of promises for all the upsert operations - const upsertPromises = parameters.map((parameter) => { - // Skip parameters that don't have a value and aren't required - if (!configValues[parameter.name] && !parameter.required) { - return Promise.resolve(); - } - - // For required parameters with no value, use the default if available - const value = - configValues[parameter.name] !== undefined - ? configValues[parameter.name] - : parameter.default; - - // Skip if there's still no value - if (value === undefined || value === null) { - return Promise.resolve(); - } - - // Create the provider-specific config key - // Format: provider.{provider_name}.{parameter_name} - const configKey = `provider.${provider.name}.${parameter.name}`; - - // Pass the is_secret flag from the parameter definition - return upsert(configKey, value, parameter.secret || false); - }); - - // Wait for all upsert operations to complete - await Promise.all(upsertPromises); - - setIsSuccess(true); - - // Call the success callback if provided - if (onSuccess) { - onSuccess(); - } - } catch (err) { - console.error('Failed to save provider configuration:', err); - setError('Failed to save configuration. Please try again.'); - } finally { - setIsSubmitting(false); - } - }; - - return { - handleSubmit, - isSubmitting, - error, - isSuccess, - }; -}; - /** * Standalone function to submit provider configuration * Useful for components that don't want to use the hook