@sqlrooms/sql-editor 0.27.0-rc.4 → 0.27.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.
@@ -1,5 +1,5 @@
1
1
  import { ArrowDataTableValueFormatter } from '@sqlrooms/data-table';
2
- import type { Row } from '@tanstack/react-table';
2
+ import type { Row, RowSelectionState } from '@tanstack/react-table';
3
3
  import React from 'react';
4
4
  export interface QueryResultPanelProps {
5
5
  /** Custom class name for styling */
@@ -30,6 +30,18 @@ export interface QueryResultPanelProps {
30
30
  * Receives the current query and error text.
31
31
  */
32
32
  onAskAiAboutError?: (query: string, error: string) => void;
33
+ /**
34
+ * Enables row selection with checkboxes.
35
+ */
36
+ enableRowSelection?: boolean;
37
+ /**
38
+ * Controlled row selection state. Keys are row indices, values are selection status.
39
+ */
40
+ rowSelection?: RowSelectionState;
41
+ /**
42
+ * Called when row selection changes.
43
+ */
44
+ onRowSelectionChange?: (rowSelection: RowSelectionState) => void;
33
45
  /** Custom value formatter for arrow data */
34
46
  formatValue?: ArrowDataTableValueFormatter;
35
47
  }
@@ -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;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
+ {"version":3,"file":"QueryResultPanel.d.ts","sourceRoot":"","sources":["../../src/components/QueryResultPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAG7B,MAAM,sBAAsB,CAAC;AAW9B,OAAO,KAAK,EAAC,GAAG,EAAE,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,MAAM,OAAO,CAAC;AA+B1B,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;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;OAEG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC;;OAEG;IACH,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,4CAA4C;IAC5C,WAAW,CAAC,EAAE,4BAA4B,CAAC;CAC5C;AAwLD,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,10 +1,10 @@
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, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@sqlrooms/ui';
3
+ import { Button, cn, SpinnerPane, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@sqlrooms/ui';
4
4
  import { formatCount } from '@sqlrooms/utils';
5
+ import { MessageCircleQuestion } from 'lucide-react';
5
6
  import React from 'react';
6
7
  import { isQueryWithResult, useStoreWithSqlEditor } from '../SqlEditorSlice';
7
- import { MessageCircleQuestion } from 'lucide-react';
8
8
  import { QueryResultLimitSelect } from './QueryResultLimitSelect';
9
9
  /**
10
10
  * Turns DuckDB's EXPLAIN result table into a readable plan string.
@@ -32,7 +32,7 @@ function arrowTableToExplainText(result) {
32
32
  }
33
33
  return lines.join('\n');
34
34
  }
35
- const QueryResultPanelRoot = ({ className, renderActions, fontSize = 'text-xs', onRowClick, onRowDoubleClick, children, onAskAiAboutError, formatValue, }) => {
35
+ const QueryResultPanelRoot = ({ className, renderActions, fontSize = 'text-xs', onRowClick, onRowDoubleClick, children, onAskAiAboutError, enableRowSelection, rowSelection, onRowSelectionChange, formatValue, }) => {
36
36
  const queryResult = useStoreWithSqlEditor((s) => {
37
37
  const selectedId = s.sqlEditor.config.selectedQueryId;
38
38
  return s.sqlEditor.queryResultsById[selectedId];
@@ -69,20 +69,21 @@ const QueryResultPanelRoot = ({ className, renderActions, fontSize = 'text-xs',
69
69
  }
70
70
  if (queryResult?.status === 'error') {
71
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 })] }));
72
+ const errorActions = children ??
73
+ (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" }) })));
74
+ return (_jsxs("div", { className: "relative h-full w-full overflow-auto p-5", children: [errorActions && (_jsx("div", { className: "absolute right-2 top-2", children: errorActions })), _jsx("pre", { className: cn('whitespace-pre-wrap text-xs leading-tight text-red-500', errorActions && 'pr-12'), children: queryResult.error })] }));
74
75
  }
75
76
  if (queryResult?.status === 'success') {
76
77
  const contentWrapperClassName = cn('relative flex h-full w-full flex-grow flex-col overflow-hidden', className);
77
78
  // Result shows the EXPLAIN schema
78
79
  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
+ 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 whitespace-pre-wrap break-words p-4 font-mono text-xs leading-tight", 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
81
  ? renderActions(queryResult.lastQueryStatement)
81
82
  : undefined] })] }) }));
82
83
  }
83
84
  // Result shows the SELECT/PRAGMA table
84
85
  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
+ return (_jsx("div", { className: contentWrapperClassName, children: _jsxs("div", { className: "flex h-full w-full flex-col", children: [_jsx(DataTablePaginated, { data: arrowTableData?.data, columns: arrowTableData?.columns, className: "flex-grow overflow-hidden", fontSize: fontSize, isFetching: false, onRowClick: onRowClick, onRowDoubleClick: onRowDoubleClick, enableRowSelection: enableRowSelection, rowSelection: rowSelection, onRowSelectionChange: onRowSelectionChange }), _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
87
  ? renderActions(queryResult.lastQueryStatement)
87
88
  : undefined] })] }) }));
88
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"QueryResultPanel.js","sourceRoot":"","sources":["../../src/components/QueryResultPanel.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n DataTablePaginated,\n useArrowDataTable,\n ArrowDataTableValueFormatter,\n} from '@sqlrooms/data-table';\nimport type {Row} from '@tanstack/react-table';\nimport {\n cn,\n SpinnerPane,\n Button,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '@sqlrooms/ui';\nimport {formatCount} from '@sqlrooms/utils';\nimport React from 'react';\nimport {isQueryWithResult, useStoreWithSqlEditor} from '../SqlEditorSlice';\nimport {MessageCircleQuestion} from 'lucide-react';\nimport {QueryResultLimitSelect} from './QueryResultLimitSelect';\n\n/**\n * Turns DuckDB's EXPLAIN result table into a readable plan string.\n * Prefer the `explain_value` column (DuckDB default); otherwise fall back\n * to the first column and join all rows with newlines.\n */\nfunction arrowTableToExplainText(result: any): string {\n if (!result) return '';\n\n const numRows: number = result.numRows ?? 0;\n const fields: {name: string}[] = result.schema?.fields ?? [];\n const fieldNames = fields.map((f) => f.name);\n\n const hasExplainValueColumn = fieldNames.includes('explain_value');\n const columnName = hasExplainValueColumn ? 'explain_value' : fieldNames[0];\n if (!columnName) return '';\n\n const col = result.getChild?.(columnName);\n if (!col) return '';\n\n const lines: string[] = [];\n for (let i = 0; i < numRows; i++) {\n const v = col.get(i);\n if (v != null && String(v).length > 0) lines.push(String(v));\n }\n return lines.join('\\n');\n}\n\nexport interface QueryResultPanelProps {\n /** Custom class name for styling */\n className?: string;\n /** Custom actions to render in the query result panel */\n renderActions?: (query: string) => React.ReactNode;\n /** Custom font size for the table e.g. text-xs, text-sm, text-md, text-lg, text-base */\n fontSize?: string;\n /**\n * Called when a row in the results table is clicked.\n */\n onRowClick?: (args: {\n row: Row<any>;\n event: React.MouseEvent<HTMLTableRowElement>;\n }) => void;\n /**\n * Called when a row in the results table is double-clicked.\n */\n onRowDoubleClick?: (args: {\n row: Row<any>;\n event: React.MouseEvent<HTMLTableRowElement>;\n }) => void;\n /** Custom content to render in the error state (e.g., QueryResultPanel.AskAi) */\n children?: React.ReactNode;\n /**\n * @deprecated Use children with QueryResultPanel.AskAi instead\n * Called when the \"Ask AI\" button is clicked on an error message.\n * Receives the current query and error text.\n */\n onAskAiAboutError?: (query: string, error: string) => void;\n /** Custom value formatter for arrow data */\n formatValue?: ArrowDataTableValueFormatter;\n}\n\nconst QueryResultPanelRoot: React.FC<QueryResultPanelProps> = ({\n className,\n renderActions,\n fontSize = 'text-xs',\n onRowClick,\n onRowDoubleClick,\n children,\n onAskAiAboutError,\n formatValue,\n}) => {\n const queryResult = useStoreWithSqlEditor((s) => {\n const selectedId = s.sqlEditor.config.selectedQueryId;\n return s.sqlEditor.queryResultsById[selectedId];\n });\n const getCurrentQuery = useStoreWithSqlEditor(\n (s) => s.sqlEditor.getCurrentQuery,\n );\n const setQueryResultLimit = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setQueryResultLimit,\n );\n const queryResultLimit = useStoreWithSqlEditor(\n (s) => s.sqlEditor.queryResultLimit,\n );\n const queryResultLimitOptions = useStoreWithSqlEditor(\n (s) => s.sqlEditor.queryResultLimitOptions,\n );\n\n const tableForDataTable =\n isQueryWithResult(queryResult) && queryResult.type !== 'explain'\n ? queryResult.result\n : undefined;\n\n const arrowTableData = useArrowDataTable(tableForDataTable, {formatValue});\n\n const explainText = React.useMemo(() => {\n if (queryResult?.status !== 'success' || queryResult.type !== 'explain') {\n return undefined;\n }\n return arrowTableToExplainText(queryResult.result);\n }, [queryResult]);\n\n const handleAskAiAboutError = React.useCallback(() => {\n if (queryResult?.status === 'error' && onAskAiAboutError) {\n const currentQuery = getCurrentQuery();\n const errorText = queryResult.error;\n onAskAiAboutError?.(currentQuery, errorText);\n }\n }, [queryResult, getCurrentQuery, onAskAiAboutError]);\n\n if (!queryResult) {\n return null;\n }\n\n if (queryResult?.status === 'loading') {\n return <SpinnerPane h=\"100%\" />;\n }\n\n if (queryResult?.status === 'aborted') {\n return (\n <div className=\"p-5 font-mono text-xs leading-tight text-red-500\">\n Query was aborted\n </div>\n );\n }\n if (queryResult?.status === 'error') {\n // Backward compat: if no children but onAskAiAboutError is provided, render default button\n const errorActions = children ?? (onAskAiAboutError && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={handleAskAiAboutError}\n title=\"Ask AI for help\"\n >\n <MessageCircleQuestion className=\"h-4 w-4\" />\n </Button>\n ));\n\n return (\n <div className=\"relative h-full w-full overflow-auto p-5\">\n {errorActions && (\n <div className=\"absolute top-2 right-2\">\n {errorActions}\n </div>\n )}\n <pre\n className={cn(\n 'text-xs leading-tight whitespace-pre-wrap text-red-500',\n errorActions && 'pr-12',\n )}\n >\n {queryResult.error}\n </pre>\n </div>\n );\n }\n\n if (queryResult?.status === 'success') {\n const contentWrapperClassName = cn(\n 'relative flex h-full w-full flex-grow flex-col overflow-hidden',\n className,\n );\n\n // Result shows the EXPLAIN schema\n if (queryResult.type === 'explain') {\n return (\n <div className={contentWrapperClassName}>\n <div className=\"flex h-full w-full flex-col overflow-hidden\">\n <pre className=\"flex-1 overflow-auto p-4 font-mono text-xs leading-tight break-words whitespace-pre-wrap\">\n {explainText}\n </pre>\n <div className=\"bg-background flex w-full items-center gap-2 px-4 py-1\">\n <div className=\"font-mono text-xs\">EXPLAIN</div>\n <div className=\"flex-1\" />\n {renderActions\n ? renderActions(queryResult.lastQueryStatement)\n : undefined}\n </div>\n </div>\n </div>\n );\n }\n\n // Result shows the SELECT/PRAGMA table\n if (isQueryWithResult(queryResult)) {\n return (\n <div className={contentWrapperClassName}>\n <div className=\"flex h-full w-full flex-col\">\n <DataTablePaginated\n {...arrowTableData}\n className=\"flex-grow overflow-hidden\"\n fontSize={fontSize}\n isFetching={false}\n onRowClick={onRowClick}\n onRowDoubleClick={onRowDoubleClick}\n />\n <div className=\"bg-background flex w-full items-center gap-2 px-4 py-1\">\n {queryResult.result ? (\n <>\n <div className=\"font-mono text-xs\">\n {`${formatCount(queryResult.result.numRows ?? 0)} rows`}\n </div>\n\n {queryResult.type === 'select' ? (\n <QueryResultLimitSelect\n value={queryResultLimit}\n onChange={setQueryResultLimit}\n options={queryResultLimitOptions}\n />\n ) : null}\n </>\n ) : null}\n <div className=\"flex-1\" />\n {renderActions\n ? renderActions(queryResult.lastQueryStatement)\n : undefined}\n </div>\n </div>\n </div>\n );\n }\n\n // Fallback message to show when the query result is not a SELECT/PRAGMA or EXPLAIN\n return (\n <div className={contentWrapperClassName}>\n <pre className=\"p-4 text-xs leading-tight text-green-500\">\n Successfully executed query\n </pre>\n </div>\n );\n }\n\n return null;\n};\n\nexport interface QueryResultPanelAskAiProps {\n /** Called when clicked with the current query and error message */\n onClick?: (query: string, error: string) => void;\n /** Custom icon (defaults to MessageCircleQuestion) */\n icon?: React.ReactNode;\n /** Custom className */\n className?: string;\n /** Tooltip text to display on hover */\n tooltipContent?: string;\n}\n\nconst QueryResultPanelAskAi = React.forwardRef<\n HTMLButtonElement,\n QueryResultPanelAskAiProps\n>(({onClick, icon, className, tooltipContent = 'Ask AI for help'}, ref) => {\n const queryResult = useStoreWithSqlEditor((s) => {\n const selectedId = s.sqlEditor.config.selectedQueryId;\n return s.sqlEditor.queryResultsById[selectedId];\n });\n const getCurrentQuery = useStoreWithSqlEditor(\n (s) => s.sqlEditor.getCurrentQuery,\n );\n\n // Only render in error state\n if (queryResult?.status !== 'error') return null;\n\n const handleClick = () => {\n onClick?.(getCurrentQuery(), queryResult.error);\n };\n\n return (\n <TooltipProvider delayDuration={200}>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-8 w-8', className)}\n onClick={handleClick}\n >\n {icon ?? <MessageCircleQuestion className=\"h-4 w-4\" />}\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p className=\"text-xs\">{tooltipContent}</p>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n});\nQueryResultPanelAskAi.displayName = 'QueryResultPanel.AskAi';\n\nexport const QueryResultPanel = Object.assign(QueryResultPanelRoot, {\n AskAi: QueryResultPanelAskAi,\n});\n"]}
1
+ {"version":3,"file":"QueryResultPanel.js","sourceRoot":"","sources":["../../src/components/QueryResultPanel.tsx"],"names":[],"mappings":";AAAA,OAAO,EAEL,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,MAAM,EACN,EAAE,EACF,WAAW,EACX,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAC,qBAAqB,EAAC,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,iBAAiB,EAAE,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAC;AAEhE;;;;GAIG;AACH,SAAS,uBAAuB,CAAC,MAAW;IAC1C,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEvB,MAAM,OAAO,GAAW,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAqB,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC;IAC7D,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAE7C,MAAM,qBAAqB,GAAG,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,qBAAqB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IAEpB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AA+CD,MAAM,oBAAoB,GAAoC,CAAC,EAC7D,SAAS,EACT,aAAa,EACb,QAAQ,GAAG,SAAS,EACpB,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,WAAW,GACZ,EAAE,EAAE;IACH,MAAM,WAAW,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9C,MAAM,UAAU,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC;QACtD,OAAO,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACH,MAAM,eAAe,GAAG,qBAAqB,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CACnC,CAAC;IACF,MAAM,mBAAmB,GAAG,qBAAqB,CAC/C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,CACvC,CAAC;IACF,MAAM,gBAAgB,GAAG,qBAAqB,CAC5C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CACpC,CAAC;IACF,MAAM,uBAAuB,GAAG,qBAAqB,CACnD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAC3C,CAAC;IAEF,MAAM,iBAAiB,GACrB,iBAAiB,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,IAAI,KAAK,SAAS;QAC9D,CAAC,CAAC,WAAW,CAAC,MAAM;QACpB,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,cAAc,GAAG,iBAAiB,CAAC,iBAAiB,EAAE,EAAC,WAAW,EAAC,CAAC,CAAC;IAE3E,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACxE,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,uBAAuB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,MAAM,qBAAqB,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QACnD,IAAI,WAAW,EAAE,MAAM,KAAK,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACzD,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;YACvC,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC;YACpC,iBAAiB,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,EAAE,eAAe,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAEtD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,KAAC,WAAW,IAAC,CAAC,EAAC,MAAM,GAAG,CAAC;IAClC,CAAC;IAED,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,CACL,cAAK,SAAS,EAAC,kDAAkD,kCAE3D,CACP,CAAC;IACJ,CAAC;IACD,IAAI,WAAW,EAAE,MAAM,KAAK,OAAO,EAAE,CAAC;QACpC,2FAA2F;QAC3F,MAAM,YAAY,GAChB,QAAQ;YACR,CAAC,iBAAiB,IAAI,CACpB,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,MAAM,EACX,SAAS,EAAC,SAAS,EACnB,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAC,iBAAiB,YAEvB,KAAC,qBAAqB,IAAC,SAAS,EAAC,SAAS,GAAG,GACtC,CACV,CAAC,CAAC;QAEL,OAAO,CACL,eAAK,SAAS,EAAC,0CAA0C,aACtD,YAAY,IAAI,CACf,cAAK,SAAS,EAAC,wBAAwB,YAAE,YAAY,GAAO,CAC7D,EACD,cACE,SAAS,EAAE,EAAE,CACX,wDAAwD,EACxD,YAAY,IAAI,OAAO,CACxB,YAEA,WAAW,CAAC,KAAK,GACd,IACF,CACP,CAAC;IACJ,CAAC;IAED,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,uBAAuB,GAAG,EAAE,CAChC,gEAAgE,EAChE,SAAS,CACV,CAAC;QAEF,kCAAkC;QAClC,IAAI,WAAW,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO,CACL,cAAK,SAAS,EAAE,uBAAuB,YACrC,eAAK,SAAS,EAAC,6CAA6C,aAC1D,cAAK,SAAS,EAAC,0FAA0F,YACtG,WAAW,GACR,EACN,eAAK,SAAS,EAAC,wDAAwD,aACrE,cAAK,SAAS,EAAC,mBAAmB,wBAAc,EAChD,cAAK,SAAS,EAAC,QAAQ,GAAG,EACzB,aAAa;oCACZ,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,kBAAkB,CAAC;oCAC/C,CAAC,CAAC,SAAS,IACT,IACF,GACF,CACP,CAAC;QACJ,CAAC;QAED,uCAAuC;QACvC,IAAI,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC;YACnC,OAAO,CACL,cAAK,SAAS,EAAE,uBAAuB,YACrC,eAAK,SAAS,EAAC,6BAA6B,aAC1C,KAAC,kBAAkB,IACjB,IAAI,EAAE,cAAc,EAAE,IAAI,EAC1B,OAAO,EAAE,cAAc,EAAE,OAAO,EAChC,SAAS,EAAC,2BAA2B,EACrC,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,KAAK,EACjB,UAAU,EAAE,UAAU,EACtB,gBAAgB,EAAE,gBAAgB,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,oBAAoB,EAAE,oBAAoB,GAC1C,EACF,eAAK,SAAS,EAAC,wDAAwD,aACpE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CACpB,8BACE,cAAK,SAAS,EAAC,mBAAmB,YAC/B,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,GACnD,EAEL,WAAW,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAC/B,KAAC,sBAAsB,IACrB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,uBAAuB,GAChC,CACH,CAAC,CAAC,CAAC,IAAI,IACP,CACJ,CAAC,CAAC,CAAC,IAAI,EACR,cAAK,SAAS,EAAC,QAAQ,GAAG,EACzB,aAAa;oCACZ,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,kBAAkB,CAAC;oCAC/C,CAAC,CAAC,SAAS,IACT,IACF,GACF,CACP,CAAC;QACJ,CAAC;QAED,mFAAmF;QACnF,OAAO,CACL,cAAK,SAAS,EAAE,uBAAuB,YACrC,cAAK,SAAS,EAAC,0CAA0C,4CAEnD,GACF,CACP,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAaF,MAAM,qBAAqB,GAAG,KAAK,CAAC,UAAU,CAG5C,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,GAAG,iBAAiB,EAAC,EAAE,GAAG,EAAE,EAAE;IACxE,MAAM,WAAW,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9C,MAAM,UAAU,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC;QACtD,OAAO,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACH,MAAM,eAAe,GAAG,qBAAqB,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CACnC,CAAC;IAEF,6BAA6B;IAC7B,IAAI,WAAW,EAAE,MAAM,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAEjD,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,OAAO,EAAE,CAAC,eAAe,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,eAAe,IAAC,aAAa,EAAE,GAAG,YACjC,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,KAAC,MAAM,IACL,GAAG,EAAE,GAAG,EACR,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,MAAM,EACX,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,EACnC,OAAO,EAAE,WAAW,YAEnB,IAAI,IAAI,KAAC,qBAAqB,IAAC,SAAS,EAAC,SAAS,GAAG,GAC/C,GACM,EACjB,KAAC,cAAc,cACb,YAAG,SAAS,EAAC,SAAS,YAAE,cAAc,GAAK,GAC5B,IACT,GACM,CACnB,CAAC;AACJ,CAAC,CAAC,CAAC;AACH,qBAAqB,CAAC,WAAW,GAAG,wBAAwB,CAAC;AAE7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE;IAClE,KAAK,EAAE,qBAAqB;CAC7B,CAAC,CAAC","sourcesContent":["import {\n ArrowDataTableValueFormatter,\n DataTablePaginated,\n useArrowDataTable,\n} from '@sqlrooms/data-table';\nimport {\n Button,\n cn,\n SpinnerPane,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '@sqlrooms/ui';\nimport {formatCount} from '@sqlrooms/utils';\nimport type {Row, RowSelectionState} from '@tanstack/react-table';\nimport {MessageCircleQuestion} from 'lucide-react';\nimport React from 'react';\nimport {isQueryWithResult, useStoreWithSqlEditor} from '../SqlEditorSlice';\nimport {QueryResultLimitSelect} from './QueryResultLimitSelect';\n\n/**\n * Turns DuckDB's EXPLAIN result table into a readable plan string.\n * Prefer the `explain_value` column (DuckDB default); otherwise fall back\n * to the first column and join all rows with newlines.\n */\nfunction arrowTableToExplainText(result: any): string {\n if (!result) return '';\n\n const numRows: number = result.numRows ?? 0;\n const fields: {name: string}[] = result.schema?.fields ?? [];\n const fieldNames = fields.map((f) => f.name);\n\n const hasExplainValueColumn = fieldNames.includes('explain_value');\n const columnName = hasExplainValueColumn ? 'explain_value' : fieldNames[0];\n if (!columnName) return '';\n\n const col = result.getChild?.(columnName);\n if (!col) return '';\n\n const lines: string[] = [];\n for (let i = 0; i < numRows; i++) {\n const v = col.get(i);\n if (v != null && String(v).length > 0) lines.push(String(v));\n }\n return lines.join('\\n');\n}\n\nexport interface QueryResultPanelProps {\n /** Custom class name for styling */\n className?: string;\n /** Custom actions to render in the query result panel */\n renderActions?: (query: string) => React.ReactNode;\n /** Custom font size for the table e.g. text-xs, text-sm, text-md, text-lg, text-base */\n fontSize?: string;\n /**\n * Called when a row in the results table is clicked.\n */\n onRowClick?: (args: {\n row: Row<any>;\n event: React.MouseEvent<HTMLTableRowElement>;\n }) => void;\n /**\n * Called when a row in the results table is double-clicked.\n */\n onRowDoubleClick?: (args: {\n row: Row<any>;\n event: React.MouseEvent<HTMLTableRowElement>;\n }) => void;\n /** Custom content to render in the error state (e.g., QueryResultPanel.AskAi) */\n children?: React.ReactNode;\n /**\n * @deprecated Use children with QueryResultPanel.AskAi instead\n * Called when the \"Ask AI\" button is clicked on an error message.\n * Receives the current query and error text.\n */\n onAskAiAboutError?: (query: string, error: string) => void;\n /**\n * Enables row selection with checkboxes.\n */\n enableRowSelection?: boolean;\n /**\n * Controlled row selection state. Keys are row indices, values are selection status.\n */\n rowSelection?: RowSelectionState;\n /**\n * Called when row selection changes.\n */\n onRowSelectionChange?: (rowSelection: RowSelectionState) => void;\n /** Custom value formatter for arrow data */\n formatValue?: ArrowDataTableValueFormatter;\n}\n\nconst QueryResultPanelRoot: React.FC<QueryResultPanelProps> = ({\n className,\n renderActions,\n fontSize = 'text-xs',\n onRowClick,\n onRowDoubleClick,\n children,\n onAskAiAboutError,\n enableRowSelection,\n rowSelection,\n onRowSelectionChange,\n formatValue,\n}) => {\n const queryResult = useStoreWithSqlEditor((s) => {\n const selectedId = s.sqlEditor.config.selectedQueryId;\n return s.sqlEditor.queryResultsById[selectedId];\n });\n const getCurrentQuery = useStoreWithSqlEditor(\n (s) => s.sqlEditor.getCurrentQuery,\n );\n const setQueryResultLimit = useStoreWithSqlEditor(\n (s) => s.sqlEditor.setQueryResultLimit,\n );\n const queryResultLimit = useStoreWithSqlEditor(\n (s) => s.sqlEditor.queryResultLimit,\n );\n const queryResultLimitOptions = useStoreWithSqlEditor(\n (s) => s.sqlEditor.queryResultLimitOptions,\n );\n\n const tableForDataTable =\n isQueryWithResult(queryResult) && queryResult.type !== 'explain'\n ? queryResult.result\n : undefined;\n\n const arrowTableData = useArrowDataTable(tableForDataTable, {formatValue});\n\n const explainText = React.useMemo(() => {\n if (queryResult?.status !== 'success' || queryResult.type !== 'explain') {\n return undefined;\n }\n return arrowTableToExplainText(queryResult.result);\n }, [queryResult]);\n\n const handleAskAiAboutError = React.useCallback(() => {\n if (queryResult?.status === 'error' && onAskAiAboutError) {\n const currentQuery = getCurrentQuery();\n const errorText = queryResult.error;\n onAskAiAboutError?.(currentQuery, errorText);\n }\n }, [queryResult, getCurrentQuery, onAskAiAboutError]);\n\n if (!queryResult) {\n return null;\n }\n\n if (queryResult?.status === 'loading') {\n return <SpinnerPane h=\"100%\" />;\n }\n\n if (queryResult?.status === 'aborted') {\n return (\n <div className=\"p-5 font-mono text-xs leading-tight text-red-500\">\n Query was aborted\n </div>\n );\n }\n if (queryResult?.status === 'error') {\n // Backward compat: if no children but onAskAiAboutError is provided, render default button\n const errorActions =\n children ??\n (onAskAiAboutError && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={handleAskAiAboutError}\n title=\"Ask AI for help\"\n >\n <MessageCircleQuestion className=\"h-4 w-4\" />\n </Button>\n ));\n\n return (\n <div className=\"relative h-full w-full overflow-auto p-5\">\n {errorActions && (\n <div className=\"absolute right-2 top-2\">{errorActions}</div>\n )}\n <pre\n className={cn(\n 'whitespace-pre-wrap text-xs leading-tight text-red-500',\n errorActions && 'pr-12',\n )}\n >\n {queryResult.error}\n </pre>\n </div>\n );\n }\n\n if (queryResult?.status === 'success') {\n const contentWrapperClassName = cn(\n 'relative flex h-full w-full flex-grow flex-col overflow-hidden',\n className,\n );\n\n // Result shows the EXPLAIN schema\n if (queryResult.type === 'explain') {\n return (\n <div className={contentWrapperClassName}>\n <div className=\"flex h-full w-full flex-col overflow-hidden\">\n <pre className=\"flex-1 overflow-auto whitespace-pre-wrap break-words p-4 font-mono text-xs leading-tight\">\n {explainText}\n </pre>\n <div className=\"bg-background flex w-full items-center gap-2 px-4 py-1\">\n <div className=\"font-mono text-xs\">EXPLAIN</div>\n <div className=\"flex-1\" />\n {renderActions\n ? renderActions(queryResult.lastQueryStatement)\n : undefined}\n </div>\n </div>\n </div>\n );\n }\n\n // Result shows the SELECT/PRAGMA table\n if (isQueryWithResult(queryResult)) {\n return (\n <div className={contentWrapperClassName}>\n <div className=\"flex h-full w-full flex-col\">\n <DataTablePaginated\n data={arrowTableData?.data}\n columns={arrowTableData?.columns}\n className=\"flex-grow overflow-hidden\"\n fontSize={fontSize}\n isFetching={false}\n onRowClick={onRowClick}\n onRowDoubleClick={onRowDoubleClick}\n enableRowSelection={enableRowSelection}\n rowSelection={rowSelection}\n onRowSelectionChange={onRowSelectionChange}\n />\n <div className=\"bg-background flex w-full items-center gap-2 px-4 py-1\">\n {queryResult.result ? (\n <>\n <div className=\"font-mono text-xs\">\n {`${formatCount(queryResult.result.numRows ?? 0)} rows`}\n </div>\n\n {queryResult.type === 'select' ? (\n <QueryResultLimitSelect\n value={queryResultLimit}\n onChange={setQueryResultLimit}\n options={queryResultLimitOptions}\n />\n ) : null}\n </>\n ) : null}\n <div className=\"flex-1\" />\n {renderActions\n ? renderActions(queryResult.lastQueryStatement)\n : undefined}\n </div>\n </div>\n </div>\n );\n }\n\n // Fallback message to show when the query result is not a SELECT/PRAGMA or EXPLAIN\n return (\n <div className={contentWrapperClassName}>\n <pre className=\"p-4 text-xs leading-tight text-green-500\">\n Successfully executed query\n </pre>\n </div>\n );\n }\n\n return null;\n};\n\nexport interface QueryResultPanelAskAiProps {\n /** Called when clicked with the current query and error message */\n onClick?: (query: string, error: string) => void;\n /** Custom icon (defaults to MessageCircleQuestion) */\n icon?: React.ReactNode;\n /** Custom className */\n className?: string;\n /** Tooltip text to display on hover */\n tooltipContent?: string;\n}\n\nconst QueryResultPanelAskAi = React.forwardRef<\n HTMLButtonElement,\n QueryResultPanelAskAiProps\n>(({onClick, icon, className, tooltipContent = 'Ask AI for help'}, ref) => {\n const queryResult = useStoreWithSqlEditor((s) => {\n const selectedId = s.sqlEditor.config.selectedQueryId;\n return s.sqlEditor.queryResultsById[selectedId];\n });\n const getCurrentQuery = useStoreWithSqlEditor(\n (s) => s.sqlEditor.getCurrentQuery,\n );\n\n // Only render in error state\n if (queryResult?.status !== 'error') return null;\n\n const handleClick = () => {\n onClick?.(getCurrentQuery(), queryResult.error);\n };\n\n return (\n <TooltipProvider delayDuration={200}>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-8 w-8', className)}\n onClick={handleClick}\n >\n {icon ?? <MessageCircleQuestion className=\"h-4 w-4\" />}\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p className=\"text-xs\">{tooltipContent}</p>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n});\nQueryResultPanelAskAi.displayName = 'QueryResultPanel.AskAi';\n\nexport const QueryResultPanel = Object.assign(QueryResultPanelRoot, {\n AskAi: QueryResultPanelAskAi,\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/sql-editor",
3
- "version": "0.27.0-rc.4",
3
+ "version": "0.27.0",
4
4
  "author": "SQLRooms Contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,14 +29,14 @@
29
29
  "@hookform/resolvers": "^5.0.0",
30
30
  "@monaco-editor/react": "^4.7.0",
31
31
  "@paralleldrive/cuid2": "^3.0.0",
32
- "@sqlrooms/data-table": "0.27.0-rc.4",
33
- "@sqlrooms/duckdb": "0.27.0-rc.4",
34
- "@sqlrooms/monaco-editor": "0.27.0-rc.4",
35
- "@sqlrooms/room-shell": "0.27.0-rc.4",
36
- "@sqlrooms/schema-tree": "0.27.0-rc.4",
37
- "@sqlrooms/sql-editor-config": "0.27.0-rc.4",
38
- "@sqlrooms/ui": "0.27.0-rc.4",
39
- "@sqlrooms/utils": "0.27.0-rc.4",
32
+ "@sqlrooms/data-table": "0.27.0",
33
+ "@sqlrooms/duckdb": "0.27.0",
34
+ "@sqlrooms/monaco-editor": "0.27.0",
35
+ "@sqlrooms/room-shell": "0.27.0",
36
+ "@sqlrooms/schema-tree": "0.27.0",
37
+ "@sqlrooms/sql-editor-config": "0.27.0",
38
+ "@sqlrooms/ui": "0.27.0",
39
+ "@sqlrooms/utils": "0.27.0",
40
40
  "@tanstack/react-table": "^8.21.3",
41
41
  "d3-dsv": "^3.0.1",
42
42
  "file-saver": "^2.0.5",
@@ -58,5 +58,5 @@
58
58
  "@types/react": "^19.1.13",
59
59
  "@types/react-dom": "^19.1.9"
60
60
  },
61
- "gitHead": "892408d49720d1fb195308029674894ae059969d"
61
+ "gitHead": "f215995ab4adeac4c58171739261a15cbba9e82b"
62
62
  }