@sqlrooms/sql-editor 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +291 -0
- package/dist/CreateTableModal.d.ts.map +1 -1
- package/dist/CreateTableModal.js +10 -4
- package/dist/CreateTableModal.js.map +1 -1
- package/dist/SqlEditor.d.ts +1 -14
- package/dist/SqlEditor.d.ts.map +1 -1
- package/dist/SqlEditor.js +111 -183
- package/dist/SqlEditor.js.map +1 -1
- package/dist/SqlEditorModal.d.ts.map +1 -1
- package/dist/SqlEditorModal.js +8 -4
- package/dist/SqlEditorModal.js.map +1 -1
- package/dist/SqlEditorSlice.d.ts +102 -5
- package/dist/SqlEditorSlice.d.ts.map +1 -1
- package/dist/SqlEditorSlice.js +107 -30
- package/dist/SqlEditorSlice.js.map +1 -1
- package/dist/SqlMonacoEditor.d.ts +30 -0
- package/dist/SqlMonacoEditor.d.ts.map +1 -0
- package/dist/SqlMonacoEditor.js +205 -0
- package/dist/SqlMonacoEditor.js.map +1 -0
- package/dist/SqlQueryDataSourcesPanel.js +2 -3
- package/dist/SqlQueryDataSourcesPanel.js.map +1 -1
- package/dist/components/internal/SqlMonacoEditor.d.ts +36 -0
- package/dist/components/internal/SqlMonacoEditor.d.ts.map +1 -0
- package/dist/components/internal/SqlMonacoEditor.js +219 -0
- package/dist/components/internal/SqlMonacoEditor.js.map +1 -0
- package/dist/constants/duckdb-dialect.d.ts +73 -0
- package/dist/constants/duckdb-dialect.d.ts.map +1 -0
- package/dist/constants/duckdb-dialect.js +392 -0
- package/dist/constants/duckdb-dialect.js.map +1 -0
- package/dist/constants/duckdb.d.ts +73 -0
- package/dist/constants/duckdb.d.ts.map +1 -0
- package/dist/constants/duckdb.js +392 -0
- package/dist/constants/duckdb.js.map +1 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useMonacoEditor.d.ts +13 -0
- package/dist/hooks/useMonacoEditor.d.ts.map +1 -0
- package/dist/hooks/useMonacoEditor.js +78 -0
- package/dist/hooks/useMonacoEditor.js.map +1 -0
- package/dist/hooks/useQueryExecution.d.ts +17 -0
- package/dist/hooks/useQueryExecution.d.ts.map +1 -0
- package/dist/hooks/useQueryExecution.js +61 -0
- package/dist/hooks/useQueryExecution.js.map +1 -0
- package/dist/hooks/useQueryTabManagement.d.ts +41 -0
- package/dist/hooks/useQueryTabManagement.d.ts.map +1 -0
- package/dist/hooks/useQueryTabManagement.js +95 -0
- package/dist/hooks/useQueryTabManagement.js.map +1 -0
- package/dist/hooks/useTableManagement.d.ts +14 -0
- package/dist/hooks/useTableManagement.d.ts.map +1 -0
- package/dist/hooks/useTableManagement.js +46 -0
- package/dist/hooks/useTableManagement.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +12 -9
package/dist/SqlEditor.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { DataTableVirtualized, QueryDataTable
|
|
3
|
-
import {
|
|
4
|
-
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, ResizableHandle, ResizablePanel, ResizablePanelGroup, SpinnerPane, Tabs, TabsContent, TabsList, TabsTrigger,
|
|
5
|
-
import { genRandomStr, generateUniqueName } from '@sqlrooms/utils';
|
|
6
|
-
import { csvFormat } from 'd3-dsv';
|
|
7
|
-
import { saveAs } from 'file-saver';
|
|
2
|
+
import { DataTableVirtualized, QueryDataTable } from '@sqlrooms/data-table';
|
|
3
|
+
import { escapeId } from '@sqlrooms/duckdb';
|
|
4
|
+
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, ResizableHandle, ResizablePanel, ResizablePanelGroup, SpinnerPane, Tabs, TabsContent, TabsList, TabsTrigger, } from '@sqlrooms/ui';
|
|
8
5
|
import { BookOpenIcon, DownloadIcon, MoreVerticalIcon, PlayIcon, PlusIcon, } from 'lucide-react';
|
|
9
|
-
import { useCallback, useEffect,
|
|
6
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
10
7
|
import CreateTableModal from './CreateTableModal';
|
|
11
8
|
import DeleteSqlQueryModal from './DeleteSqlQueryModal';
|
|
12
9
|
import RenameSqlQueryModal from './RenameSqlQueryModal';
|
|
13
10
|
import { useStoreWithSqlEditor } from './SqlEditorSlice';
|
|
14
11
|
import { TablesList } from './TablesList';
|
|
12
|
+
import { SqlMonacoEditor } from './SqlMonacoEditor';
|
|
13
|
+
import { useTableManagement, useQueryExecution, useMonacoEditor } from './hooks';
|
|
14
|
+
import { useBaseProjectStore } from '@sqlrooms/project-builder';
|
|
15
15
|
const DEFAULT_QUERY = '';
|
|
16
16
|
/**
|
|
17
17
|
* A full-featured SQL editor component with query execution, table management, and results visualization.
|
|
@@ -26,199 +26,127 @@ const DEFAULT_QUERY = '';
|
|
|
26
26
|
* - Keyboard shortcuts (Cmd/Ctrl + Enter to run queries)
|
|
27
27
|
*
|
|
28
28
|
*/
|
|
29
|
-
const
|
|
29
|
+
const SqlEditorBase = (props) => {
|
|
30
30
|
const { schema = 'main', documentationPanel } = props;
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
const
|
|
31
|
+
// Store access - directly use the selector
|
|
32
|
+
const addOrUpdateSqlQueryDataSource = useBaseProjectStore((state) => state.project.addOrUpdateSqlQueryDataSource);
|
|
33
|
+
// Get query data and methods directly from the store
|
|
34
|
+
const queries = useStoreWithSqlEditor((s) => s.project.config.sqlEditor.queries);
|
|
35
|
+
const selectedQueryId = useStoreWithSqlEditor((s) => s.project.config.sqlEditor.selectedQueryId);
|
|
36
|
+
const getCurrentQuery = useStoreWithSqlEditor((s) => s.sqlEditor.getCurrentQuery);
|
|
37
|
+
const setSelectedQueryId = useStoreWithSqlEditor((s) => s.sqlEditor.setSelectedQueryId);
|
|
38
|
+
const updateQueryText = useStoreWithSqlEditor((s) => s.sqlEditor.updateQueryText);
|
|
39
|
+
const createQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.createQueryTab);
|
|
40
|
+
const deleteQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.deleteQueryTab);
|
|
41
|
+
const renameQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.renameQueryTab);
|
|
42
|
+
// UI state
|
|
35
43
|
const [showDocs, setShowDocs] = useState(false);
|
|
36
|
-
const [tables, setTables] = useState([]);
|
|
37
|
-
const [tablesLoading, setTablesLoading] = useState(false);
|
|
38
|
-
const [tablesError, setTablesError] = useState(null);
|
|
39
|
-
const [results, setResults] = useState();
|
|
40
|
-
const resultsTableData = useArrowDataTable(results);
|
|
41
|
-
const [loading, setLoading] = useState(false);
|
|
42
|
-
const [selectedTable, setSelectedTable] = useState();
|
|
43
|
-
const [error, setError] = useState(null);
|
|
44
|
-
const fetchTables = useCallback(async () => {
|
|
45
|
-
if (!duckConn.conn)
|
|
46
|
-
return;
|
|
47
|
-
try {
|
|
48
|
-
setTablesLoading(true);
|
|
49
|
-
setTablesError(null);
|
|
50
|
-
const tablesList = await getDuckTables(schema);
|
|
51
|
-
setTables(tablesList);
|
|
52
|
-
}
|
|
53
|
-
catch (e) {
|
|
54
|
-
console.error(e);
|
|
55
|
-
setTablesError(e);
|
|
56
|
-
}
|
|
57
|
-
finally {
|
|
58
|
-
setTablesLoading(false);
|
|
59
|
-
}
|
|
60
|
-
}, [duckConn.conn, schema]);
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
void fetchTables();
|
|
63
|
-
}, [fetchTables]);
|
|
64
|
-
const runQuery = async (q) => {
|
|
65
|
-
const conn = duckConn.conn;
|
|
66
|
-
try {
|
|
67
|
-
setError(null);
|
|
68
|
-
setLoading(true);
|
|
69
|
-
await conn.query(`SET search_path = ${schema}`);
|
|
70
|
-
const results = await conn.query(q);
|
|
71
|
-
await conn.query(`SET search_path = main`);
|
|
72
|
-
setResults(results);
|
|
73
|
-
}
|
|
74
|
-
catch (e) {
|
|
75
|
-
setResults(undefined);
|
|
76
|
-
setError((e instanceof DuckQueryError
|
|
77
|
-
? e.getMessageForUser()
|
|
78
|
-
: 'Query failed') ?? e);
|
|
79
|
-
console.error(e);
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
setLoading(false);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
const handleSelectTable = (table) => {
|
|
86
|
-
setSelectedTable(table);
|
|
87
|
-
};
|
|
88
|
-
const handleRunQuery = async () => {
|
|
89
|
-
setSelectedTable(undefined);
|
|
90
|
-
const textarea = document.querySelector(`textarea[id="${sqlEditorConfig.selectedQueryId}"]`);
|
|
91
|
-
const selectedText = textarea instanceof HTMLTextAreaElement
|
|
92
|
-
? textarea?.value.substring(textarea.selectionStart, textarea.selectionEnd)
|
|
93
|
-
: undefined;
|
|
94
|
-
const queryToRun = selectedText || currentQuery;
|
|
95
|
-
await runQuery(queryToRun);
|
|
96
|
-
void fetchTables();
|
|
97
|
-
};
|
|
98
|
-
const getQueryIndexById = (id) => {
|
|
99
|
-
return sqlEditorConfig.queries.findIndex((q) => q.id === id);
|
|
100
|
-
};
|
|
101
|
-
const getCurrentQueryIndex = () => {
|
|
102
|
-
return getQueryIndexById(sqlEditorConfig.selectedQueryId);
|
|
103
|
-
};
|
|
104
|
-
const handleTabChange = (value) => {
|
|
105
|
-
onChangeSqlEditorConfig({
|
|
106
|
-
...sqlEditorConfig,
|
|
107
|
-
selectedQueryId: value,
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
const handleUpdateQuery = (e) => {
|
|
111
|
-
if (!sqlEditorConfig)
|
|
112
|
-
return;
|
|
113
|
-
const currentIndex = getCurrentQueryIndex();
|
|
114
|
-
const newQueries = [...sqlEditorConfig.queries];
|
|
115
|
-
if (!newQueries[currentIndex])
|
|
116
|
-
return;
|
|
117
|
-
newQueries[currentIndex] = {
|
|
118
|
-
...newQueries[currentIndex],
|
|
119
|
-
query: e.target.value,
|
|
120
|
-
};
|
|
121
|
-
onChangeSqlEditorConfig({
|
|
122
|
-
...sqlEditorConfig,
|
|
123
|
-
queries: newQueries,
|
|
124
|
-
});
|
|
125
|
-
};
|
|
126
|
-
const handleRunQueryRef = useRef(handleRunQuery);
|
|
127
|
-
handleRunQueryRef.current = handleRunQuery;
|
|
128
|
-
useEffect(() => {
|
|
129
|
-
const handleKeyDown = (evt) => {
|
|
130
|
-
if (evt instanceof KeyboardEvent &&
|
|
131
|
-
evt.key === 'Enter' &&
|
|
132
|
-
(evt.metaKey || evt.ctrlKey || evt.shiftKey)) {
|
|
133
|
-
void handleRunQueryRef.current();
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
globalThis.addEventListener('keydown', handleKeyDown);
|
|
137
|
-
return () => {
|
|
138
|
-
globalThis.removeEventListener('keydown', handleKeyDown);
|
|
139
|
-
};
|
|
140
|
-
}, []);
|
|
141
|
-
const handleExport = () => {
|
|
142
|
-
if (!results)
|
|
143
|
-
return;
|
|
144
|
-
const blob = new Blob([csvFormat(results.toArray())], {
|
|
145
|
-
type: 'text/plain;charset=utf-8',
|
|
146
|
-
});
|
|
147
|
-
saveAs(blob, `export-${genRandomStr(5)}.csv`);
|
|
148
|
-
};
|
|
149
44
|
const [createTableModalOpen, setCreateTableModalOpen] = useState(false);
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
}, []);
|
|
153
|
-
const handleToggleDocs = useCallback(() => {
|
|
154
|
-
setShowDocs(!showDocs);
|
|
155
|
-
}, [showDocs]);
|
|
156
|
-
const currentQuery = sqlEditorConfig.queries[getCurrentQueryIndex()]?.query ?? DEFAULT_QUERY;
|
|
45
|
+
const [lastExecutedQuery, setLastExecutedQuery] = useState('');
|
|
46
|
+
// Local state for modals
|
|
157
47
|
const [queryToDelete, setQueryToDelete] = useState(null);
|
|
158
48
|
const [queryToRename, setQueryToRename] = useState(null);
|
|
159
|
-
|
|
49
|
+
// Custom hooks
|
|
50
|
+
const { tables, tablesLoading, tablesError, tableSchemas, selectedTable, fetchTables, handleSelectTable, } = useTableManagement();
|
|
51
|
+
const { results, resultsTableData, loading, error, runQuery, exportResults } = useQueryExecution(schema);
|
|
52
|
+
const { handleEditorMount, getQueryText, setRunQueryHandler } = useMonacoEditor();
|
|
53
|
+
// Get the current query text
|
|
54
|
+
const currentQuery = getCurrentQuery(DEFAULT_QUERY);
|
|
55
|
+
// Handler functions for query tab management
|
|
56
|
+
const handleTabChange = useCallback((value) => {
|
|
57
|
+
setSelectedQueryId(value);
|
|
58
|
+
}, [setSelectedQueryId]);
|
|
59
|
+
const handleUpdateQuery = useCallback((value) => {
|
|
60
|
+
if (!value)
|
|
61
|
+
return;
|
|
62
|
+
updateQueryText(selectedQueryId, value);
|
|
63
|
+
}, [selectedQueryId, updateQueryText]);
|
|
64
|
+
const handleNewQuery = useCallback(() => {
|
|
65
|
+
return createQueryTab(DEFAULT_QUERY);
|
|
66
|
+
}, [createQueryTab]);
|
|
67
|
+
const handleStartRename = useCallback((queryId, currentName, event) => {
|
|
160
68
|
event.preventDefault();
|
|
161
69
|
setQueryToRename({ id: queryId, name: currentName });
|
|
162
|
-
};
|
|
163
|
-
const handleFinishRename = (newName) => {
|
|
70
|
+
}, []);
|
|
71
|
+
const handleFinishRename = useCallback((newName) => {
|
|
164
72
|
if (queryToRename) {
|
|
165
|
-
|
|
166
|
-
onChangeSqlEditorConfig({
|
|
167
|
-
...sqlEditorConfig,
|
|
168
|
-
queries: newQueries,
|
|
169
|
-
});
|
|
73
|
+
renameQueryTab(queryToRename.id, newName);
|
|
170
74
|
}
|
|
171
75
|
setQueryToRename(null);
|
|
172
|
-
};
|
|
173
|
-
const handleDeleteQuery = (queryId, event) => {
|
|
76
|
+
}, [queryToRename, renameQueryTab]);
|
|
77
|
+
const handleDeleteQuery = useCallback((queryId, event) => {
|
|
174
78
|
event.stopPropagation();
|
|
175
|
-
const currentIndex = getQueryIndexById(queryId);
|
|
176
79
|
setQueryToDelete(queryId);
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
80
|
+
}, []);
|
|
81
|
+
const handleConfirmDeleteQuery = useCallback(() => {
|
|
82
|
+
if (queryToDelete) {
|
|
83
|
+
deleteQueryTab(queryToDelete);
|
|
84
|
+
setQueryToDelete(null);
|
|
85
|
+
}
|
|
86
|
+
}, [queryToDelete, deleteQueryTab]);
|
|
87
|
+
// Handle run query logic
|
|
88
|
+
const handleRunQuery = useCallback(async () => {
|
|
89
|
+
// Clear selected table when running a query
|
|
90
|
+
handleSelectTable(undefined);
|
|
91
|
+
// Get the query text (either selected text or the entire query)
|
|
92
|
+
const queryToRun = getQueryText(selectedQueryId, currentQuery);
|
|
93
|
+
// Store the query that's being executed
|
|
94
|
+
setLastExecutedQuery(queryToRun);
|
|
95
|
+
// Run the query and refresh tables list
|
|
96
|
+
await runQuery(queryToRun);
|
|
97
|
+
}, [
|
|
98
|
+
handleSelectTable,
|
|
99
|
+
getQueryText,
|
|
100
|
+
selectedQueryId,
|
|
101
|
+
currentQuery,
|
|
102
|
+
runQuery,
|
|
103
|
+
setLastExecutedQuery,
|
|
104
|
+
]);
|
|
105
|
+
// Set up the run query handler reference for keyboard shortcuts
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
setRunQueryHandler(handleRunQuery);
|
|
108
|
+
}, [handleRunQuery, setRunQueryHandler]);
|
|
109
|
+
// Check if table schemas are empty and refetch if needed
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (Object.keys(tableSchemas).length === 0) {
|
|
112
|
+
void fetchTables();
|
|
186
113
|
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
...sqlEditorConfig,
|
|
198
|
-
queries: newQueries,
|
|
199
|
-
selectedQueryId: newQuery.id,
|
|
200
|
-
});
|
|
201
|
-
};
|
|
202
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute right-12 top-2", children: documentationPanel ? (_jsxs(Button, { size: "sm", variant: showDocs ? 'secondary' : 'outline', onClick: handleToggleDocs, children: [_jsx(BookOpenIcon, { className: "w-4 h-4 mr-2" }), "SQL reference"] })) : (_jsx("a", { href: "https://duckdb.org/docs/sql/introduction", target: "_blank", rel: "noreferrer", children: _jsxs(Button, { size: "sm", variant: 'outline', children: [_jsx(BookOpenIcon, { className: "w-4 h-4 mr-2" }), "SQL reference"] }) })) }), _jsxs("div", { className: "flex flex-col w-full gap-2", children: [_jsx("div", { className: "flex items-center gap-2 ml-1 mr-10 mb-2", children: _jsx("h2", { className: "text-lg font-semibold", children: "SQL Editor" }) }), _jsx("div", { className: "flex-grow h-full bg-muted", children: _jsxs(ResizablePanelGroup, { direction: "horizontal", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: showDocs ? 50 : 80, children: _jsxs(ResizablePanelGroup, { direction: "vertical", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: 50, className: "flex flex-row", children: _jsxs(ResizablePanelGroup, { direction: "horizontal", children: [_jsx(ResizablePanel, { defaultSize: 20, children: tablesLoading ? (_jsx(SpinnerPane, { h: "100%" })) : tablesError ? (_jsxs("div", { className: "p-4 text-red-500", children: ["Error loading tables: ", tablesError.message] })) : (_jsx(TablesList, { schema: "information_schema", tableNames: tables, selectedTable: selectedTable, onSelect: handleSelectTable })) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: 80, children: _jsxs(Tabs, { value: sqlEditorConfig.selectedQueryId, onValueChange: handleTabChange, className: "flex flex-col flex-grow overflow-hidden", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-border", children: [_jsxs(Button, { size: "sm", onClick: () => void handleRunQuery(), className: "uppercase", children: [_jsx(PlayIcon, { className: "w-4 h-4 mr-2" }), "Run"] }), _jsx(TabsList, { className: "flex-1", children: sqlEditorConfig.queries.map((q) => (_jsxs("div", { className: "relative", children: [_jsx(TabsTrigger, { value: q.id, className: "min-w-[60px] px-6 pr-8", children: q.name }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 h-6 w-6 flex items-center justify-center cursor-pointer hover:bg-accent rounded-sm", onClick: (e) => e.stopPropagation(), children: _jsx(MoreVerticalIcon, { className: "h-3 w-3" }) }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { onClick: (e) => {
|
|
114
|
+
}, [fetchTables, tableSchemas]);
|
|
115
|
+
// Handle toggle documentation panel
|
|
116
|
+
const handleToggleDocs = useCallback(() => {
|
|
117
|
+
setShowDocs(!showDocs);
|
|
118
|
+
}, [showDocs]);
|
|
119
|
+
// Handle create table from query results
|
|
120
|
+
const handleCreateTable = useCallback(() => {
|
|
121
|
+
setCreateTableModalOpen(true);
|
|
122
|
+
}, []);
|
|
123
|
+
return (_jsxs("div", { className: "relative flex flex-col h-full w-full overflow-hidden", children: [_jsx("div", { className: "absolute right-12 top-0", children: documentationPanel ? (_jsxs(Button, { size: "sm", variant: showDocs ? 'secondary' : 'outline', onClick: handleToggleDocs, children: [_jsx(BookOpenIcon, { className: "w-4 h-4 mr-2" }), "SQL reference"] })) : (_jsx("a", { href: "https://duckdb.org/docs/sql/introduction", target: "_blank", rel: "noreferrer", children: _jsxs(Button, { size: "sm", variant: 'outline', children: [_jsx(BookOpenIcon, { className: "w-4 h-4 mr-2" }), "SQL reference"] }) })) }), _jsxs("div", { className: "flex flex-col w-full gap-2 h-full", children: [_jsx("div", { className: "flex items-center gap-2 ml-1 mr-10 mb-2", children: _jsx("h2", { className: "text-lg font-semibold", children: "SQL Editor" }) }), _jsx("div", { className: "flex-grow h-full bg-muted", children: _jsxs(ResizablePanelGroup, { direction: "horizontal", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: showDocs ? 70 : 100, children: _jsxs(ResizablePanelGroup, { direction: "vertical", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: 50, className: "flex flex-row", children: _jsxs(ResizablePanelGroup, { direction: "horizontal", children: [_jsx(ResizablePanel, { defaultSize: 20, children: tablesLoading ? (_jsx(SpinnerPane, { h: "100%" })) : tablesError ? (_jsxs("div", { className: "p-4 text-red-500", children: ["Error loading tables: ", tablesError.message] })) : (_jsx(TablesList, { schema: "information_schema", tableNames: tables, selectedTable: selectedTable, onSelect: handleSelectTable })) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: 80, className: "flex flex-col overflow-hidden", children: _jsxs(Tabs, { value: selectedQueryId, onValueChange: handleTabChange, className: "flex flex-col h-full overflow-hidden", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-border", children: [_jsxs(Button, { size: "sm", onClick: () => void handleRunQuery(), className: "uppercase", children: [_jsx(PlayIcon, { className: "w-4 h-4 mr-2" }), "Run"] }), _jsx(TabsList, { className: "flex-1", children: queries.map((q) => (_jsxs("div", { className: "relative", children: [_jsx(TabsTrigger, { value: q.id, className: "min-w-[60px] px-6 pr-8", children: q.name }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 h-6 w-6 flex items-center justify-center cursor-pointer hover:bg-accent rounded-sm", onClick: (e) => e.stopPropagation(), children: _jsx(MoreVerticalIcon, { className: "h-3 w-3" }) }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { onClick: (e) => {
|
|
203
124
|
e.stopPropagation();
|
|
204
125
|
handleStartRename(q.id, q.name, e);
|
|
205
|
-
}, children: "Rename" }),
|
|
126
|
+
}, children: "Rename" }), queries.length > 1 && (_jsx(DropdownMenuItem, { onClick: (e) => {
|
|
206
127
|
e.stopPropagation();
|
|
207
128
|
handleDeleteQuery(q.id, e);
|
|
208
|
-
}, className: "text-red-500", children: "Delete" }))] })] })] }, q.id))) }), _jsx(Button, { size: "icon", variant: "ghost", onClick: handleNewQuery, className: "ml-2", children: _jsx(PlusIcon, { className: "h-4 w-4" }) })] }),
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
129
|
+
}, className: "text-red-500", children: "Delete" }))] })] })] }, q.id))) }), _jsx(Button, { size: "icon", variant: "ghost", onClick: handleNewQuery, className: "ml-2", children: _jsx(PlusIcon, { className: "h-4 w-4" }) })] }), queries.map((q) => (_jsx(TabsContent, { value: q.id, className: "relative flex-grow data-[state=active]:flex flex-col h-full", children: _jsx("div", { className: "flex-grow h-full w-full absolute inset-0", children: _jsx(SqlMonacoEditor, { value: q.query, onChange: handleUpdateQuery, className: "h-full w-full flex-grow", options: {
|
|
130
|
+
scrollBeyondLastLine: false,
|
|
131
|
+
automaticLayout: true,
|
|
132
|
+
minimap: { enabled: false },
|
|
133
|
+
wordWrap: 'on',
|
|
134
|
+
// Enable keyboard shortcuts
|
|
135
|
+
quickSuggestions: true,
|
|
136
|
+
suggestOnTriggerCharacters: true,
|
|
137
|
+
}, onMount: (editor, monaco) => {
|
|
138
|
+
handleEditorMount(editor, monaco, q.id, handleRunQuery);
|
|
139
|
+
}, tableSchemas: tableSchemas, getLatestSchemas: () => {
|
|
140
|
+
// If tableSchemas is empty, try to fetch tables
|
|
141
|
+
if (Object.keys(tableSchemas).length === 0) {
|
|
142
|
+
// We can't await here, but we can trigger the fetch
|
|
143
|
+
// This will update the state for next time
|
|
144
|
+
void fetchTables();
|
|
145
|
+
}
|
|
146
|
+
return { tableSchemas };
|
|
147
|
+
} }) }) }, q.id)))] }) })] }) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: 50, className: "overflow-hidden bg-muted text-sm", children: loading ? (_jsx(SpinnerPane, { h: "100%" })) : selectedTable ? (_jsx(QueryDataTable, { query: `SELECT * FROM ${schema}.${escapeId(selectedTable)}` })) : error ? (_jsx("div", { className: "w-full h-full p-5 overflow-auto", children: _jsx("pre", { className: "text-xs leading-tight text-red-500", children: error }) })) : resultsTableData ? (_jsxs("div", { className: "flex-grow overflow-hidden flex flex-col relative w-full h-full", children: [_jsx(DataTableVirtualized, { ...resultsTableData }), _jsxs("div", { className: "absolute bottom-0 right-0 flex gap-2", children: [_jsxs(Button, { size: "sm", disabled: !resultsTableData, onClick: handleCreateTable, children: [_jsx(PlusIcon, { className: "w-4 h-4 mr-2" }), "Create table"] }), _jsxs(Button, { size: "sm", disabled: !results, onClick: exportResults, children: [_jsx(DownloadIcon, { className: "w-4 h-4 mr-2" }), "Export"] })] })] })) : null })] }) }), showDocs && (_jsxs(_Fragment, { children: [_jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: 30, children: documentationPanel })] }))] }) }), _jsx(CreateTableModal, { query: lastExecutedQuery || currentQuery, isOpen: createTableModalOpen, onClose: () => setCreateTableModalOpen(false), onAddOrUpdateSqlQuery: addOrUpdateSqlQueryDataSource }), _jsx(DeleteSqlQueryModal, { isOpen: queryToDelete !== null, onClose: () => setQueryToDelete(null), onConfirm: handleConfirmDeleteQuery }), _jsx(RenameSqlQueryModal, { isOpen: queryToRename !== null, onClose: () => setQueryToRename(null), initialName: queryToRename?.name ?? '', onRename: handleFinishRename })] })] }));
|
|
222
148
|
};
|
|
149
|
+
// Wrap with React.memo to prevent unnecessary re-renders
|
|
150
|
+
const SqlEditor = React.memo(SqlEditorBase);
|
|
223
151
|
export default SqlEditor;
|
|
224
152
|
//# sourceMappingURL=SqlEditor.js.map
|
package/dist/SqlEditor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditor.js","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n DataTableVirtualized,\n QueryDataTable,\n useArrowDataTable,\n} from '@sqlrooms/data-table';\nimport {\n DuckQueryError,\n escapeId,\n getDuckTables,\n useDuckDb,\n} from '@sqlrooms/duckdb';\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n SpinnerPane,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Textarea,\n} from '@sqlrooms/ui';\nimport {genRandomStr, generateUniqueName} from '@sqlrooms/utils';\nimport {Table} from 'apache-arrow';\nimport {csvFormat} from 'd3-dsv';\nimport {saveAs} from 'file-saver';\nimport {\n BookOpenIcon,\n DownloadIcon,\n MoreVerticalIcon,\n PlayIcon,\n PlusIcon,\n} from 'lucide-react';\nimport React, {useCallback, useEffect, useRef, useState} from 'react';\nimport CreateTableModal from './CreateTableModal';\nimport DeleteSqlQueryModal from './DeleteSqlQueryModal';\nimport RenameSqlQueryModal from './RenameSqlQueryModal';\nimport {useStoreWithSqlEditor} from './SqlEditorSlice';\nimport {TablesList} from './TablesList';\n\nconst DEFAULT_QUERY = '';\n\nexport type SqlEditorProps = {\n /** The database schema to use for queries. Defaults to 'main' */\n schema?: string;\n\n /** Whether the SQL editor is currently visible */\n isOpen: boolean;\n\n /** Optional component to render SQL documentation in the side panel */\n documentationPanel?: React.ReactNode;\n\n /** Callback fired when the SQL editor should be closed */\n onClose: () => void;\n};\n\n/**\n * A full-featured SQL editor component with query execution, table management, and results visualization.\n *\n * Features:\n * - Multiple query tabs with save/rename/delete functionality\n * - Query execution with results displayed in a data table\n * - Table browser showing available tables in the schema\n * - Export results to CSV\n * - Create new tables from query results\n * - Optional SQL documentation panel\n * - Keyboard shortcuts (Cmd/Ctrl + Enter to run queries)\n *\n */\nconst SqlEditor: React.FC<SqlEditorProps> = (props) => {\n const {schema = 'main', documentationPanel} = props;\n const duckConn = useDuckDb();\n\n const addOrUpdateSqlQuery = useStoreWithSqlEditor(\n (state) => state.sqlEditor.addOrUpdateSqlQuery,\n );\n\n const sqlEditorConfig = useStoreWithSqlEditor(\n (s) => s.project.config.sqlEditor,\n );\n const onChangeSqlEditorConfig = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setSqlEditorConfig,\n );\n\n const [showDocs, setShowDocs] = useState(false);\n const [tables, setTables] = useState<string[]>([]);\n const [tablesLoading, setTablesLoading] = useState(false);\n const [tablesError, setTablesError] = useState<Error | null>(null);\n\n const [results, setResults] = useState<Table>();\n const resultsTableData = useArrowDataTable(results);\n const [loading, setLoading] = useState(false);\n const [selectedTable, setSelectedTable] = useState<string>();\n\n const [error, setError] = useState<string | null>(null);\n\n const fetchTables = useCallback(async () => {\n if (!duckConn.conn) return;\n\n try {\n setTablesLoading(true);\n setTablesError(null);\n const tablesList = await getDuckTables(schema);\n setTables(tablesList);\n } catch (e) {\n console.error(e);\n setTablesError(e as Error);\n } finally {\n setTablesLoading(false);\n }\n }, [duckConn.conn, schema]);\n\n useEffect(() => {\n void fetchTables();\n }, [fetchTables]);\n\n const runQuery = async (q: string) => {\n const conn = duckConn.conn;\n try {\n setError(null);\n setLoading(true);\n await conn.query(`SET search_path = ${schema}`);\n const results = await conn.query(q);\n await conn.query(`SET search_path = main`);\n setResults(results);\n } catch (e) {\n setResults(undefined);\n setError(\n (e instanceof DuckQueryError\n ? e.getMessageForUser()\n : 'Query failed') ?? e,\n );\n console.error(e);\n } finally {\n setLoading(false);\n }\n };\n\n const handleSelectTable = (table: string) => {\n setSelectedTable(table);\n };\n\n const handleRunQuery = async () => {\n setSelectedTable(undefined);\n const textarea = document.querySelector(\n `textarea[id=\"${sqlEditorConfig.selectedQueryId}\"]`,\n );\n const selectedText =\n textarea instanceof HTMLTextAreaElement\n ? textarea?.value.substring(\n textarea.selectionStart,\n textarea.selectionEnd,\n )\n : undefined;\n\n const queryToRun = selectedText || currentQuery;\n await runQuery(queryToRun);\n void fetchTables();\n };\n\n const getQueryIndexById = (id: string) => {\n return sqlEditorConfig.queries.findIndex((q) => q.id === id);\n };\n\n const getCurrentQueryIndex = () => {\n return getQueryIndexById(sqlEditorConfig.selectedQueryId);\n };\n\n const handleTabChange = (value: string) => {\n onChangeSqlEditorConfig({\n ...sqlEditorConfig,\n selectedQueryId: value,\n });\n };\n\n const handleUpdateQuery = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n if (!sqlEditorConfig) return;\n\n const currentIndex = getCurrentQueryIndex();\n const newQueries = [...sqlEditorConfig.queries];\n if (!newQueries[currentIndex]) return;\n newQueries[currentIndex] = {\n ...newQueries[currentIndex],\n query: e.target.value,\n };\n\n onChangeSqlEditorConfig({\n ...sqlEditorConfig,\n queries: newQueries,\n });\n };\n const handleRunQueryRef = useRef(handleRunQuery);\n handleRunQueryRef.current = handleRunQuery;\n\n useEffect(() => {\n const handleKeyDown = (evt: Event) => {\n if (\n evt instanceof KeyboardEvent &&\n evt.key === 'Enter' &&\n (evt.metaKey || evt.ctrlKey || evt.shiftKey)\n ) {\n void handleRunQueryRef.current();\n }\n };\n globalThis.addEventListener('keydown', handleKeyDown);\n return () => {\n globalThis.removeEventListener('keydown', handleKeyDown);\n };\n }, []);\n\n const handleExport = () => {\n if (!results) return;\n const blob = new Blob([csvFormat(results.toArray())], {\n type: 'text/plain;charset=utf-8',\n });\n saveAs(blob, `export-${genRandomStr(5)}.csv`);\n };\n\n const [createTableModalOpen, setCreateTableModalOpen] = useState(false);\n\n const handleCreateTable = useCallback(() => {\n setCreateTableModalOpen(true);\n }, []);\n\n const handleToggleDocs = useCallback(() => {\n setShowDocs(!showDocs);\n }, [showDocs]);\n\n const currentQuery =\n sqlEditorConfig.queries[getCurrentQueryIndex()]?.query ?? DEFAULT_QUERY;\n\n const [queryToDelete, setQueryToDelete] = useState<string | null>(null);\n\n const [queryToRename, setQueryToRename] = useState<{\n id: string;\n name: string;\n } | null>(null);\n\n const handleStartRename = (\n queryId: string,\n currentName: string,\n event: React.MouseEvent,\n ) => {\n event.preventDefault();\n setQueryToRename({id: queryId, name: currentName});\n };\n\n const handleFinishRename = (newName: string) => {\n if (queryToRename) {\n const newQueries = sqlEditorConfig.queries.map((q) =>\n q.id === queryToRename.id ? {...q, name: newName || q.name} : q,\n );\n onChangeSqlEditorConfig({\n ...sqlEditorConfig,\n queries: newQueries,\n });\n }\n setQueryToRename(null);\n };\n\n const handleDeleteQuery = (queryId: string, event: React.MouseEvent) => {\n event.stopPropagation();\n const currentIndex = getQueryIndexById(queryId);\n setQueryToDelete(queryId);\n\n // Pre-select the previous query if we're deleting the current one\n if (queryId === sqlEditorConfig.selectedQueryId && currentIndex > 0) {\n const prevId = sqlEditorConfig.queries[currentIndex - 1]?.id;\n if (prevId) {\n onChangeSqlEditorConfig({\n ...sqlEditorConfig,\n selectedQueryId: prevId,\n });\n }\n }\n };\n\n const handleNewQuery = () => {\n const newQueries = [...sqlEditorConfig.queries];\n const newQuery = {\n id: genRandomStr(8),\n name: generateUniqueName(\n 'Untitled',\n newQueries.map((q) => q.name),\n ),\n query: DEFAULT_QUERY,\n };\n newQueries.push(newQuery);\n\n onChangeSqlEditorConfig({\n ...sqlEditorConfig,\n queries: newQueries,\n selectedQueryId: newQuery.id,\n });\n };\n\n return (\n <>\n <div className=\"absolute right-12 top-2\">\n {documentationPanel ? (\n <Button\n size=\"sm\"\n variant={showDocs ? 'secondary' : 'outline'}\n onClick={handleToggleDocs}\n >\n <BookOpenIcon className=\"w-4 h-4 mr-2\" />\n SQL reference\n </Button>\n ) : (\n <a\n href=\"https://duckdb.org/docs/sql/introduction\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <Button size=\"sm\" variant={'outline'}>\n <BookOpenIcon className=\"w-4 h-4 mr-2\" />\n SQL reference\n </Button>\n </a>\n )}\n </div>\n <div className=\"flex flex-col w-full gap-2\">\n <div className=\"flex items-center gap-2 ml-1 mr-10 mb-2\">\n <h2 className=\"text-lg font-semibold\">SQL Editor</h2>\n </div>\n <div className=\"flex-grow h-full bg-muted\">\n <ResizablePanelGroup direction=\"horizontal\" className=\"h-full\">\n <ResizablePanel defaultSize={showDocs ? 50 : 80}>\n <ResizablePanelGroup direction=\"vertical\" className=\"h-full\">\n <ResizablePanel defaultSize={50} className=\"flex flex-row\">\n <ResizablePanelGroup direction=\"horizontal\">\n <ResizablePanel defaultSize={20}>\n {tablesLoading ? (\n <SpinnerPane h=\"100%\" />\n ) : tablesError ? (\n <div className=\"p-4 text-red-500\">\n Error loading tables: {tablesError.message}\n </div>\n ) : (\n <TablesList\n schema=\"information_schema\"\n tableNames={tables}\n selectedTable={selectedTable}\n onSelect={handleSelectTable}\n />\n )}\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel defaultSize={80}>\n <Tabs\n value={sqlEditorConfig.selectedQueryId}\n onValueChange={handleTabChange}\n className=\"flex flex-col flex-grow overflow-hidden\"\n >\n <div className=\"flex items-center gap-2 border-b border-border\">\n <Button\n size=\"sm\"\n onClick={() => void handleRunQuery()}\n className=\"uppercase\"\n >\n <PlayIcon className=\"w-4 h-4 mr-2\" />\n Run\n </Button>\n <TabsList className=\"flex-1\">\n {sqlEditorConfig.queries.map((q) => (\n <div key={q.id} className=\"relative\">\n <TabsTrigger\n value={q.id}\n className=\"min-w-[60px] px-6 pr-8\"\n >\n {q.name}\n </TabsTrigger>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <div\n className=\"absolute right-0 top-1/2 -translate-y-1/2 h-6 w-6 flex items-center justify-center cursor-pointer hover:bg-accent rounded-sm\"\n onClick={(e) => e.stopPropagation()}\n >\n <MoreVerticalIcon className=\"h-3 w-3\" />\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent>\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n handleStartRename(q.id, q.name, e);\n }}\n >\n Rename\n </DropdownMenuItem>\n {sqlEditorConfig.queries.length > 1 && (\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n handleDeleteQuery(q.id, e);\n }}\n className=\"text-red-500\"\n >\n Delete\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n ))}\n </TabsList>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={handleNewQuery}\n className=\"ml-2\"\n >\n <PlusIcon className=\"h-4 w-4\" />\n </Button>\n </div>\n {sqlEditorConfig.queries.map((q) => (\n <TabsContent\n key={q.id}\n value={q.id}\n className=\"flex-grow data-[state=active]:flex-grow\"\n >\n <Textarea\n id={q.id}\n value={q.query}\n onChange={handleUpdateQuery}\n className=\"h-full font-mono text-sm resize-none bg-muted\"\n />\n </TabsContent>\n ))}\n </Tabs>\n </ResizablePanel>\n </ResizablePanelGroup>\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel defaultSize={50}>\n <div className=\"h-full overflow-hidden bg-muted text-sm\">\n {loading ? (\n <SpinnerPane h=\"100%\" />\n ) : selectedTable ? (\n <QueryDataTable\n query={`SELECT * FROM ${schema}.${escapeId(selectedTable)}`}\n />\n ) : error ? (\n <div className=\"w-full h-full p-5 overflow-auto\">\n <pre className=\"text-xs leading-tight text-red-500\">\n {error}\n </pre>\n </div>\n ) : resultsTableData ? (\n <div className=\"flex-grow overflow-hidden flex flex-col relative\">\n <DataTableVirtualized {...resultsTableData} />\n <div className=\"absolute bottom-0 right-0 flex gap-2 p-2\">\n <Button\n size=\"sm\"\n disabled={!resultsTableData}\n onClick={handleCreateTable}\n >\n <PlusIcon className=\"w-4 h-4 mr-2\" />\n Create table\n </Button>\n <Button\n size=\"sm\"\n disabled={!results}\n onClick={handleExport}\n >\n <DownloadIcon className=\"w-4 h-4 mr-2\" />\n Export\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n </ResizablePanel>\n </ResizablePanelGroup>\n </ResizablePanel>\n {showDocs && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel defaultSize={30}>\n {documentationPanel}\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n </div>\n <CreateTableModal\n query={currentQuery}\n isOpen={createTableModalOpen}\n onClose={() => setCreateTableModalOpen(false)}\n onAddOrUpdateSqlQuery={addOrUpdateSqlQuery}\n />\n <DeleteSqlQueryModal\n isOpen={queryToDelete !== null}\n onClose={() => setQueryToDelete(null)}\n onConfirm={() => {\n const newQueries = sqlEditorConfig.queries.filter(\n (q) => q.id !== queryToDelete,\n );\n const deletedIndex = getQueryIndexById(queryToDelete!);\n\n const selectedQueryId =\n newQueries[Math.min(deletedIndex, newQueries.length - 1)]?.id ||\n newQueries[0]?.id;\n if (selectedQueryId) {\n onChangeSqlEditorConfig({\n ...sqlEditorConfig,\n queries: newQueries,\n selectedQueryId,\n });\n }\n setQueryToDelete(null);\n }}\n />\n <RenameSqlQueryModal\n isOpen={queryToRename !== null}\n onClose={() => setQueryToRename(null)}\n initialName={queryToRename?.name ?? ''}\n onRename={handleFinishRename}\n />\n </div>\n </>\n );\n};\n\nexport default SqlEditor;\n"]}
|
|
1
|
+
{"version":3,"file":"SqlEditor.js","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["import {DataTableVirtualized, QueryDataTable} from '@sqlrooms/data-table';\nimport {escapeId} from '@sqlrooms/duckdb';\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n SpinnerPane,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@sqlrooms/ui';\nimport {\n BookOpenIcon,\n DownloadIcon,\n MoreVerticalIcon,\n PlayIcon,\n PlusIcon,\n} from 'lucide-react';\nimport React, {useCallback, useEffect, useState} from 'react';\nimport CreateTableModal from './CreateTableModal';\nimport DeleteSqlQueryModal from './DeleteSqlQueryModal';\nimport RenameSqlQueryModal from './RenameSqlQueryModal';\nimport {useStoreWithSqlEditor} from './SqlEditorSlice';\nimport {TablesList} from './TablesList';\nimport {SqlMonacoEditor} from './SqlMonacoEditor';\nimport type * as Monaco from 'monaco-editor';\nimport {useTableManagement, useQueryExecution, useMonacoEditor} from './hooks';\nimport {useBaseProjectStore} from '@sqlrooms/project-builder';\n\n// Define the types for Monaco Editor\ntype EditorInstance = Monaco.editor.IStandaloneCodeEditor;\ntype MonacoInstance = typeof Monaco;\n\nconst DEFAULT_QUERY = '';\n\nexport type SqlEditorProps = {\n /** The database schema to use for queries. Defaults to 'main' */\n schema?: string;\n\n /** Whether the SQL editor is currently visible */\n isOpen: boolean;\n\n /** Optional component to render SQL documentation in the side panel */\n documentationPanel?: React.ReactNode;\n\n /** Callback fired when the SQL editor should be closed */\n onClose: () => void;\n};\n\n/**\n * A full-featured SQL editor component with query execution, table management, and results visualization.\n *\n * Features:\n * - Multiple query tabs with save/rename/delete functionality\n * - Query execution with results displayed in a data table\n * - Table browser showing available tables in the schema\n * - Export results to CSV\n * - Create new tables from query results\n * - Optional SQL documentation panel\n * - Keyboard shortcuts (Cmd/Ctrl + Enter to run queries)\n *\n */\nconst SqlEditorBase: React.FC<SqlEditorProps> = (props) => {\n const {schema = 'main', documentationPanel} = props;\n\n // Store access - directly use the selector\n const addOrUpdateSqlQueryDataSource = useBaseProjectStore(\n (state) => state.project.addOrUpdateSqlQueryDataSource,\n );\n\n // Get query data and methods directly from the store\n const queries = useStoreWithSqlEditor(\n (s) => s.project.config.sqlEditor.queries,\n );\n const selectedQueryId = useStoreWithSqlEditor(\n (s) => s.project.config.sqlEditor.selectedQueryId,\n );\n const getCurrentQuery = useStoreWithSqlEditor(\n (s) => s.sqlEditor.getCurrentQuery,\n );\n const setSelectedQueryId = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setSelectedQueryId,\n );\n const updateQueryText = useStoreWithSqlEditor(\n (s) => s.sqlEditor.updateQueryText,\n );\n const createQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.createQueryTab,\n );\n const deleteQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.deleteQueryTab,\n );\n const renameQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.renameQueryTab,\n );\n\n // UI state\n const [showDocs, setShowDocs] = useState(false);\n const [createTableModalOpen, setCreateTableModalOpen] = useState(false);\n const [lastExecutedQuery, setLastExecutedQuery] = useState<string>('');\n\n // Local state for modals\n const [queryToDelete, setQueryToDelete] = useState<string | null>(null);\n const [queryToRename, setQueryToRename] = useState<{\n id: string;\n name: string;\n } | null>(null);\n\n // Custom hooks\n const {\n tables,\n tablesLoading,\n tablesError,\n tableSchemas,\n selectedTable,\n fetchTables,\n handleSelectTable,\n } = useTableManagement();\n\n const {results, resultsTableData, loading, error, runQuery, exportResults} =\n useQueryExecution(schema);\n\n const {handleEditorMount, getQueryText, setRunQueryHandler} =\n useMonacoEditor();\n\n // Get the current query text\n const currentQuery = getCurrentQuery(DEFAULT_QUERY);\n\n // Handler functions for query tab management\n const handleTabChange = useCallback(\n (value: string) => {\n setSelectedQueryId(value);\n },\n [setSelectedQueryId],\n );\n\n const handleUpdateQuery = useCallback(\n (value: string | undefined) => {\n if (!value) return;\n updateQueryText(selectedQueryId, value);\n },\n [selectedQueryId, updateQueryText],\n );\n\n const handleNewQuery = useCallback(() => {\n return createQueryTab(DEFAULT_QUERY);\n }, [createQueryTab]);\n\n const handleStartRename = useCallback(\n (queryId: string, currentName: string, event: React.MouseEvent) => {\n event.preventDefault();\n setQueryToRename({id: queryId, name: currentName});\n },\n [],\n );\n\n const handleFinishRename = useCallback(\n (newName: string) => {\n if (queryToRename) {\n renameQueryTab(queryToRename.id, newName);\n }\n setQueryToRename(null);\n },\n [queryToRename, renameQueryTab],\n );\n\n const handleDeleteQuery = useCallback(\n (queryId: string, event: React.MouseEvent) => {\n event.stopPropagation();\n setQueryToDelete(queryId);\n },\n [],\n );\n\n const handleConfirmDeleteQuery = useCallback(() => {\n if (queryToDelete) {\n deleteQueryTab(queryToDelete);\n setQueryToDelete(null);\n }\n }, [queryToDelete, deleteQueryTab]);\n\n // Handle run query logic\n const handleRunQuery = useCallback(async () => {\n // Clear selected table when running a query\n handleSelectTable(undefined);\n\n // Get the query text (either selected text or the entire query)\n const queryToRun = getQueryText(selectedQueryId, currentQuery);\n\n // Store the query that's being executed\n setLastExecutedQuery(queryToRun);\n\n // Run the query and refresh tables list\n await runQuery(queryToRun);\n }, [\n handleSelectTable,\n getQueryText,\n selectedQueryId,\n currentQuery,\n runQuery,\n setLastExecutedQuery,\n ]);\n\n // Set up the run query handler reference for keyboard shortcuts\n useEffect(() => {\n setRunQueryHandler(handleRunQuery);\n }, [handleRunQuery, setRunQueryHandler]);\n\n // Check if table schemas are empty and refetch if needed\n useEffect(() => {\n if (Object.keys(tableSchemas).length === 0) {\n void fetchTables();\n }\n }, [fetchTables, tableSchemas]);\n\n // Handle toggle documentation panel\n const handleToggleDocs = useCallback(() => {\n setShowDocs(!showDocs);\n }, [showDocs]);\n\n // Handle create table from query results\n const handleCreateTable = useCallback(() => {\n setCreateTableModalOpen(true);\n }, []);\n\n return (\n <div className=\"relative flex flex-col h-full w-full overflow-hidden\">\n <div className=\"absolute right-12 top-0\">\n {documentationPanel ? (\n <Button\n size=\"sm\"\n variant={showDocs ? 'secondary' : 'outline'}\n onClick={handleToggleDocs}\n >\n <BookOpenIcon className=\"w-4 h-4 mr-2\" />\n SQL reference\n </Button>\n ) : (\n <a\n href=\"https://duckdb.org/docs/sql/introduction\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <Button size=\"sm\" variant={'outline'}>\n <BookOpenIcon className=\"w-4 h-4 mr-2\" />\n SQL reference\n </Button>\n </a>\n )}\n </div>\n <div className=\"flex flex-col w-full gap-2 h-full\">\n <div className=\"flex items-center gap-2 ml-1 mr-10 mb-2\">\n <h2 className=\"text-lg font-semibold\">SQL Editor</h2>\n </div>\n <div className=\"flex-grow h-full bg-muted\">\n <ResizablePanelGroup direction=\"horizontal\" className=\"h-full\">\n {/* Main panel - takes full width when docs not shown, or 70% when docs shown */}\n <ResizablePanel defaultSize={showDocs ? 70 : 100}>\n <ResizablePanelGroup direction=\"vertical\" className=\"h-full\">\n <ResizablePanel defaultSize={50} className=\"flex flex-row\">\n <ResizablePanelGroup direction=\"horizontal\">\n <ResizablePanel defaultSize={20}>\n {tablesLoading ? (\n <SpinnerPane h=\"100%\" />\n ) : tablesError ? (\n <div className=\"p-4 text-red-500\">\n Error loading tables: {tablesError.message}\n </div>\n ) : (\n <TablesList\n schema=\"information_schema\"\n tableNames={tables}\n selectedTable={selectedTable}\n onSelect={handleSelectTable}\n />\n )}\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel\n defaultSize={80}\n className=\"flex flex-col overflow-hidden\"\n >\n <Tabs\n value={selectedQueryId}\n onValueChange={handleTabChange}\n className=\"flex flex-col h-full overflow-hidden\"\n >\n <div className=\"flex items-center gap-2 border-b border-border\">\n <Button\n size=\"sm\"\n onClick={() => void handleRunQuery()}\n className=\"uppercase\"\n >\n <PlayIcon className=\"w-4 h-4 mr-2\" />\n Run\n </Button>\n <TabsList className=\"flex-1\">\n {queries.map((q: any) => (\n <div key={q.id} className=\"relative\">\n <TabsTrigger\n value={q.id}\n className=\"min-w-[60px] px-6 pr-8\"\n >\n {q.name}\n </TabsTrigger>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <div\n className=\"absolute right-0 top-1/2 -translate-y-1/2 h-6 w-6 flex items-center justify-center cursor-pointer hover:bg-accent rounded-sm\"\n onClick={(e) => e.stopPropagation()}\n >\n <MoreVerticalIcon className=\"h-3 w-3\" />\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent>\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n handleStartRename(q.id, q.name, e);\n }}\n >\n Rename\n </DropdownMenuItem>\n {queries.length > 1 && (\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n handleDeleteQuery(q.id, e);\n }}\n className=\"text-red-500\"\n >\n Delete\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n ))}\n </TabsList>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={handleNewQuery}\n className=\"ml-2\"\n >\n <PlusIcon className=\"h-4 w-4\" />\n </Button>\n </div>\n {queries.map((q: any) => (\n <TabsContent\n key={q.id}\n value={q.id}\n className=\"relative flex-grow data-[state=active]:flex flex-col h-full\"\n >\n <div className=\"flex-grow h-full w-full absolute inset-0\">\n <SqlMonacoEditor\n value={q.query}\n onChange={handleUpdateQuery}\n className=\"h-full w-full flex-grow\"\n options={{\n scrollBeyondLastLine: false,\n automaticLayout: true,\n minimap: {enabled: false},\n wordWrap: 'on',\n // Enable keyboard shortcuts\n quickSuggestions: true,\n suggestOnTriggerCharacters: true,\n }}\n onMount={(\n editor: EditorInstance,\n monaco: MonacoInstance,\n ) => {\n handleEditorMount(\n editor,\n monaco,\n q.id,\n handleRunQuery,\n );\n }}\n tableSchemas={tableSchemas}\n getLatestSchemas={() => {\n // If tableSchemas is empty, try to fetch tables\n if (Object.keys(tableSchemas).length === 0) {\n // We can't await here, but we can trigger the fetch\n // This will update the state for next time\n void fetchTables();\n }\n return {tableSchemas};\n }}\n />\n </div>\n </TabsContent>\n ))}\n </Tabs>\n </ResizablePanel>\n </ResizablePanelGroup>\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel\n defaultSize={50}\n className=\"overflow-hidden bg-muted text-sm\"\n >\n {loading ? (\n <SpinnerPane h=\"100%\" />\n ) : selectedTable ? (\n <QueryDataTable\n query={`SELECT * FROM ${schema}.${escapeId(selectedTable)}`}\n />\n ) : error ? (\n <div className=\"w-full h-full p-5 overflow-auto\">\n <pre className=\"text-xs leading-tight text-red-500\">\n {error}\n </pre>\n </div>\n ) : resultsTableData ? (\n <div className=\"flex-grow overflow-hidden flex flex-col relative w-full h-full\">\n <DataTableVirtualized {...resultsTableData} />\n <div className=\"absolute bottom-0 right-0 flex gap-2\">\n <Button\n size=\"sm\"\n disabled={!resultsTableData}\n onClick={handleCreateTable}\n >\n <PlusIcon className=\"w-4 h-4 mr-2\" />\n Create table\n </Button>\n <Button\n size=\"sm\"\n disabled={!results}\n onClick={exportResults}\n >\n <DownloadIcon className=\"w-4 h-4 mr-2\" />\n Export\n </Button>\n </div>\n </div>\n ) : null}\n </ResizablePanel>\n </ResizablePanelGroup>\n </ResizablePanel>\n {showDocs && (\n <>\n <ResizableHandle withHandle />\n {/* Documentation panel - 30% width */}\n <ResizablePanel defaultSize={30}>\n {documentationPanel}\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n </div>\n <CreateTableModal\n query={lastExecutedQuery || currentQuery}\n isOpen={createTableModalOpen}\n onClose={() => setCreateTableModalOpen(false)}\n onAddOrUpdateSqlQuery={addOrUpdateSqlQueryDataSource}\n />\n <DeleteSqlQueryModal\n isOpen={queryToDelete !== null}\n onClose={() => setQueryToDelete(null)}\n onConfirm={handleConfirmDeleteQuery}\n />\n <RenameSqlQueryModal\n isOpen={queryToRename !== null}\n onClose={() => setQueryToRename(null)}\n initialName={queryToRename?.name ?? ''}\n onRename={handleFinishRename}\n />\n </div>\n </div>\n );\n};\n\n// Wrap with React.memo to prevent unnecessary re-renders\nconst SqlEditor = React.memo(SqlEditorBase);\n\nexport default SqlEditor;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditorModal.d.ts","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SqlEditorModal.d.ts","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAkB,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA2B5C,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
package/dist/SqlEditorModal.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { SpinnerPane } from '@sqlrooms/ui';
|
|
4
|
-
import {
|
|
5
|
-
import { Suspense } from 'react';
|
|
3
|
+
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogOverlay, DialogTitle, SpinnerPane, } from '@sqlrooms/ui';
|
|
4
|
+
import { Suspense, useCallback } from 'react';
|
|
6
5
|
import SqlEditor from './SqlEditor';
|
|
7
6
|
/**
|
|
8
7
|
* A modal wrapper for the SQL Editor component that provides a full-screen dialog interface.
|
|
@@ -35,7 +34,12 @@ import SqlEditor from './SqlEditor';
|
|
|
35
34
|
*/
|
|
36
35
|
const SqlEditorModal = (props) => {
|
|
37
36
|
const { isOpen, onClose } = props;
|
|
38
|
-
|
|
37
|
+
// Memoize the handler to prevent re-renders
|
|
38
|
+
const handleOpenChange = useCallback((open) => {
|
|
39
|
+
if (!open)
|
|
40
|
+
onClose();
|
|
41
|
+
}, [onClose]);
|
|
42
|
+
return (_jsxs(Dialog, { open: isOpen, onOpenChange: handleOpenChange, children: [_jsx(DialogOverlay, { className: "bg-background/80" }), _jsxs(DialogContent, { className: "max-w-[100vw] max-h-[100vh] w-[100vw] h-[100vh] p-3", children: [_jsxs(DialogHeader, { className: "sr-only", children: [_jsx(DialogTitle, { children: "SQL Editor" }), _jsx(DialogDescription, { children: "SQL editor for querying and managing database tables" })] }), _jsx(Suspense, { fallback: _jsx(SpinnerPane, { h: "100%" }), children: _jsx(SqlEditor, { ...props }) })] })] }));
|
|
39
43
|
};
|
|
40
44
|
export default SqlEditorModal;
|
|
41
45
|
//# sourceMappingURL=SqlEditorModal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditorModal.js","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,
|
|
1
|
+
{"version":3,"file":"SqlEditorModal.js","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAc,EAAC,QAAQ,EAAE,WAAW,EAAC,MAAM,OAAO,CAAC;AACnD,OAAO,SAA2B,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,cAAc,GAA6B,CAAC,KAAK,EAAE,EAAE;IACzD,MAAM,EAAC,MAAM,EAAE,OAAO,EAAC,GAAG,KAAK,CAAC;IAEhC,4CAA4C;IAC5C,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,IAAa,EAAE,EAAE;QAChB,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;IACvB,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,CACL,MAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,gBAAgB,aAClD,KAAC,aAAa,IAAC,SAAS,EAAC,kBAAkB,GAAG,EAC9C,MAAC,aAAa,IAAC,SAAS,EAAC,qDAAqD,aAC5E,MAAC,YAAY,IAAC,SAAS,EAAC,SAAS,aAC/B,KAAC,WAAW,6BAAyB,EACrC,KAAC,iBAAiB,uEAEE,IACP,EACf,KAAC,QAAQ,IAAC,QAAQ,EAAE,KAAC,WAAW,IAAC,CAAC,EAAC,MAAM,GAAG,YAC1C,KAAC,SAAS,OAAK,KAAK,GAAI,GACf,IACG,IACT,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["'use client';\n\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogOverlay,\n DialogTitle,\n SpinnerPane,\n} from '@sqlrooms/ui';\nimport React, {Suspense, useCallback} from 'react';\nimport SqlEditor, {SqlEditorProps} from './SqlEditor';\n\n/**\n * A modal wrapper for the SQL Editor component that provides a full-screen dialog interface.\n *\n * This component wraps the main SqlEditor component in a modal dialog, making it suitable for\n * overlay/popup usage scenarios. It inherits all props from SqlEditorProps and handles the\n * modal-specific behavior.\n *\n * @example\n * ```tsx\n * <SqlEditorModal\n * isOpen={true}\n * onClose={() => setIsOpen(false)}\n * sqlEditorConfig={config}\n * onChange={handleConfigChange}\n * />\n * ```\n *\n * @see {@link SqlEditor} for detailed documentation of all available props\n *\n * @props {@link SqlEditorProps}\n * The component accepts all props from SqlEditorProps:\n * - `isOpen` - Whether the SQL editor modal is currently visible\n * - `onClose` - Callback fired when the modal should be closed\n * - `sqlEditorConfig` - Configuration object containing queries and selected query state\n * - `onChange` - Callback fired when the SQL editor configuration changes\n * - `schema` - Optional database schema to use for queries (defaults to 'main')\n * - `documentationPanel` - Optional component to render SQL documentation in the side panel\n * - `onAddOrUpdateSqlQuery` - Callback fired when a new table should be created from query results\n */\nconst SqlEditorModal: React.FC<SqlEditorProps> = (props) => {\n const {isOpen, onClose} = props;\n\n // Memoize the handler to prevent re-renders\n const handleOpenChange = useCallback(\n (open: boolean) => {\n if (!open) onClose();\n },\n [onClose],\n );\n\n return (\n <Dialog open={isOpen} onOpenChange={handleOpenChange}>\n <DialogOverlay className=\"bg-background/80\" />\n <DialogContent className=\"max-w-[100vw] max-h-[100vh] w-[100vw] h-[100vh] p-3\">\n <DialogHeader className=\"sr-only\">\n <DialogTitle>SQL Editor</DialogTitle>\n <DialogDescription>\n SQL editor for querying and managing database tables\n </DialogDescription>\n </DialogHeader>\n <Suspense fallback={<SpinnerPane h=\"100%\" />}>\n <SqlEditor {...props} />\n </Suspense>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default SqlEditorModal;\n"]}
|