diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index 84c51117..e2d7d7ed 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -106,8 +106,17 @@ const DynamicJsonForm = forwardRef( const parsed = JSON.parse(jsonString); onChange(parsed); setJsonError(undefined); - } catch { - // Don't set error during normal typing + } catch (err) { + // For invalid JSON, set error and reset to default if it's clearly malformed + const errorMessage = + err instanceof Error ? err.message : "Invalid JSON"; + setJsonError(errorMessage); + + // Reset to default for clearly invalid JSON (not just incomplete typing) + const trimmed = jsonString.trim(); + if (trimmed.length > 5 && !trimmed.match(/^[\s\[{]/)) { + onChange(generateDefaultValue(schema)); + } } }, 300); }, @@ -164,7 +173,12 @@ const DynamicJsonForm = forwardRef( try { const jsonStr = rawJsonValue.trim(); if (!jsonStr) return { isValid: true, error: null }; - JSON.parse(jsonStr); + const parsed = JSON.parse(jsonStr); + // Clear any pending debounced update and immediately update parent + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + onChange(parsed); setJsonError(undefined); return { isValid: true, error: null }; } catch (err) { diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index c73fcd09..31979f0d 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -66,10 +66,20 @@ const ToolsTab = ({ const [isToolRunning, setIsToolRunning] = useState(false); const [isOutputSchemaExpanded, setIsOutputSchemaExpanded] = useState(false); const [isMetaExpanded, setIsMetaExpanded] = useState(false); + const [hasValidationErrors, setHasValidationErrors] = useState(false); const formRefs = useRef>({}); const { toast } = useToast(); const { copied, setCopied } = useCopy(); + // Function to check if any form has validation errors + const checkValidationErrors = () => { + const errors = Object.values(formRefs.current).some( + (ref) => ref && !ref.validateJson().isValid, + ); + setHasValidationErrors(errors); + return errors; + }; + useEffect(() => { const params = Object.entries( selectedTool?.inputSchema.properties ?? [], @@ -82,6 +92,12 @@ const ToolsTab = ({ ), ]); setParams(Object.fromEntries(params)); + + // Reset validation errors when switching tools + setHasValidationErrors(false); + + // Clear form refs for the previous tool + formRefs.current = {}; }, [selectedTool]); return ( @@ -199,6 +215,8 @@ const ToolsTab = ({ ...params, [key]: newValue, }); + // Check validation after a short delay to allow form to update + setTimeout(checkValidationErrors, 100); }} /> @@ -235,6 +253,8 @@ const ToolsTab = ({ ...params, [key]: newValue, }); + // Check validation after a short delay to allow form to update + setTimeout(checkValidationErrors, 100); }} /> @@ -317,10 +337,7 @@ const ToolsTab = ({