Skip to content

Add JSON editor indentation setting and auto-format JSON on paste#191

Closed
Pranav-0440 wants to merge 2 commits intoeclipse-editdor:masterfrom
Pranav-0440:feature/json-editor-settings
Closed

Add JSON editor indentation setting and auto-format JSON on paste#191
Pranav-0440 wants to merge 2 commits intoeclipse-editdor:masterfrom
Pranav-0440:feature/json-editor-settings

Conversation

@Pranav-0440
Copy link
Contributor

  • JSON content is automatically formatted on paste according to the selected indentation

fixes - #185

Signed-off-by: Pranav-0440 <pranavghorpade61@gmail.com>
Copilot AI review requested due to automatic review settings February 8, 2026 17:15
@Pranav-0440
Copy link
Contributor Author

Hi @TejInaco 👋
The PR is ready and implements the JSON Editor indentation setting,
auto-formats JSON on paste, and syncs Monaco formatting.
The schema validation error shown in screenshots is expected when the
input is not a full Thing Description.

Thanks!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a user-configurable JSON editor indentation setting and attempts to auto-format JSON content based on that setting, addressing Issue #185.

Changes:

  • Adds a new “JSON Editor” section to Settings with a 2/4 space indentation selector.
  • Updates the JSON editor to apply indentation settings to Monaco.
  • Adds JSON auto-formatting logic (currently triggered on any valid change).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
src/components/Editor/JsonEditor.tsx Reads indentation setting and updates Monaco options; adds JSON auto-formatting logic and refactors linked-TD dropdown generation.
src/components/App/Settings.tsx Extends SettingsData with jsonIndentation and adds UI for configuring indentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


const handleJsonIndentationChange = useCallback(
(e: React.ChangeEvent<HTMLSelectElement>) => {
const value = Number(e.target.value) as 2 | 4;
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleJsonIndentationChange trusts/casts the DOM value to 2 | 4. At runtime this can still become another number (e.g. if the DOM is modified), which would violate the intended constraint. Add a small runtime guard to coerce/validate the value (fallback to 2) before updating state.

Suggested change
const value = Number(e.target.value) as 2 | 4;
const parsed = Number(e.target.value);
const value: 2 | 4 = parsed === 2 || parsed === 4 ? (parsed as 2 | 4) : 2;

Copilot uses AI. Check for mistakes.
Comment on lines 253 to 264
<label className="block text-sm text-gray-300 mb-1">
Space indentation
</label>

<select
value={data.jsonIndentation}
onChange={handleJsonIndentationChange}
className="w-full rounded-md border-2 border-gray-600 bg-gray-600 p-2 text-white focus:border-blue-500 focus:outline-none sm:text-sm"
>
<option value={2}>2 spaces</option>
<option value={4}>4 spaces</option>
</select>
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label "Space indentation" is not programmatically associated with the <select> (no htmlFor on the label and no id on the select). This reduces accessibility for screen readers. Add an id to the select and htmlFor on the label (or wrap the select inside the label) so they are correctly linked.

Copilot uses AI. Check for mistakes.
Comment on lines 49 to 50
// Read indentation from settings (default = 2)
const jsonIndentation = context.settings?.jsonIndentation ?? 2;
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context.settings?.jsonIndentation is read here, but IEdiTDorContext (and the GlobalState provider value) does not expose a settings object. This will not compile and the editor will never pick up the setting. Consider sourcing the indentation from the same place Settings are persisted (currently localStorage via getLocalStorage/setLocalStorage) or extend the context/provider to include the persisted settings and update it on save.

Suggested change
// Read indentation from settings (default = 2)
const jsonIndentation = context.settings?.jsonIndentation ?? 2;
// Indentation used for JSON formatting (default = 2)
const jsonIndentation = 2;

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +89
const updateMonacoSchemas = (schemaMap: SchemaMapMessage) => {
proxy.splice(0, proxy.length);

schemaMap.forEach((schema, schemaUri) => {
proxy.push({ schemaUri, schema });
});
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateMonacoSchemas calls proxy.splice(...) but proxy state is initialized as undefined and the effect registers worker onmessage handlers before setProxy(proxy) runs in editorDidMount. If a worker message arrives before proxy is set, this will throw. Add a guard (e.g. return early when !proxy) or initialize proxy to an empty array/proxy so the handler is always safe.

Copilot uses AI. Check for mistakes.
Comment on lines 197 to 207
const parsed = JSON.parse(editorText);

// Auto-format JSON using selected indentation
const formatted = JSON.stringify(parsed, null, jsonIndentation);

// Prevent infinite update loop
if (formatted !== editorText) {
editorInstance.current?.setValue(formatted);
}

context.updateOfflineTD(formatted);
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onChange handler reformats the entire document (JSON.parse + JSON.stringify + setValue) whenever the JSON is valid. This is expensive for large documents and will reset cursor/selection while the user edits (it also goes beyond the stated requirement of formatting on paste). Prefer formatting only on paste (e.g. via Monaco paste event / editor.onDidPaste) and rely on tabSize/insertSpaces to keep indentation for normal edits, or use Monaco’s built-in editor.action.formatDocument in response to paste.

Suggested change
const parsed = JSON.parse(editorText);
// Auto-format JSON using selected indentation
const formatted = JSON.stringify(parsed, null, jsonIndentation);
// Prevent infinite update loop
if (formatted !== editorText) {
editorInstance.current?.setValue(formatted);
}
context.updateOfflineTD(formatted);
// Parse to validate JSON, but avoid reformatting on every change
JSON.parse(editorText);
// Store the current editor text as-is to avoid cursor resets and
// expensive full-document reformatting on each change.
context.updateOfflineTD(editorText);

Copilot uses AI. Check for mistakes.
Comment on lines 221 to 225
const tabs = Object.keys(context.linkedTd).map((key, index) => (
<option value={key} key={index}>
{key}
</option>
));
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linked-TD dropdown options previously filtered out entries that were neither a file handle (kind === "file") nor a non-empty object. This change now lists all keys, including empty placeholder entries (which can be created when a link is added but the linked TD couldn't be fetched). Selecting such an entry can result in changeBetweenTd doing nothing. Reintroduce the previous filter condition when building tabs (and consider using key={key} instead of the index).

Suggested change
const tabs = Object.keys(context.linkedTd).map((key, index) => (
<option value={key} key={index}>
{key}
</option>
));
const tabs = Object.entries(context.linkedTd)
.filter(([_, value]) => {
if (!value || typeof value !== "object") {
return false;
}
const typedValue = value as { kind?: string } & Record<string, unknown>;
if (typedValue.kind === "file") {
return true;
}
// Only include non-empty objects
return Object.keys(typedValue).length > 0;
})
.map(([key]) => (
<option value={key} key={key}>
{key}
</option>
));

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +23
export interface SettingsData {
northboundUrl: string;
southboundUrl: string;
pathToValue: string;
jsonIndentation: 2 | 4;
}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding jsonIndentation to SettingsData makes it a required field for all existing callers (e.g. the Settings dialog constructs SettingsData objects and persists settings). Those call sites currently only provide northboundUrl/southboundUrl/pathToValue, so this will break compilation and the new setting won’t be persisted unless the save logic/localStorage key set is extended. Update the settings persistence and all SettingsData initializations to include a default jsonIndentation (2) and store/load it alongside the other settings.

Copilot uses AI. Check for mistakes.
Signed-off-by: Pranav-0440 <pranavghorpade61@gmail.com>
@TejInaco TejInaco self-requested a review February 18, 2026 12:55
@TejInaco
Copy link
Contributor

Cannot accept your solution. Reason: 1) Solution out of the issue scope 2) The commits modified the entire file instead of only the code necessary for the proposed solution. Note to @egekorkan

@TejInaco TejInaco closed this Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants