import useSWR from "swr"; import * as monaco from "monaco-editor"; import { configureMonacoYaml } from "monaco-yaml"; import { useCallback, useEffect, useRef, useState } from "react"; import { useApiHost } from "@/api"; import Heading from "@/components/ui/heading"; import ActivityIndicator from "@/components/ui/activity-indicator"; import { Button } from "@/components/ui/button"; import axios from "axios"; import copy from "copy-to-clipboard"; import { useTheme } from "@/context/theme-provider"; import { Toaster } from "@/components/ui/sonner"; import { toast } from "sonner"; type SaveOptions = "saveonly" | "restart"; function ConfigEditor() { const apiHost = useApiHost(); const { data: config } = useSWR("config/raw"); const { theme } = useTheme(); const [error, setError] = useState(); const editorRef = useRef(null); const modelRef = useRef(null); const configRef = useRef(null); const onHandleSaveConfig = useCallback( async (save_option: SaveOptions) => { if (!editorRef.current) { return; } axios .post( `config/save?save_option=${save_option}`, editorRef.current.getValue(), { headers: { "Content-Type": "text/plain" }, } ) .then((response) => { if (response.status === 200) { setError(""); toast.success(response.data.message, { position: "top-center" }); } }) .catch((error) => { toast.error("Error saving config", { position: "top-center" }); if (error.response) { setError(error.response.data.message); } else { setError(error.message); } }); }, [editorRef] ); const handleCopyConfig = useCallback(async () => { if (!editorRef.current) { return; } copy(editorRef.current.getValue()); }, [editorRef]); useEffect(() => { if (!config) { return; } if (modelRef.current != null) { // we don't need to recreate the editor if it already exists editorRef.current?.layout(); return; } const modelUri = monaco.Uri.parse("a://b/api/config/schema.json"); if (monaco.editor.getModels().length > 0) { modelRef.current = monaco.editor.getModel(modelUri); } else { modelRef.current = monaco.editor.createModel(config, "yaml", modelUri); } configureMonacoYaml(monaco, { enableSchemaRequest: true, hover: true, completion: true, validate: true, format: true, schemas: [ { uri: `${apiHost}api/config/schema.json`, fileMatch: [String(modelUri)], }, ], }); const container = configRef.current; if (container != null) { editorRef.current = monaco.editor.create(container, { language: "yaml", model: modelRef.current, scrollBeyondLastLine: false, theme: theme == "dark" ? "vs-dark" : "vs-light", }); } return () => { configRef.current = null; editorRef.current = null; modelRef.current = null; }; }); if (!config) { return ; } return (
Config
{error && (
{error}
)}
); } export default ConfigEditor;