diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index 66a36fd..ff26118 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -4,10 +4,16 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import JsonEditor from "./JsonEditor"; -export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }; +export type JsonValue = + | string + | number + | boolean + | null + | JsonValue[] + | { [key: string]: JsonValue }; export type JsonSchemaType = { - type: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + type: "string" | "number" | "integer" | "boolean" | "array" | "object"; description?: string; properties?: Record; items?: JsonSchemaType; @@ -24,32 +30,32 @@ interface DynamicJsonFormProps { const formatFieldLabel = (key: string): string => { return key - .replace(/([A-Z])/g, ' $1') // Insert space before capital letters - .replace(/_/g, ' ') // Replace underscores with spaces - .replace(/^\w/, c => c.toUpperCase()); // Capitalize first letter + .replace(/([A-Z])/g, " $1") // Insert space before capital letters + .replace(/_/g, " ") // Replace underscores with spaces + .replace(/^\w/, (c) => c.toUpperCase()); // Capitalize first letter }; const DynamicJsonForm = ({ schema, value, onChange, - maxDepth = 3 + maxDepth = 3, }: DynamicJsonFormProps) => { const [isJsonMode, setIsJsonMode] = useState(false); const [jsonError, setJsonError] = useState(); const generateDefaultValue = (propSchema: JsonSchemaType): JsonValue => { switch (propSchema.type) { - case 'string': - return ''; - case 'number': - case 'integer': + case "string": + return ""; + case "number": + case "integer": return 0; - case 'boolean': + case "boolean": return false; - case 'array': + case "array": return []; - case 'object': { + case "object": { const obj: JsonObject = {}; if (propSchema.properties) { Object.entries(propSchema.properties).forEach(([key, prop]) => { @@ -67,20 +73,27 @@ const DynamicJsonForm = ({ propSchema: JsonSchemaType, currentValue: JsonValue, path: string[] = [], - depth: number = 0 + depth: number = 0, ) => { - if (depth >= maxDepth && (propSchema.type === 'object' || propSchema.type === 'array')) { + if ( + depth >= maxDepth && + (propSchema.type === "object" || propSchema.type === "array") + ) { // Render as JSON editor when max depth is reached return ( { try { const parsed = JSON.parse(newValue); handleFieldChange(path, parsed); setJsonError(undefined); } catch (err) { - setJsonError(err instanceof Error ? err.message : 'Invalid JSON'); + setJsonError(err instanceof Error ? err.message : "Invalid JSON"); } }} error={jsonError} @@ -89,20 +102,25 @@ const DynamicJsonForm = ({ } switch (propSchema.type) { - case 'string': - case 'number': - case 'integer': + case "string": + case "number": + case "integer": return ( handleFieldChange(path, - propSchema.type === 'string' ? e.target.value : Number(e.target.value) - )} + type={propSchema.type === "string" ? "text" : "number"} + value={(currentValue as string | number) ?? ""} + onChange={(e) => + handleFieldChange( + path, + propSchema.type === "string" + ? e.target.value + : Number(e.target.value), + ) + } placeholder={propSchema.description} /> ); - case 'boolean': + case "boolean": return ( ); - case 'object': + case "object": if (!propSchema.properties) return null; return (
@@ -122,13 +140,13 @@ const DynamicJsonForm = ({ prop, (currentValue as JsonObject)?.[key], [...path, key], - depth + 1 + depth + 1, )}
))} ); - case 'array': { + case "array": { const arrayValue = Array.isArray(currentValue) ? currentValue : []; if (!propSchema.items) return null; return ( @@ -136,7 +154,7 @@ const DynamicJsonForm = ({ {propSchema.description && (

{propSchema.description}

)} - + {propSchema.items?.description && (

Items: {propSchema.items.description} @@ -145,36 +163,40 @@ const DynamicJsonForm = ({

{arrayValue.map((item, index) => ( -
- {renderFormFields( - propSchema.items as JsonSchemaType, - item, - [...path, index.toString()], - depth + 1 - )} - -
- ))} +
+ {renderFormFields( + propSchema.items as JsonSchemaType, + item, + [...path, index.toString()], + depth + 1, + )} + +
+ ))} @@ -193,9 +215,13 @@ const DynamicJsonForm = ({ return; } - const newValue = { ...(typeof value === 'object' && value !== null && !Array.isArray(value) ? value : {}) } as JsonObject; + const newValue = { + ...(typeof value === "object" && value !== null && !Array.isArray(value) + ? value + : {}), + } as JsonObject; let current: JsonObject = newValue; - + for (let i = 0; i < path.length - 1; i++) { const key = path[i]; if (!(key in current)) { @@ -203,7 +229,7 @@ const DynamicJsonForm = ({ } current = current[key] as JsonObject; } - + current[path[path.length - 1]] = fieldValue; onChange(newValue); }; @@ -228,7 +254,7 @@ const DynamicJsonForm = ({ onChange(JSON.parse(newValue)); setJsonError(undefined); } catch (err) { - setJsonError(err instanceof Error ? err.message : 'Invalid JSON'); + setJsonError(err instanceof Error ? err.message : "Invalid JSON"); } }} error={jsonError} diff --git a/client/src/components/JsonEditor.tsx b/client/src/components/JsonEditor.tsx index e9d90dc..2fb7e26 100644 --- a/client/src/components/JsonEditor.tsx +++ b/client/src/components/JsonEditor.tsx @@ -1,7 +1,7 @@ -import Editor from 'react-simple-code-editor'; -import Prism from 'prismjs'; -import 'prismjs/components/prism-json'; -import 'prismjs/themes/prism.css'; +import Editor from "react-simple-code-editor"; +import Prism from "prismjs"; +import "prismjs/components/prism-json"; +import "prismjs/themes/prism.css"; import { Button } from "@/components/ui/button"; interface JsonEditorProps { @@ -32,28 +32,26 @@ const JsonEditor = ({ value, onChange, error }: JsonEditorProps) => {
- Prism.highlight(code, Prism.languages.json, 'json') + highlight={(code) => + Prism.highlight(code, Prism.languages.json, "json") } padding={10} style={{ fontFamily: '"Fira code", "Fira Mono", monospace', fontSize: 14, - backgroundColor: 'transparent', - minHeight: '100px', + backgroundColor: "transparent", + minHeight: "100px", }} className="w-full" />
- {error && ( -

{error}

- )} + {error &&

{error}

} ); }; diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 77a1cd2..41b2ef7 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -192,12 +192,14 @@ const ToolsTab = ({ ) : prop.type === "object" ? (
{ setParams({ ...params, @@ -226,7 +228,7 @@ const ToolsTab = ({ )}
); - } + }, )}