Skip to content

Commit 8c6a020

Browse files
committed
feat: remove save query feature
1 parent 644029c commit 8c6a020

File tree

6 files changed

+145
-409
lines changed

6 files changed

+145
-409
lines changed

ui/package-lock.json

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"format": "biome format --write"
1212
},
1313
"dependencies": {
14+
"@monaco-editor/react": "^4.7.0",
1415
"@radix-ui/react-alert-dialog": "^1.1.14",
1516
"@radix-ui/react-dialog": "^1.1.14",
1617
"@radix-ui/react-dropdown-menu": "^2.1.15",

ui/src/components/editor.tsx

Lines changed: 110 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
import "@/editorWorker";
2-
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
1+
import { FunctionComponent, useEffect, useRef } from "react";
2+
3+
import type { IDisposable } from "monaco-editor";
34
import { vsPlusTheme } from "monaco-sql-languages";
4-
import { FunctionComponent, useEffect, useRef, useState } from "react";
5+
import EditorComponent, { useMonaco } from "@monaco-editor/react";
56

6-
import { useTheme } from "@/provider/theme.provider";
77
import {
88
COMMAND_CONFIG,
99
ID_LANGUAGE_SQL,
1010
autoSuggestionCompletionItems,
1111
} from "./editor.config";
12-
import { Card } from "./ui/card";
12+
1313
import { fetchAutocomplete } from "@/api";
14+
import { Card } from "@/components/ui/card";
1415
import { useQuery } from "@tanstack/react-query";
16+
import { useTheme } from "@/provider/theme.provider";
1517

1618
type Props = {
1719
value: string;
@@ -20,151 +22,125 @@ type Props = {
2022

2123
export const Editor: FunctionComponent<Props> = ({ value, onChange }) => {
2224
const currentTheme = useTheme();
23-
const [editor, setEditor] =
24-
useState<monaco.editor.IStandaloneCodeEditor | null>(null);
25-
const monacoEl = useRef<HTMLDivElement>(null);
25+
const monacoInstance = useMonaco();
26+
const providerRef = useRef<IDisposable | null>(null);
2627

2728
const { data: autoCompleteData } = useQuery({
2829
queryKey: ["autocomplete"],
2930
queryFn: () => fetchAutocomplete(),
3031
});
3132

32-
// biome-ignore lint: lint/correctness/useExhaustiveDependencies: the fix doesn't work
33+
// Configure Monaco
3334
useEffect(() => {
34-
if (monacoEl) {
35-
setEditor((editor) => {
36-
if (editor) return editor;
37-
38-
monaco.languages.register({ id: ID_LANGUAGE_SQL });
39-
monaco.languages.setLanguageConfiguration(
40-
ID_LANGUAGE_SQL,
41-
COMMAND_CONFIG,
42-
);
43-
44-
monaco.editor.defineTheme("sql-dark", vsPlusTheme.darkThemeData);
45-
monaco.editor.defineTheme("sql-light", vsPlusTheme.lightThemeData);
46-
47-
const newEditor = monaco.editor.create(monacoEl.current!, {
48-
value,
49-
language: ID_LANGUAGE_SQL,
50-
minimap: {
51-
enabled: false,
52-
},
53-
fontSize: 20,
54-
padding: {
55-
top: 20,
56-
bottom: 20,
57-
},
58-
fontFamily: "JetBrains Mono",
59-
automaticLayout: true,
60-
readOnly: onChange === undefined,
61-
});
35+
if (!monacoInstance) return;
6236

63-
newEditor.onDidChangeModelContent((_) => {
64-
onChange?.(newEditor.getValue());
65-
});
66-
67-
return newEditor;
68-
});
69-
}
37+
monacoInstance.languages.register({ id: ID_LANGUAGE_SQL });
38+
monacoInstance.languages.setLanguageConfiguration(
39+
ID_LANGUAGE_SQL,
40+
COMMAND_CONFIG
41+
);
7042

71-
return () => editor?.dispose();
72-
}, [monacoEl.current]);
43+
monacoInstance.editor.defineTheme("sql-dark", vsPlusTheme.darkThemeData);
44+
monacoInstance.editor.defineTheme("sql-light", vsPlusTheme.lightThemeData);
45+
}, [monacoInstance]);
7346

47+
// Register completion provider
7448
useEffect(() => {
75-
if (!autoCompleteData) return;
76-
77-
monaco.languages.registerCompletionItemProvider(ID_LANGUAGE_SQL, {
78-
provideCompletionItems: (model, position) => {
79-
const word = model.getWordUntilPosition(position);
80-
const range = {
81-
startLineNumber: position.lineNumber,
82-
endLineNumber: position.lineNumber,
83-
startColumn: word.startColumn,
84-
endColumn: word.endColumn,
85-
};
86-
const { suggestions } = autoSuggestionCompletionItems(range);
87-
88-
const tableColumnSuggestions = autoCompleteData.tables.reduce(
89-
(
90-
acc: {
91-
label: string;
92-
kind: monaco.languages.CompletionItemKind;
93-
insertText: string;
94-
range: {
95-
startLineNumber: number;
96-
endLineNumber: number;
97-
startColumn: number;
98-
endColumn: number;
49+
if (!monacoInstance || !autoCompleteData) return;
50+
51+
providerRef.current?.dispose();
52+
53+
providerRef.current =
54+
monacoInstance.languages.registerCompletionItemProvider(ID_LANGUAGE_SQL, {
55+
provideCompletionItems: (model, position) => {
56+
const word = model.getWordUntilPosition(position);
57+
const range = {
58+
startLineNumber: position.lineNumber,
59+
endLineNumber: position.lineNumber,
60+
startColumn: word.startColumn,
61+
endColumn: word.endColumn,
62+
};
63+
const { suggestions } = autoSuggestionCompletionItems(range);
64+
65+
const tableColumnSuggestions = autoCompleteData.tables.flatMap(
66+
({ table_name, columns }) => {
67+
const alias = table_name.substring(0, 3);
68+
69+
const table = {
70+
label: table_name,
71+
kind: monacoInstance.languages.CompletionItemKind.Variable,
72+
insertText: table_name,
73+
range,
9974
};
100-
}[],
101-
{ table_name, columns },
102-
) => {
103-
const alias = table_name.substring(0, 3);
104-
105-
const table = {
106-
label: table_name,
107-
kind: monaco.languages.CompletionItemKind.Variable,
108-
insertText: table_name,
109-
range,
110-
};
111-
112-
const aliasTable = {
113-
label: `${table_name} AS ${alias}`,
114-
kind: monaco.languages.CompletionItemKind.Variable,
115-
insertText: `${table_name} AS ${alias}`,
116-
range,
117-
};
118-
119-
const col = columns.map((column) => ({
120-
label: column,
121-
kind: monaco.languages.CompletionItemKind.Variable,
122-
insertText: column,
123-
range,
124-
}));
125-
126-
const tableColumn = columns.map((column) => ({
127-
label: `${table_name}.${column}`,
128-
kind: monaco.languages.CompletionItemKind.Variable,
129-
insertText: `${table_name}.${column}`,
130-
range,
131-
}));
132-
133-
const tableColumnAlias = columns.map((column) => ({
134-
label: `${alias}.${column}`,
135-
kind: monaco.languages.CompletionItemKind.Variable,
136-
insertText: `${alias}.${column}`,
137-
range,
138-
}));
139-
140-
return [
141-
...acc,
142-
table,
143-
aliasTable,
144-
...col,
145-
...tableColumn,
146-
...tableColumnAlias,
147-
];
148-
},
149-
[],
150-
);
151-
152-
return { suggestions: [...suggestions, ...tableColumnSuggestions] };
153-
},
154-
});
155-
}, [autoCompleteData]);
15675

157-
useEffect(() => {
158-
if (monacoEl.current) {
159-
monaco.editor.setTheme(
160-
currentTheme === "light" ? "sql-light" : "sql-dark",
161-
);
162-
}
163-
}, [currentTheme]);
76+
const aliasTable = {
77+
label: `${table_name} AS ${alias}`,
78+
kind: monacoInstance.languages.CompletionItemKind.Variable,
79+
insertText: `${table_name} AS ${alias}`,
80+
range,
81+
};
82+
83+
const col = columns.map((column) => ({
84+
label: column,
85+
kind: monacoInstance.languages.CompletionItemKind.Variable,
86+
insertText: column,
87+
range,
88+
}));
89+
90+
const tableColumn = columns.map((column) => ({
91+
label: `${table_name}.${column}`,
92+
kind: monacoInstance.languages.CompletionItemKind.Variable,
93+
insertText: `${table_name}.${column}`,
94+
range,
95+
}));
96+
97+
const tableColumnAlias = columns.map((column) => ({
98+
label: `${alias}.${column}`,
99+
kind: monacoInstance.languages.CompletionItemKind.Variable,
100+
insertText: `${alias}.${column}`,
101+
range,
102+
}));
103+
104+
return [
105+
table,
106+
aliasTable,
107+
...col,
108+
...tableColumn,
109+
...tableColumnAlias,
110+
];
111+
}
112+
);
113+
114+
return { suggestions: [...suggestions, ...tableColumnSuggestions] };
115+
},
116+
});
117+
118+
return () => {
119+
providerRef.current?.dispose();
120+
providerRef.current = null;
121+
};
122+
}, [monacoInstance, autoCompleteData]);
123+
124+
// Avoid rendering until theme is known
125+
if (!currentTheme) return null;
164126

165127
return (
166128
<Card className="p-2">
167-
<div className="w-full h-[200px]" ref={monacoEl} />
129+
<EditorComponent
130+
height="200px"
131+
value={value}
132+
onChange={(val) => onChange?.(val ?? "")}
133+
language={ID_LANGUAGE_SQL}
134+
theme={currentTheme === "light" ? "sql-light" : "sql-dark"}
135+
options={{
136+
minimap: { enabled: false },
137+
fontSize: 20,
138+
fontFamily: "JetBrains Mono",
139+
padding: { top: 20, bottom: 20 },
140+
automaticLayout: true,
141+
readOnly: onChange === undefined,
142+
}}
143+
/>
168144
</Card>
169145
);
170146
};

ui/src/editorWorker.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)