diff --git a/src/components/common/CodeEditor.tsx b/src/components/common/CodeEditor.tsx index 7c3fed27..610bb8be 100644 --- a/src/components/common/CodeEditor.tsx +++ b/src/components/common/CodeEditor.tsx @@ -13,6 +13,8 @@ import { useTheme } from "next-themes"; import { useEffect, useRef } from "react"; import { StreamLanguage } from "@codemirror/language"; import { toml } from "@codemirror/legacy-modes/mode/toml"; +import { keymap } from "@codemirror/view"; +import { indentWithTab } from "@codemirror/commands"; function tomlParseLinter() { return (view: EditorView): Diagnostic[] => { @@ -52,6 +54,7 @@ interface Props { language?: Language; onChange: (value: string) => void; onValidation?: (isValid: boolean) => void; + onSave: () => void; readOnly?: boolean; } @@ -72,6 +75,7 @@ const CodeEditor = ({ language = "json", onChange, onValidation, + onSave, readOnly = false, }: Props) => { const containerRef = useRef(null); @@ -80,6 +84,8 @@ const CodeEditor = ({ onChangeRef.current = onChange; const onValidationRef = useRef(onValidation); onValidationRef.current = onValidation; + const onSaveRef = useRef(onSave); + onSaveRef.current = onSave; const valueRef = useRef(value); valueRef.current = value; @@ -88,6 +94,18 @@ const CodeEditor = ({ useEffect(() => { if (!containerRef.current) return; + const tabExtension = keymap.of([indentWithTab]); + + const saveKeymap = keymap.of([ + { + key: "Mod-s", + preventDefault: true, + run: () => { + onSaveRef.current(); + return true; + }, + }, + ]); const langLinter = languageLinters[language]; @@ -118,6 +136,8 @@ const CodeEditor = ({ "&": { height: "100%", fontSize: "13px" }, ".cm-scroller": { overflow: "auto", fontFamily: "monospace" }, }), + tabExtension, + saveKeymap, ], }), parent: containerRef.current, diff --git a/src/components/common/ConfigFileEditor.tsx b/src/components/common/ConfigFileEditor.tsx index 5fbbf626..691ff0e2 100644 --- a/src/components/common/ConfigFileEditor.tsx +++ b/src/components/common/ConfigFileEditor.tsx @@ -9,6 +9,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { browserApiClient } from "@/services/devGuardApi"; import { Pencil } from "lucide-react"; import { useEffect, useState } from "react"; +import { toast } from "sonner"; import useSWR from "swr"; const defaultConfigFiles = [ @@ -71,6 +72,7 @@ const ConfigFileEditor = ({ if (!configFileUrl) { return; } + const resp = await browserApiClient(configFileUrl, { method: "PUT", headers: { "Content-Type": "text/plain" }, @@ -81,6 +83,7 @@ const ConfigFileEditor = ({ setCodeError("Failed to save the new Configuration"); return; } + toast.success("Config saved successfully"); setEditorValue(newConfig); setCodeError(null); mutate(); @@ -118,6 +121,10 @@ const ConfigFileEditor = ({ value={editorValue} onChange={setEditorValue} onValidation={handleEditorValidation} + onSave={() => { + if (!!codeError || editorValue === configFile || configFile === undefined) return; + handleConfigFileChange(editorValue); + }} language={selectedLanguage} /> {codeError &&

{codeError}

}