Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions components/webui/client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/webui/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"chart.js": "^4.4.9",
"chartjs-adapter-dayjs-4": "^1.0.4",
"chartjs-plugin-zoom": "^2.2.0",
"color": "^5.0.0",
Comment thread
davemarco marked this conversation as resolved.
Resolved
"dayjs": "^1.11.13",
"monaco-editor": "^0.52.2",
"react": "^19.0.0",
Expand Down
193 changes: 83 additions & 110 deletions components/webui/client/src/components/SqlEditor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,145 +1,118 @@
import {
useCallback,
useEffect,
useState,
useImperativeHandle,
useRef,
} from "react";

import {
Editor,
EditorProps,
useMonaco,
} from "@monaco-editor/react";
import {language as sqlLanguage} from "monaco-editor/esm/vs/basic-languages/sql/sql.js";
import {theme} from "antd";
import color from "color";
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";

import "./monaco-loader";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Sanity-check: ensure SQL language contributions remain loaded.

Using our retrieved learnings: we previously broke autocomplete when editor.all.js wasn’t imported in the Monaco setup. Since this PR removes some Monaco contributions/custom SQL declarations, please verify the loader still pulls in the required language and completion contributions (or that you explicitly set the options to achieve the same).


🏁 Script executed:

#!/bin/bash
# Look for language contributions and editor.all.js usage
rg -nP 'editor\.all\.js|sql\.contribution|monaco-editor/esm/vs/editor/editor\.all\.js|basic-languages/sql' -S
# Confirm we still use @monaco-editor/react loader
rg -n 'monaco-loader' components/webui/client/src/components/SqlEditor

Length of output: 409


Add missing editor.all.js import in Monaco loader

The loader currently only brings in the SQL contribution, but our previous findings show that without editor.all.js the SQL autocomplete will break. Please update monaco-loader.ts to import the full editor API before the SQL contribution:

• File: components/webui/client/src/components/SqlEditor/monaco-loader.ts

 // ensure the full editor API is loaded first
+import "monaco-editor/esm/vs/editor/editor.all.js";
 // then register SQL language support
 import "monaco-editor/esm/vs/basic-languages/sql/sql.contribution.js";

This will restore the required SQL autocomplete capabilities.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import "./monaco-loader";
// ensure the full editor API is loaded first
import "monaco-editor/esm/vs/editor/editor.all.js";
// then register SQL language support
import "monaco-editor/esm/vs/basic-languages/sql/sql.contribution.js";
🤖 Prompt for AI Agents
In components/webui/client/src/components/SqlEditor/index.tsx around line 17 and
in components/webui/client/src/components/SqlEditor/monaco-loader.ts, the Monaco
loader currently only imports the SQL contribution which causes SQL autocomplete
to break; update monaco-loader.ts to import the full Monaco editor API
(editor.all) before importing the SQL contribution so the complete editor
runtime is available for SQL autocomplete to work correctly. Ensure the editor
all import appears earlier than any vs/language or SQL contribution imports and
keep module resolution consistent with the project’s Monaco import style.



const MAX_VISIBLE_LINES: number = 5;
type SqlEditorRef = {
focus: () => void;
};

type SqlEditorProps = Omit<EditorProps, "language"> & React.RefAttributes<SqlEditorRef> & {
disabled: boolean;

type SqlEditorProps = Omit<EditorProps, "language">;
/** Callback when the editor is mounted and ref is ready to use. */
onEditorReady?: () => void;
};
Comment thread
hoophalab marked this conversation as resolved.
Resolved

/**
* Monaco editor with highlighting and autocomplete for SQL syntax.
* Monaco editor with highlighting for SQL syntax.
*
* @param props
* @return
*/
const SqlEditor = (props: SqlEditorProps) => {
const {ref, disabled, onEditorReady, ...editorProps} = props;
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>(null);
const monacoEditor = useMonaco();

const {token} = theme.useToken();

useImperativeHandle(ref, () => ({
focus: () => {
editorRef.current?.focus();
},
}), []);

const handleEditorDidMount = useCallback((
editor: monaco.editor.IStandaloneCodeEditor,
) => {
editorRef.current = editor;
onEditorReady?.();
}, [onEditorReady]);

// Define disabled theme for monaco editor
useEffect(() => {
if (null === monacoEditor) {
return () => {
};
return;
}

// Adds autocomplete suggestions for SQL keywords on editor load
const provider = monacoEditor.languages.registerCompletionItemProvider("sql", {
provideCompletionItems: (model, position) => {
const word = model.getWordUntilPosition(position);
const range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn,
};
const suggestions = sqlLanguage.keywords.map((keyword: string) => ({
detail: "Presto SQL (CLP)",
insertText: `${keyword} `,
kind: monacoEditor.languages.CompletionItemKind.Keyword,
label: keyword,
range: range,
}));

// When SQL keyword suggestions appear (e.g., after "SELECT a"), hitting Enter
// accepts the first suggestion. To prevent accidental auto-completion
// in multi-line queries and to allow users to dismiss suggestions more easily,
// we make the current input the first suggestion.
// Users can then use arrow keys to select a keyword if needed.
const typedWord = model.getValueInRange(range);
if (0 < typedWord.length) {
suggestions.push({
detail: "Current",
insertText: `${typedWord}\n`,
kind: monaco.languages.CompletionItemKind.Text,
label: typedWord,
range: range,
});
}

return {
suggestions: suggestions,
incomplete: true,
};
monacoEditor.editor.defineTheme("disabled-theme", {
base: "vs",
inherit: true,
rules: [],
colors: {
"editor.background": color(token.colorBgContainerDisabled).hexa(),
"editor.foreground": color(token.colorTextDisabled).hexa(),

// transparent
"focusBorder": "#00000000",
},
triggerCharacters: [
" ",
"\n",
],
});

return () => {
provider.dispose();
};
}, [monacoEditor]);

const [isContentMultiline, setIsContentMultiline] = useState<boolean>(false);

const handleMonacoMount = useCallback((editor: monaco.editor.IStandaloneCodeEditor) => {
editor.onDidContentSizeChange((ev) => {
if (false === ev.contentHeightChanged) {
return;
}
if (null === monacoEditor) {
throw new Error("Unexpected null Monaco instance");
}
const domNode = editor.getDomNode();
if (null === domNode) {
throw new Error("Unexpected null editor DOM node");
}
const model = editor.getModel();
if (null === model) {
throw new Error("Unexpected null editor model");
}
const lineHeight = editor.getOption(monacoEditor.editor.EditorOption.lineHeight);
const contentHeight = editor.getContentHeight();
const approxWrappedLines = Math.round(contentHeight / lineHeight);
setIsContentMultiline(1 < approxWrappedLines);
if (MAX_VISIBLE_LINES >= approxWrappedLines) {
domNode.style.height = `${contentHeight}px`;
} else {
domNode.style.height = `${lineHeight * MAX_VISIBLE_LINES}px`;
}
});
}, [monacoEditor]);
}, [
monacoEditor,
token,
]);
Comment on lines +57 to +76

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Avoid the color lib if tokens are already valid CSS; Monaco accepts rgba().

If token.colorBgContainerDisabled and token.colorTextDisabled are valid CSS colour strings (often hex or rgba), you can pass them directly. This would let you remove the color dependency.

-                "editor.background": color(token.colorBgContainerDisabled).hexa(),
-                "editor.foreground": color(token.colorTextDisabled).hexa(),
+                "editor.background": token.colorBgContainerDisabled,
+                "editor.foreground": token.colorTextDisabled,

If you’ve seen cases where tokens are in non-standard formats, keep the dependency and ignore this comment.

Also applies to: 67-69

🤖 Prompt for AI Agents
components/webui/client/src/components/SqlEditor/index.tsx around lines 57 to 77
(and specifically lines 67-69): the code wraps token.colorBgContainerDisabled
and token.colorTextDisabled with the external color(...) library to call
.hexa(), but Monaco accepts standard CSS color strings (hex, rgba) directly; if
these token values are already valid CSS colors, remove the color(...) wrapper
and pass token.colorBgContainerDisabled and token.colorTextDisabled directly to
the theme colors, and then remove the unused import of the color library; if
tokens can be nonstandard, leave the wrapper and add a short defensive comment
explaining why it’s required.


return (
<Editor
language={"sql"}

// Use white background while loading (default is grey) so transition to editor with
// white background is less jarring.
loading={<div style={{backgroundColor: "white", height: "100%", width: "100%"}}/>}
options={{
automaticLayout: true,
folding: isContentMultiline,
fontSize: 20,
lineHeight: 30,
lineNumbers: isContentMultiline ?
"on" :
"off",
lineNumbersMinChars: 2,
minimap: {enabled: false},
overviewRulerBorder: false,
placeholder: "Enter your SQL query",
renderLineHighlightOnlyWhenFocus: true,
scrollBeyondLastLine: false,
wordWrap: "on",
}}
onMount={handleMonacoMount}
{...props}/>
<div
style={
disabled ?
{pointerEvents: "none"} :
{}
}
>
Comment thread
hoophalab marked this conversation as resolved.
Resolved
<Editor
Comment on lines 78 to +86

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

UX consideration: pointer-events disables scrolling; verify that’s desired.

While querying, users cannot scroll or select text with the mouse. If read-only is sufficient, consider dropping pointerEvents: "none" to keep scrolling/selecting available.

🤖 Prompt for AI Agents
In components/webui/client/src/components/SqlEditor/index.tsx around lines 78 to
86, the current use of style { pointerEvents: "none" } when disabled prevents
scrolling and selection; replace this approach by removing pointerEvents and
instead pass a readOnly (or disabled) prop to the Editor component when
disabled, and if you need to prevent editing but allow selection/scrolling
ensure the wrapper does not set pointerEvents:none and use editor config
(readOnly: true) or CSS (e.g., user-select, overflow) to preserve scrolling and
selection while disabling edits.

language={"sql"}
loading={
<div
style={{
backgroundColor: "white",
height: "100%",
width: "100%",
}}/>
}
options={{
automaticLayout: true,
folding: false,
fontSize: 16,
lineNumbers: "off",
minimap: {enabled: false},
overviewRulerBorder: false,
placeholder: "Enter your SQL query",
renderLineHighlightOnlyWhenFocus: true,
scrollBeyondLastLine: false,
wordWrap: "on",
}}
Comment thread
davemarco marked this conversation as resolved.
Resolved
theme={disabled ?
Comment thread
hoophalab marked this conversation as resolved.
Resolved
"disabled-theme" :
"light"}
onMount={handleEditorDidMount}
Comment thread
hoophalab marked this conversation as resolved.
Resolved
{...editorProps}/>
</div>
);
};

export default SqlEditor;
export type {SqlEditorRef};
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@
import {loader} from "@monaco-editor/react";
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
import EditorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";

import "monaco-editor/esm/vs/basic-languages/sql/sql.contribution.js";
import "monaco-editor/esm/vs/editor/contrib/clipboard/browser/clipboard.js";
import "monaco-editor/esm/vs/editor/contrib/contextmenu/browser/contextmenu.js";
import "monaco-editor/esm/vs/editor/contrib/find/browser/findController.js";
import "monaco-editor/esm/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.js";
import "monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestController.js";
import "monaco-editor/esm/vs/editor/contrib/placeholderText/browser/placeholderText.contribution.js";


/* eslint-enable import/default, @stylistic/max-len */
Expand Down

This file was deleted.

Loading