Start adding changes to address json fields
This commit is contained in:
@@ -41,9 +41,6 @@ const DynamicJsonForm = ({
|
|||||||
onChange,
|
onChange,
|
||||||
maxDepth = 3,
|
maxDepth = 3,
|
||||||
}: DynamicJsonFormProps) => {
|
}: DynamicJsonFormProps) => {
|
||||||
const [isJsonMode, setIsJsonMode] = useState(false);
|
|
||||||
const [jsonError, setJsonError] = useState<string>();
|
|
||||||
|
|
||||||
const generateDefaultValue = (propSchema: JsonSchemaType): JsonValue => {
|
const generateDefaultValue = (propSchema: JsonSchemaType): JsonValue => {
|
||||||
switch (propSchema.type) {
|
switch (propSchema.type) {
|
||||||
case "string":
|
case "string":
|
||||||
@@ -69,6 +66,40 @@ const DynamicJsonForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [isJsonMode, setIsJsonMode] = useState(false);
|
||||||
|
const [jsonError, setJsonError] = useState<string>();
|
||||||
|
// Add state for storing raw JSON value
|
||||||
|
const [rawJsonValue, setRawJsonValue] = useState<string>(
|
||||||
|
JSON.stringify(value ?? generateDefaultValue(schema), null, 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
const validateJsonBeforeSubmit = () => {
|
||||||
|
if (isJsonMode && rawJsonValue) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(rawJsonValue);
|
||||||
|
onChange(parsed);
|
||||||
|
setJsonError(undefined);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
setJsonError(err instanceof Error ? err.message : "Invalid JSON");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSwitchToFormMode = () => {
|
||||||
|
if (isJsonMode) {
|
||||||
|
if (validateJsonBeforeSubmit()) {
|
||||||
|
setIsJsonMode(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Update raw JSON value when switching to JSON mode
|
||||||
|
setRawJsonValue(JSON.stringify(value ?? generateDefaultValue(schema), null, 2));
|
||||||
|
setIsJsonMode(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderFormFields = (
|
const renderFormFields = (
|
||||||
propSchema: JsonSchemaType,
|
propSchema: JsonSchemaType,
|
||||||
currentValue: JsonValue,
|
currentValue: JsonValue,
|
||||||
@@ -329,7 +360,7 @@ const DynamicJsonForm = ({
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setIsJsonMode(!isJsonMode)}
|
onClick={handleSwitchToFormMode}
|
||||||
>
|
>
|
||||||
{isJsonMode ? "Switch to Form" : "Switch to JSON"}
|
{isJsonMode ? "Switch to Form" : "Switch to JSON"}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -337,13 +368,18 @@ const DynamicJsonForm = ({
|
|||||||
|
|
||||||
{isJsonMode ? (
|
{isJsonMode ? (
|
||||||
<JsonEditor
|
<JsonEditor
|
||||||
value={JSON.stringify(value ?? generateDefaultValue(schema), null, 2)}
|
value={rawJsonValue}
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
|
setRawJsonValue(newValue);
|
||||||
try {
|
try {
|
||||||
onChange(JSON.parse(newValue));
|
if (/^\s*[{[].*[}\]]\s*$/.test(newValue)) {
|
||||||
setJsonError(undefined);
|
const parsed = JSON.parse(newValue);
|
||||||
} catch (err) {
|
onChange(parsed);
|
||||||
setJsonError(err instanceof Error ? err.message : "Invalid JSON");
|
setJsonError(undefined);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Don't set an error during typing - that will happen when the user
|
||||||
|
// tries to save or submit the form
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
error={jsonError}
|
error={jsonError}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
import Editor from "react-simple-code-editor";
|
import Editor from "react-simple-code-editor";
|
||||||
import Prism from "prismjs";
|
import Prism from "prismjs";
|
||||||
import "prismjs/components/prism-json";
|
import "prismjs/components/prism-json";
|
||||||
@@ -10,34 +11,63 @@ interface JsonEditorProps {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const JsonEditor = ({ value, onChange, error }: JsonEditorProps) => {
|
const JsonEditor = ({ value, onChange, error: externalError }: JsonEditorProps) => {
|
||||||
|
const [editorContent, setEditorContent] = useState(value);
|
||||||
|
const [internalError, setInternalError] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setEditorContent(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
const formatJson = (json: string): string => {
|
const formatJson = (json: string): string => {
|
||||||
try {
|
try {
|
||||||
|
// Handle empty arrays and objects specifically
|
||||||
|
if (json.trim() === '[]') return '[]';
|
||||||
|
if (json.trim() === '{}') return '{}';
|
||||||
return JSON.stringify(JSON.parse(json), null, 2);
|
return JSON.stringify(JSON.parse(json), null, 2);
|
||||||
} catch {
|
} catch {
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEditorChange = (newContent: string) => {
|
||||||
|
setEditorContent(newContent);
|
||||||
|
setInternalError(undefined);
|
||||||
|
onChange(newContent);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFormatJson = () => {
|
||||||
|
try {
|
||||||
|
const formatted = formatJson(editorContent);
|
||||||
|
setEditorContent(formatted);
|
||||||
|
onChange(formatted);
|
||||||
|
setInternalError(undefined);
|
||||||
|
} catch (err) {
|
||||||
|
setInternalError(err instanceof Error ? err.message : "Invalid JSON");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const displayError = internalError || externalError;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative space-y-2">
|
<div className="relative space-y-2">
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => onChange(formatJson(value))}
|
onClick={handleFormatJson}
|
||||||
>
|
>
|
||||||
Format JSON
|
Format JSON
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`border rounded-md ${
|
className={`border rounded-md ${
|
||||||
error ? "border-red-500" : "border-gray-200 dark:border-gray-800"
|
displayError ? "border-red-500" : "border-gray-200 dark:border-gray-800"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<Editor
|
<Editor
|
||||||
value={value}
|
value={editorContent}
|
||||||
onValueChange={onChange}
|
onValueChange={handleEditorChange}
|
||||||
highlight={(code) =>
|
highlight={(code) =>
|
||||||
Prism.highlight(code, Prism.languages.json, "json")
|
Prism.highlight(code, Prism.languages.json, "json")
|
||||||
}
|
}
|
||||||
@@ -51,7 +81,7 @@ const JsonEditor = ({ value, onChange, error }: JsonEditorProps) => {
|
|||||||
className="w-full"
|
className="w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{error && <p className="text-sm text-red-500 mt-1">{error}</p>}
|
{displayError && <p className="text-sm text-red-500 mt-1">{displayError}</p>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user