Files
app/frontend/src/components/Flow/NodeEditor.tsx
T
stroblme 5a145b8f59 Edit JSON node settings in a dialog from a one-line preview
A free setting typed json and a declared object or array setting (a Switch
node's rules, HTTP headers) show one line of their value; clicking opens a
Monaco JSON editor in a dialog that saves only once the text parses.
Declared object settings were not shown at all before. Escape in a dialog
opened from a side panel no longer closes the panel too.
2026-10-05 23:49:42 +02:00

65 lines
1.9 KiB
TypeScript

import Editor from "@monaco-editor/react"
import { useEffect, useMemo, useState } from "react"
import { useTheme } from "@/components/theme-provider"
import { Skeleton } from "@/components/ui/skeleton"
import { monacoFontFamily, setupMonaco } from "./monacoSetup"
/**
* The embedded code editor, Python unless asked for JSON. Highlighting and
* bracket handling only: what the code actually does is checked by the engine,
* which reports load and run errors back onto the node.
*/
export default function NodeEditor({
value,
onChange,
language = "python",
readOnly = false,
autoFocus = false,
}: {
value: string
onChange: (next: string) => void
language?: "python" | "json"
/** Generated code: readable, and not this panel's to change. */
readOnly?: boolean
/** Take the caret once mounted, as an editor opened on purpose should. */
autoFocus?: boolean
}) {
const { resolvedTheme } = useTheme()
const [ready, setReady] = useState(false)
useEffect(() => {
setupMonaco()
setReady(true)
}, [])
const fontFamily = useMemo(() => (ready ? monacoFontFamily() : ""), [ready])
if (!ready) return <Skeleton className="h-full w-full rounded-md" />
return (
<Editor
language={language}
theme={resolvedTheme === "dark" ? "fluksio-dark" : "fluksio-light"}
value={value}
onChange={(next) => onChange(next ?? "")}
onMount={autoFocus ? (editor) => editor.focus() : undefined}
loading={<Skeleton className="h-full w-full rounded-md" />}
options={{
readOnly,
fontFamily,
fontSize: 13,
minimap: { enabled: false },
scrollBeyondLastLine: false,
automaticLayout: true,
tabSize: 4,
lineNumbersMinChars: 3,
padding: { top: 12, bottom: 12 },
renderLineHighlight: "line",
overviewRulerLanes: 0,
scrollbar: { verticalScrollbarSize: 8, horizontalScrollbarSize: 8 },
}}
/>
)
}