@sqlrooms/sql-editor 0.27.0-rc.2 → 0.27.0-rc.4

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.
@@ -3,7 +3,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
3
3
  import { makeQualifiedTableName } from '@sqlrooms/duckdb';
4
4
  import { Alert, AlertDescription, Button, Checkbox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Form, FormControl, FormField, FormItem, FormLabel, FormMessage, Input, Label, Popover, PopoverContent, PopoverTrigger, Spinner, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, cn, } from '@sqlrooms/ui';
5
5
  import { Check, ChevronsUpDown, HelpCircle } from 'lucide-react';
6
- import { useCallback, useMemo, useState } from 'react';
6
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
  import { useForm } from 'react-hook-form';
8
8
  import * as z from 'zod';
9
9
  import { useStoreWithSqlEditor } from '../SqlEditorSlice';
@@ -21,6 +21,15 @@ const formSchema = z.object({
21
21
  temp: z.boolean(),
22
22
  view: z.boolean(),
23
23
  });
24
+ const isAbortError = (err) => {
25
+ if (err instanceof DOMException) {
26
+ return err.name === 'AbortError';
27
+ }
28
+ if (err instanceof Error) {
29
+ return err.name === 'AbortError' || /cancelled|canceled/i.test(err.message);
30
+ }
31
+ return false;
32
+ };
24
33
  /**
25
34
  * Compact searchable combobox for selecting schema or database.
26
35
  */
@@ -35,7 +44,7 @@ const SchemaCombobox = ({ value, onChange, options, placeholder, searchPlacehold
35
44
  * Compact checkbox option with clickable label and tooltip.
36
45
  */
37
46
  const OptionCheckbox = ({ id, label, tooltip, checked, onCheckedChange, disabled }) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Checkbox, { id: id, checked: checked, onCheckedChange: onCheckedChange, disabled: disabled, className: "h-3.5 w-3.5" }), _jsx(Label, { htmlFor: id, className: cn('cursor-pointer text-xs font-normal', disabled && 'cursor-not-allowed opacity-50'), children: label }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(HelpCircle, { className: "text-muted-foreground h-3 w-3 cursor-help" }) }), _jsx(TooltipContent, { side: "top", className: "max-w-[200px] text-xs", children: tooltip })] })] }));
38
- const CreateTableForm = ({ query, onClose, editDataSource, allowMultipleStatements = false, showSchemaSelection = false, onAddOrUpdateSqlQuery, initialValues, }) => {
47
+ const CreateTableForm = ({ query, onClose, onRequestClose, editDataSource, allowMultipleStatements = false, showSchemaSelection = false, onAddOrUpdateSqlQuery, initialValues, onSubmittingChange, onRegisterCancel, }) => {
39
48
  const connector = useStoreWithSqlEditor((state) => state.db.connector);
40
49
  const createTableFromQuery = useStoreWithSqlEditor((state) => state.db.createTableFromQuery);
41
50
  const refreshTableSchemas = useStoreWithSqlEditor((state) => state.db.refreshTableSchemas);
@@ -77,12 +86,26 @@ const CreateTableForm = ({ query, onClose, editDataSource, allowMultipleStatemen
77
86
  },
78
87
  });
79
88
  const isSubmitting = form.formState.isSubmitting;
89
+ const [isCancelling, setIsCancelling] = useState(false);
90
+ const abortControllerRef = useRef(null);
91
+ useEffect(() => {
92
+ return () => {
93
+ abortControllerRef.current?.abort();
94
+ abortControllerRef.current = null;
95
+ };
96
+ }, []);
97
+ useEffect(() => {
98
+ onSubmittingChange?.(isSubmitting);
99
+ }, [isSubmitting, onSubmittingChange]);
80
100
  const onSubmit = useCallback(async (values) => {
101
+ const abortController = new AbortController();
102
+ abortControllerRef.current = abortController;
103
+ setIsCancelling(false);
81
104
  try {
82
105
  const { tableName, query, schema, database, replace, temp, view } = values;
83
106
  if (onAddOrUpdateSqlQuery) {
84
107
  // Legacy path: use the callback
85
- await onAddOrUpdateSqlQuery(tableName, query, editDataSource?.tableName);
108
+ await onAddOrUpdateSqlQuery(tableName, query, editDataSource?.tableName, abortController.signal);
86
109
  }
87
110
  else {
88
111
  // New path: call createTableFromQuery directly
@@ -94,6 +117,7 @@ const CreateTableForm = ({ query, onClose, editDataSource, allowMultipleStatemen
94
117
  temp,
95
118
  view,
96
119
  allowMultipleStatements,
120
+ abortSignal: abortController.signal,
97
121
  });
98
122
  // Refresh table schemas to show the new table
99
123
  await refreshTableSchemas();
@@ -102,8 +126,15 @@ const CreateTableForm = ({ query, onClose, editDataSource, allowMultipleStatemen
102
126
  onClose();
103
127
  }
104
128
  catch (err) {
129
+ if (isAbortError(err)) {
130
+ return;
131
+ }
105
132
  form.setError('root', { type: 'manual', message: `${err}` });
106
133
  }
134
+ finally {
135
+ abortControllerRef.current = null;
136
+ setIsCancelling(false);
137
+ }
107
138
  }, [
108
139
  onAddOrUpdateSqlQuery,
109
140
  editDataSource?.tableName,
@@ -116,13 +147,22 @@ const CreateTableForm = ({ query, onClose, editDataSource, allowMultipleStatemen
116
147
  const watchView = form.watch('view');
117
148
  const watchTemp = form.watch('temp');
118
149
  const watchTableName = form.watch('tableName');
150
+ const handleCancel = useCallback(async () => {
151
+ if (abortControllerRef.current) {
152
+ setIsCancelling(true);
153
+ abortControllerRef.current.abort();
154
+ }
155
+ }, []);
156
+ useEffect(() => {
157
+ onRegisterCancel?.(handleCancel);
158
+ }, [handleCancel, onRegisterCancel]);
119
159
  return (_jsx(TooltipProvider, { delayDuration: 200, children: _jsx(Form, { ...form, children: _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "space-y-4", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: editDataSource
120
160
  ? 'Edit table query'
121
161
  : watchView
122
162
  ? 'Create view from query'
123
163
  : 'Create table from query' }), !editDataSource && (_jsx(DialogDescription, { children: watchView
124
164
  ? 'Create a new view from an SQL query.'
125
- : 'Create a new table from the results of an SQL query.' }))] }), form.formState.errors.root && (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { className: "whitespace-pre-wrap font-mono text-xs", children: form.formState.errors.root.message }) })), _jsxs("div", { className: "flex items-end gap-3", children: [_jsx(FormField, { control: form.control, name: "tableName", render: ({ field }) => (_jsxs(FormItem, { className: "min-w-0 flex-[2]", children: [_jsx(FormLabel, { className: "text-xs", children: watchView ? 'View name' : 'Table name' }), _jsx(FormControl, { children: _jsx(Input, { ...field, className: "h-9 font-mono text-xs", autoFocus: true, disabled: isSubmitting }) }), _jsx(FormMessage, { className: "text-xs" })] })) }), showSchemaSelection && (_jsxs(_Fragment, { children: [_jsx(FormField, { control: form.control, name: "schema", render: ({ field }) => (_jsxs(FormItem, { className: "min-w-0 flex-1", children: [_jsx(FormLabel, { className: "text-xs", children: "Schema" }), _jsx(FormControl, { children: _jsx(SchemaCombobox, { value: field.value, onChange: field.onChange, options: schemas, placeholder: "Schema...", searchPlaceholder: "Search...", emptyMessage: "No schemas.", disabled: isSubmitting }) })] })) }), (databases.length > 1 || watchTemp) && (_jsx(FormField, { control: form.control, name: "database", render: ({ field }) => (_jsxs(FormItem, { className: "min-w-0 flex-1", children: [_jsx(FormLabel, { className: "text-xs", children: "Database" }), _jsx(FormControl, { children: _jsx(SchemaCombobox, { value: watchTemp ? 'temp' : field.value, onChange: field.onChange, options: databases, placeholder: "Database...", searchPlaceholder: "Search...", emptyMessage: "No databases.", disabled: isSubmitting || watchTemp }) })] })) }))] }))] }), _jsx(FormField, { control: form.control, name: "query", render: ({ field }) => (_jsxs(FormItem, { className: "relative flex h-[200px] flex-col", children: [_jsx(FormControl, { children: _jsx(SqlMonacoEditor, { connector: connector, value: field.value, onChange: field.onChange, className: "absolute inset-0 h-full w-full", options: {
165
+ : 'Create a new table from the results of an SQL query.' }))] }), form.formState.errors.root && (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { className: "whitespace-pre-wrap font-mono text-xs", children: form.formState.errors.root.message }) })), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(FormField, { control: form.control, name: "tableName", render: ({ field }) => (_jsxs(FormItem, { className: "min-w-0 flex-[2]", children: [_jsx(FormLabel, { className: "text-xs", children: watchView ? 'View name' : 'Table name' }), _jsx(FormControl, { children: _jsx(Input, { ...field, className: "h-9 font-mono text-xs", autoFocus: true, disabled: isSubmitting }) }), _jsx(FormMessage, { className: "text-xs" })] })) }), showSchemaSelection && (_jsxs(_Fragment, { children: [_jsx(FormField, { control: form.control, name: "schema", render: ({ field }) => (_jsxs(FormItem, { className: "min-w-0 flex-1", children: [_jsx(FormLabel, { className: "text-xs", children: "Schema" }), _jsx(FormControl, { children: _jsx(SchemaCombobox, { value: field.value, onChange: field.onChange, options: schemas, placeholder: "Schema...", searchPlaceholder: "Search...", emptyMessage: "No schemas.", disabled: isSubmitting }) })] })) }), (databases.length > 1 || watchTemp) && (_jsx(FormField, { control: form.control, name: "database", render: ({ field }) => (_jsxs(FormItem, { className: "min-w-0 flex-1", children: [_jsx(FormLabel, { className: "text-xs", children: "Database" }), _jsx(FormControl, { children: _jsx(SchemaCombobox, { value: watchTemp ? 'temp' : field.value, onChange: field.onChange, options: databases, placeholder: "Database...", searchPlaceholder: "Search...", emptyMessage: "No databases.", disabled: isSubmitting || watchTemp }) })] })) }))] }))] }), _jsx(FormField, { control: form.control, name: "query", render: ({ field }) => (_jsxs(FormItem, { className: "relative flex h-[200px] flex-col", children: [_jsx(FormControl, { children: _jsx(SqlMonacoEditor, { connector: connector, value: field.value, onChange: field.onChange, className: "absolute inset-0 h-full w-full", options: {
126
166
  scrollBeyondLastLine: false,
127
167
  automaticLayout: true,
128
168
  minimap: { enabled: false },
@@ -131,11 +171,46 @@ const CreateTableForm = ({ query, onClose, editDataSource, allowMultipleStatemen
131
171
  lineNumbers: 'off',
132
172
  readOnly: isSubmitting,
133
173
  fixedOverflowWidgets: false, // default true doesn't work well in a modal
134
- } }) }), _jsx(FormMessage, { className: "text-xs" })] })) }), !onAddOrUpdateSqlQuery && (_jsxs("div", { className: "flex items-center gap-6 rounded-md border px-3 py-2", children: [_jsx(FormField, { control: form.control, name: "view", render: ({ field }) => (_jsx(OptionCheckbox, { id: "create-table-view", label: "View", tooltip: "Create a view instead of a table. Views store the query, not the data.", checked: field.value, onCheckedChange: field.onChange, disabled: isSubmitting })) }), _jsx(FormField, { control: form.control, name: "replace", render: ({ field }) => (_jsx(OptionCheckbox, { id: "create-table-replace", label: "Overwrite", tooltip: `Overwrite existing ${watchView ? 'view' : 'table'} with the same name if it exists.`, checked: field.value, onCheckedChange: field.onChange, disabled: isSubmitting })) })] })), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "outline", onClick: onClose, disabled: isSubmitting, children: "Cancel" }), _jsxs(Button, { type: "submit", disabled: isSubmitting || !watchTableName?.trim(), children: [isSubmitting && _jsx(Spinner, { className: "mr-2" }), editDataSource ? 'Update' : 'Create'] })] })] }) }) }));
174
+ } }) }), _jsx(FormMessage, { className: "text-xs" })] })) }), !onAddOrUpdateSqlQuery && (_jsxs("div", { className: "flex items-center gap-6 rounded-md border px-3 py-2", children: [_jsx(FormField, { control: form.control, name: "view", render: ({ field }) => (_jsx(OptionCheckbox, { id: "create-table-view", label: "View", tooltip: "Create a view instead of a table. Views store the query, not the data.", checked: field.value, onCheckedChange: field.onChange, disabled: isSubmitting })) }), _jsx(FormField, { control: form.control, name: "replace", render: ({ field }) => (_jsx(OptionCheckbox, { id: "create-table-replace", label: "Overwrite", tooltip: `Overwrite existing ${watchView ? 'view' : 'table'} with the same name if it exists.`, checked: field.value, onCheckedChange: field.onChange, disabled: isSubmitting })) })] })), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "outline", onClick: onRequestClose, children: "Close" }), _jsxs(Button, { type: isSubmitting ? 'button' : 'submit', onClick: isSubmitting ? handleCancel : undefined, disabled: isSubmitting ? isCancelling : !watchTableName?.trim(), children: [isSubmitting && _jsx(Spinner, { className: "mr-2" }), isSubmitting
175
+ ? isCancelling
176
+ ? 'Cancelling...'
177
+ : 'Cancel'
178
+ : editDataSource
179
+ ? 'Update'
180
+ : 'Create'] })] })] }) }) }));
135
181
  };
136
182
  const CreateTableModal = (props) => {
137
183
  const { isOpen, onClose, query, editDataSource, allowMultipleStatements, showSchemaSelection, onAddOrUpdateSqlQuery, className, initialValues, } = props;
138
- return (_jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: _jsx(DialogContent, { className: cn('w-3xl max-w-[80%]', className), children: isOpen && (_jsx(CreateTableForm, { query: query, onClose: onClose, editDataSource: editDataSource, allowMultipleStatements: allowMultipleStatements, showSchemaSelection: showSchemaSelection, onAddOrUpdateSqlQuery: onAddOrUpdateSqlQuery, initialValues: initialValues })) }) }));
184
+ const [isSubmitting, setIsSubmitting] = useState(false);
185
+ const [isConfirmOpen, setIsConfirmOpen] = useState(false);
186
+ const cancelRef = useRef(null);
187
+ const resetState = useCallback(() => {
188
+ setIsSubmitting(false);
189
+ setIsConfirmOpen(false);
190
+ cancelRef.current = null;
191
+ }, []);
192
+ const handleClose = useCallback(() => {
193
+ resetState();
194
+ onClose();
195
+ }, [onClose, resetState]);
196
+ const handleRequestClose = useCallback(() => {
197
+ if (!isSubmitting) {
198
+ handleClose();
199
+ return;
200
+ }
201
+ setIsConfirmOpen(true);
202
+ }, [handleClose, isSubmitting]);
203
+ const handleConfirmClose = useCallback(() => {
204
+ cancelRef.current?.();
205
+ handleClose();
206
+ }, [handleClose]);
207
+ return (_jsxs(Dialog, { open: isOpen, onOpenChange: (open) => {
208
+ if (!open) {
209
+ handleRequestClose();
210
+ }
211
+ }, children: [_jsx(DialogContent, { className: cn('w-3xl max-w-[80%]', className), children: isOpen && (_jsx(CreateTableForm, { query: query, onClose: handleClose, onRequestClose: handleRequestClose, editDataSource: editDataSource, allowMultipleStatements: allowMultipleStatements, showSchemaSelection: showSchemaSelection, onAddOrUpdateSqlQuery: onAddOrUpdateSqlQuery, initialValues: initialValues, onSubmittingChange: setIsSubmitting, onRegisterCancel: (cancel) => {
212
+ cancelRef.current = cancel;
213
+ } })) }), _jsx(Dialog, { open: isConfirmOpen, onOpenChange: setIsConfirmOpen, children: _jsxs(DialogContent, { className: "max-w-md", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Cancel running query?" }), _jsx(DialogDescription, { children: "A query is still running. Cancelling it will stop the query and close this dialog." })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "outline", onClick: () => setIsConfirmOpen(false), children: "Keep running" }), _jsx(Button, { type: "button", onClick: handleConfirmClose, children: "Cancel & close" })] })] }) })] }));
139
214
  };
140
215
  export default CreateTableModal;
141
216
  //# sourceMappingURL=CreateTableModal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CreateTableModal.js","sourceRoot":"","sources":["../../src/components/CreateTableModal.tsx"],"names":[],"mappings":"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","sourcesContent":["import {zodResolver} from '@hookform/resolvers/zod';\nimport {makeQualifiedTableName} from '@sqlrooms/duckdb';\nimport {SqlQueryDataSource} from '@sqlrooms/room-shell';\nimport {\n Alert,\n AlertDescription,\n Button,\n Checkbox,\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n Label,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Spinner,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n cn,\n} from '@sqlrooms/ui';\nimport {Check, ChevronsUpDown, HelpCircle} from 'lucide-react';\nimport {FC, useCallback, useMemo, useState} from 'react';\nimport {useForm} from 'react-hook-form';\nimport * as z from 'zod';\nimport {useStoreWithSqlEditor} from '../SqlEditorSlice';\nimport {SqlMonacoEditor} from '../SqlMonacoEditor';\n\nconst VALID_TABLE_OR_COLUMN_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]{0,62}$/;\n\nconst formSchema = z.object({\n tableName: z\n .string()\n .min(1, 'Table name is required')\n .regex(\n VALID_TABLE_OR_COLUMN_REGEX,\n 'Only letters, digits and underscores are allowed; should not start with a digit',\n ),\n query: z.string().min(1, 'Query is required'),\n schema: z.string().optional(),\n database: z.string().optional(),\n replace: z.boolean(),\n temp: z.boolean(),\n view: z.boolean(),\n});\n\ntype FormValues = z.infer<typeof formSchema>;\n\n/**\n * Initial values for the create table form.\n */\nexport type CreateTableFormInitialValues = Partial<{\n tableName: string;\n replace: boolean;\n temp: boolean;\n view: boolean;\n schema: string;\n database: string;\n}>;\n\nexport type CreateTableModalProps = {\n query: string;\n isOpen: boolean;\n onClose: () => void;\n editDataSource?: SqlQueryDataSource;\n /**\n * Allow multiple statements in the query. When true, preceding statements\n * will be executed before the final SELECT is wrapped in CREATE TABLE/VIEW.\n */\n allowMultipleStatements?: boolean;\n /**\n * Show schema/database selection UI.\n * @default false\n */\n showSchemaSelection?: boolean;\n /**\n * @deprecated Use createTableFromQuery directly instead.\n * When not provided, the modal will call createTableFromQuery directly.\n */\n onAddOrUpdateSqlQuery?: (\n tableName: string,\n query: string,\n oldTableName?: string,\n ) => Promise<void>;\n /**\n * Additional class name for the dialog content.\n */\n className?: string;\n /**\n * Initial values for the form fields.\n */\n initialValues?: CreateTableFormInitialValues;\n};\n\ntype CreateTableFormProps = {\n query: string;\n onClose: () => void;\n editDataSource?: SqlQueryDataSource;\n allowMultipleStatements?: boolean;\n showSchemaSelection?: boolean;\n onAddOrUpdateSqlQuery?: (\n tableName: string,\n query: string,\n oldTableName?: string,\n ) => Promise<void>;\n initialValues?: CreateTableFormInitialValues;\n};\n\n/**\n * Compact searchable combobox for selecting schema or database.\n */\nconst SchemaCombobox: FC<{\n value: string | undefined;\n onChange: (value: string | undefined) => void;\n options: string[];\n placeholder: string;\n searchPlaceholder: string;\n emptyMessage: string;\n disabled?: boolean;\n}> = ({\n value,\n onChange,\n options,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n disabled,\n}) => {\n const [open, setOpen] = useState(false);\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n className=\"h-9 w-full min-w-0 justify-between font-mono text-xs\"\n disabled={disabled}\n >\n <span className=\"min-w-0 truncate\">{value || placeholder}</span>\n <ChevronsUpDown className=\"ml-1 h-3 w-3 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[180px] p-0\">\n <Command>\n <CommandInput placeholder={searchPlaceholder} className=\"text-xs\" />\n <CommandList>\n <CommandEmpty className=\"text-xs\">{emptyMessage}</CommandEmpty>\n <CommandGroup>\n {options.map((option) => (\n <CommandItem\n key={option}\n value={option}\n className=\"text-xs\"\n onSelect={(currentValue) => {\n onChange(currentValue === value ? undefined : currentValue);\n setOpen(false);\n }}\n >\n <Check\n className={cn(\n 'mr-2 h-3 w-3',\n value === option ? 'opacity-100' : 'opacity-0',\n )}\n />\n {option}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n};\n\n/**\n * Compact checkbox option with clickable label and tooltip.\n */\nconst OptionCheckbox: FC<{\n id: string;\n label: string;\n tooltip: string;\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n disabled?: boolean;\n}> = ({id, label, tooltip, checked, onCheckedChange, disabled}) => (\n <div className=\"flex items-center gap-1.5\">\n <Checkbox\n id={id}\n checked={checked}\n onCheckedChange={onCheckedChange}\n disabled={disabled}\n className=\"h-3.5 w-3.5\"\n />\n <Label\n htmlFor={id}\n className={cn(\n 'cursor-pointer text-xs font-normal',\n disabled && 'cursor-not-allowed opacity-50',\n )}\n >\n {label}\n </Label>\n <Tooltip>\n <TooltipTrigger asChild>\n <HelpCircle className=\"text-muted-foreground h-3 w-3 cursor-help\" />\n </TooltipTrigger>\n <TooltipContent side=\"top\" className=\"max-w-[200px] text-xs\">\n {tooltip}\n </TooltipContent>\n </Tooltip>\n </div>\n);\n\nconst CreateTableForm: FC<CreateTableFormProps> = ({\n query,\n onClose,\n editDataSource,\n allowMultipleStatements = false,\n showSchemaSelection = false,\n onAddOrUpdateSqlQuery,\n initialValues,\n}) => {\n const connector = useStoreWithSqlEditor((state) => state.db.connector);\n const createTableFromQuery = useStoreWithSqlEditor(\n (state) => state.db.createTableFromQuery,\n );\n const refreshTableSchemas = useStoreWithSqlEditor(\n (state) => state.db.refreshTableSchemas,\n );\n const tables = useStoreWithSqlEditor((state) => state.db.tables);\n const currentSchema = useStoreWithSqlEditor(\n (state) => state.db.currentSchema,\n );\n const currentDatabase = useStoreWithSqlEditor(\n (state) => state.db.currentDatabase,\n );\n\n // Extract unique schemas and databases from tables (excluding system ones)\n const {schemas, databases} = useMemo(() => {\n const schemaSet = new Set<string>();\n const databaseSet = new Set<string>();\n\n for (const table of tables) {\n if (table.table.schema && !table.table.schema.startsWith('pg_')) {\n schemaSet.add(table.table.schema);\n }\n if (table.table.database) {\n databaseSet.add(table.table.database);\n }\n }\n\n // Ensure current schema/database are included\n if (currentSchema) schemaSet.add(currentSchema);\n if (currentDatabase) databaseSet.add(currentDatabase);\n\n return {\n schemas: Array.from(schemaSet).sort(),\n databases: Array.from(databaseSet).sort(),\n };\n }, [tables, currentSchema, currentDatabase]);\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema as any),\n defaultValues: {\n tableName: editDataSource?.tableName ?? initialValues?.tableName ?? '',\n query: editDataSource?.sqlQuery ?? query.trim(),\n schema: initialValues?.schema ?? currentSchema,\n database: initialValues?.database ?? currentDatabase,\n replace: initialValues?.replace ?? false,\n temp: initialValues?.temp ?? false,\n view: initialValues?.view ?? false,\n },\n });\n\n const isSubmitting = form.formState.isSubmitting;\n\n const onSubmit = useCallback(\n async (values: FormValues) => {\n try {\n const {tableName, query, schema, database, replace, temp, view} =\n values;\n\n if (onAddOrUpdateSqlQuery) {\n // Legacy path: use the callback\n await onAddOrUpdateSqlQuery(\n tableName,\n query,\n editDataSource?.tableName,\n );\n } else {\n // New path: call createTableFromQuery directly\n const qualifiedName =\n schema || database\n ? makeQualifiedTableName({table: tableName, schema, database})\n : tableName;\n\n await createTableFromQuery(qualifiedName, query, {\n replace,\n temp,\n view,\n allowMultipleStatements,\n });\n\n // Refresh table schemas to show the new table\n await refreshTableSchemas();\n }\n\n form.reset();\n onClose();\n } catch (err) {\n form.setError('root', {type: 'manual', message: `${err}`});\n }\n },\n [\n onAddOrUpdateSqlQuery,\n editDataSource?.tableName,\n createTableFromQuery,\n allowMultipleStatements,\n refreshTableSchemas,\n onClose,\n form,\n ],\n );\n\n const watchView = form.watch('view');\n const watchTemp = form.watch('temp');\n const watchTableName = form.watch('tableName');\n\n return (\n <TooltipProvider delayDuration={200}>\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-4\">\n <DialogHeader>\n <DialogTitle>\n {editDataSource\n ? 'Edit table query'\n : watchView\n ? 'Create view from query'\n : 'Create table from query'}\n </DialogTitle>\n {!editDataSource && (\n <DialogDescription>\n {watchView\n ? 'Create a new view from an SQL query.'\n : 'Create a new table from the results of an SQL query.'}\n </DialogDescription>\n )}\n </DialogHeader>\n\n {form.formState.errors.root && (\n <Alert variant=\"destructive\">\n <AlertDescription className=\"whitespace-pre-wrap font-mono text-xs\">\n {form.formState.errors.root.message}\n </AlertDescription>\n </Alert>\n )}\n\n {/* Table name, schema, database in single row */}\n <div className=\"flex items-end gap-3\">\n <FormField\n control={form.control}\n name=\"tableName\"\n render={({field}) => (\n <FormItem className=\"min-w-0 flex-[2]\">\n <FormLabel className=\"text-xs\">\n {watchView ? 'View name' : 'Table name'}\n </FormLabel>\n <FormControl>\n <Input\n {...field}\n className=\"h-9 font-mono text-xs\"\n autoFocus\n disabled={isSubmitting}\n />\n </FormControl>\n <FormMessage className=\"text-xs\" />\n </FormItem>\n )}\n />\n\n {showSchemaSelection && (\n <>\n <FormField\n control={form.control}\n name=\"schema\"\n render={({field}) => (\n <FormItem className=\"min-w-0 flex-1\">\n <FormLabel className=\"text-xs\">Schema</FormLabel>\n <FormControl>\n <SchemaCombobox\n value={field.value}\n onChange={field.onChange}\n options={schemas}\n placeholder=\"Schema...\"\n searchPlaceholder=\"Search...\"\n emptyMessage=\"No schemas.\"\n disabled={isSubmitting}\n />\n </FormControl>\n </FormItem>\n )}\n />\n\n {(databases.length > 1 || watchTemp) && (\n <FormField\n control={form.control}\n name=\"database\"\n render={({field}) => (\n <FormItem className=\"min-w-0 flex-1\">\n <FormLabel className=\"text-xs\">Database</FormLabel>\n <FormControl>\n <SchemaCombobox\n value={watchTemp ? 'temp' : field.value}\n onChange={field.onChange}\n options={databases}\n placeholder=\"Database...\"\n searchPlaceholder=\"Search...\"\n emptyMessage=\"No databases.\"\n disabled={isSubmitting || watchTemp}\n />\n </FormControl>\n </FormItem>\n )}\n />\n )}\n </>\n )}\n </div>\n\n <FormField\n control={form.control}\n name=\"query\"\n render={({field}) => (\n <FormItem className=\"relative flex h-[200px] flex-col\">\n <FormControl>\n <SqlMonacoEditor\n connector={connector}\n value={field.value}\n onChange={field.onChange}\n className=\"absolute inset-0 h-full w-full\"\n options={{\n scrollBeyondLastLine: false,\n automaticLayout: true,\n minimap: {enabled: false},\n wordWrap: 'on',\n folding: false,\n lineNumbers: 'off',\n readOnly: isSubmitting,\n fixedOverflowWidgets: false, // default true doesn't work well in a modal\n }}\n />\n </FormControl>\n <FormMessage className=\"text-xs\" />\n </FormItem>\n )}\n />\n\n {/* Compact options row */}\n {!onAddOrUpdateSqlQuery && (\n <div className=\"flex items-center gap-6 rounded-md border px-3 py-2\">\n <FormField\n control={form.control}\n name=\"view\"\n render={({field}) => (\n <OptionCheckbox\n id=\"create-table-view\"\n label=\"View\"\n tooltip=\"Create a view instead of a table. Views store the query, not the data.\"\n checked={field.value}\n onCheckedChange={field.onChange}\n disabled={isSubmitting}\n />\n )}\n />\n\n {/* <FormField\n control={form.control}\n name=\"temp\"\n render={({field}) => (\n <OptionCheckbox\n id=\"create-table-temp\"\n label=\"Temporary\"\n tooltip={`${watchView ? 'View' : 'Table'} will be deleted when the session ends.`}\n checked={field.value}\n onCheckedChange={field.onChange}\n disabled={isSubmitting}\n />\n )}\n /> */}\n\n <FormField\n control={form.control}\n name=\"replace\"\n render={({field}) => (\n <OptionCheckbox\n id=\"create-table-replace\"\n label=\"Overwrite\"\n tooltip={`Overwrite existing ${watchView ? 'view' : 'table'} with the same name if it exists.`}\n checked={field.value}\n onCheckedChange={field.onChange}\n disabled={isSubmitting}\n />\n )}\n />\n </div>\n )}\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onClose}\n disabled={isSubmitting}\n >\n Cancel\n </Button>\n <Button\n type=\"submit\"\n disabled={isSubmitting || !watchTableName?.trim()}\n >\n {isSubmitting && <Spinner className=\"mr-2\" />}\n {editDataSource ? 'Update' : 'Create'}\n </Button>\n </DialogFooter>\n </form>\n </Form>\n </TooltipProvider>\n );\n};\n\nconst CreateTableModal: FC<CreateTableModalProps> = (props) => {\n const {\n isOpen,\n onClose,\n query,\n editDataSource,\n allowMultipleStatements,\n showSchemaSelection,\n onAddOrUpdateSqlQuery,\n className,\n initialValues,\n } = props;\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>\n <DialogContent className={cn('w-3xl max-w-[80%]', className)}>\n {isOpen && (\n <CreateTableForm\n query={query}\n onClose={onClose}\n editDataSource={editDataSource}\n allowMultipleStatements={allowMultipleStatements}\n showSchemaSelection={showSchemaSelection}\n onAddOrUpdateSqlQuery={onAddOrUpdateSqlQuery}\n initialValues={initialValues}\n />\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default CreateTableModal;\n"]}
1
+ {"version":3,"file":"CreateTableModal.js","sourceRoot":"","sources":["../../src/components/CreateTableModal.tsx"],"names":[],"mappings":"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","sourcesContent":["import {zodResolver} from '@hookform/resolvers/zod';\nimport {makeQualifiedTableName} from '@sqlrooms/duckdb';\nimport {SqlQueryDataSource} from '@sqlrooms/room-shell';\nimport {\n Alert,\n AlertDescription,\n Button,\n Checkbox,\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n Label,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Spinner,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n cn,\n} from '@sqlrooms/ui';\nimport {Check, ChevronsUpDown, HelpCircle} from 'lucide-react';\nimport {FC, useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useForm} from 'react-hook-form';\nimport * as z from 'zod';\nimport {useStoreWithSqlEditor} from '../SqlEditorSlice';\nimport {SqlMonacoEditor} from '../SqlMonacoEditor';\n\nconst VALID_TABLE_OR_COLUMN_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]{0,62}$/;\n\nconst formSchema = z.object({\n tableName: z\n .string()\n .min(1, 'Table name is required')\n .regex(\n VALID_TABLE_OR_COLUMN_REGEX,\n 'Only letters, digits and underscores are allowed; should not start with a digit',\n ),\n query: z.string().min(1, 'Query is required'),\n schema: z.string().optional(),\n database: z.string().optional(),\n replace: z.boolean(),\n temp: z.boolean(),\n view: z.boolean(),\n});\n\ntype FormValues = z.infer<typeof formSchema>;\n\n/**\n * Initial values for the create table form.\n */\nexport type CreateTableFormInitialValues = Partial<{\n tableName: string;\n replace: boolean;\n temp: boolean;\n view: boolean;\n schema: string;\n database: string;\n}>;\n\nexport type CreateTableModalProps = {\n query: string;\n isOpen: boolean;\n onClose: () => void;\n editDataSource?: SqlQueryDataSource;\n /**\n * Allow multiple statements in the query. When true, preceding statements\n * will be executed before the final SELECT is wrapped in CREATE TABLE/VIEW.\n */\n allowMultipleStatements?: boolean;\n /**\n * Show schema/database selection UI.\n * @default false\n */\n showSchemaSelection?: boolean;\n /**\n * @deprecated Use createTableFromQuery directly instead.\n * When not provided, the modal will call createTableFromQuery directly.\n */\n onAddOrUpdateSqlQuery?: (\n tableName: string,\n query: string,\n oldTableName?: string,\n abortSignal?: AbortSignal,\n ) => Promise<void>;\n /**\n * Additional class name for the dialog content.\n */\n className?: string;\n /**\n * Initial values for the form fields.\n */\n initialValues?: CreateTableFormInitialValues;\n};\n\ntype CreateTableFormProps = {\n query: string;\n onClose: () => void;\n onRequestClose: () => void;\n editDataSource?: SqlQueryDataSource;\n allowMultipleStatements?: boolean;\n showSchemaSelection?: boolean;\n onAddOrUpdateSqlQuery?: (\n tableName: string,\n query: string,\n oldTableName?: string,\n abortSignal?: AbortSignal,\n ) => Promise<void>;\n initialValues?: CreateTableFormInitialValues;\n onSubmittingChange?: (isSubmitting: boolean) => void;\n onRegisterCancel?: (cancel: () => void) => void;\n};\n\nconst isAbortError = (err: unknown): boolean => {\n if (err instanceof DOMException) {\n return err.name === 'AbortError';\n }\n if (err instanceof Error) {\n return err.name === 'AbortError' || /cancelled|canceled/i.test(err.message);\n }\n return false;\n};\n\n/**\n * Compact searchable combobox for selecting schema or database.\n */\nconst SchemaCombobox: FC<{\n value: string | undefined;\n onChange: (value: string | undefined) => void;\n options: string[];\n placeholder: string;\n searchPlaceholder: string;\n emptyMessage: string;\n disabled?: boolean;\n}> = ({\n value,\n onChange,\n options,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n disabled,\n}) => {\n const [open, setOpen] = useState(false);\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n className=\"h-9 w-full min-w-0 justify-between font-mono text-xs\"\n disabled={disabled}\n >\n <span className=\"min-w-0 truncate\">{value || placeholder}</span>\n <ChevronsUpDown className=\"ml-1 h-3 w-3 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[180px] p-0\">\n <Command>\n <CommandInput placeholder={searchPlaceholder} className=\"text-xs\" />\n <CommandList>\n <CommandEmpty className=\"text-xs\">{emptyMessage}</CommandEmpty>\n <CommandGroup>\n {options.map((option) => (\n <CommandItem\n key={option}\n value={option}\n className=\"text-xs\"\n onSelect={(currentValue) => {\n onChange(currentValue === value ? undefined : currentValue);\n setOpen(false);\n }}\n >\n <Check\n className={cn(\n 'mr-2 h-3 w-3',\n value === option ? 'opacity-100' : 'opacity-0',\n )}\n />\n {option}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n};\n\n/**\n * Compact checkbox option with clickable label and tooltip.\n */\nconst OptionCheckbox: FC<{\n id: string;\n label: string;\n tooltip: string;\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n disabled?: boolean;\n}> = ({id, label, tooltip, checked, onCheckedChange, disabled}) => (\n <div className=\"flex items-center gap-1.5\">\n <Checkbox\n id={id}\n checked={checked}\n onCheckedChange={onCheckedChange}\n disabled={disabled}\n className=\"h-3.5 w-3.5\"\n />\n <Label\n htmlFor={id}\n className={cn(\n 'cursor-pointer text-xs font-normal',\n disabled && 'cursor-not-allowed opacity-50',\n )}\n >\n {label}\n </Label>\n <Tooltip>\n <TooltipTrigger asChild>\n <HelpCircle className=\"text-muted-foreground h-3 w-3 cursor-help\" />\n </TooltipTrigger>\n <TooltipContent side=\"top\" className=\"max-w-[200px] text-xs\">\n {tooltip}\n </TooltipContent>\n </Tooltip>\n </div>\n);\n\nconst CreateTableForm: FC<CreateTableFormProps> = ({\n query,\n onClose,\n onRequestClose,\n editDataSource,\n allowMultipleStatements = false,\n showSchemaSelection = false,\n onAddOrUpdateSqlQuery,\n initialValues,\n onSubmittingChange,\n onRegisterCancel,\n}) => {\n const connector = useStoreWithSqlEditor((state) => state.db.connector);\n const createTableFromQuery = useStoreWithSqlEditor(\n (state) => state.db.createTableFromQuery,\n );\n const refreshTableSchemas = useStoreWithSqlEditor(\n (state) => state.db.refreshTableSchemas,\n );\n const tables = useStoreWithSqlEditor((state) => state.db.tables);\n const currentSchema = useStoreWithSqlEditor(\n (state) => state.db.currentSchema,\n );\n const currentDatabase = useStoreWithSqlEditor(\n (state) => state.db.currentDatabase,\n );\n\n // Extract unique schemas and databases from tables (excluding system ones)\n const {schemas, databases} = useMemo(() => {\n const schemaSet = new Set<string>();\n const databaseSet = new Set<string>();\n\n for (const table of tables) {\n if (table.table.schema && !table.table.schema.startsWith('pg_')) {\n schemaSet.add(table.table.schema);\n }\n if (table.table.database) {\n databaseSet.add(table.table.database);\n }\n }\n\n // Ensure current schema/database are included\n if (currentSchema) schemaSet.add(currentSchema);\n if (currentDatabase) databaseSet.add(currentDatabase);\n\n return {\n schemas: Array.from(schemaSet).sort(),\n databases: Array.from(databaseSet).sort(),\n };\n }, [tables, currentSchema, currentDatabase]);\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema as any),\n defaultValues: {\n tableName: editDataSource?.tableName ?? initialValues?.tableName ?? '',\n query: editDataSource?.sqlQuery ?? query.trim(),\n schema: initialValues?.schema ?? currentSchema,\n database: initialValues?.database ?? currentDatabase,\n replace: initialValues?.replace ?? false,\n temp: initialValues?.temp ?? false,\n view: initialValues?.view ?? false,\n },\n });\n\n const isSubmitting = form.formState.isSubmitting;\n const [isCancelling, setIsCancelling] = useState(false);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n useEffect(() => {\n return () => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n };\n }, []);\n useEffect(() => {\n onSubmittingChange?.(isSubmitting);\n }, [isSubmitting, onSubmittingChange]);\n\n const onSubmit = useCallback(\n async (values: FormValues) => {\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n setIsCancelling(false);\n try {\n const {tableName, query, schema, database, replace, temp, view} =\n values;\n\n if (onAddOrUpdateSqlQuery) {\n // Legacy path: use the callback\n await onAddOrUpdateSqlQuery(\n tableName,\n query,\n editDataSource?.tableName,\n abortController.signal,\n );\n } else {\n // New path: call createTableFromQuery directly\n const qualifiedName =\n schema || database\n ? makeQualifiedTableName({table: tableName, schema, database})\n : tableName;\n\n await createTableFromQuery(qualifiedName, query, {\n replace,\n temp,\n view,\n allowMultipleStatements,\n abortSignal: abortController.signal,\n });\n\n // Refresh table schemas to show the new table\n await refreshTableSchemas();\n }\n\n form.reset();\n onClose();\n } catch (err) {\n if (isAbortError(err)) {\n return;\n }\n form.setError('root', {type: 'manual', message: `${err}`});\n } finally {\n abortControllerRef.current = null;\n setIsCancelling(false);\n }\n },\n [\n onAddOrUpdateSqlQuery,\n editDataSource?.tableName,\n createTableFromQuery,\n allowMultipleStatements,\n refreshTableSchemas,\n onClose,\n form,\n ],\n );\n\n const watchView = form.watch('view');\n const watchTemp = form.watch('temp');\n const watchTableName = form.watch('tableName');\n\n const handleCancel = useCallback(async () => {\n if (abortControllerRef.current) {\n setIsCancelling(true);\n abortControllerRef.current.abort();\n }\n }, []);\n useEffect(() => {\n onRegisterCancel?.(handleCancel);\n }, [handleCancel, onRegisterCancel]);\n\n return (\n <TooltipProvider delayDuration={200}>\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-4\">\n <DialogHeader>\n <DialogTitle>\n {editDataSource\n ? 'Edit table query'\n : watchView\n ? 'Create view from query'\n : 'Create table from query'}\n </DialogTitle>\n {!editDataSource && (\n <DialogDescription>\n {watchView\n ? 'Create a new view from an SQL query.'\n : 'Create a new table from the results of an SQL query.'}\n </DialogDescription>\n )}\n </DialogHeader>\n\n {form.formState.errors.root && (\n <Alert variant=\"destructive\">\n <AlertDescription className=\"whitespace-pre-wrap font-mono text-xs\">\n {form.formState.errors.root.message}\n </AlertDescription>\n </Alert>\n )}\n\n {/* Table name, schema, database in single row */}\n <div className=\"flex items-start gap-3\">\n <FormField\n control={form.control}\n name=\"tableName\"\n render={({field}) => (\n <FormItem className=\"min-w-0 flex-[2]\">\n <FormLabel className=\"text-xs\">\n {watchView ? 'View name' : 'Table name'}\n </FormLabel>\n <FormControl>\n <Input\n {...field}\n className=\"h-9 font-mono text-xs\"\n autoFocus\n disabled={isSubmitting}\n />\n </FormControl>\n <FormMessage className=\"text-xs\" />\n </FormItem>\n )}\n />\n\n {showSchemaSelection && (\n <>\n <FormField\n control={form.control}\n name=\"schema\"\n render={({field}) => (\n <FormItem className=\"min-w-0 flex-1\">\n <FormLabel className=\"text-xs\">Schema</FormLabel>\n <FormControl>\n <SchemaCombobox\n value={field.value}\n onChange={field.onChange}\n options={schemas}\n placeholder=\"Schema...\"\n searchPlaceholder=\"Search...\"\n emptyMessage=\"No schemas.\"\n disabled={isSubmitting}\n />\n </FormControl>\n </FormItem>\n )}\n />\n\n {(databases.length > 1 || watchTemp) && (\n <FormField\n control={form.control}\n name=\"database\"\n render={({field}) => (\n <FormItem className=\"min-w-0 flex-1\">\n <FormLabel className=\"text-xs\">Database</FormLabel>\n <FormControl>\n <SchemaCombobox\n value={watchTemp ? 'temp' : field.value}\n onChange={field.onChange}\n options={databases}\n placeholder=\"Database...\"\n searchPlaceholder=\"Search...\"\n emptyMessage=\"No databases.\"\n disabled={isSubmitting || watchTemp}\n />\n </FormControl>\n </FormItem>\n )}\n />\n )}\n </>\n )}\n </div>\n\n <FormField\n control={form.control}\n name=\"query\"\n render={({field}) => (\n <FormItem className=\"relative flex h-[200px] flex-col\">\n <FormControl>\n <SqlMonacoEditor\n connector={connector}\n value={field.value}\n onChange={field.onChange}\n className=\"absolute inset-0 h-full w-full\"\n options={{\n scrollBeyondLastLine: false,\n automaticLayout: true,\n minimap: {enabled: false},\n wordWrap: 'on',\n folding: false,\n lineNumbers: 'off',\n readOnly: isSubmitting,\n fixedOverflowWidgets: false, // default true doesn't work well in a modal\n }}\n />\n </FormControl>\n <FormMessage className=\"text-xs\" />\n </FormItem>\n )}\n />\n\n {/* Compact options row */}\n {!onAddOrUpdateSqlQuery && (\n <div className=\"flex items-center gap-6 rounded-md border px-3 py-2\">\n <FormField\n control={form.control}\n name=\"view\"\n render={({field}) => (\n <OptionCheckbox\n id=\"create-table-view\"\n label=\"View\"\n tooltip=\"Create a view instead of a table. Views store the query, not the data.\"\n checked={field.value}\n onCheckedChange={field.onChange}\n disabled={isSubmitting}\n />\n )}\n />\n\n {/* <FormField\n control={form.control}\n name=\"temp\"\n render={({field}) => (\n <OptionCheckbox\n id=\"create-table-temp\"\n label=\"Temporary\"\n tooltip={`${watchView ? 'View' : 'Table'} will be deleted when the session ends.`}\n checked={field.value}\n onCheckedChange={field.onChange}\n disabled={isSubmitting}\n />\n )}\n /> */}\n\n <FormField\n control={form.control}\n name=\"replace\"\n render={({field}) => (\n <OptionCheckbox\n id=\"create-table-replace\"\n label=\"Overwrite\"\n tooltip={`Overwrite existing ${watchView ? 'view' : 'table'} with the same name if it exists.`}\n checked={field.value}\n onCheckedChange={field.onChange}\n disabled={isSubmitting}\n />\n )}\n />\n </div>\n )}\n\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={onRequestClose}>\n Close\n </Button>\n <Button\n type={isSubmitting ? 'button' : 'submit'}\n onClick={isSubmitting ? handleCancel : undefined}\n disabled={isSubmitting ? isCancelling : !watchTableName?.trim()}\n >\n {isSubmitting && <Spinner className=\"mr-2\" />}\n {isSubmitting\n ? isCancelling\n ? 'Cancelling...'\n : 'Cancel'\n : editDataSource\n ? 'Update'\n : 'Create'}\n </Button>\n </DialogFooter>\n </form>\n </Form>\n </TooltipProvider>\n );\n};\n\nconst CreateTableModal: FC<CreateTableModalProps> = (props) => {\n const {\n isOpen,\n onClose,\n query,\n editDataSource,\n allowMultipleStatements,\n showSchemaSelection,\n onAddOrUpdateSqlQuery,\n className,\n initialValues,\n } = props;\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isConfirmOpen, setIsConfirmOpen] = useState(false);\n const cancelRef = useRef<(() => void) | null>(null);\n\n const resetState = useCallback(() => {\n setIsSubmitting(false);\n setIsConfirmOpen(false);\n cancelRef.current = null;\n }, []);\n\n const handleClose = useCallback(() => {\n resetState();\n onClose();\n }, [onClose, resetState]);\n\n const handleRequestClose = useCallback(() => {\n if (!isSubmitting) {\n handleClose();\n return;\n }\n setIsConfirmOpen(true);\n }, [handleClose, isSubmitting]);\n\n const handleConfirmClose = useCallback(() => {\n cancelRef.current?.();\n handleClose();\n }, [handleClose]);\n\n return (\n <Dialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) {\n handleRequestClose();\n }\n }}\n >\n <DialogContent className={cn('w-3xl max-w-[80%]', className)}>\n {isOpen && (\n <CreateTableForm\n query={query}\n onClose={handleClose}\n onRequestClose={handleRequestClose}\n editDataSource={editDataSource}\n allowMultipleStatements={allowMultipleStatements}\n showSchemaSelection={showSchemaSelection}\n onAddOrUpdateSqlQuery={onAddOrUpdateSqlQuery}\n initialValues={initialValues}\n onSubmittingChange={setIsSubmitting}\n onRegisterCancel={(cancel) => {\n cancelRef.current = cancel;\n }}\n />\n )}\n </DialogContent>\n <Dialog open={isConfirmOpen} onOpenChange={setIsConfirmOpen}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>Cancel running query?</DialogTitle>\n <DialogDescription>\n A query is still running. Cancelling it will stop the query and\n close this dialog.\n </DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setIsConfirmOpen(false)}\n >\n Keep running\n </Button>\n <Button type=\"button\" onClick={handleConfirmClose}>\n Cancel & close\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </Dialog>\n );\n};\n\nexport default CreateTableModal;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"QueryEditorPanelTabsList.d.ts","sourceRoot":"","sources":["../../src/components/QueryEditorPanelTabsList.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,CAgInE,CAAC"}
1
+ {"version":3,"file":"QueryEditorPanelTabsList.d.ts","sourceRoot":"","sources":["../../src/components/QueryEditorPanelTabsList.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,CAuInE,CAAC"}
@@ -46,6 +46,6 @@ export const QueryEditorPanelTabsList = ({ className, }) => {
46
46
  setQueryToDelete(null);
47
47
  }
48
48
  }, [queryToDelete, deleteQueryTab]);
49
- return (_jsxs(_Fragment, { children: [_jsx(TabStrip, { className: className, tabs: queries, openTabs: openTabs, selectedTabId: selectedQueryId, onClose: closeQueryTab, onOpenTabsChange: setOpenTabs, onSelect: setSelectedQueryId, onCreate: createQueryTab, onRename: renameQueryTab, renderTabMenu: (tab) => (_jsxs(_Fragment, { children: [_jsxs(TabStrip.MenuItem, { onClick: () => handleRenameRequest(tab.id), children: [_jsx(PencilIcon, { className: "mr-2 h-4 w-4" }), "Rename"] }), _jsx(TabStrip.MenuSeparator, {}), _jsxs(TabStrip.MenuItem, { variant: "destructive", onClick: () => handleDelete(tab.id), children: [_jsx(TrashIcon, { className: "mr-2 h-4 w-4" }), "Delete"] })] })), renderSearchItemActions: (tab) => (_jsxs(_Fragment, { children: [_jsx(TabStrip.SearchItemAction, { icon: _jsx(PencilIcon, { className: "h-3 w-3", size: 5 }), "aria-label": `Rename ${tab.name}`, onClick: () => handleRenameRequest(tab.id) }), _jsx(TabStrip.SearchItemAction, { icon: _jsx(TrashIcon, { className: "h-3 w-3" }), "aria-label": `Delete ${tab.name}`, onClick: () => handleDelete(tab.id) })] })) }), _jsx(DeleteSqlQueryModal, { isOpen: queryToDelete !== null, onClose: () => setQueryToDelete(null), onConfirm: handleConfirmDelete }), _jsx(RenameSqlQueryModal, { isOpen: queryToRename !== null, onClose: () => setQueryToRename(null), initialName: queryToRename?.name ?? '', onRename: handleFinishRename })] }));
49
+ return (_jsxs(_Fragment, { children: [_jsxs(TabStrip, { className: className, tabs: queries, openTabs: openTabs, selectedTabId: selectedQueryId, onClose: closeQueryTab, onOpenTabsChange: setOpenTabs, onSelect: setSelectedQueryId, onCreate: createQueryTab, onRename: renameQueryTab, renderTabMenu: (tab) => (_jsxs(_Fragment, { children: [_jsxs(TabStrip.MenuItem, { onClick: () => handleRenameRequest(tab.id), children: [_jsx(PencilIcon, { className: "mr-2 h-4 w-4" }), "Rename"] }), _jsx(TabStrip.MenuSeparator, {}), _jsxs(TabStrip.MenuItem, { variant: "destructive", onClick: () => handleDelete(tab.id), children: [_jsx(TrashIcon, { className: "mr-2 h-4 w-4" }), "Delete"] })] })), renderSearchItemActions: (tab) => (_jsxs(_Fragment, { children: [_jsx(TabStrip.SearchItemAction, { icon: _jsx(PencilIcon, { className: "h-3 w-3", size: 5 }), "aria-label": `Rename ${tab.name}`, onClick: () => handleRenameRequest(tab.id) }), _jsx(TabStrip.SearchItemAction, { icon: _jsx(TrashIcon, { className: "h-3 w-3" }), "aria-label": `Delete ${tab.name}`, onClick: () => handleDelete(tab.id) })] })), children: [_jsx(TabStrip.SearchDropdown, { sortSearchItems: "recent", getTabLastOpenedAt: (tab) => tab.lastOpenedAt }), _jsx(TabStrip.Tabs, {}), _jsx(TabStrip.NewButton, {})] }), _jsx(DeleteSqlQueryModal, { isOpen: queryToDelete !== null, onClose: () => setQueryToDelete(null), onConfirm: handleConfirmDelete }), _jsx(RenameSqlQueryModal, { isOpen: queryToRename !== null, onClose: () => setQueryToRename(null), initialName: queryToRename?.name ?? '', onRename: handleFinishRename })] }));
50
50
  };
51
51
  //# sourceMappingURL=QueryEditorPanelTabsList.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"QueryEditorPanelTabsList.js","sourceRoot":"","sources":["../../src/components/QueryEditorPanelTabsList.tsx"],"names":[],"mappings":"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","sourcesContent":["import {TabStrip} from '@sqlrooms/ui';\nimport {PencilIcon, TrashIcon} from 'lucide-react';\nimport React, {useCallback, useState} from 'react';\nimport {useStoreWithSqlEditor} from '../SqlEditorSlice';\nimport DeleteSqlQueryModal from './DeleteSqlQueryModal';\nimport RenameSqlQueryModal from './RenameSqlQueryModal';\n\nexport const QueryEditorPanelTabsList: React.FC<{className?: string}> = ({\n className,\n}) => {\n const queries = useStoreWithSqlEditor((s) => s.sqlEditor.config.queries);\n const openTabs = useStoreWithSqlEditor((s) => s.sqlEditor.config.openTabs);\n const selectedQueryId = useStoreWithSqlEditor(\n (s) => s.sqlEditor.config.selectedQueryId,\n );\n\n const renameQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.renameQueryTab,\n );\n const closeQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.closeQueryTab);\n const setSelectedQueryId = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setSelectedQueryId,\n );\n const createQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.createQueryTab,\n );\n const deleteQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.deleteQueryTab,\n );\n const setOpenTabs = useStoreWithSqlEditor((s) => s.sqlEditor.setOpenTabs);\n\n const [queryToDelete, setQueryToDelete] = useState<string | null>(null);\n const [queryToRename, setQueryToRename] = useState<{\n id: string;\n name: string;\n } | null>(null);\n\n const handleRenameRequest = useCallback(\n (queryId: string) => {\n const query = queries.find((q) => q.id === queryId);\n if (query) {\n setQueryToRename({id: queryId, name: query.name});\n }\n },\n [queries],\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 handleDelete = useCallback(\n (queryId: string) => {\n const query = queries.find((q) => q.id === queryId);\n // If query is empty (no content), delete immediately without confirmation\n if (query && query.query.trim() === '') {\n deleteQueryTab(queryId);\n } else {\n // Otherwise, show confirmation modal\n setQueryToDelete(queryId);\n }\n },\n [queries, deleteQueryTab],\n );\n\n const handleConfirmDelete = useCallback(() => {\n if (queryToDelete) {\n deleteQueryTab(queryToDelete);\n setQueryToDelete(null);\n }\n }, [queryToDelete, deleteQueryTab]);\n\n return (\n <>\n <TabStrip\n className={className}\n tabs={queries}\n openTabs={openTabs}\n selectedTabId={selectedQueryId}\n onClose={closeQueryTab}\n onOpenTabsChange={setOpenTabs}\n onSelect={setSelectedQueryId}\n onCreate={createQueryTab}\n onRename={renameQueryTab}\n renderTabMenu={(tab) => (\n <>\n <TabStrip.MenuItem onClick={() => handleRenameRequest(tab.id)}>\n <PencilIcon className=\"mr-2 h-4 w-4\" />\n Rename\n </TabStrip.MenuItem>\n <TabStrip.MenuSeparator />\n <TabStrip.MenuItem\n variant=\"destructive\"\n onClick={() => handleDelete(tab.id)}\n >\n <TrashIcon className=\"mr-2 h-4 w-4\" />\n Delete\n </TabStrip.MenuItem>\n </>\n )}\n renderSearchItemActions={(tab) => (\n <>\n <TabStrip.SearchItemAction\n icon={<PencilIcon className=\"h-3 w-3\" size={5} />}\n aria-label={`Rename ${tab.name}`}\n onClick={() => handleRenameRequest(tab.id)}\n />\n <TabStrip.SearchItemAction\n icon={<TrashIcon className=\"h-3 w-3\" />}\n aria-label={`Delete ${tab.name}`}\n onClick={() => handleDelete(tab.id)}\n />\n </>\n )}\n />\n\n <DeleteSqlQueryModal\n isOpen={queryToDelete !== null}\n onClose={() => setQueryToDelete(null)}\n onConfirm={handleConfirmDelete}\n />\n <RenameSqlQueryModal\n isOpen={queryToRename !== null}\n onClose={() => setQueryToRename(null)}\n initialName={queryToRename?.name ?? ''}\n onRename={handleFinishRename}\n />\n </>\n );\n};\n"]}
1
+ {"version":3,"file":"QueryEditorPanelTabsList.js","sourceRoot":"","sources":["../../src/components/QueryEditorPanelTabsList.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,cAAc,CAAC;AACnD,OAAc,EAAC,WAAW,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAC;AACnD,OAAO,EAAC,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AACxD,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AAExD,MAAM,CAAC,MAAM,wBAAwB,GAAmC,CAAC,EACvE,SAAS,GACV,EAAE,EAAE;IACH,MAAM,OAAO,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3E,MAAM,eAAe,GAAG,qBAAqB,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAC1C,CAAC;IAEF,MAAM,cAAc,GAAG,qBAAqB,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAClC,CAAC;IACF,MAAM,aAAa,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC9E,MAAM,kBAAkB,GAAG,qBAAqB,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,kBAAkB,CACtC,CAAC;IACF,MAAM,cAAc,GAAG,qBAAqB,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAClC,CAAC;IACF,MAAM,cAAc,GAAG,qBAAqB,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAClC,CAAC;IACF,MAAM,WAAW,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAE1E,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAGxC,IAAI,CAAC,CAAC;IAEhB,MAAM,mBAAmB,GAAG,WAAW,CACrC,CAAC,OAAe,EAAE,EAAE;QAClB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;QACpD,IAAI,KAAK,EAAE,CAAC;YACV,gBAAgB,CAAC,EAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,MAAM,kBAAkB,GAAG,WAAW,CACpC,CAAC,OAAe,EAAE,EAAE;QAClB,IAAI,aAAa,EAAE,CAAC;YAClB,cAAc,CAAC,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;QACD,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,EACD,CAAC,aAAa,EAAE,cAAc,CAAC,CAChC,CAAC;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,OAAe,EAAE,EAAE;QAClB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;QACpD,0EAA0E;QAC1E,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACvC,cAAc,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,qCAAqC;YACrC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,EACD,CAAC,OAAO,EAAE,cAAc,CAAC,CAC1B,CAAC;IAEF,MAAM,mBAAmB,GAAG,WAAW,CAAC,GAAG,EAAE;QAC3C,IAAI,aAAa,EAAE,CAAC;YAClB,cAAc,CAAC,aAAa,CAAC,CAAC;YAC9B,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,EAAE,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;IAEpC,OAAO,CACL,8BACE,MAAC,QAAQ,IACP,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,eAAe,EAC9B,OAAO,EAAE,aAAa,EACtB,gBAAgB,EAAE,WAAW,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CACtB,8BACE,MAAC,QAAQ,CAAC,QAAQ,IAAC,OAAO,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,aAC3D,KAAC,UAAU,IAAC,SAAS,EAAC,cAAc,GAAG,cAErB,EACpB,KAAC,QAAQ,CAAC,aAAa,KAAG,EAC1B,MAAC,QAAQ,CAAC,QAAQ,IAChB,OAAO,EAAC,aAAa,EACrB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,aAEnC,KAAC,SAAS,IAAC,SAAS,EAAC,cAAc,GAAG,cAEpB,IACnB,CACJ,EACD,uBAAuB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAChC,8BACE,KAAC,QAAQ,CAAC,gBAAgB,IACxB,IAAI,EAAE,KAAC,UAAU,IAAC,SAAS,EAAC,SAAS,EAAC,IAAI,EAAE,CAAC,GAAI,gBACrC,UAAU,GAAG,CAAC,IAAI,EAAE,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,GAC1C,EACF,KAAC,QAAQ,CAAC,gBAAgB,IACxB,IAAI,EAAE,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,gBAC3B,UAAU,GAAG,CAAC,IAAI,EAAE,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,GACnC,IACD,CACJ,aAED,KAAC,QAAQ,CAAC,cAAc,IACtB,eAAe,EAAC,QAAQ,EACxB,kBAAkB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAkC,GACnE,EACF,KAAC,QAAQ,CAAC,IAAI,KAAG,EACjB,KAAC,QAAQ,CAAC,SAAS,KAAG,IACb,EAEX,KAAC,mBAAmB,IAClB,MAAM,EAAE,aAAa,KAAK,IAAI,EAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EACrC,SAAS,EAAE,mBAAmB,GAC9B,EACF,KAAC,mBAAmB,IAClB,MAAM,EAAE,aAAa,KAAK,IAAI,EAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EACrC,WAAW,EAAE,aAAa,EAAE,IAAI,IAAI,EAAE,EACtC,QAAQ,EAAE,kBAAkB,GAC5B,IACD,CACJ,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {TabStrip} from '@sqlrooms/ui';\nimport {PencilIcon, TrashIcon} from 'lucide-react';\nimport React, {useCallback, useState} from 'react';\nimport {useStoreWithSqlEditor} from '../SqlEditorSlice';\nimport DeleteSqlQueryModal from './DeleteSqlQueryModal';\nimport RenameSqlQueryModal from './RenameSqlQueryModal';\n\nexport const QueryEditorPanelTabsList: React.FC<{className?: string}> = ({\n className,\n}) => {\n const queries = useStoreWithSqlEditor((s) => s.sqlEditor.config.queries);\n const openTabs = useStoreWithSqlEditor((s) => s.sqlEditor.config.openTabs);\n const selectedQueryId = useStoreWithSqlEditor(\n (s) => s.sqlEditor.config.selectedQueryId,\n );\n\n const renameQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.renameQueryTab,\n );\n const closeQueryTab = useStoreWithSqlEditor((s) => s.sqlEditor.closeQueryTab);\n const setSelectedQueryId = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setSelectedQueryId,\n );\n const createQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.createQueryTab,\n );\n const deleteQueryTab = useStoreWithSqlEditor(\n (s) => s.sqlEditor.deleteQueryTab,\n );\n const setOpenTabs = useStoreWithSqlEditor((s) => s.sqlEditor.setOpenTabs);\n\n const [queryToDelete, setQueryToDelete] = useState<string | null>(null);\n const [queryToRename, setQueryToRename] = useState<{\n id: string;\n name: string;\n } | null>(null);\n\n const handleRenameRequest = useCallback(\n (queryId: string) => {\n const query = queries.find((q) => q.id === queryId);\n if (query) {\n setQueryToRename({id: queryId, name: query.name});\n }\n },\n [queries],\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 handleDelete = useCallback(\n (queryId: string) => {\n const query = queries.find((q) => q.id === queryId);\n // If query is empty (no content), delete immediately without confirmation\n if (query && query.query.trim() === '') {\n deleteQueryTab(queryId);\n } else {\n // Otherwise, show confirmation modal\n setQueryToDelete(queryId);\n }\n },\n [queries, deleteQueryTab],\n );\n\n const handleConfirmDelete = useCallback(() => {\n if (queryToDelete) {\n deleteQueryTab(queryToDelete);\n setQueryToDelete(null);\n }\n }, [queryToDelete, deleteQueryTab]);\n\n return (\n <>\n <TabStrip\n className={className}\n tabs={queries}\n openTabs={openTabs}\n selectedTabId={selectedQueryId}\n onClose={closeQueryTab}\n onOpenTabsChange={setOpenTabs}\n onSelect={setSelectedQueryId}\n onCreate={createQueryTab}\n onRename={renameQueryTab}\n renderTabMenu={(tab) => (\n <>\n <TabStrip.MenuItem onClick={() => handleRenameRequest(tab.id)}>\n <PencilIcon className=\"mr-2 h-4 w-4\" />\n Rename\n </TabStrip.MenuItem>\n <TabStrip.MenuSeparator />\n <TabStrip.MenuItem\n variant=\"destructive\"\n onClick={() => handleDelete(tab.id)}\n >\n <TrashIcon className=\"mr-2 h-4 w-4\" />\n Delete\n </TabStrip.MenuItem>\n </>\n )}\n renderSearchItemActions={(tab) => (\n <>\n <TabStrip.SearchItemAction\n icon={<PencilIcon className=\"h-3 w-3\" size={5} />}\n aria-label={`Rename ${tab.name}`}\n onClick={() => handleRenameRequest(tab.id)}\n />\n <TabStrip.SearchItemAction\n icon={<TrashIcon className=\"h-3 w-3\" />}\n aria-label={`Delete ${tab.name}`}\n onClick={() => handleDelete(tab.id)}\n />\n </>\n )}\n >\n <TabStrip.SearchDropdown\n sortSearchItems=\"recent\"\n getTabLastOpenedAt={(tab) => tab.lastOpenedAt as number | undefined}\n />\n <TabStrip.Tabs />\n <TabStrip.NewButton />\n </TabStrip>\n\n <DeleteSqlQueryModal\n isOpen={queryToDelete !== null}\n onClose={() => setQueryToDelete(null)}\n onConfirm={handleConfirmDelete}\n />\n <RenameSqlQueryModal\n isOpen={queryToRename !== null}\n onClose={() => setQueryToRename(null)}\n initialName={queryToRename?.name ?? ''}\n onRename={handleFinishRename}\n />\n </>\n );\n};\n"]}
@@ -22,7 +22,10 @@ export interface QueryResultPanelProps {
22
22
  row: Row<any>;
23
23
  event: React.MouseEvent<HTMLTableRowElement>;
24
24
  }) => void;
25
+ /** Custom content to render in the error state (e.g., QueryResultPanel.AskAi) */
26
+ children?: React.ReactNode;
25
27
  /**
28
+ * @deprecated Use children with QueryResultPanel.AskAi instead
26
29
  * Called when the "Ask AI" button is clicked on an error message.
27
30
  * Receives the current query and error text.
28
31
  */
@@ -30,5 +33,17 @@ export interface QueryResultPanelProps {
30
33
  /** Custom value formatter for arrow data */
31
34
  formatValue?: ArrowDataTableValueFormatter;
32
35
  }
33
- export declare const QueryResultPanel: React.FC<QueryResultPanelProps>;
36
+ export interface QueryResultPanelAskAiProps {
37
+ /** Called when clicked with the current query and error message */
38
+ onClick?: (query: string, error: string) => void;
39
+ /** Custom icon (defaults to MessageCircleQuestion) */
40
+ icon?: React.ReactNode;
41
+ /** Custom className */
42
+ className?: string;
43
+ /** Tooltip text to display on hover */
44
+ tooltipContent?: string;
45
+ }
46
+ export declare const QueryResultPanel: React.FC<QueryResultPanelProps> & {
47
+ AskAi: React.ForwardRefExoticComponent<QueryResultPanelAskAiProps & React.RefAttributes<HTMLButtonElement>>;
48
+ };
34
49
  //# sourceMappingURL=QueryResultPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"QueryResultPanel.d.ts","sourceRoot":"","sources":["../../src/components/QueryResultPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,4BAA4B,EAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAC;AAG/C,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,MAAM,WAAW,qBAAqB;IACpC,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IACnD,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAClB,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;KAC9C,KAAK,IAAI,CAAC;IACX;;OAEG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE;QACxB,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;KAC9C,KAAK,IAAI,CAAC;IACX;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,4CAA4C;IAC5C,WAAW,CAAC,EAAE,4BAA4B,CAAC;CAC5C;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAgI5D,CAAC"}
1
+ {"version":3,"file":"QueryResultPanel.d.ts","sourceRoot":"","sources":["../../src/components/QueryResultPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,4BAA4B,EAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAC;AAW/C,OAAO,KAAK,MAAM,OAAO,CAAC;AAgC1B,MAAM,WAAW,qBAAqB;IACpC,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IACnD,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAClB,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;KAC9C,KAAK,IAAI,CAAC;IACX;;OAEG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE;QACxB,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;KAC9C,KAAK,IAAI,CAAC;IACX,iFAAiF;IACjF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,4CAA4C;IAC5C,WAAW,CAAC,EAAE,4BAA4B,CAAC;CAC5C;AAiLD,MAAM,WAAW,0BAA0B;IACzC,mEAAmE;IACnE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sDAAsD;IACtD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA4CD,eAAO,MAAM,gBAAgB;;CAE3B,CAAC"}
@@ -1,12 +1,38 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { DataTablePaginated, useArrowDataTable, } from '@sqlrooms/data-table';
3
- import { cn, SpinnerPane, Button } from '@sqlrooms/ui';
3
+ import { cn, SpinnerPane, Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@sqlrooms/ui';
4
4
  import { formatCount } from '@sqlrooms/utils';
5
5
  import React from 'react';
6
6
  import { isQueryWithResult, useStoreWithSqlEditor } from '../SqlEditorSlice';
7
7
  import { MessageCircleQuestion } from 'lucide-react';
8
8
  import { QueryResultLimitSelect } from './QueryResultLimitSelect';
9
- export const QueryResultPanel = ({ className, renderActions, fontSize = 'text-xs', onRowClick, onRowDoubleClick, onAskAiAboutError, formatValue, }) => {
9
+ /**
10
+ * Turns DuckDB's EXPLAIN result table into a readable plan string.
11
+ * Prefer the `explain_value` column (DuckDB default); otherwise fall back
12
+ * to the first column and join all rows with newlines.
13
+ */
14
+ function arrowTableToExplainText(result) {
15
+ if (!result)
16
+ return '';
17
+ const numRows = result.numRows ?? 0;
18
+ const fields = result.schema?.fields ?? [];
19
+ const fieldNames = fields.map((f) => f.name);
20
+ const hasExplainValueColumn = fieldNames.includes('explain_value');
21
+ const columnName = hasExplainValueColumn ? 'explain_value' : fieldNames[0];
22
+ if (!columnName)
23
+ return '';
24
+ const col = result.getChild?.(columnName);
25
+ if (!col)
26
+ return '';
27
+ const lines = [];
28
+ for (let i = 0; i < numRows; i++) {
29
+ const v = col.get(i);
30
+ if (v != null && String(v).length > 0)
31
+ lines.push(String(v));
32
+ }
33
+ return lines.join('\n');
34
+ }
35
+ const QueryResultPanelRoot = ({ className, renderActions, fontSize = 'text-xs', onRowClick, onRowDoubleClick, children, onAskAiAboutError, formatValue, }) => {
10
36
  const queryResult = useStoreWithSqlEditor((s) => {
11
37
  const selectedId = s.sqlEditor.config.selectedQueryId;
12
38
  return s.sqlEditor.queryResultsById[selectedId];
@@ -15,12 +41,21 @@ export const QueryResultPanel = ({ className, renderActions, fontSize = 'text-xs
15
41
  const setQueryResultLimit = useStoreWithSqlEditor((s) => s.sqlEditor.setQueryResultLimit);
16
42
  const queryResultLimit = useStoreWithSqlEditor((s) => s.sqlEditor.queryResultLimit);
17
43
  const queryResultLimitOptions = useStoreWithSqlEditor((s) => s.sqlEditor.queryResultLimitOptions);
18
- const arrowTableData = useArrowDataTable(isQueryWithResult(queryResult) ? queryResult.result : undefined, { formatValue });
44
+ const tableForDataTable = isQueryWithResult(queryResult) && queryResult.type !== 'explain'
45
+ ? queryResult.result
46
+ : undefined;
47
+ const arrowTableData = useArrowDataTable(tableForDataTable, { formatValue });
48
+ const explainText = React.useMemo(() => {
49
+ if (queryResult?.status !== 'success' || queryResult.type !== 'explain') {
50
+ return undefined;
51
+ }
52
+ return arrowTableToExplainText(queryResult.result);
53
+ }, [queryResult]);
19
54
  const handleAskAiAboutError = React.useCallback(() => {
20
55
  if (queryResult?.status === 'error' && onAskAiAboutError) {
21
56
  const currentQuery = getCurrentQuery();
22
57
  const errorText = queryResult.error;
23
- onAskAiAboutError(currentQuery, errorText);
58
+ onAskAiAboutError?.(currentQuery, errorText);
24
59
  }
25
60
  }, [queryResult, getCurrentQuery, onAskAiAboutError]);
26
61
  if (!queryResult) {
@@ -33,13 +68,45 @@ export const QueryResultPanel = ({ className, renderActions, fontSize = 'text-xs
33
68
  return (_jsx("div", { className: "p-5 font-mono text-xs leading-tight text-red-500", children: "Query was aborted" }));
34
69
  }
35
70
  if (queryResult?.status === 'error') {
36
- return (_jsxs("div", { className: "relative h-full w-full overflow-auto p-5", children: [onAskAiAboutError && (_jsx(Button, { variant: "ghost", size: "icon", className: "absolute top-2 right-2 h-8 w-8", onClick: handleAskAiAboutError, title: "Ask AI for help", children: _jsx(MessageCircleQuestion, { className: "h-4 w-4" }) })), _jsx("pre", { className: cn('text-xs leading-tight whitespace-pre-wrap text-red-500', onAskAiAboutError && 'pr-12'), children: queryResult.error })] }));
71
+ // Backward compat: if no children but onAskAiAboutError is provided, render default button
72
+ const errorActions = children ?? (onAskAiAboutError && (_jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8", onClick: handleAskAiAboutError, title: "Ask AI for help", children: _jsx(MessageCircleQuestion, { className: "h-4 w-4" }) })));
73
+ return (_jsxs("div", { className: "relative h-full w-full overflow-auto p-5", children: [errorActions && (_jsx("div", { className: "absolute top-2 right-2", children: errorActions })), _jsx("pre", { className: cn('text-xs leading-tight whitespace-pre-wrap text-red-500', errorActions && 'pr-12'), children: queryResult.error })] }));
37
74
  }
38
75
  if (queryResult?.status === 'success') {
39
- return (_jsx("div", { className: cn('relative flex h-full w-full flex-grow flex-col overflow-hidden', className), children: isQueryWithResult(queryResult) ? (_jsxs("div", { className: "flex h-full w-full flex-col", children: [_jsx(DataTablePaginated, { ...arrowTableData, className: "flex-grow overflow-hidden", fontSize: fontSize, isFetching: false, onRowClick: onRowClick, onRowDoubleClick: onRowDoubleClick }), _jsxs("div", { className: "bg-background flex w-full items-center gap-2 px-4 py-1", children: [queryResult.result ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "font-mono text-xs", children: `${formatCount(queryResult.result.numRows ?? 0)} rows` }), _jsx(QueryResultLimitSelect, { value: queryResultLimit, onChange: setQueryResultLimit, options: queryResultLimitOptions })] })) : null, _jsx("div", { className: "flex-1" }), renderActions
40
- ? renderActions(queryResult.lastQueryStatement)
41
- : undefined] })] })) : (_jsx("pre", { className: "p-4 text-xs leading-tight text-green-500", children: "Successfully executed query" })) }));
76
+ const contentWrapperClassName = cn('relative flex h-full w-full flex-grow flex-col overflow-hidden', className);
77
+ // Result shows the EXPLAIN schema
78
+ if (queryResult.type === 'explain') {
79
+ return (_jsx("div", { className: contentWrapperClassName, children: _jsxs("div", { className: "flex h-full w-full flex-col overflow-hidden", children: [_jsx("pre", { className: "flex-1 overflow-auto p-4 font-mono text-xs leading-tight break-words whitespace-pre-wrap", children: explainText }), _jsxs("div", { className: "bg-background flex w-full items-center gap-2 px-4 py-1", children: [_jsx("div", { className: "font-mono text-xs", children: "EXPLAIN" }), _jsx("div", { className: "flex-1" }), renderActions
80
+ ? renderActions(queryResult.lastQueryStatement)
81
+ : undefined] })] }) }));
82
+ }
83
+ // Result shows the SELECT/PRAGMA table
84
+ if (isQueryWithResult(queryResult)) {
85
+ return (_jsx("div", { className: contentWrapperClassName, children: _jsxs("div", { className: "flex h-full w-full flex-col", children: [_jsx(DataTablePaginated, { ...arrowTableData, className: "flex-grow overflow-hidden", fontSize: fontSize, isFetching: false, onRowClick: onRowClick, onRowDoubleClick: onRowDoubleClick }), _jsxs("div", { className: "bg-background flex w-full items-center gap-2 px-4 py-1", children: [queryResult.result ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "font-mono text-xs", children: `${formatCount(queryResult.result.numRows ?? 0)} rows` }), queryResult.type === 'select' ? (_jsx(QueryResultLimitSelect, { value: queryResultLimit, onChange: setQueryResultLimit, options: queryResultLimitOptions })) : null] })) : null, _jsx("div", { className: "flex-1" }), renderActions
86
+ ? renderActions(queryResult.lastQueryStatement)
87
+ : undefined] })] }) }));
88
+ }
89
+ // Fallback message to show when the query result is not a SELECT/PRAGMA or EXPLAIN
90
+ return (_jsx("div", { className: contentWrapperClassName, children: _jsx("pre", { className: "p-4 text-xs leading-tight text-green-500", children: "Successfully executed query" }) }));
42
91
  }
43
92
  return null;
44
93
  };
94
+ const QueryResultPanelAskAi = React.forwardRef(({ onClick, icon, className, tooltipContent = 'Ask AI for help' }, ref) => {
95
+ const queryResult = useStoreWithSqlEditor((s) => {
96
+ const selectedId = s.sqlEditor.config.selectedQueryId;
97
+ return s.sqlEditor.queryResultsById[selectedId];
98
+ });
99
+ const getCurrentQuery = useStoreWithSqlEditor((s) => s.sqlEditor.getCurrentQuery);
100
+ // Only render in error state
101
+ if (queryResult?.status !== 'error')
102
+ return null;
103
+ const handleClick = () => {
104
+ onClick?.(getCurrentQuery(), queryResult.error);
105
+ };
106
+ return (_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { ref: ref, variant: "ghost", size: "icon", className: cn('h-8 w-8', className), onClick: handleClick, children: icon ?? _jsx(MessageCircleQuestion, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { children: _jsx("p", { className: "text-xs", children: tooltipContent }) })] }) }));
107
+ });
108
+ QueryResultPanelAskAi.displayName = 'QueryResultPanel.AskAi';
109
+ export const QueryResultPanel = Object.assign(QueryResultPanelRoot, {
110
+ AskAi: QueryResultPanelAskAi,
111
+ });
45
112
  //# sourceMappingURL=QueryResultPanel.js.map