Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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.
"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.

/**
* 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,
]);

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.
<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.
theme={disabled ?
"disabled-theme" :
"light"}
onMount={handleEditorDidMount}
Comment thread
hoophalab marked this conversation as 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