diff --git a/client/src/components/AppsTab.tsx b/client/src/components/AppsTab.tsx index 2b6d75358..8df67e305 100644 --- a/client/src/components/AppsTab.tsx +++ b/client/src/components/AppsTab.tsx @@ -127,9 +127,29 @@ const AppsTab = ({ }, []); // Function to check if any form has validation errors + const validateJsonParams = useCallback(() => { + const validatedParams = { ...params }; + let hasErrors = false; + + for (const [key, ref] of Object.entries(formRefs.current)) { + if (!ref) continue; + + const result = ref.validateJson(); + if (!result.isValid) { + hasErrors = true; + } else if (result.value !== undefined) { + validatedParams[key] = result.value; + } + } + + setHasValidationErrors(hasErrors); + if (!hasErrors) setParams(validatedParams); + return { hasErrors, validatedParams }; + }, [params]); + const checkValidationErrors = useCallback(() => { const errors = Object.values(formRefs.current).some( - (ref) => ref && !ref.validateJson().isValid, + (ref) => ref && ref.hasJsonError(), ); setHasValidationErrors(errors); return errors; @@ -249,12 +269,15 @@ const AppsTab = ({ }, []); const handleOpenApp = useCallback(async () => { - if (!selectedTool || checkValidationErrors()) { + if (!selectedTool) { return; } - await executeToolAndOpenApp(selectedTool, params); - }, [checkValidationErrors, executeToolAndOpenApp, params, selectedTool]); + const { hasErrors, validatedParams } = validateJsonParams(); + if (hasErrors) return; + + await executeToolAndOpenApp(selectedTool, validatedParams); + }, [executeToolAndOpenApp, selectedTool, validateJsonParams]); const handleSelectTool = useCallback( (tool: Tool) => { diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index ba1cc73f9..34e85cd70 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -27,7 +27,11 @@ interface DynamicJsonFormProps { } export interface DynamicJsonFormRef { - validateJson: () => { isValid: boolean; error: string | null }; + validateJson: () => { + isValid: boolean; + error: string | null; + value?: JsonValue; + }; hasJsonError: () => boolean; } @@ -245,10 +249,10 @@ const DynamicJsonForm = forwardRef( }; const validateJson = () => { - if (!isJsonMode) return { isValid: true, error: null }; + if (!isJsonMode) return { isValid: true, error: null, value }; try { const jsonStr = rawJsonValue?.trim(); - if (!jsonStr) return { isValid: true, error: null }; + if (!jsonStr) return { isValid: true, error: null, value }; const parsed = JSON.parse(jsonStr); // Clear any pending debounced update and immediately update parent if (timeoutRef.current) { @@ -256,7 +260,7 @@ const DynamicJsonForm = forwardRef( } onChange(parsed); setJsonError(undefined); - return { isValid: true, error: null }; + return { isValid: true, error: null, value: parsed }; } catch (err) { const errorMessage = err instanceof Error ? err.message : "Invalid JSON"; diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 15b85fd67..cc92f81ca 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -224,6 +224,26 @@ const ToolsTab = ({ return errors; }; + const validateJsonParams = () => { + const validatedParams = { ...params }; + let hasErrors = false; + + for (const [key, ref] of Object.entries(formRefs.current)) { + if (!ref) continue; + + const result = ref.validateJson(); + if (!result.isValid) { + hasErrors = true; + } else if (result.value !== undefined) { + validatedParams[key] = result.value; + } + } + + setHasValidationErrors(hasErrors); + if (!hasErrors) setParams(validatedParams); + return { hasErrors, validatedParams }; + }; + useEffect(() => { const params = Object.entries( selectedTool?.inputSchema.properties ?? [], @@ -808,7 +828,8 @@ const ToolsTab = ({