diff --git a/packages/core/components/AdvancedEditor/AdvancedEditor.tsx b/packages/core/components/AdvancedEditor/AdvancedEditor.tsx index 1675b4d37..2d7293e7a 100644 --- a/packages/core/components/AdvancedEditor/AdvancedEditor.tsx +++ b/packages/core/components/AdvancedEditor/AdvancedEditor.tsx @@ -8,6 +8,26 @@ import _ from 'lodash' import Tooltip from '../ui/Tooltip' import EmbedEditor from './EmbedEditor' +const UNDEFINED_SENTINELS = new Set(['__undefined__', '__\u200bundefined__']) + +const sanitizeConfigForAdvancedEditor = (input: T): T => { + if (input === undefined || input === null) return input + + // Normalize values so copy/export from JsonEditor stays valid JSON. + const serialized = JSON.stringify(input, (_key, value) => { + if (typeof value === 'string' && UNDEFINED_SENTINELS.has(value)) return undefined + return value + }) + + if (serialized === undefined) return input + + try { + return JSON.parse(serialized) + } catch { + return input + } +} + export const AdvancedEditor = ({ loadConfig, config, @@ -28,18 +48,22 @@ export const AdvancedEditor = ({ } const onUpdate: UpdateFunction = val => { - setConfigTextbox(val.newData) + setConfigTextbox(sanitizeConfigForAdvancedEditor(val.newData)) + } + + const getParsedConfig = () => { + let parsedConfig = stripConfig(config) + if (config.type !== 'dashboard') { + parsedConfig = convertStateToConfig() + } + + return sanitizeConfigForAdvancedEditor(parsedConfig) } useEffect(() => { // Only process config when advanced editor is open to improve performance if (advancedToggle) { - let parsedConfig = stripConfig(config) - if (config.type !== 'dashboard') { - parsedConfig = convertStateToConfig() - } - - setConfigTextbox(parsedConfig) + setConfigTextbox(getParsedConfig()) } }, [config, advancedToggle]) @@ -47,11 +71,7 @@ export const AdvancedEditor = ({ const handleToggleOpen = () => { if (!advancedToggle) { // Process config only when opening for the first time - let parsedConfig = stripConfig(config) - if (config.type !== 'dashboard') { - parsedConfig = convertStateToConfig() - } - setConfigTextbox(parsedConfig) + setConfigTextbox(getParsedConfig()) } setAdvancedToggle(!advancedToggle) } @@ -107,7 +127,7 @@ export const AdvancedEditor = ({