@sqlrooms/sql-editor 0.7.0 → 0.8.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 CHANGED
@@ -1,3 +1,5 @@
1
+ This package is part of the SQLRooms framework.
2
+
1
3
  # SQL Editor
2
4
 
3
5
  A powerful SQL editor component for SQLRooms applications. This package provides React components and hooks for creating interactive SQL query interfaces with Monaco editor integration, table management, and results visualization.
@@ -22,23 +24,70 @@ npm install @sqlrooms/sql-editor
22
24
 
23
25
  ### Simple SQL Editor
24
26
 
27
+ The most basic way to use the SQL Editor with show/hide functionality:
28
+
25
29
  ```tsx
26
30
  import {SqlEditor} from '@sqlrooms/sql-editor';
31
+ import {useDisclosure} from '@sqlrooms/ui';
32
+
33
+ function MyApp() {
34
+ const {isOpen, onOpen, onClose} = useDisclosure({defaultIsOpen: true});
27
35
 
28
- function MySqlEditor() {
29
- const [isOpen, setIsOpen] = useState(true);
36
+ return (
37
+ <div className="my-app">
38
+ <button onClick={isOpen ? onClose : onOpen}>
39
+ {isOpen ? 'Hide' : 'Show'} SQL Editor
40
+ </button>
30
41
 
31
- return <SqlEditor isOpen={isOpen} onClose={() => setIsOpen(false)} />;
42
+ {isOpen && <SqlEditor isOpen={true} onClose={onClose} />}
43
+ </div>
44
+ );
32
45
  }
33
46
  ```
34
47
 
35
- ### With Custom Schema and Documentation
48
+ ### SQL Editor with Custom Configuration
49
+
50
+ Using the SQL Editor with project store integration for advanced functionality:
36
51
 
37
52
  ```tsx
38
53
  import {SqlEditor} from '@sqlrooms/sql-editor';
54
+ import {useProjectStore} from './store';
55
+
56
+ function AdvancedEditor() {
57
+ // Use the store to access SQL editor state and actions
58
+ const executeQuery = useProjectStore((state) => state.executeQuery);
59
+ const currentQuery = useProjectStore((state) => state.getCurrentQuery());
60
+
61
+ return (
62
+ <div className="sql-workspace">
63
+ <h2>SQL Workspace</h2>
64
+
65
+ <div className="tools">
66
+ <button onClick={() => executeQuery(currentQuery)}>Run Query</button>
67
+ <button onClick={() => exportResultsToCsv()}>Export Results</button>
68
+ </div>
69
+
70
+ <SqlEditor
71
+ isOpen={true}
72
+ onClose={() => {}}
73
+ schema="analytics"
74
+ initialQuery="SELECT * FROM users LIMIT 10;"
75
+ />
76
+ </div>
77
+ );
78
+ }
79
+ ```
80
+
81
+ ### With Custom Documentation Panel
82
+
83
+ Adding a custom documentation panel to provide SQL reference materials:
84
+
85
+ ```tsx
86
+ import {SqlEditor} from '@sqlrooms/sql-editor';
87
+ import {useDisclosure} from '@sqlrooms/ui';
39
88
 
40
89
  function AdvancedSqlEditor() {
41
- const [isOpen, setIsOpen] = useState(true);
90
+ const {isOpen, onClose} = useDisclosure({defaultIsOpen: true});
42
91
 
43
92
  // Custom documentation component
44
93
  const Documentation = () => (
@@ -60,7 +109,7 @@ function AdvancedSqlEditor() {
60
109
  return (
61
110
  <SqlEditor
62
111
  isOpen={isOpen}
63
- onClose={() => setIsOpen(false)}
112
+ onClose={onClose}
64
113
  schema="analytics"
65
114
  documentationPanel={<Documentation />}
66
115
  />
@@ -68,74 +117,33 @@ function AdvancedSqlEditor() {
68
117
  }
69
118
  ```
70
119
 
71
- ## Available Components
72
-
73
- ### SqlEditor
120
+ ### Using SQL Monaco Editor Standalone
74
121
 
75
- The main component providing a full-featured SQL editor interface.
76
-
77
- ```tsx
78
- import {SqlEditor} from '@sqlrooms/sql-editor';
79
-
80
- <SqlEditor
81
- isOpen={boolean}
82
- onClose={() => void}
83
- schema="main"
84
- documentationPanel={ReactNode}
85
- />
86
- ```
87
-
88
- ### SqlMonacoEditor
89
-
90
- A standalone SQL-specific Monaco editor component.
122
+ For cases where you only need the editor component without the full interface:
91
123
 
92
124
  ```tsx
93
125
  import {SqlMonacoEditor} from '@sqlrooms/sql-editor';
94
126
 
95
- <SqlMonacoEditor
96
- value="SELECT * FROM users"
97
- onChange={(value) => console.log(value)}
98
- onExecuteQuery={() => executeQuery()}
99
- />;
100
- ```
101
-
102
- ### SqlEditorModal
103
-
104
- A modal wrapper around the SQL editor.
105
-
106
- ```tsx
107
- import {SqlEditorModal} from '@sqlrooms/sql-editor';
108
-
109
- <SqlEditorModal isOpen={isOpen} onClose={() => setIsOpen(false)} />;
110
- ```
111
-
112
- ### CreateTableModal
127
+ function SimpleSqlEditor() {
128
+ const [query, setQuery] = useState('SELECT * FROM products');
113
129
 
114
- A modal for creating new tables from SQL queries.
115
-
116
- ```tsx
117
- import {CreateTableModal} from '@sqlrooms/sql-editor';
118
-
119
- <CreateTableModal
120
- isOpen={isOpen}
121
- onClose={() => setIsOpen(false)}
122
- onCreateTable={(tableName) => console.log(`Created table: ${tableName}`)}
123
- tableData={queryResults}
124
- />;
125
- ```
126
-
127
- ### SqlQueryDataSourcesPanel
128
-
129
- A panel showing available data sources for SQL queries.
130
-
131
- ```tsx
132
- import {SqlQueryDataSourcesPanel} from '@sqlrooms/sql-editor';
130
+ const handleExecute = () => {
131
+ // Execute the query using your own logic
132
+ console.log('Executing query:', query);
133
+ };
133
134
 
134
- <SqlQueryDataSourcesPanel
135
- onSelectTable={(tableName) => {
136
- console.log(`Selected table: ${tableName}`);
137
- }}
138
- />;
135
+ return (
136
+ <>
137
+ <SqlMonacoEditor
138
+ value={query}
139
+ onChange={setQuery}
140
+ onExecuteQuery={handleExecute}
141
+ height="400px"
142
+ />
143
+ <button onClick={handleExecute}>Execute</button>
144
+ </>
145
+ );
146
+ }
139
147
  ```
140
148
 
141
149
  ## State Management
@@ -250,6 +258,139 @@ const {executeQuery, getCurrentQuery} = useStoreWithSqlEditor(useStore);
250
258
  - `setSelectedQueryId(queryId: string)`: Set the selected query tab
251
259
  - `getCurrentQuery(defaultQuery?: string)`: Get current query text
252
260
 
261
+ ## Available Components
262
+
263
+ ### SqlEditor
264
+
265
+ The main component providing a full-featured SQL editor interface.
266
+
267
+ ```tsx
268
+ import {SqlEditor} from '@sqlrooms/sql-editor';
269
+
270
+ <SqlEditor
271
+ isOpen={boolean}
272
+ onClose={() => void}
273
+ schema="main"
274
+ documentationPanel={ReactNode}
275
+ />
276
+ ```
277
+
278
+ ### SqlMonacoEditor
279
+
280
+ A standalone SQL-specific Monaco editor component.
281
+
282
+ ```tsx
283
+ import {SqlMonacoEditor} from '@sqlrooms/sql-editor';
284
+
285
+ <SqlMonacoEditor
286
+ value="SELECT * FROM users"
287
+ onChange={(value) => console.log(value)}
288
+ onExecuteQuery={() => executeQuery()}
289
+ />;
290
+ ```
291
+
292
+ ### SqlEditorModal
293
+
294
+ A modal wrapper around the SQL editor.
295
+
296
+ ```tsx
297
+ import {SqlEditorModal} from '@sqlrooms/sql-editor';
298
+ import {useDisclosure} from '@sqlrooms/ui';
299
+
300
+ function EditorWithModal() {
301
+ const {isOpen, onOpen, onClose} = useDisclosure();
302
+
303
+ return (
304
+ <>
305
+ <button onClick={onOpen}>Open SQL Editor</button>
306
+ <SqlEditorModal isOpen={isOpen} onClose={onClose} />
307
+ </>
308
+ );
309
+ }
310
+ ```
311
+
312
+ ### CreateTableModal
313
+
314
+ A modal for creating new tables from SQL queries.
315
+
316
+ ```tsx
317
+ import {CreateTableModal} from '@sqlrooms/sql-editor';
318
+ import {useDisclosure} from '@sqlrooms/ui';
319
+
320
+ function TableCreator() {
321
+ const {isOpen, onOpen, onClose} = useDisclosure();
322
+
323
+ return (
324
+ <>
325
+ <button onClick={onOpen}>Create Table from Results</button>
326
+ <CreateTableModal
327
+ isOpen={isOpen}
328
+ onClose={onClose}
329
+ onCreateTable={(tableName) =>
330
+ console.log(`Created table: ${tableName}`)
331
+ }
332
+ tableData={queryResults}
333
+ />
334
+ </>
335
+ );
336
+ }
337
+ ```
338
+
339
+ ### SqlQueryDataSourcesPanel
340
+
341
+ A panel showing available data sources for SQL queries.
342
+
343
+ ```tsx
344
+ import {SqlQueryDataSourcesPanel} from '@sqlrooms/sql-editor';
345
+
346
+ <SqlQueryDataSourcesPanel
347
+ onSelectTable={(tableName) => {
348
+ console.log(`Selected table: ${tableName}`);
349
+ }}
350
+ />;
351
+ ```
352
+
353
+ ## Props
354
+
355
+ ### SqlEditor Props
356
+
357
+ | Prop | Type | Default | Description |
358
+ | ------------------ | ----------- | --------- | -------------------------------------- |
359
+ | isOpen | boolean | - | Whether the editor is open |
360
+ | onClose | function | - | Callback when the editor is closed |
361
+ | schema | string | 'main' | Default schema to use for queries |
362
+ | documentationPanel | ReactNode | undefined | Custom documentation panel to display |
363
+ | initialQuery | string | '' | Initial query to display in the editor |
364
+ | store | StoreObject | undefined | Custom Zustand store to use (optional) |
365
+
366
+ ### SqlMonacoEditor Props
367
+
368
+ | Prop | Type | Default | Description |
369
+ | -------------- | -------- | ------- | -------------------------------------------- |
370
+ | value | string | '' | The SQL query text |
371
+ | onChange | function | - | Callback when the query text changes |
372
+ | onExecuteQuery | function | - | Callback when the execute command is invoked |
373
+ | height | string | '300px' | Height of the editor |
374
+ | readOnly | boolean | false | Whether the editor is read-only |
375
+ | theme | string | 'dark' | Editor theme ('dark' or 'light') |
376
+
377
+ ### SqlEditorModal Props
378
+
379
+ | Prop | Type | Default | Description |
380
+ | ------- | -------- | ------- | --------------------------------- |
381
+ | isOpen | boolean | - | Whether the modal is open |
382
+ | onClose | function | - | Callback when the modal is closed |
383
+ | schema | string | 'main' | Default schema to use for queries |
384
+
385
+ ### CreateTableModal Props
386
+
387
+ | Prop | Type | Default | Description |
388
+ | ------------- | -------- | ------- | ----------------------------------------- |
389
+ | isOpen | boolean | - | Whether the modal is open |
390
+ | onClose | function | - | Callback when the modal is closed |
391
+ | onCreateTable | function | - | Callback when a table is created |
392
+ | tableData | Table | - | Apache Arrow Table data for the new table |
393
+
253
394
  ## Configuration
254
395
 
255
396
  The SQL editor can be configured through the Zustand store.
@@ -265,27 +406,4 @@ const config = {
265
406
  };
266
407
  ```
267
408
 
268
- ## Integration with DuckDB
269
-
270
- This package integrates with `@sqlrooms/duckdb` for query execution and table management.
271
-
272
- ```tsx
273
- import {getDuckDb} from '@sqlrooms/duckdb';
274
- import {Table} from 'apache-arrow';
275
-
276
- // Execute a query directly
277
- async function runQuery(query: string): Promise<Table> {
278
- const db = await getDuckDb();
279
- return db.query(query);
280
- }
281
- ```
282
-
283
- ## Advanced Features
284
-
285
- - **Custom Monaco Configuration**: Customize editor settings and SQL language support
286
- - **Tab Management**: Create, rename, and delete query tabs
287
- - **Table Creation**: Create new tables from query results
288
- - **Table Schema Inspection**: View table schemas and column types
289
- - **Export Functionality**: Export query results to various formats
290
-
291
409
  For more information, visit the SQLRooms documentation.
@@ -1 +1 @@
1
- {"version":3,"file":"SqlEditor.d.ts","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAiB9D,MAAM,MAAM,cAAc,GAAG;IAC3B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAC;IAEhB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAErC,0DAA0D;IAC1D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AA2aF,QAAA,MAAM,SAAS,4CAA4B,CAAC;AAE5C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"SqlEditor.d.ts","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAiB9D,MAAM,MAAM,cAAc,GAAG;IAC3B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAC;IAEhB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAErC,0DAA0D;IAC1D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAyaF,QAAA,MAAM,SAAS,4CAA4B,CAAC;AAE5C,eAAe,SAAS,CAAC"}
package/dist/SqlEditor.js CHANGED
@@ -31,8 +31,8 @@ const SqlEditorBase = (props) => {
31
31
  // Store access - directly use the selector
32
32
  const addOrUpdateSqlQueryDataSource = useBaseProjectStore((state) => state.project.addOrUpdateSqlQueryDataSource);
33
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);
34
+ const queries = useStoreWithSqlEditor((s) => s.config.sqlEditor.queries);
35
+ const selectedQueryId = useStoreWithSqlEditor((s) => s.config.sqlEditor.selectedQueryId);
36
36
  const getCurrentQuery = useStoreWithSqlEditor((s) => s.sqlEditor.getCurrentQuery);
37
37
  const setSelectedQueryId = useStoreWithSqlEditor((s) => s.sqlEditor.setSelectedQueryId);
38
38
  const updateQueryText = useStoreWithSqlEditor((s) => s.sqlEditor.updateQueryText);
@@ -1 +1 @@
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
+ {"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((s) => s.config.sqlEditor.queries);\n const selectedQueryId = useStoreWithSqlEditor(\n (s) => s.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"]}
@@ -59,20 +59,20 @@ export function createSqlEditorSlice() {
59
59
  saveAs(blob, filename || `export-${genRandomStr(5)}.csv`);
60
60
  },
61
61
  createQueryTab: (initialQuery = '') => {
62
- const sqlEditorConfig = get().project.config.sqlEditor;
62
+ const sqlEditorConfig = get().config.sqlEditor;
63
63
  const newQuery = {
64
64
  id: genRandomStr(8),
65
65
  name: generateUniqueName('Untitled', sqlEditorConfig.queries.map((q) => q.name)),
66
66
  query: initialQuery,
67
67
  };
68
68
  set((state) => produce(state, (draft) => {
69
- draft.project.config.sqlEditor.queries.push(newQuery);
70
- draft.project.config.sqlEditor.selectedQueryId = newQuery.id;
69
+ draft.config.sqlEditor.queries.push(newQuery);
70
+ draft.config.sqlEditor.selectedQueryId = newQuery.id;
71
71
  }));
72
72
  return newQuery;
73
73
  },
74
74
  deleteQueryTab: (queryId) => {
75
- const sqlEditorConfig = get().project.config.sqlEditor;
75
+ const sqlEditorConfig = get().config.sqlEditor;
76
76
  const queries = sqlEditorConfig.queries;
77
77
  if (queries.length <= 1) {
78
78
  // Don't delete the last query
@@ -84,21 +84,21 @@ export function createSqlEditorSlice() {
84
84
  const isSelected = sqlEditorConfig.selectedQueryId === queryId;
85
85
  const filteredQueries = queries.filter((q) => q.id !== queryId);
86
86
  set((state) => produce(state, (draft) => {
87
- draft.project.config.sqlEditor.queries = filteredQueries;
87
+ draft.config.sqlEditor.queries = filteredQueries;
88
88
  // If we're deleting the selected tab, select the previous one or the first one
89
89
  if (isSelected && filteredQueries.length > 0) {
90
90
  const newSelectedIndex = Math.max(0, index - 1);
91
91
  // Safely access the ID with fallback to the first query if needed
92
92
  const newSelectedId = filteredQueries[newSelectedIndex]?.id ?? filteredQueries[0]?.id;
93
93
  if (newSelectedId) {
94
- draft.project.config.sqlEditor.selectedQueryId = newSelectedId;
94
+ draft.config.sqlEditor.selectedQueryId = newSelectedId;
95
95
  }
96
96
  }
97
97
  }));
98
98
  },
99
99
  renameQueryTab: (queryId, newName) => {
100
100
  set((state) => produce(state, (draft) => {
101
- const query = draft.project.config.sqlEditor.queries.find((q) => q.id === queryId);
101
+ const query = draft.config.sqlEditor.queries.find((q) => q.id === queryId);
102
102
  if (query) {
103
103
  query.name = newName || query.name;
104
104
  }
@@ -106,7 +106,7 @@ export function createSqlEditorSlice() {
106
106
  },
107
107
  updateQueryText: (queryId, queryText) => {
108
108
  set((state) => produce(state, (draft) => {
109
- const query = draft.project.config.sqlEditor.queries.find((q) => q.id === queryId);
109
+ const query = draft.config.sqlEditor.queries.find((q) => q.id === queryId);
110
110
  if (query) {
111
111
  query.query = queryText;
112
112
  }
@@ -114,11 +114,11 @@ export function createSqlEditorSlice() {
114
114
  },
115
115
  setSelectedQueryId: (queryId) => {
116
116
  set((state) => produce(state, (draft) => {
117
- draft.project.config.sqlEditor.selectedQueryId = queryId;
117
+ draft.config.sqlEditor.selectedQueryId = queryId;
118
118
  }));
119
119
  },
120
120
  getCurrentQuery: (defaultQuery = '') => {
121
- const sqlEditorConfig = get().project.config.sqlEditor;
121
+ const sqlEditorConfig = get().config.sqlEditor;
122
122
  const selectedId = sqlEditorConfig.selectedQueryId;
123
123
  // Find query by ID
124
124
  const query = sqlEditorConfig.queries.find((q) => q.id === selectedId);
@@ -1 +1 @@
1
- {"version":3,"file":"SqlEditorSlice.js","sourceRoot":"","sources":["../src/SqlEditorSlice.tsx"],"names":[],"mappings":"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","sourcesContent":["import {DuckQueryError, getDuckDb, getDuckTableSchemas} from '@sqlrooms/duckdb';\nimport {\n createSlice,\n ProjectState,\n StateCreator,\n useBaseProjectStore,\n} from '@sqlrooms/project-builder';\nimport {BaseProjectConfig} from '@sqlrooms/project-config';\nimport {generateUniqueName, genRandomStr} from '@sqlrooms/utils';\nimport {Table} from 'apache-arrow';\nimport {csvFormat} from 'd3-dsv';\nimport {saveAs} from 'file-saver';\nimport {produce} from 'immer';\nimport {z} from 'zod';\n\nexport const SqlEditorSliceConfig = z.object({\n sqlEditor: z.object({\n queries: z.array(\n z.object({\n id: z.string().describe('Query identifier.'),\n name: z.string().describe('Query name.'),\n query: z.string().describe('SQL query to execute.'),\n }),\n ),\n selectedQueryId: z\n .string()\n .default('default')\n .describe('The id of the currently selected query.'),\n }),\n});\nexport type SqlEditorSliceConfig = z.infer<typeof SqlEditorSliceConfig>;\n\nexport function createDefaultSqlEditorConfig(): SqlEditorSliceConfig {\n return {\n sqlEditor: {\n queries: [{id: 'default', name: 'Untitled', query: ''}],\n selectedQueryId: 'default',\n },\n };\n}\n\nexport type SqlEditorSliceState = {\n sqlEditor: {\n /**\n * Execute a SQL query and return the results.\n * @param query - The SQL query to execute.\n * @param schema - The schema to use (default: main).\n */\n executeQuery(\n query: string,\n schema?: string,\n ): Promise<{\n results?: Table;\n error?: string;\n }>;\n\n /**\n * Export query results to CSV.\n * @param results - The query results to export.\n * @param filename - Optional filename (default is generated).\n */\n exportResultsToCsv(results: Table, filename?: string): void;\n\n /**\n * Create a new query tab.\n * @param initialQuery - Optional initial query text.\n */\n createQueryTab(initialQuery?: string): {\n id: string;\n name: string;\n query: string;\n };\n\n /**\n * Delete a query tab.\n * @param queryId - The ID of the query to delete.\n */\n deleteQueryTab(queryId: string): void;\n\n /**\n * Rename a query tab.\n * @param queryId - The ID of the query to rename.\n * @param newName - The new name for the query.\n */\n renameQueryTab(queryId: string, newName: string): void;\n\n /**\n * Update the SQL text for a query.\n * @param queryId - The ID of the query to update.\n * @param queryText - The new SQL text.\n */\n updateQueryText(queryId: string, queryText: string): void;\n\n /**\n * Set the selected query tab.\n * @param queryId - The ID of the query to select.\n */\n setSelectedQueryId(queryId: string): void;\n\n /**\n * Get the currently selected query's SQL text.\n * @param defaultQuery - Optional default query text to return if no query is found.\n */\n getCurrentQuery(defaultQuery?: string): string;\n };\n};\n\nexport function createSqlEditorSlice<\n PC extends BaseProjectConfig & SqlEditorSliceConfig,\n>(): StateCreator<SqlEditorSliceState> {\n return createSlice<PC, SqlEditorSliceState>((set, get) => ({\n sqlEditor: {\n executeQuery: async (query, schema = 'main') => {\n const duckDb = await getDuckDb();\n if (!duckDb.conn) {\n return {error: 'No DuckDB connection available'};\n }\n\n try {\n await duckDb.conn.query(`SET search_path = ${schema}`);\n const results = await duckDb.conn.query(query);\n await duckDb.conn.query(`SET search_path = main`);\n\n // Refresh table schemas after query execution\n await get().project.refreshTableSchemas();\n\n return {results};\n } catch (e) {\n console.error(e);\n const errorMessage =\n e instanceof DuckQueryError\n ? e.getMessageForUser()\n : 'Query failed';\n\n return {error: errorMessage || String(e)};\n }\n },\n\n exportResultsToCsv: (results, filename) => {\n if (!results) return;\n const blob = new Blob([csvFormat(results.toArray())], {\n type: 'text/plain;charset=utf-8',\n });\n saveAs(blob, filename || `export-${genRandomStr(5)}.csv`);\n },\n\n createQueryTab: (initialQuery = '') => {\n const sqlEditorConfig = get().project.config.sqlEditor;\n const newQuery = {\n id: genRandomStr(8),\n name: generateUniqueName(\n 'Untitled',\n sqlEditorConfig.queries.map((q) => q.name),\n ),\n query: initialQuery,\n };\n\n set((state) =>\n produce(state, (draft) => {\n draft.project.config.sqlEditor.queries.push(newQuery);\n draft.project.config.sqlEditor.selectedQueryId = newQuery.id;\n }),\n );\n\n return newQuery;\n },\n\n deleteQueryTab: (queryId) => {\n const sqlEditorConfig = get().project.config.sqlEditor;\n const queries = sqlEditorConfig.queries;\n\n if (queries.length <= 1) {\n // Don't delete the last query\n return;\n }\n\n const index = queries.findIndex((q) => q.id === queryId);\n if (index === -1) return;\n\n const isSelected = sqlEditorConfig.selectedQueryId === queryId;\n const filteredQueries = queries.filter((q) => q.id !== queryId);\n\n set((state) =>\n produce(state, (draft) => {\n draft.project.config.sqlEditor.queries = filteredQueries;\n\n // If we're deleting the selected tab, select the previous one or the first one\n if (isSelected && filteredQueries.length > 0) {\n const newSelectedIndex = Math.max(0, index - 1);\n // Safely access the ID with fallback to the first query if needed\n const newSelectedId =\n filteredQueries[newSelectedIndex]?.id ?? filteredQueries[0]?.id;\n if (newSelectedId) {\n draft.project.config.sqlEditor.selectedQueryId = newSelectedId;\n }\n }\n }),\n );\n },\n\n renameQueryTab: (queryId, newName) => {\n set((state) =>\n produce(state, (draft) => {\n const query = draft.project.config.sqlEditor.queries.find(\n (q) => q.id === queryId,\n );\n if (query) {\n query.name = newName || query.name;\n }\n }),\n );\n },\n\n updateQueryText: (queryId, queryText) => {\n set((state) =>\n produce(state, (draft) => {\n const query = draft.project.config.sqlEditor.queries.find(\n (q) => q.id === queryId,\n );\n if (query) {\n query.query = queryText;\n }\n }),\n );\n },\n\n setSelectedQueryId: (queryId) => {\n set((state) =>\n produce(state, (draft) => {\n draft.project.config.sqlEditor.selectedQueryId = queryId;\n }),\n );\n },\n\n getCurrentQuery: (defaultQuery = '') => {\n const sqlEditorConfig = get().project.config.sqlEditor;\n const selectedId = sqlEditorConfig.selectedQueryId;\n // Find query by ID\n const query = sqlEditorConfig.queries.find((q) => q.id === selectedId);\n // If found, return its query text, otherwise default\n return query?.query || defaultQuery;\n },\n },\n }));\n}\n\ntype ProjectConfigWithSqlEditor = BaseProjectConfig & SqlEditorSliceConfig;\ntype ProjectStateWithSqlEditor = ProjectState<ProjectConfigWithSqlEditor> &\n SqlEditorSliceState;\n\nexport function useStoreWithSqlEditor<T>(\n selector: (state: ProjectStateWithSqlEditor) => T,\n): T {\n return useBaseProjectStore<\n BaseProjectConfig & SqlEditorSliceConfig,\n ProjectState<ProjectConfigWithSqlEditor>,\n T\n >((state) => selector(state as unknown as ProjectStateWithSqlEditor));\n}\n"]}
1
+ {"version":3,"file":"SqlEditorSlice.js","sourceRoot":"","sources":["../src/SqlEditorSlice.tsx"],"names":[],"mappings":"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","sourcesContent":["import {DuckQueryError, getDuckDb, getDuckTableSchemas} from '@sqlrooms/duckdb';\nimport {\n createSlice,\n ProjectState,\n StateCreator,\n useBaseProjectStore,\n} from '@sqlrooms/project-builder';\nimport {BaseProjectConfig} from '@sqlrooms/project-config';\nimport {generateUniqueName, genRandomStr} from '@sqlrooms/utils';\nimport {Table} from 'apache-arrow';\nimport {csvFormat} from 'd3-dsv';\nimport {saveAs} from 'file-saver';\nimport {produce} from 'immer';\nimport {z} from 'zod';\n\nexport const SqlEditorSliceConfig = z.object({\n sqlEditor: z.object({\n queries: z.array(\n z.object({\n id: z.string().describe('Query identifier.'),\n name: z.string().describe('Query name.'),\n query: z.string().describe('SQL query to execute.'),\n }),\n ),\n selectedQueryId: z\n .string()\n .default('default')\n .describe('The id of the currently selected query.'),\n }),\n});\nexport type SqlEditorSliceConfig = z.infer<typeof SqlEditorSliceConfig>;\n\nexport function createDefaultSqlEditorConfig(): SqlEditorSliceConfig {\n return {\n sqlEditor: {\n queries: [{id: 'default', name: 'Untitled', query: ''}],\n selectedQueryId: 'default',\n },\n };\n}\n\nexport type SqlEditorSliceState = {\n sqlEditor: {\n /**\n * Execute a SQL query and return the results.\n * @param query - The SQL query to execute.\n * @param schema - The schema to use (default: main).\n */\n executeQuery(\n query: string,\n schema?: string,\n ): Promise<{\n results?: Table;\n error?: string;\n }>;\n\n /**\n * Export query results to CSV.\n * @param results - The query results to export.\n * @param filename - Optional filename (default is generated).\n */\n exportResultsToCsv(results: Table, filename?: string): void;\n\n /**\n * Create a new query tab.\n * @param initialQuery - Optional initial query text.\n */\n createQueryTab(initialQuery?: string): {\n id: string;\n name: string;\n query: string;\n };\n\n /**\n * Delete a query tab.\n * @param queryId - The ID of the query to delete.\n */\n deleteQueryTab(queryId: string): void;\n\n /**\n * Rename a query tab.\n * @param queryId - The ID of the query to rename.\n * @param newName - The new name for the query.\n */\n renameQueryTab(queryId: string, newName: string): void;\n\n /**\n * Update the SQL text for a query.\n * @param queryId - The ID of the query to update.\n * @param queryText - The new SQL text.\n */\n updateQueryText(queryId: string, queryText: string): void;\n\n /**\n * Set the selected query tab.\n * @param queryId - The ID of the query to select.\n */\n setSelectedQueryId(queryId: string): void;\n\n /**\n * Get the currently selected query's SQL text.\n * @param defaultQuery - Optional default query text to return if no query is found.\n */\n getCurrentQuery(defaultQuery?: string): string;\n };\n};\n\nexport function createSqlEditorSlice<\n PC extends BaseProjectConfig & SqlEditorSliceConfig,\n>(): StateCreator<SqlEditorSliceState> {\n return createSlice<PC, SqlEditorSliceState>((set, get) => ({\n sqlEditor: {\n executeQuery: async (query, schema = 'main') => {\n const duckDb = await getDuckDb();\n if (!duckDb.conn) {\n return {error: 'No DuckDB connection available'};\n }\n\n try {\n await duckDb.conn.query(`SET search_path = ${schema}`);\n const results = await duckDb.conn.query(query);\n await duckDb.conn.query(`SET search_path = main`);\n\n // Refresh table schemas after query execution\n await get().project.refreshTableSchemas();\n\n return {results};\n } catch (e) {\n console.error(e);\n const errorMessage =\n e instanceof DuckQueryError\n ? e.getMessageForUser()\n : 'Query failed';\n\n return {error: errorMessage || String(e)};\n }\n },\n\n exportResultsToCsv: (results, filename) => {\n if (!results) return;\n const blob = new Blob([csvFormat(results.toArray())], {\n type: 'text/plain;charset=utf-8',\n });\n saveAs(blob, filename || `export-${genRandomStr(5)}.csv`);\n },\n\n createQueryTab: (initialQuery = '') => {\n const sqlEditorConfig = get().config.sqlEditor;\n const newQuery = {\n id: genRandomStr(8),\n name: generateUniqueName(\n 'Untitled',\n sqlEditorConfig.queries.map((q) => q.name),\n ),\n query: initialQuery,\n };\n\n set((state) =>\n produce(state, (draft) => {\n draft.config.sqlEditor.queries.push(newQuery);\n draft.config.sqlEditor.selectedQueryId = newQuery.id;\n }),\n );\n\n return newQuery;\n },\n\n deleteQueryTab: (queryId) => {\n const sqlEditorConfig = get().config.sqlEditor;\n const queries = sqlEditorConfig.queries;\n\n if (queries.length <= 1) {\n // Don't delete the last query\n return;\n }\n\n const index = queries.findIndex((q) => q.id === queryId);\n if (index === -1) return;\n\n const isSelected = sqlEditorConfig.selectedQueryId === queryId;\n const filteredQueries = queries.filter((q) => q.id !== queryId);\n\n set((state) =>\n produce(state, (draft) => {\n draft.config.sqlEditor.queries = filteredQueries;\n\n // If we're deleting the selected tab, select the previous one or the first one\n if (isSelected && filteredQueries.length > 0) {\n const newSelectedIndex = Math.max(0, index - 1);\n // Safely access the ID with fallback to the first query if needed\n const newSelectedId =\n filteredQueries[newSelectedIndex]?.id ?? filteredQueries[0]?.id;\n if (newSelectedId) {\n draft.config.sqlEditor.selectedQueryId = newSelectedId;\n }\n }\n }),\n );\n },\n\n renameQueryTab: (queryId, newName) => {\n set((state) =>\n produce(state, (draft) => {\n const query = draft.config.sqlEditor.queries.find(\n (q) => q.id === queryId,\n );\n if (query) {\n query.name = newName || query.name;\n }\n }),\n );\n },\n\n updateQueryText: (queryId, queryText) => {\n set((state) =>\n produce(state, (draft) => {\n const query = draft.config.sqlEditor.queries.find(\n (q) => q.id === queryId,\n );\n if (query) {\n query.query = queryText;\n }\n }),\n );\n },\n\n setSelectedQueryId: (queryId) => {\n set((state) =>\n produce(state, (draft) => {\n draft.config.sqlEditor.selectedQueryId = queryId;\n }),\n );\n },\n\n getCurrentQuery: (defaultQuery = '') => {\n const sqlEditorConfig = get().config.sqlEditor;\n const selectedId = sqlEditorConfig.selectedQueryId;\n // Find query by ID\n const query = sqlEditorConfig.queries.find((q) => q.id === selectedId);\n // If found, return its query text, otherwise default\n return query?.query || defaultQuery;\n },\n },\n }));\n}\n\ntype ProjectConfigWithSqlEditor = BaseProjectConfig & SqlEditorSliceConfig;\ntype ProjectStateWithSqlEditor = ProjectState<ProjectConfigWithSqlEditor> &\n SqlEditorSliceState;\n\nexport function useStoreWithSqlEditor<T>(\n selector: (state: ProjectStateWithSqlEditor) => T,\n): T {\n return useBaseProjectStore<\n BaseProjectConfig & SqlEditorSliceConfig,\n ProjectState<ProjectConfigWithSqlEditor>,\n T\n >((state) => selector(state as unknown as ProjectStateWithSqlEditor));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useQueryTabManagement.d.ts","sourceRoot":"","sources":["../../src/hooks/useQueryTabManagement.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,GAAE,MAAW;;;;;;;;;YA2BvD,MAAM;cACJ,MAAM;;;6BAcJ,MAAM;+BAUN,MAAM,GAAG,SAAS;;;;;;iCAkBhB,MAAM,eAAe,MAAM,SAAS,KAAK,CAAC,UAAU;kCAWpD,MAAM;iCAaN,MAAM,SAAS,KAAK,CAAC,UAAU;;;;YAnErC,MAAM;cACJ,MAAM;;EAmGf"}
1
+ {"version":3,"file":"useQueryTabManagement.d.ts","sourceRoot":"","sources":["../../src/hooks/useQueryTabManagement.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,GAAE,MAAW;;;;;;;;;YAyBvD,MAAM;cACJ,MAAM;;;6BAcJ,MAAM;+BAUN,MAAM,GAAG,SAAS;;;;;;iCAkBhB,MAAM,eAAe,MAAM,SAAS,KAAK,CAAC,UAAU;kCAWpD,MAAM;iCAaN,MAAM,SAAS,KAAK,CAAC,UAAU;;;;YAnErC,MAAM;cACJ,MAAM;;EAmGf"}
@@ -7,7 +7,7 @@ import { useStoreWithSqlEditor } from '../SqlEditorSlice';
7
7
  */
8
8
  export function useQueryTabManagement(defaultQuery = '') {
9
9
  // Get SQL editor config and functions from the store
10
- const sqlEditorConfig = useStoreWithSqlEditor((s) => s.project.config.sqlEditor);
10
+ const sqlEditorConfig = useStoreWithSqlEditor((s) => s.config.sqlEditor);
11
11
  const createQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.createQueryTab);
12
12
  const deleteQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.deleteQueryTab);
13
13
  const renameQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.renameQueryTab);
@@ -1 +1 @@
1
- {"version":3,"file":"useQueryTabManagement.js","sourceRoot":"","sources":["../../src/hooks/useQueryTabManagement.ts"],"names":[],"mappings":"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","sourcesContent":["import {useState, useCallback} from 'react';\nimport {useStoreWithSqlEditor} from '../SqlEditorSlice';\n\nexport type SqlQuery = {\n id: string;\n name: string;\n query: string;\n};\n\n/**\n * Hook for managing query tabs (adding, renaming, deleting)\n *\n * @deprecated Use the methods directly from SqlEditorSlice instead\n */\nexport function useQueryTabManagement(defaultQuery: string = '') {\n // Get SQL editor config and functions from the store\n const sqlEditorConfig = useStoreWithSqlEditor(\n (s) => s.project.config.sqlEditor,\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 const updateQueryText = useStoreWithSqlEditor(\n (s) => s.sqlEditor.updateQueryText,\n );\n const setSelectedQueryId = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setSelectedQueryId,\n );\n const getCurrentQueryFn = useStoreWithSqlEditor(\n (s) => s.sqlEditor.getCurrentQuery,\n );\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 /**\n * Get the currently selected query's SQL text\n */\n const getCurrentQuery = useCallback(() => {\n return getCurrentQueryFn(defaultQuery);\n }, [getCurrentQueryFn, defaultQuery]);\n\n /**\n * Change the selected tab\n */\n const handleTabChange = useCallback(\n (value: string) => {\n setSelectedQueryId(value);\n },\n [setSelectedQueryId],\n );\n\n /**\n * Update a query's SQL text\n */\n const handleUpdateQuery = useCallback(\n (value: string | undefined) => {\n if (!value) return;\n updateQueryText(sqlEditorConfig.selectedQueryId, value);\n },\n [sqlEditorConfig.selectedQueryId, updateQueryText],\n );\n\n /**\n * Create a new query tab\n */\n const handleNewQuery = useCallback(() => {\n return createQueryTab(defaultQuery);\n }, [createQueryTab, defaultQuery]);\n\n /**\n * Begin the rename process for a query\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 /**\n * Complete the rename process for a query\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 /**\n * Begin the delete process for a query\n */\n const handleDeleteQuery = useCallback(\n (queryId: string, event: React.MouseEvent) => {\n event.stopPropagation();\n setQueryToDelete(queryId);\n },\n [],\n );\n\n /**\n * Confirm and execute the deletion of a query\n */\n const handleConfirmDeleteQuery = useCallback(() => {\n if (queryToDelete) {\n deleteQueryTab(queryToDelete);\n setQueryToDelete(null);\n }\n }, [queryToDelete, deleteQueryTab]);\n\n return {\n queries: sqlEditorConfig.queries,\n selectedQueryId: sqlEditorConfig.selectedQueryId,\n queryToDelete,\n queryToRename,\n getCurrentQuery,\n handleTabChange,\n handleUpdateQuery,\n handleNewQuery,\n handleStartRename,\n handleFinishRename,\n handleDeleteQuery,\n handleConfirmDeleteQuery,\n setQueryToDelete,\n setQueryToRename,\n };\n}\n"]}
1
+ {"version":3,"file":"useQueryTabManagement.js","sourceRoot":"","sources":["../../src/hooks/useQueryTabManagement.ts"],"names":[],"mappings":"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","sourcesContent":["import {useState, useCallback} from 'react';\nimport {useStoreWithSqlEditor} from '../SqlEditorSlice';\n\nexport type SqlQuery = {\n id: string;\n name: string;\n query: string;\n};\n\n/**\n * Hook for managing query tabs (adding, renaming, deleting)\n *\n * @deprecated Use the methods directly from SqlEditorSlice instead\n */\nexport function useQueryTabManagement(defaultQuery: string = '') {\n // Get SQL editor config and functions from the store\n const sqlEditorConfig = useStoreWithSqlEditor((s) => s.config.sqlEditor);\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 const updateQueryText = useStoreWithSqlEditor(\n (s) => s.sqlEditor.updateQueryText,\n );\n const setSelectedQueryId = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setSelectedQueryId,\n );\n const getCurrentQueryFn = useStoreWithSqlEditor(\n (s) => s.sqlEditor.getCurrentQuery,\n );\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 /**\n * Get the currently selected query's SQL text\n */\n const getCurrentQuery = useCallback(() => {\n return getCurrentQueryFn(defaultQuery);\n }, [getCurrentQueryFn, defaultQuery]);\n\n /**\n * Change the selected tab\n */\n const handleTabChange = useCallback(\n (value: string) => {\n setSelectedQueryId(value);\n },\n [setSelectedQueryId],\n );\n\n /**\n * Update a query's SQL text\n */\n const handleUpdateQuery = useCallback(\n (value: string | undefined) => {\n if (!value) return;\n updateQueryText(sqlEditorConfig.selectedQueryId, value);\n },\n [sqlEditorConfig.selectedQueryId, updateQueryText],\n );\n\n /**\n * Create a new query tab\n */\n const handleNewQuery = useCallback(() => {\n return createQueryTab(defaultQuery);\n }, [createQueryTab, defaultQuery]);\n\n /**\n * Begin the rename process for a query\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 /**\n * Complete the rename process for a query\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 /**\n * Begin the delete process for a query\n */\n const handleDeleteQuery = useCallback(\n (queryId: string, event: React.MouseEvent) => {\n event.stopPropagation();\n setQueryToDelete(queryId);\n },\n [],\n );\n\n /**\n * Confirm and execute the deletion of a query\n */\n const handleConfirmDeleteQuery = useCallback(() => {\n if (queryToDelete) {\n deleteQueryTab(queryToDelete);\n setQueryToDelete(null);\n }\n }, [queryToDelete, deleteQueryTab]);\n\n return {\n queries: sqlEditorConfig.queries,\n selectedQueryId: sqlEditorConfig.selectedQueryId,\n queryToDelete,\n queryToRename,\n getCurrentQuery,\n handleTabChange,\n handleUpdateQuery,\n handleNewQuery,\n handleStartRename,\n handleFinishRename,\n handleDeleteQuery,\n handleConfirmDeleteQuery,\n setQueryToDelete,\n setQueryToRename,\n };\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * {@include ../README.md}
3
+ * @packageDocumentation
4
+ */
1
5
  export { default as CreateTableModal } from './CreateTableModal';
2
6
  export { default as SqlEditor } from './SqlEditor';
3
7
  export type { SqlEditorProps as Props } from './SqlEditor';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,aAAa,CAAC;AACjD,YAAY,EAAC,cAAc,IAAI,KAAK,EAAC,MAAM,aAAa,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAC,mBAAmB,EAAC,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAC,wBAAwB,EAAC,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,aAAa,CAAC;AACjD,YAAY,EAAC,cAAc,IAAI,KAAK,EAAC,MAAM,aAAa,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAC,mBAAmB,EAAC,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAC,wBAAwB,EAAC,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * {@include ../README.md}
3
+ * @packageDocumentation
4
+ */
1
5
  export { default as CreateTableModal } from './CreateTableModal';
2
6
  export { default as SqlEditor } from './SqlEditor';
3
7
  export { default as SqlEditorModal } from './SqlEditorModal';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAC,wBAAwB,EAAC,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC","sourcesContent":["export {default as CreateTableModal} from './CreateTableModal';\nexport {default as SqlEditor} from './SqlEditor';\nexport type {SqlEditorProps as Props} from './SqlEditor';\nexport {default as SqlEditorModal} from './SqlEditorModal';\nexport {\n createDefaultSqlEditorConfig,\n createSqlEditorSlice,\n SqlEditorSliceConfig,\n} from './SqlEditorSlice';\nexport type {SqlEditorSliceState} from './SqlEditorSlice';\nexport {SqlQueryDataSourcesPanel} from './SqlQueryDataSourcesPanel';\nexport {SqlMonacoEditor} from './SqlMonacoEditor';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAC,wBAAwB,EAAC,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * {@include ../README.md}\n * @packageDocumentation\n */\nexport {default as CreateTableModal} from './CreateTableModal';\nexport {default as SqlEditor} from './SqlEditor';\nexport type {SqlEditorProps as Props} from './SqlEditor';\nexport {default as SqlEditorModal} from './SqlEditorModal';\nexport {\n createDefaultSqlEditorConfig,\n createSqlEditorSlice,\n SqlEditorSliceConfig,\n} from './SqlEditorSlice';\nexport type {SqlEditorSliceState} from './SqlEditorSlice';\nexport {SqlQueryDataSourcesPanel} from './SqlQueryDataSourcesPanel';\nexport {SqlMonacoEditor} from './SqlMonacoEditor';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/sql-editor",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "author": "Ilya Boyandin <ilya@boyandin.me>",
6
6
  "license": "MIT",
@@ -27,14 +27,14 @@
27
27
  "dependencies": {
28
28
  "@hookform/resolvers": "^3.10.0",
29
29
  "@monaco-editor/react": "^4.7.0",
30
- "@sqlrooms/data-table": "0.7.0",
31
- "@sqlrooms/duckdb": "0.7.0",
32
- "@sqlrooms/layout": "0.7.0",
33
- "@sqlrooms/monaco-editor": "0.7.0",
34
- "@sqlrooms/project-builder": "0.7.0",
35
- "@sqlrooms/project-config": "0.7.0",
36
- "@sqlrooms/ui": "0.7.0",
37
- "@sqlrooms/utils": "0.7.0",
30
+ "@sqlrooms/data-table": "0.8.0",
31
+ "@sqlrooms/duckdb": "0.8.0",
32
+ "@sqlrooms/layout": "0.8.0",
33
+ "@sqlrooms/monaco-editor": "0.8.0",
34
+ "@sqlrooms/project-builder": "0.8.0",
35
+ "@sqlrooms/project-config": "0.8.0",
36
+ "@sqlrooms/ui": "0.8.0",
37
+ "@sqlrooms/utils": "0.8.0",
38
38
  "apache-arrow": "^18.1.0",
39
39
  "d3-dsv": "^3.0.1",
40
40
  "file-saver": "^2.0.5",
@@ -55,5 +55,5 @@
55
55
  "@types/react": "^18.2.48",
56
56
  "@types/react-dom": "^18.2.18"
57
57
  },
58
- "gitHead": "8be65f051c588d3a963f721322429657913b6c63"
58
+ "gitHead": "99b46a96ab900e6b005bcd30cfbfe7b3c9d51f8d"
59
59
  }