JsonEditor() — supabase Function Reference
Architecture documentation for the JsonEditor() function in JsonEditor.tsx from the supabase codebase.
Entity Profile
Dependency Diagram
graph TD 50bc62ef_1d39_0ed0_7e0c_1bec2d8d5b85["JsonEditor()"] ba33b09c_bc18_30d6_2ff3_8b87e531dcd1["tryFormatInitialValue()"] 50bc62ef_1d39_0ed0_7e0c_1bec2d8d5b85 -->|calls| ba33b09c_bc18_30d6_2ff3_8b87e531dcd1 b8f814ec_f6bc_2a0a_e400_fd5df18b3190["verifyJSON()"] 50bc62ef_1d39_0ed0_7e0c_1bec2d8d5b85 -->|calls| b8f814ec_f6bc_2a0a_e400_fd5df18b3190 style 50bc62ef_1d39_0ed0_7e0c_1bec2d8d5b85 fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
apps/studio/components/grid/components/editor/JsonEditor.tsx lines 47–229
export const JsonEditor = <TRow, TSummaryRow = unknown>({
row,
column,
isEditable = true,
onRowChange,
onExpandEditor,
}: JsonEditorProps<TRow, TSummaryRow>) => {
const { id: _id } = useParams()
const id = _id ? Number(_id) : undefined
const { data: project } = useSelectedProjectQuery()
const { data: selectedTable } = useTableEditorQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
id,
})
const rawInitialValue = row[column.key as keyof TRow] as unknown
const initialValue =
rawInitialValue === null || rawInitialValue === undefined || typeof rawInitialValue === 'string'
? rawInitialValue
: JSON.stringify(rawInitialValue)
const jsonString = prettifyJSON(initialValue ? tryFormatInitialValue(initialValue) : '')
const isTruncated = isValueTruncated(initialValue)
const [isPopoverOpen, setIsPopoverOpen] = useState(true)
const [value, setValue] = useState<string | null>(jsonString)
const { mutate: getCellValue, isPending, isSuccess } = useGetCellValueMutation()
const loadFullValue = () => {
if (selectedTable === undefined || project === undefined || !isTableLike(selectedTable)) return
if (selectedTable.primary_keys.length === 0) {
return toast('Unable to load value as table has no primary keys')
}
const pkMatch = selectedTable.primary_keys.reduce((a, b) => {
return { ...a, [b.name]: (row as any)[b.name] }
}, {})
getCellValue(
{
table: { schema: selectedTable.schema, name: selectedTable.name },
column: column.name as string,
pkMatch,
projectRef: project?.ref,
connectionString: project?.connectionString,
},
{
onSuccess: (data) => {
setValue(JSON.stringify(data))
},
}
)
}
const cancelChanges = useCallback(() => {
if (isEditable) onRowChange(row, true)
setIsPopoverOpen(false)
}, [])
const saveChanges = useCallback(
(newValue: string | null) => {
const updatedValue = newValue !== null ? removeJSONTrailingComma(newValue) : newValue
if (updatedValue !== value) {
commitChange(newValue)
} else {
setIsPopoverOpen(false)
}
},
[isSuccess]
)
const onChange = (_value: string | undefined) => {
if (!isEditable) return
if (!_value || _value == '') setValue(null)
else setValue(_value)
}
const onSelectExpand = () => {
cancelChanges()
onExpandEditor(column.key, {
...row,
[column.key]: tryParseJson(value) || (row as any)[column.key],
})
}
const commitChange = (newValue: string | null) => {
if (!isEditable) return
if (!newValue) {
onRowChange({ ...row, [column.key]: null }, true)
setIsPopoverOpen(false)
} else if (verifyJSON(newValue)) {
const jsonValue = JSON.parse(newValue)
onRowChange({ ...row, [column.key]: jsonValue }, true)
setIsPopoverOpen(false)
} else {
toast.error('Please enter a valid JSON')
}
}
return (
<Popover
open={isPopoverOpen}
side="bottom"
align="start"
sideOffset={-35}
className="rounded-none"
overlay={
isTruncated && !isSuccess ? (
<div
style={{ width: `${column.width}px` }}
className="flex items-center justify-center flex-col relative"
>
<MonacoEditor
readOnly
onChange={() => {}}
width={`${column.width}px`}
value={value ?? ''}
language="markdown"
/>
<TruncatedWarningOverlay isLoading={isPending} loadFullValue={loadFullValue} />
</div>
) : (
<BlockKeys value={value} onEscape={cancelChanges} onEnter={saveChanges}>
<MonacoEditor
width={`${column.width}px`}
value={value ?? ''}
language="json"
readOnly={!isEditable}
onChange={onChange}
/>
<div className="flex items-start justify-between p-2 bg-surface-200 gap-x-2">
{isEditable && (
<div className="space-y-1">
<div className="flex items-center space-x-2">
<div className="px-1.5 py-[2.5px] rounded bg-selection border border-strong flex items-center justify-center">
<span className="text-[10px]">⏎</span>
</div>
<p className="text-xs text-foreground-light">Save changes</p>
</div>
<div className="flex items-center space-x-2">
<div className="px-1 py-[2.5px] rounded bg-selection border border-strong flex items-center justify-center">
<span className="text-[10px]">Esc</span>
</div>
<p className="text-xs text-foreground-light">Cancel changes</p>
</div>
</div>
)}
<Tooltip>
<TooltipTrigger asChild>
<div
className={[
'border border-strong rounded p-1 flex items-center justify-center',
'transition cursor-pointer bg-selection hover:bg-border-strong',
].join(' ')}
onClick={() => onSelectExpand()}
>
<Maximize size={12} strokeWidth={2} />
</div>
</TooltipTrigger>
<TooltipContent side="bottom" align="center">
<span>Expand editor</span>
</TooltipContent>
</Tooltip>
</div>
</BlockKeys>
)
}
>
<div
className={`${
!!value && jsonString.trim().length == 0 ? 'sb-grid-fill-container' : ''
} sb-grid-json-editor__trigger`}
onClick={() => setIsPopoverOpen(!isPopoverOpen)}
>
{value === null || value === '' ? <NullValue /> : jsonString}
</div>
</Popover>
)
}
Domain
Subdomains
Source
Frequently Asked Questions
What does JsonEditor() do?
JsonEditor() is a function in the supabase codebase.
What does JsonEditor() call?
JsonEditor() calls 2 function(s): tryFormatInitialValue, verifyJSON.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free