diff --git a/src/components/App/Settings.tsx b/src/components/App/Settings.tsx index 875708e9..ef1c7669 100644 --- a/src/components/App/Settings.tsx +++ b/src/components/App/Settings.tsx @@ -10,10 +10,12 @@ * * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 ********************************************************************************/ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useEffect, useCallback, useContext } from "react"; import InfoIconWrapper from "../base/InfoIconWrapper"; import TextField from "../base/TextField"; import { isValidUrl } from "../../utils/strings"; +import EdiTDorContext from "../../context/ediTDorContext"; +import Dropdown from "../base/Dropdown"; export interface SettingsData { northboundUrl: string; @@ -44,6 +46,7 @@ const Settings: React.FC = ({ hideTitle = false, className = "", }) => { + const context = useContext(EdiTDorContext); const [data, setData] = useState(initialData); const [errors, setErrors] = useState({ northboundUrl: "", @@ -51,10 +54,6 @@ const Settings: React.FC = ({ pathToValue: "", }); - useEffect(() => { - setData(initialData); - }, [initialData]); - useEffect(() => { if (onChange) { const isValid = @@ -127,8 +126,31 @@ const Settings: React.FC = ({ [] ); + const handleJsonIndentationChange = useCallback( + (e: React.ChangeEvent) => { + const parsed = Number(e.target.value); + const value: 2 | 4 = parsed === 4 ? 4 : 2; + context.updateJsonIndentation(value); + }, + [context] + ); + return (
+
+ {!hideTitle &&

JSON Editor

} +
+ +
+
+
{!hideTitle && (

Third Party Service Configuration

diff --git a/src/components/Editor/JsonEditor.tsx b/src/components/Editor/JsonEditor.tsx index 9e92eff6..4ba90f28 100644 --- a/src/components/Editor/JsonEditor.tsx +++ b/src/components/Editor/JsonEditor.tsx @@ -27,13 +27,6 @@ import { IValidationMessage } from "../../types/context"; type SchemaMapMessage = Map>; // List of all Options can be found here: https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html -const editorOptions: editor.IStandaloneEditorConstructionOptions = { - selectOnLineNumbers: true, - automaticLayout: true, - lineDecorationsWidth: 20, - tabSize: 2, - insertSpaces: true, -}; // delay function that executes the callback once it hasn't been called for // at least x ms. @@ -54,6 +47,7 @@ interface JsonSchemaEntry { const JsonEditor: React.FC = ({ editorRef }) => { const context = useContext(ediTDorContext); + const jsonIndentation = context.jsonIndentation ?? 2; const [schemas] = useState([]); const [proxy, setProxy] = useState(undefined); const editorInstance = useRef(null); @@ -85,6 +79,8 @@ const JsonEditor: React.FC = ({ editorRef }) => { ); useEffect(() => { + if (!proxy) return; + const updateMonacoSchemas = (schemaMap: SchemaMapMessage) => { proxy.splice(0, proxy.length); @@ -165,10 +161,8 @@ const JsonEditor: React.FC = ({ editorRef }) => { setProxy(proxy); }; - const onChange: OnChange = async (editorText: string | undefined) => { - if (!editorText) { - return; - } + const onChange: OnChange = (editorText: string | undefined) => { + if (!editorText) return; let validate: IValidationMessage = { report: { json: null, @@ -199,15 +193,19 @@ const JsonEditor: React.FC = ({ editorRef }) => { }, customMessage: "", }; + try { JSON.parse(editorText); - context.updateOfflineTD(editorText); + if (editorText !== context.offlineTD) { + context.updateOfflineTD(editorText); + } + + setLocalTextState(editorText); context.updateValidationMessage(validate); + + delay(messageWorkers, editorText, 500); } catch (error) { - let message: string = - "Invalid JSON: " + - (error instanceof Error ? error.message : String(error)); validate.report.json = "failed"; context.updateValidationMessage(validate); setLocalTextState(editorText); @@ -242,6 +240,19 @@ const JsonEditor: React.FC = ({ editorRef }) => { } }, [context.linkedTd, context.offlineTD]); + useEffect(() => { + try { + const parsed = JSON.parse(context.offlineTD); + const formatted = JSON.stringify(parsed, null, jsonIndentation); + + if (formatted !== context.offlineTD) { + context.updateOfflineTD(formatted); + } + } catch { + // ignore invalid JSON + } + }, [jsonIndentation, context.offlineTD]); + const changeLinkedTd = async () => { let href = (document.getElementById("linkedTd") as HTMLSelectElement).value; changeBetweenTd(context, href); @@ -255,6 +266,18 @@ const JsonEditor: React.FC = ({ editorRef }) => { }); }; + const editorOptions = useMemo( + () => ({ + selectOnLineNumbers: true, + automaticLayout: true, + lineDecorationsWidth: 20, + tabSize: jsonIndentation, + insertSpaces: true, + detectIndentation: false, + }), + [jsonIndentation] + ); + return ( <>
diff --git a/src/components/base/Dropdown.tsx b/src/components/base/Dropdown.tsx index 74d2fe5f..34c04f35 100644 --- a/src/components/base/Dropdown.tsx +++ b/src/components/base/Dropdown.tsx @@ -17,6 +17,8 @@ interface IDropdownProps { id: string; label: string; options: string[]; + value?: string; + onChange?: (event: React.ChangeEvent) => void; className?: string; } @@ -33,6 +35,8 @@ const Dropdown: React.FC = (props) => {