diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index 90249ab1c..c8c40ef2b 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -8,9 +8,11 @@ import { } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { Switch } from "@/components/ui/switch"; import JsonEditor from "./JsonEditor"; import { updateValueAtPath } from "@/utils/jsonUtils"; -import { generateDefaultValue } from "@/utils/schemaUtils"; +import { generateDefaultValue, normalizeUnionType } from "@/utils/schemaUtils"; import type { JsonValue, JsonSchemaType, @@ -87,6 +89,9 @@ const DynamicJsonForm = forwardRef( // - Arrays with defined items are form-capable // - Primitive types are form-capable const canRenderTopLevelForm = (s: JsonSchemaType): boolean => { + // Unwrap Optional[X] at the top level so anyOf:[X,null] is treated as X + s = normalizeUnionType(s); + const primitiveTypes = ["string", "number", "integer", "boolean", "null"]; const hasType = Array.isArray(s.type) ? s.type.length > 0 : !!s.type; @@ -303,6 +308,19 @@ const DynamicJsonForm = forwardRef( parentSchema?: JsonSchemaType, propertyName?: string, ) => { + // Unwrap Optional[X] / nullable unions (anyOf: [X, null]) before ANY type checks + // so that maxDepth enforcement and the type switch both see the real type. + propSchema = normalizeUnionType(propSchema); + + // Trim description to remove leading/trailing whitespace from multi-line + // Python triple-quoted strings (e.g. """\n - text\n """) + if (propSchema.description) { + propSchema = { + ...propSchema, + description: propSchema.description.trim(), + }; + } + if ( depth >= maxDepth && (propSchema.type === "object" || propSchema.type === "array") @@ -422,39 +440,41 @@ const DynamicJsonForm = forwardRef( ); } - let inputType = "text"; - switch (propSchema.format) { - case "email": - inputType = "email"; - break; - case "uri": - inputType = "url"; - break; - case "date": - inputType = "date"; - break; - case "date-time": - inputType = "datetime-local"; - break; - default: - inputType = "text"; - break; + // Special formats keep a typed ; plain text uses