Add explicit Save button to the schema JSON editor

The JSON view no longer parses/saves on every keystroke — you type freely
and click "Save JSON" to apply. Invalid JSON (or a non-object) shows the
parse error inline instead of auto-rejecting; valid JSON is pretty-printed,
applied to the form/preview, and saved. The form editor still auto-saves.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parththakkar106
2026-07-21 16:01:42 +05:30
co-authored by Claude Opus 4.8
parent 67fbe17cee
commit 80fb5b0c89
2 changed files with 30 additions and 11 deletions
+7
View File
@@ -660,6 +660,13 @@ button:disabled { opacity: 0.45; cursor: default; transform: none; box-shadow: n
color: var(--danger, #e5484d); color: var(--danger, #e5484d);
font-size: 0.82rem; font-size: 0.82rem;
} }
.schema-json-actions {
display: flex;
align-items: center;
gap: 12px;
margin-top: 8px;
}
.schema-json-actions .schema-error { margin-top: 0; }
.schema-preview { .schema-preview {
margin-top: 14px; margin-top: 14px;
padding: 14px 16px; padding: 14px 16px;
+23 -11
View File
@@ -43,32 +43,37 @@ export default function ScenarioEditor() {
}) })
} }
// RPG world-state schema: edited as raw JSON, only saved when it parses to an // JSON view: typing only updates the text buffer; nothing is parsed or saved
// object (empty text clears the RPG layer). Invalid JSON shows an inline error // until the user clicks Save (so a half-typed edit doesn't spam errors).
// and holds off saving. const onJsonText = (text) => {
const setSchema = (text) => {
setSchemaText(text) setSchemaText(text)
const trimmed = text.trim() if (schemaError) setSchemaError('')
}
// Parse the JSON box on demand: apply + save if valid, else show the error.
const commitJson = () => {
const trimmed = schemaText.trim()
if (!trimmed) { if (!trimmed) {
setSchemaError('') setSchemaError('')
setParsedSchema(null) setParsedSchema(null)
debounceSave('stat_schema', () => saveSchema(null)) saveSchema(null)
return return
} }
let parsed let parsed
try { try {
parsed = JSON.parse(trimmed) parsed = JSON.parse(trimmed)
} catch (err) { } catch (err) {
setSchemaError(`Invalid JSON: ${err.message}`) // keep last-good preview setSchemaError(`Invalid JSON: ${err.message}`)
return return
} }
if (typeof parsed !== 'object' || Array.isArray(parsed)) { if (typeof parsed !== 'object' || Array.isArray(parsed)) {
setSchemaError('The schema must be a JSON object.') setSchemaError('The schema must be a JSON object (e.g. { "player": { … } }).')
return return
} }
setSchemaError('') setSchemaError('')
setParsedSchema(parsed) setParsedSchema(parsed)
debounceSave('stat_schema', () => saveSchema(parsed)) setSchemaText(JSON.stringify(parsed, null, 2)) // normalize / pretty-print
saveSchema(parsed)
} }
const saveSchema = async (parsed) => { const saveSchema = async (parsed) => {
@@ -230,12 +235,19 @@ export default function ScenarioEditor() {
<textarea <textarea
className="schema-editor" className="schema-editor"
value={schemaText} value={schemaText}
onChange={(e) => setSchema(e.target.value)} onChange={(e) => onJsonText(e.target.value)}
rows={14} rows={14}
spellCheck={false} spellCheck={false}
placeholder={'{\n "player": { "hp": { "min": 0, "max": 100, "initial": 100 } },\n "npcs": {\n "gwen": { "name": "Gwen", "keys": "Gwen, ranger", "desc": "...",\n "stats": { "trust": { "min": -100, "max": 100, "initial": 20 } } }\n },\n "flags": { "has_key": { "desc": "...", "initial": false } },\n "milestones": { "goal": { "desc": "..." } }\n}'} placeholder={'{\n "player": { "hp": { "min": 0, "max": 100, "initial": 100 } },\n "npcs": {\n "gwen": { "name": "Gwen", "keys": "Gwen, ranger", "desc": "...",\n "stats": { "trust": { "min": -100, "max": 100, "initial": 20 } } }\n },\n "flags": { "has_key": { "desc": "...", "initial": false } },\n "milestones": { "goal": { "desc": "..." } }\n}'}
/> />
{schemaError && <div className="schema-error">⚠ {schemaError}</div>} <div className="schema-json-actions">
<button type="button" className="primary" onClick={commitJson}>Save JSON</button>
{schemaError
? <span className="schema-error">⚠ {schemaError}</span>
: <span className="dim" style={{ fontSize: '0.8rem' }}>
Edits apply when you click Save.
</span>}
</div>
<SchemaPreview schema={parsedSchema} /> <SchemaPreview schema={parsedSchema} />
</> </>
)} )}