@sqlrooms/cells 0.29.0-rc.1 → 0.29.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/cellsSlice.d.ts.map +1 -1
- package/dist/cellsSlice.js +305 -264
- package/dist/cellsSlice.js.map +1 -1
- package/dist/components/AggregationSelector.d.ts +8 -0
- package/dist/components/AggregationSelector.d.ts.map +1 -0
- package/dist/components/AggregationSelector.js +13 -0
- package/dist/components/AggregationSelector.js.map +1 -0
- package/dist/components/CellSourceSelector.d.ts +12 -0
- package/dist/components/CellSourceSelector.d.ts.map +1 -0
- package/dist/components/CellSourceSelector.js +34 -0
- package/dist/components/CellSourceSelector.js.map +1 -0
- package/dist/components/ChartTypeSelector.d.ts +8 -0
- package/dist/components/ChartTypeSelector.d.ts.map +1 -0
- package/dist/components/ChartTypeSelector.js +13 -0
- package/dist/components/ChartTypeSelector.js.map +1 -0
- package/dist/components/CollapsibleSectionButton.d.ts +10 -0
- package/dist/components/CollapsibleSectionButton.d.ts.map +1 -0
- package/dist/components/CollapsibleSectionButton.js +10 -0
- package/dist/components/CollapsibleSectionButton.js.map +1 -0
- package/dist/components/ColorSelector.d.ts +24 -0
- package/dist/components/ColorSelector.d.ts.map +1 -0
- package/dist/components/ColorSelector.js +17 -0
- package/dist/components/ColorSelector.js.map +1 -0
- package/dist/components/FieldSelector.d.ts +11 -0
- package/dist/components/FieldSelector.d.ts.map +1 -0
- package/dist/components/FieldSelector.js +11 -0
- package/dist/components/FieldSelector.js.map +1 -0
- package/dist/components/FieldTypeIcon.d.ts +8 -0
- package/dist/components/FieldTypeIcon.d.ts.map +1 -0
- package/dist/components/FieldTypeIcon.js +27 -0
- package/dist/components/FieldTypeIcon.js.map +1 -0
- package/dist/components/InputCellContent.d.ts.map +1 -1
- package/dist/components/InputCellContent.js +3 -3
- package/dist/components/InputCellContent.js.map +1 -1
- package/dist/components/SelectionListener.d.ts +15 -0
- package/dist/components/SelectionListener.d.ts.map +1 -0
- package/dist/components/SelectionListener.js +74 -0
- package/dist/components/SelectionListener.js.map +1 -0
- package/dist/components/SqlCellConnectionSelector.d.ts +9 -0
- package/dist/components/SqlCellConnectionSelector.d.ts.map +1 -0
- package/dist/components/SqlCellConnectionSelector.js +21 -0
- package/dist/components/SqlCellConnectionSelector.js.map +1 -0
- package/dist/components/SqlCellContent.d.ts.map +1 -1
- package/dist/components/SqlCellContent.js +31 -156
- package/dist/components/SqlCellContent.js.map +1 -1
- package/dist/components/SqlCellDependentsMenu.d.ts +11 -0
- package/dist/components/SqlCellDependentsMenu.d.ts.map +1 -0
- package/dist/components/SqlCellDependentsMenu.js +62 -0
- package/dist/components/SqlCellDependentsMenu.js.map +1 -0
- package/dist/components/SqlCellEditor.d.ts +14 -0
- package/dist/components/SqlCellEditor.d.ts.map +1 -0
- package/dist/components/SqlCellEditor.js +17 -0
- package/dist/components/SqlCellEditor.js.map +1 -0
- package/dist/components/SqlCellResultNameEditor.d.ts +8 -0
- package/dist/components/SqlCellResultNameEditor.d.ts.map +1 -0
- package/dist/components/SqlCellResultNameEditor.js +38 -0
- package/dist/components/SqlCellResultNameEditor.js.map +1 -0
- package/dist/components/SqlCellResults.d.ts +17 -0
- package/dist/components/SqlCellResults.d.ts.map +1 -0
- package/dist/components/SqlCellResults.js +45 -0
- package/dist/components/SqlCellResults.js.map +1 -0
- package/dist/components/SqlCellRunButton.d.ts +5 -6
- package/dist/components/SqlCellRunButton.d.ts.map +1 -1
- package/dist/components/SqlCellRunButton.js +11 -7
- package/dist/components/SqlCellRunButton.js.map +1 -1
- package/dist/components/SqlQueryPreview.d.ts +9 -0
- package/dist/components/SqlQueryPreview.d.ts.map +1 -0
- package/dist/components/SqlQueryPreview.js +14 -0
- package/dist/components/SqlQueryPreview.js.map +1 -0
- package/dist/components/TextCellContent.d.ts.map +1 -1
- package/dist/components/TextCellContent.js +24 -7
- package/dist/components/TextCellContent.js.map +1 -1
- package/dist/components/VegaCellContent.d.ts +0 -1
- package/dist/components/VegaCellContent.d.ts.map +1 -1
- package/dist/components/VegaCellContent.js +61 -47
- package/dist/components/VegaCellContent.js.map +1 -1
- package/dist/components/VegaCellHeader.d.ts +11 -0
- package/dist/components/VegaCellHeader.d.ts.map +1 -0
- package/dist/components/VegaCellHeader.js +32 -0
- package/dist/components/VegaCellHeader.js.map +1 -0
- package/dist/components/VegaConfigPanel.d.ts +5 -0
- package/dist/components/VegaConfigPanel.d.ts.map +1 -1
- package/dist/components/VegaConfigPanel.js +53 -63
- package/dist/components/VegaConfigPanel.js.map +1 -1
- package/dist/dagUtils.d.ts +10 -9
- package/dist/dagUtils.d.ts.map +1 -1
- package/dist/dagUtils.js +76 -50
- package/dist/dagUtils.js.map +1 -1
- package/dist/defaultCellRegistry.d.ts.map +1 -1
- package/dist/defaultCellRegistry.js +79 -36
- package/dist/defaultCellRegistry.js.map +1 -1
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +24 -17
- package/dist/execution.js.map +1 -1
- package/dist/helpers.d.ts +20 -16
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +79 -44
- package/dist/helpers.js.map +1 -1
- package/dist/hooks/useVegaCellDataSource.d.ts +18 -0
- package/dist/hooks/useVegaCellDataSource.d.ts.map +1 -0
- package/dist/hooks/useVegaCellDataSource.js +40 -0
- package/dist/hooks/useVegaCellDataSource.js.map +1 -0
- package/dist/hooks/useVegaCellQuery.d.ts +16 -0
- package/dist/hooks/useVegaCellQuery.d.ts.map +1 -0
- package/dist/hooks/useVegaCellQuery.js +25 -0
- package/dist/hooks/useVegaCellQuery.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/sqlHelpers.d.ts +8 -8
- package/dist/sqlHelpers.d.ts.map +1 -1
- package/dist/sqlHelpers.js +16 -12
- package/dist/sqlHelpers.js.map +1 -1
- package/dist/types.d.ts +113 -70
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +22 -13
- package/dist/types.js.map +1 -1
- package/dist/useValidateResultName.d.ts +34 -0
- package/dist/useValidateResultName.d.ts.map +1 -0
- package/dist/useValidateResultName.js +111 -0
- package/dist/useValidateResultName.js.map +1 -0
- package/dist/utils.d.ts +10 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +20 -4
- package/dist/utils.js.map +1 -1
- package/dist/vegaSelectionUtils.d.ts +14 -0
- package/dist/vegaSelectionUtils.d.ts.map +1 -0
- package/dist/vegaSelectionUtils.js +97 -0
- package/dist/vegaSelectionUtils.js.map +1 -0
- package/dist/vegaSpecBuilder.d.ts +34 -0
- package/dist/vegaSpecBuilder.d.ts.map +1 -0
- package/dist/vegaSpecBuilder.js +90 -0
- package/dist/vegaSpecBuilder.js.map +1 -0
- package/package.json +12 -13
- package/dist/components/DeleteSheetModal.d.ts +0 -9
- package/dist/components/DeleteSheetModal.d.ts.map +0 -1
- package/dist/components/DeleteSheetModal.js +0 -6
- package/dist/components/DeleteSheetModal.js.map +0 -1
- package/dist/components/SheetsTabBar.d.ts +0 -6
- package/dist/components/SheetsTabBar.d.ts.map +0 -1
- package/dist/components/SheetsTabBar.js +0 -57
- package/dist/components/SheetsTabBar.js.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Calendar, Hash, Type, HelpCircle, ToggleLeft, Binary, Braces, Box, Map, } from 'lucide-react';
|
|
3
|
+
import { cn } from '@sqlrooms/ui';
|
|
4
|
+
export const FieldTypeIcon = ({ typeCategory, className, }) => {
|
|
5
|
+
const iconClass = cn('h-3.5 w-3.5 shrink-0 text-gray-400', className);
|
|
6
|
+
switch (typeCategory) {
|
|
7
|
+
case 'number':
|
|
8
|
+
return _jsx(Hash, { className: iconClass });
|
|
9
|
+
case 'string':
|
|
10
|
+
return _jsx(Type, { className: iconClass });
|
|
11
|
+
case 'datetime':
|
|
12
|
+
return _jsx(Calendar, { className: iconClass });
|
|
13
|
+
case 'boolean':
|
|
14
|
+
return _jsx(ToggleLeft, { className: iconClass });
|
|
15
|
+
case 'binary':
|
|
16
|
+
return _jsx(Binary, { className: iconClass });
|
|
17
|
+
case 'json':
|
|
18
|
+
return _jsx(Braces, { className: iconClass });
|
|
19
|
+
case 'struct':
|
|
20
|
+
return _jsx(Box, { className: iconClass });
|
|
21
|
+
case 'geometry':
|
|
22
|
+
return _jsx(Map, { className: iconClass });
|
|
23
|
+
default:
|
|
24
|
+
return _jsx(HelpCircle, { className: iconClass });
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=FieldTypeIcon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FieldTypeIcon.js","sourceRoot":"","sources":["../../src/components/FieldTypeIcon.tsx"],"names":[],"mappings":";AAEA,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,UAAU,EACV,UAAU,EACV,MAAM,EACN,MAAM,EACN,GAAG,EACH,GAAG,GACJ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAOhC,MAAM,CAAC,MAAM,aAAa,GAAiC,CAAC,EAC1D,YAAY,EACZ,SAAS,GACV,EAAE,EAAE;IACH,MAAM,SAAS,GAAG,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,CAAC;IAEtE,QAAQ,YAAY,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,KAAC,IAAI,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QACxC,KAAK,QAAQ;YACX,OAAO,KAAC,IAAI,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QACxC,KAAK,UAAU;YACb,OAAO,KAAC,QAAQ,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QAC5C,KAAK,SAAS;YACZ,OAAO,KAAC,UAAU,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QAC9C,KAAK,QAAQ;YACX,OAAO,KAAC,MAAM,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QAC1C,KAAK,MAAM;YACT,OAAO,KAAC,MAAM,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QAC1C,KAAK,QAAQ;YACX,OAAO,KAAC,GAAG,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QACvC,KAAK,UAAU;YACb,OAAO,KAAC,GAAG,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QACvC;YACE,OAAO,KAAC,UAAU,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;IAChD,CAAC;AACH,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport {type ColumnTypeCategory} from '@sqlrooms/duckdb';\nimport {\n Calendar,\n Hash,\n Type,\n HelpCircle,\n ToggleLeft,\n Binary,\n Braces,\n Box,\n Map,\n} from 'lucide-react';\nimport {cn} from '@sqlrooms/ui';\n\nexport interface FieldTypeIconProps {\n typeCategory: ColumnTypeCategory | undefined;\n className?: string;\n}\n\nexport const FieldTypeIcon: React.FC<FieldTypeIconProps> = ({\n typeCategory,\n className,\n}) => {\n const iconClass = cn('h-3.5 w-3.5 shrink-0 text-gray-400', className);\n\n switch (typeCategory) {\n case 'number':\n return <Hash className={iconClass} />;\n case 'string':\n return <Type className={iconClass} />;\n case 'datetime':\n return <Calendar className={iconClass} />;\n case 'boolean':\n return <ToggleLeft className={iconClass} />;\n case 'binary':\n return <Binary className={iconClass} />;\n case 'json':\n return <Braces className={iconClass} />;\n case 'struct':\n return <Box className={iconClass} />;\n case 'geometry':\n return <Map className={iconClass} />;\n default:\n return <HelpCircle className={iconClass} />;\n }\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputCellContent.d.ts","sourceRoot":"","sources":["../../src/components/InputCellContent.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InputCellContent.d.ts","sourceRoot":"","sources":["../../src/components/InputCellContent.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAEzC,OAAO,KAAK,EAAO,kBAAkB,EAAE,SAAS,EAAa,MAAM,UAAU,CAAC;AAG9E,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,eAAe,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,KAAK,CAAC,YAAY,CAAC;CACpE,CAAC;AAqDF,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwD5D,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { EditableText, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider, } from '@sqlrooms/ui';
|
|
3
|
+
import { produce } from 'immer';
|
|
2
4
|
import { useCallback } from 'react';
|
|
3
|
-
import { EditableText, Input, Slider, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@sqlrooms/ui';
|
|
4
5
|
import { useCellsStore } from '../hooks';
|
|
5
6
|
import { InputConfigPanel } from './Input/ConfigPanel/InputConfigPanel';
|
|
6
|
-
import { produce } from 'immer';
|
|
7
7
|
const RenderInput = ({ input, updateInput }) => {
|
|
8
8
|
switch (input.kind) {
|
|
9
9
|
case 'text':
|
|
@@ -28,7 +28,7 @@ export const InputCellContent = ({ id, cell, renderContainer, }) => {
|
|
|
28
28
|
}
|
|
29
29
|
}), isValueChange ? { cascade: true } : undefined);
|
|
30
30
|
}, [id, updateCell]);
|
|
31
|
-
const header = (_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(EditableText, { value: input.varName, onChange: (varName) => updateInput({ varName }), className: "h-6 text-xs font-semibold shadow-none outline-
|
|
31
|
+
const header = (_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(EditableText, { value: input.varName, onChange: (varName) => updateInput({ varName }), className: "h-6 text-xs font-semibold shadow-none ring-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1" }), _jsx("span", { className: "text-[10px] font-bold text-gray-400 uppercase", children: "Input" })] }), _jsx(InputConfigPanel, { input: input, updateInput: updateInput, onRemove: () => removeCell(id) })] }));
|
|
32
32
|
const content = (_jsx("div", { className: "p-2", children: _jsx(RenderInput, { input: input, updateInput: updateInput }) }));
|
|
33
33
|
return renderContainer({
|
|
34
34
|
header,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputCellContent.js","sourceRoot":"","sources":["../../src/components/InputCellContent.tsx"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"InputCellContent.js","sourceRoot":"","sources":["../../src/components/InputCellContent.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,YAAY,EACZ,KAAK,EACL,MAAM,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACb,WAAW,EACX,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AAC9B,OAAc,EAAC,WAAW,EAAC,MAAM,OAAO,CAAC;AACzC,OAAO,EAAC,aAAa,EAAuB,MAAM,UAAU,CAAC;AAE7D,OAAO,EAAC,gBAAgB,EAAC,MAAM,sCAAsC,CAAC;AAQtE,MAAM,WAAW,GAGZ,CAAC,EAAC,KAAK,EAAE,WAAW,EAAC,EAAE,EAAE;IAC5B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,CACL,KAAC,KAAK,IACJ,SAAS,EAAC,6CAA6C,EACvD,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,EAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAC,CAAC,GACrD,CACH,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,CACL,eAAK,SAAS,EAAC,iCAAiC,aAC9C,KAAC,MAAM,IACL,GAAG,EAAE,KAAK,CAAC,GAAG,EACd,GAAG,EAAE,KAAK,CAAC,GAAG,EACd,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,KAAK,EAAE,CAAC,KAAK,CAAC,KAAe,CAAC,EAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,EAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAC,CAAC,GAC7D,EACF,eAAM,SAAS,EAAC,4CAA4C,YACzD,KAAK,CAAC,KAAK,GACP,IACH,CACP,CAAC;QACJ,KAAK,UAAU;YACb,OAAO,CACL,MAAC,MAAM,IACL,KAAK,EAAE,KAAK,CAAC,KAAe,EAC5B,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,EAAC,KAAK,EAAC,CAAC,aAE9C,KAAC,aAAa,IAAC,SAAS,EAAC,yBAAyB,YAChD,KAAC,WAAW,KAAG,GACD,EAChB,KAAC,aAAa,IAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,YACtD,KAAK,CAAC,OAAoB,CAAC,GAAG,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC,CACnD,KAAC,UAAU,IAAC,SAAS,EAAC,SAAS,EAAc,KAAK,EAAE,MAAM,YACvD,MAAM,IAD4B,MAAM,CAE9B,CACd,CAAC,GACY,IACT,CACV,CAAC;QACJ;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAoC,CAAC,EAChE,EAAE,EACF,IAAI,EACJ,eAAe,GAChB,EAAE,EAAE;IACH,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC7E,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAE9B,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,KAA0B,EAAE,EAAE;QAC7B,MAAM,aAAa,GAAG,OAAO,IAAI,KAAK,CAAC;QACvC,UAAU,CACR,EAAE,EACF,CAAC,CAAO,EAAE,EAAE,CACV,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,EAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,KAAK,EAAQ,CAAC;YAC5D,CAAC;QACH,CAAC,CAAC,EACJ,aAAa,CAAC,CAAC,CAAC,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC,CAAC,CAAC,SAAS,CAC5C,CAAC;IACJ,CAAC,EACD,CAAC,EAAE,EAAE,UAAU,CAAC,CACjB,CAAC;IAEF,MAAM,MAAM,GAAG,CACb,eAAK,SAAS,EAAC,yCAAyC,aACtD,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,YAAY,IACX,KAAK,EAAE,KAAK,CAAC,OAAO,EACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,EAAC,OAAO,EAAC,CAAC,EAC7C,SAAS,EAAC,2HAA2H,GACrI,EACF,eAAM,SAAS,EAAC,+CAA+C,sBAExD,IACH,EACN,KAAC,gBAAgB,IACf,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,GAC9B,IACE,CACP,CAAC;IAEF,MAAM,OAAO,GAAG,CACd,cAAK,SAAS,EAAC,KAAK,YAClB,KAAC,WAAW,IAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,GAAI,GACnD,CACP,CAAC;IAEF,OAAO,eAAe,CAAC;QACrB,MAAM;QACN,OAAO;KACR,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import {\n EditableText,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Slider,\n} from '@sqlrooms/ui';\nimport {produce} from 'immer';\nimport React, {useCallback} from 'react';\nimport {useCellsStore, type CellsStoreState} from '../hooks';\nimport type {Cell, CellContainerProps, InputCell, InputUnion} from '../types';\nimport {InputConfigPanel} from './Input/ConfigPanel/InputConfigPanel';\n\nexport type InputCellContentProps = {\n id: string;\n cell: InputCell;\n renderContainer: (props: CellContainerProps) => React.ReactElement;\n};\n\nconst RenderInput: React.FC<{\n input: InputUnion;\n updateInput: (patch: Partial<InputUnion>) => void;\n}> = ({input, updateInput}) => {\n switch (input.kind) {\n case 'text':\n return (\n <Input\n className=\"h-8 w-full rounded border px-2 py-1 text-sm\"\n value={input.value}\n onChange={(e) => updateInput({value: e.target.value})}\n />\n );\n case 'slider':\n return (\n <div className=\"flex h-8 items-center space-x-1\">\n <Slider\n min={input.min}\n max={input.max}\n step={input.step}\n value={[input.value as number]}\n onValueChange={(value) => updateInput({value: Number(value)})}\n />\n <span className=\"min-w-[3ch] text-right text-sm font-medium\">\n {input.value}\n </span>\n </div>\n );\n case 'dropdown':\n return (\n <Select\n value={input.value as string}\n onValueChange={(value) => updateInput({value})}\n >\n <SelectTrigger className=\"h-8 text-xs shadow-none\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent onCloseAutoFocus={(e) => e.preventDefault()}>\n {(input.options as string[]).map((option: string) => (\n <SelectItem className=\"text-xs\" key={option} value={option}>\n {option}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n default:\n return null;\n }\n};\n\nexport const InputCellContent: React.FC<InputCellContentProps> = ({\n id,\n cell,\n renderContainer,\n}) => {\n const updateCell = useCellsStore((s: CellsStoreState) => s.cells.updateCell);\n const removeCell = useCellsStore((s: CellsStoreState) => s.cells.removeCell);\n const input = cell.data.input;\n\n const updateInput = useCallback(\n (patch: Partial<InputUnion>) => {\n const isValueChange = 'value' in patch;\n updateCell(\n id,\n (c: Cell) =>\n produce(c, (draft) => {\n if (draft.type === 'input') {\n draft.data.input = {...draft.data.input, ...patch} as any;\n }\n }),\n isValueChange ? {cascade: true} : undefined,\n );\n },\n [id, updateCell],\n );\n\n const header = (\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2\">\n <EditableText\n value={input.varName}\n onChange={(varName) => updateInput({varName})}\n className=\"h-6 text-xs font-semibold shadow-none ring-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1\"\n />\n <span className=\"text-[10px] font-bold text-gray-400 uppercase\">\n Input\n </span>\n </div>\n <InputConfigPanel\n input={input}\n updateInput={updateInput}\n onRemove={() => removeCell(id)}\n />\n </div>\n );\n\n const content = (\n <div className=\"p-2\">\n <RenderInput input={input} updateInput={updateInput} />\n </div>\n );\n\n return renderContainer({\n header,\n content,\n });\n};\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { BrushFieldType } from '../types';
|
|
3
|
+
type SelectionListenerProps = {
|
|
4
|
+
cellId: string;
|
|
5
|
+
sqlId: string;
|
|
6
|
+
brushField: string;
|
|
7
|
+
brushFieldType?: BrushFieldType;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Attaches a debounced Vega signal listener for the brush param
|
|
11
|
+
* and reports selection changes to the cross-filter state.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SelectionListener: React.FC<SelectionListenerProps>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=SelectionListener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionListener.d.ts","sourceRoot":"","sources":["../../src/components/SelectionListener.tsx"],"names":[],"mappings":"AACA,OAAO,KAA0B,MAAM,OAAO,CAAC;AAE/C,OAAO,KAAK,EAAC,cAAc,EAAuB,MAAM,UAAU,CAAC;AAGnE,KAAK,sBAAsB,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA8E9D,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useVegaChartContext } from '@sqlrooms/vega';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { useCellsStore } from '../hooks';
|
|
4
|
+
import { BRUSH_PARAM_NAME } from '../vegaSelectionUtils';
|
|
5
|
+
/**
|
|
6
|
+
* Attaches a debounced Vega signal listener for the brush param
|
|
7
|
+
* and reports selection changes to the cross-filter state.
|
|
8
|
+
*/
|
|
9
|
+
export const SelectionListener = ({ cellId, sqlId, brushField, brushFieldType, }) => {
|
|
10
|
+
const { embed } = useVegaChartContext();
|
|
11
|
+
const setCrossFilterSelection = useCellsStore((s) => s.cells.setCrossFilterSelection);
|
|
12
|
+
const timerRef = useRef(null);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!embed?.view) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const handler = (_name, value) => {
|
|
18
|
+
if (timerRef.current) {
|
|
19
|
+
clearTimeout(timerRef.current);
|
|
20
|
+
}
|
|
21
|
+
timerRef.current = setTimeout(() => {
|
|
22
|
+
if (!value || Object.keys(value).length === 0) {
|
|
23
|
+
setCrossFilterSelection(cellId, sqlId, null);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const fieldValue = value.x ?? value[brushField];
|
|
27
|
+
if (Array.isArray(fieldValue) && fieldValue.length === 2) {
|
|
28
|
+
const selection = {
|
|
29
|
+
field: brushField,
|
|
30
|
+
fieldType: brushFieldType,
|
|
31
|
+
type: 'interval',
|
|
32
|
+
value: fieldValue,
|
|
33
|
+
};
|
|
34
|
+
setCrossFilterSelection(cellId, sqlId, selection);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
setCrossFilterSelection(cellId, sqlId, null);
|
|
38
|
+
}
|
|
39
|
+
}, 200);
|
|
40
|
+
};
|
|
41
|
+
try {
|
|
42
|
+
embed.view.addSignalListener(BRUSH_PARAM_NAME, handler);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
// Signal doesn't exist yet (view is still rendering a spec without the brush param).
|
|
46
|
+
// Will retry when embed reference changes after the new spec is compiled.
|
|
47
|
+
console.warn('Failed to add signal listener:', error);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
return () => {
|
|
51
|
+
if (timerRef.current) {
|
|
52
|
+
clearTimeout(timerRef.current);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
embed.view.removeSignalListener(BRUSH_PARAM_NAME, handler);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
// View may have been finalized
|
|
59
|
+
console.warn('Failed to remove signal listener:', error);
|
|
60
|
+
}
|
|
61
|
+
// Clear this chart's selection from crossFilterSelections
|
|
62
|
+
setCrossFilterSelection(cellId, sqlId, null);
|
|
63
|
+
};
|
|
64
|
+
}, [
|
|
65
|
+
embed,
|
|
66
|
+
cellId,
|
|
67
|
+
sqlId,
|
|
68
|
+
brushField,
|
|
69
|
+
brushFieldType,
|
|
70
|
+
setCrossFilterSelection,
|
|
71
|
+
]);
|
|
72
|
+
return null;
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=SelectionListener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionListener.js","sourceRoot":"","sources":["../../src/components/SelectionListener.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SignalListenerHandler, useVegaChartContext} from '@sqlrooms/vega';\nimport React, {useEffect, useRef} from 'react';\nimport {useCellsStore} from '../hooks';\nimport type {BrushFieldType, CrossFilterSelection} from '../types';\nimport {BRUSH_PARAM_NAME} from '../vegaSelectionUtils';\n\ntype SelectionListenerProps = {\n cellId: string;\n sqlId: string;\n brushField: string;\n brushFieldType?: BrushFieldType;\n};\n\n/**\n * Attaches a debounced Vega signal listener for the brush param\n * and reports selection changes to the cross-filter state.\n */\nexport const SelectionListener: React.FC<SelectionListenerProps> = ({\n cellId,\n sqlId,\n brushField,\n brushFieldType,\n}) => {\n const {embed} = useVegaChartContext();\n const setCrossFilterSelection = useCellsStore(\n (s) => s.cells.setCrossFilterSelection,\n );\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (!embed?.view) {\n return;\n }\n\n const handler: SignalListenerHandler = (_name, value) => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n }\n\n timerRef.current = setTimeout(() => {\n if (!value || Object.keys(value).length === 0) {\n setCrossFilterSelection(cellId, sqlId, null);\n return;\n }\n\n const fieldValue = value.x ?? value[brushField];\n\n if (Array.isArray(fieldValue) && fieldValue.length === 2) {\n const selection: CrossFilterSelection = {\n field: brushField,\n fieldType: brushFieldType,\n type: 'interval',\n value: fieldValue,\n };\n setCrossFilterSelection(cellId, sqlId, selection);\n } else {\n setCrossFilterSelection(cellId, sqlId, null);\n }\n }, 200);\n };\n\n try {\n embed.view.addSignalListener(BRUSH_PARAM_NAME, handler);\n } catch (error) {\n // Signal doesn't exist yet (view is still rendering a spec without the brush param).\n // Will retry when embed reference changes after the new spec is compiled.\n console.warn('Failed to add signal listener:', error);\n return;\n }\n\n return () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n }\n\n try {\n embed.view.removeSignalListener(BRUSH_PARAM_NAME, handler);\n } catch (error) {\n // View may have been finalized\n console.warn('Failed to remove signal listener:', error);\n }\n\n // Clear this chart's selection from crossFilterSelections\n setCrossFilterSelection(cellId, sqlId, null);\n };\n }, [\n embed,\n cellId,\n sqlId,\n brushField,\n brushFieldType,\n setCrossFilterSelection,\n ]);\n\n return null;\n};\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DbConnection } from '@sqlrooms/db';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export type SqlCellConnectionSelectorProps = {
|
|
4
|
+
connectors: Record<string, DbConnection>;
|
|
5
|
+
selectedConnectorId: string;
|
|
6
|
+
onChange: (connectorId: string) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare const SqlCellConnectionSelector: React.FC<SqlCellConnectionSelectorProps>;
|
|
9
|
+
//# sourceMappingURL=SqlCellConnectionSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlCellConnectionSelector.d.ts","sourceRoot":"","sources":["../../src/components/SqlCellConnectionSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,YAAY,EAAC,MAAM,cAAc,CAAC;AAQ1E,OAAO,KAAgB,MAAM,OAAO,CAAC;AAErC,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,KAAK,CAAC,EAAE,CAC9C,8BAA8B,CAkC/B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getCoreDuckDbConnectionId } from '@sqlrooms/db';
|
|
3
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@sqlrooms/ui';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
export const SqlCellConnectionSelector = ({ connectors, selectedConnectorId, onChange }) => {
|
|
6
|
+
const connectionOptions = useMemo(() => {
|
|
7
|
+
const entries = Object.values(connectors);
|
|
8
|
+
if (!entries.length) {
|
|
9
|
+
return [{ id: getCoreDuckDbConnectionId(), title: 'Core DuckDB' }];
|
|
10
|
+
}
|
|
11
|
+
return entries.map(({ id, title }) => ({
|
|
12
|
+
id,
|
|
13
|
+
title: title || id,
|
|
14
|
+
}));
|
|
15
|
+
}, [connectors]);
|
|
16
|
+
if (connectionOptions.length <= 1) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return (_jsx("div", { className: "flex-1", children: _jsxs(Select, { value: selectedConnectorId, onValueChange: onChange, children: [_jsx(SelectTrigger, { className: "h-7 text-xs", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: connectionOptions.map(({ id, title }) => (_jsx(SelectItem, { value: id, children: title }, id))) })] }) }));
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=SqlCellConnectionSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlCellConnectionSelector.js","sourceRoot":"","sources":["../../src/components/SqlCellConnectionSelector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,yBAAyB,EAAoB,MAAM,cAAc,CAAC;AAC1E,OAAO,EACL,MAAM,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACb,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAc,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AAQrC,MAAM,CAAC,MAAM,yBAAyB,GAElC,CAAC,EAAC,UAAU,EAAE,mBAAmB,EAAE,QAAQ,EAAC,EAAE,EAAE;IAClD,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,EAAE;QACrC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,OAAO,CAAC,EAAC,EAAE,EAAE,yBAAyB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAC,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAC,EAAE,EAAE,KAAK,EAAC,EAAE,EAAE,CAAC,CAAC;YACnC,EAAE;YACF,KAAK,EAAE,KAAK,IAAI,EAAE;SACnB,CAAC,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,IAAI,iBAAiB,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,cAAK,SAAS,EAAC,QAAQ,YACrB,MAAC,MAAM,IAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,QAAQ,aACzD,KAAC,aAAa,IAAC,SAAS,EAAC,aAAa,YACpC,KAAC,WAAW,KAAG,GACD,EAChB,KAAC,aAAa,cACX,iBAAiB,CAAC,GAAG,CAAC,CAAC,EAAC,EAAE,EAAE,KAAK,EAAC,EAAE,EAAE,CAAC,CACtC,KAAC,UAAU,IAAU,KAAK,EAAE,EAAE,YAC3B,KAAK,IADS,EAAE,CAEN,CACd,CAAC,GACY,IACT,GACL,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {getCoreDuckDbConnectionId, type DbConnection} from '@sqlrooms/db';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@sqlrooms/ui';\nimport React, {useMemo} from 'react';\n\nexport type SqlCellConnectionSelectorProps = {\n connectors: Record<string, DbConnection>;\n selectedConnectorId: string;\n onChange: (connectorId: string) => void;\n};\n\nexport const SqlCellConnectionSelector: React.FC<\n SqlCellConnectionSelectorProps\n> = ({connectors, selectedConnectorId, onChange}) => {\n const connectionOptions = useMemo(() => {\n const entries = Object.values(connectors);\n if (!entries.length) {\n return [{id: getCoreDuckDbConnectionId(), title: 'Core DuckDB'}];\n }\n\n return entries.map(({id, title}) => ({\n id,\n title: title || id,\n }));\n }, [connectors]);\n\n if (connectionOptions.length <= 1) {\n return null;\n }\n\n return (\n <div className=\"flex-1\">\n <Select value={selectedConnectorId} onValueChange={onChange}>\n <SelectTrigger className=\"h-7 text-xs\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {connectionOptions.map(({id, title}) => (\n <SelectItem key={id} value={id}>\n {title}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlCellContent.d.ts","sourceRoot":"","sources":["../../src/components/SqlCellContent.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SqlCellContent.d.ts","sourceRoot":"","sources":["../../src/components/SqlCellContent.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAgD,MAAM,OAAO,CAAC;AAErE,OAAO,KAAK,EACV,kBAAkB,EAElB,OAAO,EAER,MAAM,UAAU,CAAC;AAQlB,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,KAAK,CAAC,YAAY,CAAC;CACpE,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA8KxD,CAAC"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { DataTablePaginated, QueryDataTableActionsMenu, useArrowDataTable, } from '@sqlrooms/data-table';
|
|
3
2
|
import { getCoreDuckDbConnectionId } from '@sqlrooms/db';
|
|
4
3
|
import { useRoomStoreApi } from '@sqlrooms/room-store';
|
|
5
|
-
import { SqlMonacoEditor } from '@sqlrooms/sql-editor';
|
|
6
|
-
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, EditableText, Tooltip, TooltipContent, TooltipTrigger, } from '@sqlrooms/ui';
|
|
7
|
-
import { convertToValidColumnOrTableName } from '@sqlrooms/utils';
|
|
8
4
|
import { produce } from 'immer';
|
|
9
5
|
import { CornerDownRightIcon } from 'lucide-react';
|
|
10
|
-
import { useCallback, useEffect, useMemo, useRef
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
11
7
|
import { useCellsStore } from '../hooks';
|
|
12
|
-
import {
|
|
8
|
+
import { SqlCellConnectionSelector } from './SqlCellConnectionSelector';
|
|
9
|
+
import { SqlCellDependentsMenu } from './SqlCellDependentsMenu';
|
|
10
|
+
import { SqlCellEditor } from './SqlCellEditor';
|
|
11
|
+
import { SqlCellResultNameEditor } from './SqlCellResultNameEditor';
|
|
12
|
+
import { SqlCellResults } from './SqlCellResults';
|
|
13
13
|
import { SqlCellRunButton } from './SqlCellRunButton';
|
|
14
14
|
export const SqlCellContent = ({ id, cell, renderContainer, }) => {
|
|
15
15
|
const storeApi = useRoomStoreApi();
|
|
@@ -17,19 +17,21 @@ export const SqlCellContent = ({ id, cell, renderContainer, }) => {
|
|
|
17
17
|
const runCell = useCellsStore((s) => s.cells.runCell);
|
|
18
18
|
const cancelCell = useCellsStore((s) => s.cells.cancelCell);
|
|
19
19
|
const getDownstream = useCellsStore((s) => s.cells.getDownstream);
|
|
20
|
-
const
|
|
20
|
+
const artifactId = useCellsStore((s) => s.cells.getArtifactIdForCell(id));
|
|
21
21
|
const cellsData = useCellsStore((s) => s.cells.config.data);
|
|
22
|
-
const
|
|
22
|
+
const artifacts = useCellsStore((s) => s.cells.config.artifacts);
|
|
23
23
|
const cellStatus = useCellsStore((s) => s.cells.status[id]);
|
|
24
24
|
const resultVersion = useCellsStore((s) => s.cells.resultVersion?.[id] ?? 0);
|
|
25
25
|
const pageVersion = useCellsStore((s) => s.cells.pageVersion?.[id] ?? 0);
|
|
26
26
|
const getCellResult = useCellsStore((s) => s.cells.getCellResult);
|
|
27
27
|
const fetchCellResultPage = useCellsStore((s) => s.cells.fetchCellResultPage);
|
|
28
28
|
const dbConnections = useCellsStore((s) => s.db.config.connections);
|
|
29
|
+
const connector = useCellsStore((s) => s.db.connector);
|
|
30
|
+
const tableSchemas = useCellsStore((s) => s.db.tables);
|
|
29
31
|
// Re-read the cache whenever resultVersion or pageVersion changes
|
|
32
|
+
const cellResult = useMemo(() => getCellResult(id),
|
|
30
33
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
31
|
-
|
|
32
|
-
const arrowTableData = useArrowDataTable(cellResult?.arrowTable);
|
|
34
|
+
[getCellResult, id, resultVersion, pageVersion]);
|
|
33
35
|
const handleSqlChange = useCallback((v) => {
|
|
34
36
|
updateCell(id, (c) => produce(c, (draft) => {
|
|
35
37
|
if (draft.type === 'sql') {
|
|
@@ -40,6 +42,17 @@ export const SqlCellContent = ({ id, cell, renderContainer, }) => {
|
|
|
40
42
|
const handleRun = useCallback(() => {
|
|
41
43
|
runCell(id);
|
|
42
44
|
}, [id, runCell]);
|
|
45
|
+
const handleRunQuery = useCallback((query) => {
|
|
46
|
+
// Sync the actual query being executed to store before running
|
|
47
|
+
// to avoid race condition with onChange callback
|
|
48
|
+
storeApi.setState(produce(storeApi.getState(), (draft) => {
|
|
49
|
+
const c = draft.cells?.config?.data?.[id];
|
|
50
|
+
if (c && c.type === 'sql') {
|
|
51
|
+
c.data.sql = query;
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
handleRunRef.current();
|
|
55
|
+
}, [id, storeApi]);
|
|
43
56
|
const handleConnectorChange = useCallback((connectorId) => {
|
|
44
57
|
updateCell(id, (c) => produce(c, (draft) => {
|
|
45
58
|
if (draft.type === 'sql') {
|
|
@@ -50,171 +63,33 @@ export const SqlCellContent = ({ id, cell, renderContainer, }) => {
|
|
|
50
63
|
const handleCancel = useCallback(() => {
|
|
51
64
|
cancelCell(id);
|
|
52
65
|
}, [id, cancelCell]);
|
|
53
|
-
const validateResultName = useCallback((value) => {
|
|
54
|
-
const nextValue = value.trim();
|
|
55
|
-
return Boolean(nextValue) && isValidSqlIdentifier(nextValue);
|
|
56
|
-
}, []);
|
|
57
|
-
const handleResultNameInputChange = useCallback((value) => {
|
|
58
|
-
setIsResultNameInvalid(!validateResultName(value));
|
|
59
|
-
}, [validateResultName]);
|
|
60
66
|
const handleResultNameChange = useCallback((value) => {
|
|
61
|
-
const nextValue = value.trim();
|
|
62
|
-
if (!validateResultName(nextValue)) {
|
|
63
|
-
setIsResultNameInvalid(true);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
67
|
updateCell(id, (c) => produce(c, (draft) => {
|
|
67
68
|
if (draft.type === 'sql') {
|
|
68
|
-
draft.data.resultName =
|
|
69
|
+
draft.data.resultName = value;
|
|
69
70
|
}
|
|
70
71
|
}));
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const effectiveResultName = getEffectiveResultName(cell.data, convertToValidColumnOrTableName);
|
|
74
|
-
const explicitResultName = cell.data.resultName || '';
|
|
72
|
+
}, [id, updateCell]);
|
|
73
|
+
const resultName = cell.data.resultName || '';
|
|
75
74
|
const selectedConnectorId = cell.data.connectorId || getCoreDuckDbConnectionId();
|
|
76
|
-
const connectionOptions = useMemo(() => {
|
|
77
|
-
const entries = Object.values(dbConnections);
|
|
78
|
-
if (!entries.length) {
|
|
79
|
-
return [{ id: getCoreDuckDbConnectionId(), title: 'Core DuckDB' }];
|
|
80
|
-
}
|
|
81
|
-
return entries.map((conn) => ({
|
|
82
|
-
id: conn.id,
|
|
83
|
-
title: conn.title || conn.id,
|
|
84
|
-
}));
|
|
85
|
-
}, [dbConnections]);
|
|
86
|
-
const [dependentsMenuOpen, setDependentsMenuOpen] = useState(false);
|
|
87
|
-
const closeDependentsMenuTimerRef = useRef(null);
|
|
88
|
-
const [isResultNameInvalid, setIsResultNameInvalid] = useState(false);
|
|
89
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
-
const downstreamCellIds = useMemo(() => {
|
|
91
|
-
if (!currentSheetId)
|
|
92
|
-
return [];
|
|
93
|
-
return getDownstream(currentSheetId, id);
|
|
94
|
-
}, [currentSheetId, getDownstream, id, cellsData, sheets]);
|
|
95
|
-
const downstreamCells = useMemo(() => downstreamCellIds.map((cellId) => {
|
|
96
|
-
const downstreamCell = cellsData[cellId];
|
|
97
|
-
return {
|
|
98
|
-
id: cellId,
|
|
99
|
-
label: downstreamCell?.data?.title?.trim() || 'Untitled',
|
|
100
|
-
};
|
|
101
|
-
}), [cellsData, downstreamCellIds]);
|
|
102
|
-
const scrollToDependentCell = useCallback((targetCellId) => {
|
|
103
|
-
const selectorTargets = [
|
|
104
|
-
`[data-cell-container-id="${targetCellId}"]`,
|
|
105
|
-
`#cell-${targetCellId}`,
|
|
106
|
-
];
|
|
107
|
-
const el = selectorTargets
|
|
108
|
-
.map((selector) => document.querySelector(selector))
|
|
109
|
-
.find(Boolean) ?? null;
|
|
110
|
-
if (el) {
|
|
111
|
-
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
112
|
-
}
|
|
113
|
-
}, []);
|
|
114
75
|
const status = cellStatus?.type === 'sql'
|
|
115
76
|
? {
|
|
116
77
|
state: cellStatus.status,
|
|
117
78
|
message: cellStatus.lastError,
|
|
118
|
-
resultName: cellStatus.resultView ||
|
|
79
|
+
resultName: cellStatus.resultView ||
|
|
80
|
+
cellStatus.resultName,
|
|
119
81
|
lastRunTime: cellStatus.lastRunTime,
|
|
120
82
|
}
|
|
121
83
|
: undefined;
|
|
122
|
-
const resultName = status?.resultName;
|
|
123
84
|
const isRunning = status?.state === 'running';
|
|
124
|
-
// Pagination and sorting state for the result table
|
|
125
|
-
const [sorting, setSorting] = useState([]);
|
|
126
|
-
const [pagination, setPagination] = useState({
|
|
127
|
-
pageIndex: 0,
|
|
128
|
-
pageSize: 10,
|
|
129
|
-
});
|
|
130
|
-
// Fetch new page when pagination or sorting changes (not on initial render
|
|
131
|
-
// since executeSqlCell already fetches the first page)
|
|
132
|
-
const isFirstRender = useRef(true);
|
|
133
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
if (isFirstRender.current) {
|
|
136
|
-
isFirstRender.current = false;
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (resultName) {
|
|
140
|
-
fetchCellResultPage(id, pagination, sorting);
|
|
141
|
-
}
|
|
142
|
-
}, [pagination, sorting, id, fetchCellResultPage]);
|
|
143
|
-
const clearDependentsCloseTimer = useCallback(() => {
|
|
144
|
-
if (closeDependentsMenuTimerRef.current) {
|
|
145
|
-
clearTimeout(closeDependentsMenuTimerRef.current);
|
|
146
|
-
closeDependentsMenuTimerRef.current = null;
|
|
147
|
-
}
|
|
148
|
-
}, []);
|
|
149
|
-
const openDependentsMenu = useCallback(() => {
|
|
150
|
-
clearDependentsCloseTimer();
|
|
151
|
-
setDependentsMenuOpen(true);
|
|
152
|
-
}, [clearDependentsCloseTimer]);
|
|
153
|
-
const scheduleCloseDependentsMenu = useCallback(() => {
|
|
154
|
-
clearDependentsCloseTimer();
|
|
155
|
-
closeDependentsMenuTimerRef.current = setTimeout(() => {
|
|
156
|
-
setDependentsMenuOpen(false);
|
|
157
|
-
closeDependentsMenuTimerRef.current = null;
|
|
158
|
-
}, 120);
|
|
159
|
-
}, [clearDependentsCloseTimer]);
|
|
160
|
-
useEffect(() => {
|
|
161
|
-
return () => {
|
|
162
|
-
clearDependentsCloseTimer();
|
|
163
|
-
};
|
|
164
|
-
}, [clearDependentsCloseTimer]);
|
|
165
|
-
// Reset pagination when a new result arrives (new run)
|
|
166
|
-
const prevResultVersion = useRef(resultVersion);
|
|
167
|
-
useEffect(() => {
|
|
168
|
-
if (resultVersion !== prevResultVersion.current) {
|
|
169
|
-
prevResultVersion.current = resultVersion;
|
|
170
|
-
setPagination((prev) => prev.pageIndex === 0 ? prev : { ...prev, pageIndex: 0 });
|
|
171
|
-
setSorting((prev) => (prev.length === 0 ? prev : []));
|
|
172
|
-
}
|
|
173
|
-
}, [resultVersion]);
|
|
174
85
|
const handleRunRef = useRef(handleRun);
|
|
175
86
|
useEffect(() => {
|
|
176
87
|
handleRunRef.current = handleRun;
|
|
177
88
|
}, [handleRun]);
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
// to THIS specific editor instance. Monaco's addCommand registers
|
|
181
|
-
// globally, so the last editor mounted wins -- breaking multi-cell
|
|
182
|
-
// notebooks.
|
|
183
|
-
editor.onKeyDown((e) => {
|
|
184
|
-
if ((e.ctrlKey || e.metaKey) && e.keyCode === monaco.KeyCode.Enter) {
|
|
185
|
-
e.preventDefault();
|
|
186
|
-
e.stopPropagation();
|
|
187
|
-
// Flush the current editor value directly to the store
|
|
188
|
-
// synchronously before running. Monaco's onChange may not have
|
|
189
|
-
// fired yet for the latest content, so we read the editor model
|
|
190
|
-
// directly and write it to the Zustand store in a single
|
|
191
|
-
// synchronous call, bypassing the async updateCell path.
|
|
192
|
-
const currentSql = editor.getValue();
|
|
193
|
-
storeApi.setState(produce(storeApi.getState(), (draft) => {
|
|
194
|
-
const c = draft.cells?.config?.data?.[id];
|
|
195
|
-
if (c && c.type === 'sql') {
|
|
196
|
-
c.data.sql = currentSql;
|
|
197
|
-
}
|
|
198
|
-
}));
|
|
199
|
-
handleRunRef.current();
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
}, [id, storeApi]);
|
|
203
|
-
const content = (_jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "h-full w-full py-1", children: _jsx("div", { className: "relative h-full min-h-[200px] w-full", children: _jsx(SqlMonacoEditor, { className: "absolute inset-0 h-full w-full", value: cell.data.sql, onChange: handleSqlChange, onMount: handleSqlEditorMount, options: {
|
|
204
|
-
minimap: { enabled: false },
|
|
205
|
-
scrollBeyondLastLine: false,
|
|
206
|
-
scrollbar: {
|
|
207
|
-
alwaysConsumeMouseWheel: false,
|
|
208
|
-
},
|
|
209
|
-
} }) }) }), status?.state === 'error' ? (_jsx("div", { className: "relative max-h-[400px] overflow-auto p-4", children: _jsx("span", { className: "font-mono text-xs whitespace-pre-wrap text-red-600", children: status.message }) })) : resultName && arrowTableData ? (_jsxs("div", { className: "relative min-h-[200px] overflow-hidden", children: [_jsx(DataTablePaginated, { className: "absolute inset-0 h-full w-full", fontSize: "text-xs", data: arrowTableData.data, columns: arrowTableData.columns, numRows: cellResult?.totalRows, pagination: pagination, onPaginationChange: setPagination, sorting: sorting, onSortingChange: setSorting, isFetching: isRunning, footerActions: _jsx(QueryDataTableActionsMenu, { query: `SELECT * FROM ${resultName}` }) }), _jsx("div", { "aria-hidden": !isRunning, className: `bg-background/45 pointer-events-none absolute inset-0 z-10 transition-opacity duration-200 ${isRunning ? 'animate-pulse opacity-100' : 'opacity-0'}` })] })) : null] }));
|
|
210
|
-
const footer = (_jsxs("div", { className: "text-muted-foreground flex items-center gap-1 px-2 py-1 text-xs", children: [_jsx(CornerDownRightIcon, { className: "h-3 w-3" }), downstreamCells.length > 0 ? (_jsxs(DropdownMenu, { open: dependentsMenuOpen, onOpenChange: setDependentsMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { className: "h-5", size: "xs", variant: "secondary", "aria-label": `${downstreamCells.length} dependent cells`, onMouseEnter: openDependentsMenu, onMouseLeave: scheduleCloseDependentsMenu, children: downstreamCells.length }) }), _jsxs(DropdownMenuContent, { align: "start", onCloseAutoFocus: (e) => e.preventDefault(), onMouseEnter: openDependentsMenu, onMouseLeave: scheduleCloseDependentsMenu, children: [_jsx(DropdownMenuLabel, { className: "text-xs", children: "Referenced in" }), downstreamCells.map((dependentCell) => (_jsx(DropdownMenuItem, { className: "cursor-pointer text-xs", onSelect: (e) => {
|
|
211
|
-
e.preventDefault();
|
|
212
|
-
scrollToDependentCell(dependentCell.id);
|
|
213
|
-
}, children: dependentCell.label }, dependentCell.id)))] })] })) : null, _jsxs(Tooltip, { open: isResultNameInvalid, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { children: _jsx(EditableText, { className: `h-6 w-40 font-mono text-xs text-green-500 shadow-none ${isResultNameInvalid
|
|
214
|
-
? 'border-red-500 ring-1 ring-red-500 focus:border-red-500 focus:ring-red-500'
|
|
215
|
-
: ''}`, value: explicitResultName || effectiveResultName, onInputChange: handleResultNameInputChange, onChange: handleResultNameChange }) }) }), _jsx(TooltipContent, { side: "top", children: _jsx("span", { className: "text-xs", children: "Invalid result name" }) })] })] }));
|
|
89
|
+
const content = (_jsxs("div", { className: "flex flex-col", children: [_jsx(SqlCellEditor, { sql: cell.data.sql, connector: connector, tableSchemas: tableSchemas, onChange: handleSqlChange, onRunQuery: handleRunQuery }), _jsx(SqlCellResults, { cellId: id, cellResult: cellResult, resultName: resultName, isRunning: isRunning, errorMessage: status?.state === 'error' ? status.message : undefined, resultVersion: resultVersion, fetchCellResultPage: fetchCellResultPage })] }));
|
|
90
|
+
const footer = (_jsxs("div", { className: "text-muted-foreground flex items-center gap-1 px-2 py-1 text-xs", children: [_jsx(CornerDownRightIcon, { className: "h-3 w-3" }), _jsx(SqlCellDependentsMenu, { cellId: id, artifactId: artifactId, cellsData: cellsData, artifacts: artifacts, getDownstream: getDownstream }), _jsx(SqlCellResultNameEditor, { cellId: id, value: resultName, onChange: handleResultNameChange })] }));
|
|
216
91
|
return renderContainer({
|
|
217
|
-
header: (_jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(
|
|
92
|
+
header: (_jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(SqlCellConnectionSelector, { connectors: dbConnections, selectedConnectorId: selectedConnectorId, onChange: handleConnectorChange }), _jsx(SqlCellRunButton, { onRun: handleRun, onCancel: handleCancel, status: status, runLabel: "Run" })] })),
|
|
218
93
|
content,
|
|
219
94
|
footer,
|
|
220
95
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlCellContent.js","sourceRoot":"","sources":["../../src/components/SqlCellContent.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n DataTablePaginated,\n QueryDataTableActionsMenu,\n useArrowDataTable,\n} from '@sqlrooms/data-table';\nimport {getCoreDuckDbConnectionId, type DbConnection} from '@sqlrooms/db';\nimport {useRoomStoreApi} from '@sqlrooms/room-store';\nimport {SqlMonacoEditor} from '@sqlrooms/sql-editor';\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuTrigger,\n EditableText,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@sqlrooms/ui';\nimport {convertToValidColumnOrTableName} from '@sqlrooms/utils';\nimport type {PaginationState, SortingState} from '@tanstack/react-table';\nimport {type Draft, produce} from 'immer';\nimport {CornerDownRightIcon} from 'lucide-react';\nimport type * as Monaco from 'monaco-editor';\nimport React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useCellsStore} from '../hooks';\nimport type {CellContainerProps, CellsRootState, SqlCell} from '../types';\nimport {getEffectiveResultName, isValidSqlIdentifier} from '../utils';\nimport {SqlCellRunButton} from './SqlCellRunButton';\n\nexport type SqlCellContentProps = {\n id: string;\n cell: SqlCell;\n renderContainer: (props: CellContainerProps) => React.ReactElement;\n};\n\nexport const SqlCellContent: React.FC<SqlCellContentProps> = ({\n id,\n cell,\n renderContainer,\n}) => {\n const storeApi = useRoomStoreApi<CellsRootState>();\n const updateCell = useCellsStore((s) => s.cells.updateCell);\n const runCell = useCellsStore((s) => s.cells.runCell);\n const cancelCell = useCellsStore((s) => s.cells.cancelCell);\n const getDownstream = useCellsStore((s) => s.cells.getDownstream);\n const currentSheetId = useCellsStore((s) => s.cells.config.currentSheetId);\n const cellsData = useCellsStore((s) => s.cells.config.data);\n const sheets = useCellsStore((s) => s.cells.config.sheets);\n const cellStatus = useCellsStore((s) => s.cells.status[id]);\n const resultVersion = useCellsStore((s) => s.cells.resultVersion?.[id] ?? 0);\n const pageVersion = useCellsStore((s) => s.cells.pageVersion?.[id] ?? 0);\n const getCellResult = useCellsStore((s) => s.cells.getCellResult);\n const fetchCellResultPage = useCellsStore((s) => s.cells.fetchCellResultPage);\n const dbConnections = useCellsStore((s) => s.db.config.connections);\n\n // Re-read the cache whenever resultVersion or pageVersion changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const cellResult = useMemo(\n () => getCellResult(id),\n [getCellResult, id, resultVersion, pageVersion],\n );\n const arrowTableData = useArrowDataTable(cellResult?.arrowTable);\n\n const handleSqlChange = useCallback(\n (v: string | undefined) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'sql') {\n draft.data.sql = v || '';\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const handleRun = useCallback(() => {\n runCell(id);\n }, [id, runCell]);\n\n const handleConnectorChange = useCallback(\n (connectorId: string) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'sql') {\n draft.data.connectorId = connectorId || undefined;\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const handleCancel = useCallback(() => {\n cancelCell(id);\n }, [id, cancelCell]);\n\n const validateResultName = useCallback((value: string) => {\n const nextValue = value.trim();\n return Boolean(nextValue) && isValidSqlIdentifier(nextValue);\n }, []);\n\n const handleResultNameInputChange = useCallback(\n (value: string) => {\n setIsResultNameInvalid(!validateResultName(value));\n },\n [validateResultName],\n );\n\n const handleResultNameChange = useCallback(\n (value: string) => {\n const nextValue = value.trim();\n if (!validateResultName(nextValue)) {\n setIsResultNameInvalid(true);\n return;\n }\n\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'sql') {\n draft.data.resultName = nextValue;\n }\n }),\n );\n setIsResultNameInvalid(false);\n },\n [id, updateCell, validateResultName],\n );\n\n const effectiveResultName = getEffectiveResultName(\n cell.data,\n convertToValidColumnOrTableName,\n );\n const explicitResultName = cell.data.resultName || '';\n const selectedConnectorId =\n cell.data.connectorId || getCoreDuckDbConnectionId();\n const connectionOptions = useMemo(() => {\n const entries = Object.values(dbConnections);\n if (!entries.length) {\n return [{id: getCoreDuckDbConnectionId(), title: 'Core DuckDB'}];\n }\n return entries.map((conn: DbConnection) => ({\n id: conn.id,\n title: conn.title || conn.id,\n }));\n }, [dbConnections]);\n const [dependentsMenuOpen, setDependentsMenuOpen] = useState(false);\n const closeDependentsMenuTimerRef = useRef<ReturnType<\n typeof setTimeout\n > | null>(null);\n const [isResultNameInvalid, setIsResultNameInvalid] = useState(false);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const downstreamCellIds = useMemo(() => {\n if (!currentSheetId) return [];\n return getDownstream(currentSheetId, id);\n }, [currentSheetId, getDownstream, id, cellsData, sheets]);\n\n const downstreamCells = useMemo(\n () =>\n downstreamCellIds.map((cellId) => {\n const downstreamCell = cellsData[cellId];\n return {\n id: cellId,\n label: downstreamCell?.data?.title?.trim() || 'Untitled',\n };\n }),\n [cellsData, downstreamCellIds],\n );\n\n const scrollToDependentCell = useCallback((targetCellId: string) => {\n const selectorTargets = [\n `[data-cell-container-id=\"${targetCellId}\"]`,\n `#cell-${targetCellId}`,\n ];\n const el =\n selectorTargets\n .map((selector) => document.querySelector<HTMLElement>(selector))\n .find(Boolean) ?? null;\n if (el) {\n el.scrollIntoView({behavior: 'smooth', block: 'center'});\n }\n }, []);\n\n const status =\n cellStatus?.type === 'sql'\n ? {\n state: cellStatus.status,\n message: cellStatus.lastError,\n resultName: cellStatus.resultView || cellStatus.resultName,\n lastRunTime: cellStatus.lastRunTime,\n }\n : undefined;\n\n const resultName = status?.resultName;\n const isRunning = status?.state === 'running';\n\n // Pagination and sorting state for the result table\n const [sorting, setSorting] = useState<SortingState>([]);\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n });\n\n // Fetch new page when pagination or sorting changes (not on initial render\n // since executeSqlCell already fetches the first page)\n const isFirstRender = useRef(true);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n if (isFirstRender.current) {\n isFirstRender.current = false;\n return;\n }\n if (resultName) {\n fetchCellResultPage(id, pagination, sorting);\n }\n }, [pagination, sorting, id, fetchCellResultPage]);\n\n const clearDependentsCloseTimer = useCallback(() => {\n if (closeDependentsMenuTimerRef.current) {\n clearTimeout(closeDependentsMenuTimerRef.current);\n closeDependentsMenuTimerRef.current = null;\n }\n }, []);\n\n const openDependentsMenu = useCallback(() => {\n clearDependentsCloseTimer();\n setDependentsMenuOpen(true);\n }, [clearDependentsCloseTimer]);\n\n const scheduleCloseDependentsMenu = useCallback(() => {\n clearDependentsCloseTimer();\n closeDependentsMenuTimerRef.current = setTimeout(() => {\n setDependentsMenuOpen(false);\n closeDependentsMenuTimerRef.current = null;\n }, 120);\n }, [clearDependentsCloseTimer]);\n\n useEffect(() => {\n return () => {\n clearDependentsCloseTimer();\n };\n }, [clearDependentsCloseTimer]);\n\n // Reset pagination when a new result arrives (new run)\n const prevResultVersion = useRef(resultVersion);\n useEffect(() => {\n if (resultVersion !== prevResultVersion.current) {\n prevResultVersion.current = resultVersion;\n setPagination((prev) =>\n prev.pageIndex === 0 ? prev : {...prev, pageIndex: 0},\n );\n setSorting((prev) => (prev.length === 0 ? prev : []));\n }\n }, [resultVersion]);\n\n const handleRunRef = useRef(handleRun);\n useEffect(() => {\n handleRunRef.current = handleRun;\n }, [handleRun]);\n\n const handleSqlEditorMount = useCallback(\n (editor: Monaco.editor.IStandaloneCodeEditor, monaco: typeof Monaco) => {\n // Use onKeyDown instead of addCommand to scope the shortcut\n // to THIS specific editor instance. Monaco's addCommand registers\n // globally, so the last editor mounted wins -- breaking multi-cell\n // notebooks.\n editor.onKeyDown((e) => {\n if ((e.ctrlKey || e.metaKey) && e.keyCode === monaco.KeyCode.Enter) {\n e.preventDefault();\n e.stopPropagation();\n // Flush the current editor value directly to the store\n // synchronously before running. Monaco's onChange may not have\n // fired yet for the latest content, so we read the editor model\n // directly and write it to the Zustand store in a single\n // synchronous call, bypassing the async updateCell path.\n const currentSql = editor.getValue();\n storeApi.setState(\n produce(storeApi.getState(), (draft: Draft<CellsRootState>) => {\n const c = draft.cells?.config?.data?.[id];\n if (c && c.type === 'sql') {\n c.data.sql = currentSql;\n }\n }),\n );\n handleRunRef.current();\n }\n });\n },\n [id, storeApi],\n );\n\n const content = (\n <div className=\"flex flex-col\">\n <div className=\"h-full w-full py-1\">\n <div className=\"relative h-full min-h-[200px] w-full\">\n <SqlMonacoEditor\n className=\"absolute inset-0 h-full w-full\"\n value={cell.data.sql}\n onChange={handleSqlChange}\n onMount={handleSqlEditorMount}\n options={{\n minimap: {enabled: false},\n scrollBeyondLastLine: false,\n scrollbar: {\n alwaysConsumeMouseWheel: false,\n },\n }}\n />\n </div>\n </div>\n {status?.state === 'error' ? (\n <div className=\"relative max-h-[400px] overflow-auto p-4\">\n <span className=\"font-mono text-xs whitespace-pre-wrap text-red-600\">\n {status.message}\n </span>\n </div>\n ) : resultName && arrowTableData ? (\n <div className=\"relative min-h-[200px] overflow-hidden\">\n <DataTablePaginated\n className=\"absolute inset-0 h-full w-full\"\n fontSize=\"text-xs\"\n data={arrowTableData.data}\n columns={arrowTableData.columns}\n numRows={cellResult?.totalRows}\n pagination={pagination}\n onPaginationChange={setPagination}\n sorting={sorting}\n onSortingChange={setSorting}\n isFetching={isRunning}\n footerActions={\n <QueryDataTableActionsMenu\n query={`SELECT * FROM ${resultName}`}\n />\n }\n />\n <div\n aria-hidden={!isRunning}\n className={`bg-background/45 pointer-events-none absolute inset-0 z-10 transition-opacity duration-200 ${\n isRunning ? 'animate-pulse opacity-100' : 'opacity-0'\n }`}\n />\n </div>\n ) : null}\n </div>\n );\n\n const footer = (\n <div className=\"text-muted-foreground flex items-center gap-1 px-2 py-1 text-xs\">\n <CornerDownRightIcon className=\"h-3 w-3\" />\n {downstreamCells.length > 0 ? (\n <DropdownMenu\n open={dependentsMenuOpen}\n onOpenChange={setDependentsMenuOpen}\n >\n <DropdownMenuTrigger asChild>\n <Button\n className=\"h-5\"\n size=\"xs\"\n variant=\"secondary\"\n aria-label={`${downstreamCells.length} dependent cells`}\n onMouseEnter={openDependentsMenu}\n onMouseLeave={scheduleCloseDependentsMenu}\n >\n {downstreamCells.length}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align=\"start\"\n onCloseAutoFocus={(e) => e.preventDefault()}\n onMouseEnter={openDependentsMenu}\n onMouseLeave={scheduleCloseDependentsMenu}\n >\n <DropdownMenuLabel className=\"text-xs\">\n Referenced in\n </DropdownMenuLabel>\n {downstreamCells.map((dependentCell) => (\n <DropdownMenuItem\n key={dependentCell.id}\n className=\"cursor-pointer text-xs\"\n onSelect={(e) => {\n e.preventDefault();\n scrollToDependentCell(dependentCell.id);\n }}\n >\n {dependentCell.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n <Tooltip open={isResultNameInvalid}>\n <TooltipTrigger asChild>\n <div>\n <EditableText\n className={`h-6 w-40 font-mono text-xs text-green-500 shadow-none ${\n isResultNameInvalid\n ? 'border-red-500 ring-1 ring-red-500 focus:border-red-500 focus:ring-red-500'\n : ''\n }`}\n value={explicitResultName || effectiveResultName}\n onInputChange={handleResultNameInputChange}\n onChange={handleResultNameChange}\n />\n </div>\n </TooltipTrigger>\n <TooltipContent side=\"top\">\n <span className=\"text-xs\">Invalid result name</span>\n </TooltipContent>\n </Tooltip>\n </div>\n );\n\n return renderContainer({\n header: (\n <div className=\"flex w-full items-center gap-2\">\n <div className=\"flex-1\">\n <select\n className=\"border-input bg-background text-foreground h-7 rounded border px-2 text-xs\"\n value={selectedConnectorId}\n onChange={(e) => handleConnectorChange(e.target.value)}\n >\n {connectionOptions.map((connection) => (\n <option key={connection.id} value={connection.id}>\n {connection.title}\n </option>\n ))}\n </select>\n </div>\n <SqlCellRunButton\n onRun={handleRun}\n onCancel={handleCancel}\n status={status}\n runLabel=\"Run\"\n />\n </div>\n ),\n content,\n footer,\n });\n};\n"]}
|
|
1
|
+
{"version":3,"file":"SqlCellContent.js","sourceRoot":"","sources":["../../src/components/SqlCellContent.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,yBAAyB,EAAC,MAAM,cAAc,CAAC;AACvD,OAAO,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAa,OAAO,EAAC,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAC,mBAAmB,EAAC,MAAM,cAAc,CAAC;AACjD,OAAc,EAAC,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;AACrE,OAAO,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AAOvC,OAAO,EAAC,yBAAyB,EAAC,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,uBAAuB,EAAC,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAQpD,MAAM,CAAC,MAAM,cAAc,GAAkC,CAAC,EAC5D,EAAE,EACF,IAAI,EACJ,eAAe,GAChB,EAAE,EAAE;IACH,MAAM,QAAQ,GAAG,eAAe,EAAkB,CAAC;IACnD,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7E,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClE,MAAM,mBAAmB,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC9E,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAEvD,kEAAkE;IAClE,MAAM,UAAU,GAAG,OAAO,CACxB,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC;IACvB,uDAAuD;IACvD,CAAC,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,WAAW,CAAC,CAChD,CAAC;IAEF,MAAM,eAAe,GAAG,WAAW,CACjC,CAAC,CAAqB,EAAE,EAAE;QACxB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,EACD,CAAC,EAAE,EAAE,UAAU,CAAC,CACjB,CAAC;IAEF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;QACjC,OAAO,CAAC,EAAE,CAAC,CAAC;IACd,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAElB,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,KAAa,EAAE,EAAE;QAChB,+DAA+D;QAC/D,iDAAiD;QACjD,QAAQ,CAAC,QAAQ,CACf,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,KAA4B,EAAE,EAAE;YAC5D,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBAC1B,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;YACrB,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QACF,YAAY,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC,EACD,CAAC,EAAE,EAAE,QAAQ,CAAC,CACf,CAAC;IAEF,MAAM,qBAAqB,GAAG,WAAW,CACvC,CAAC,WAAmB,EAAE,EAAE;QACtB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,SAAS,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,EACD,CAAC,EAAE,EAAE,UAAU,CAAC,CACjB,CAAC;IAEF,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QACpC,UAAU,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;IAErB,MAAM,sBAAsB,GAAG,WAAW,CACxC,CAAC,KAAa,EAAE,EAAE;QAChB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;YAChC,CAAC;QACH,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,EACD,CAAC,EAAE,EAAE,UAAU,CAAC,CACjB,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IAC9C,MAAM,mBAAmB,GACvB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,yBAAyB,EAAE,CAAC;IAEvD,MAAM,MAAM,GACV,UAAU,EAAE,IAAI,KAAK,KAAK;QACxB,CAAC,CAAC;YACE,KAAK,EAAG,UAA4B,CAAC,MAAM;YAC3C,OAAO,EAAG,UAA4B,CAAC,SAAS;YAChD,UAAU,EACP,UAA4B,CAAC,UAAU;gBACvC,UAA4B,CAAC,UAAU;YAC1C,WAAW,EAAG,UAA4B,CAAC,WAAW;SACvD;QACH,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,SAAS,GAAG,MAAM,EAAE,KAAK,KAAK,SAAS,CAAC;IAE9C,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IACvC,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC;IACnC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,MAAM,OAAO,GAAG,CACd,eAAK,SAAS,EAAC,eAAe,aAC5B,KAAC,aAAa,IACZ,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAClB,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,cAAc,GAC1B,EACF,KAAC,cAAc,IACb,MAAM,EAAE,EAAE,EACV,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,MAAM,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EACpE,aAAa,EAAE,aAAa,EAC5B,mBAAmB,EAAE,mBAAmB,GACxC,IACE,CACP,CAAC;IAEF,MAAM,MAAM,GAAG,CACb,eAAK,SAAS,EAAC,iEAAiE,aAC9E,KAAC,mBAAmB,IAAC,SAAS,EAAC,SAAS,GAAG,EAC3C,KAAC,qBAAqB,IACpB,MAAM,EAAE,EAAE,EACV,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,aAAa,GAC5B,EACF,KAAC,uBAAuB,IACtB,MAAM,EAAE,EAAE,EACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,sBAAsB,GAChC,IACE,CACP,CAAC;IAEF,OAAO,eAAe,CAAC;QACrB,MAAM,EAAE,CACN,eAAK,SAAS,EAAC,gCAAgC,aAC7C,KAAC,yBAAyB,IACxB,UAAU,EAAE,aAAa,EACzB,mBAAmB,EAAE,mBAAmB,EACxC,QAAQ,EAAE,qBAAqB,GAC/B,EACF,KAAC,gBAAgB,IACf,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAC,KAAK,GACd,IACE,CACP;QACD,OAAO;QACP,MAAM;KACP,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import {getCoreDuckDbConnectionId} from '@sqlrooms/db';\nimport {useRoomStoreApi} from '@sqlrooms/room-store';\nimport {type Draft, produce} from 'immer';\nimport {CornerDownRightIcon} from 'lucide-react';\nimport React, {useCallback, useEffect, useMemo, useRef} from 'react';\nimport {useCellsStore} from '../hooks';\nimport type {\n CellContainerProps,\n CellsRootState,\n SqlCell,\n SqlCellStatus,\n} from '../types';\nimport {SqlCellConnectionSelector} from './SqlCellConnectionSelector';\nimport {SqlCellDependentsMenu} from './SqlCellDependentsMenu';\nimport {SqlCellEditor} from './SqlCellEditor';\nimport {SqlCellResultNameEditor} from './SqlCellResultNameEditor';\nimport {SqlCellResults} from './SqlCellResults';\nimport {SqlCellRunButton} from './SqlCellRunButton';\n\nexport type SqlCellContentProps = {\n id: string;\n cell: SqlCell;\n renderContainer: (props: CellContainerProps) => React.ReactElement;\n};\n\nexport const SqlCellContent: React.FC<SqlCellContentProps> = ({\n id,\n cell,\n renderContainer,\n}) => {\n const storeApi = useRoomStoreApi<CellsRootState>();\n const updateCell = useCellsStore((s) => s.cells.updateCell);\n const runCell = useCellsStore((s) => s.cells.runCell);\n const cancelCell = useCellsStore((s) => s.cells.cancelCell);\n const getDownstream = useCellsStore((s) => s.cells.getDownstream);\n const artifactId = useCellsStore((s) => s.cells.getArtifactIdForCell(id));\n const cellsData = useCellsStore((s) => s.cells.config.data);\n const artifacts = useCellsStore((s) => s.cells.config.artifacts);\n const cellStatus = useCellsStore((s) => s.cells.status[id]);\n const resultVersion = useCellsStore((s) => s.cells.resultVersion?.[id] ?? 0);\n const pageVersion = useCellsStore((s) => s.cells.pageVersion?.[id] ?? 0);\n const getCellResult = useCellsStore((s) => s.cells.getCellResult);\n const fetchCellResultPage = useCellsStore((s) => s.cells.fetchCellResultPage);\n const dbConnections = useCellsStore((s) => s.db.config.connections);\n const connector = useCellsStore((s) => s.db.connector);\n const tableSchemas = useCellsStore((s) => s.db.tables);\n\n // Re-read the cache whenever resultVersion or pageVersion changes\n const cellResult = useMemo(\n () => getCellResult(id),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [getCellResult, id, resultVersion, pageVersion],\n );\n\n const handleSqlChange = useCallback(\n (v: string | undefined) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'sql') {\n draft.data.sql = v || '';\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const handleRun = useCallback(() => {\n runCell(id);\n }, [id, runCell]);\n\n const handleRunQuery = useCallback(\n (query: string) => {\n // Sync the actual query being executed to store before running\n // to avoid race condition with onChange callback\n storeApi.setState(\n produce(storeApi.getState(), (draft: Draft<CellsRootState>) => {\n const c = draft.cells?.config?.data?.[id];\n if (c && c.type === 'sql') {\n c.data.sql = query;\n }\n }),\n );\n handleRunRef.current();\n },\n [id, storeApi],\n );\n\n const handleConnectorChange = useCallback(\n (connectorId: string) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'sql') {\n draft.data.connectorId = connectorId || undefined;\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const handleCancel = useCallback(() => {\n cancelCell(id);\n }, [id, cancelCell]);\n\n const handleResultNameChange = useCallback(\n (value: string) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'sql') {\n draft.data.resultName = value;\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const resultName = cell.data.resultName || '';\n const selectedConnectorId =\n cell.data.connectorId || getCoreDuckDbConnectionId();\n\n const status =\n cellStatus?.type === 'sql'\n ? {\n state: (cellStatus as SqlCellStatus).status,\n message: (cellStatus as SqlCellStatus).lastError,\n resultName:\n (cellStatus as SqlCellStatus).resultView ||\n (cellStatus as SqlCellStatus).resultName,\n lastRunTime: (cellStatus as SqlCellStatus).lastRunTime,\n }\n : undefined;\n\n const isRunning = status?.state === 'running';\n\n const handleRunRef = useRef(handleRun);\n useEffect(() => {\n handleRunRef.current = handleRun;\n }, [handleRun]);\n\n const content = (\n <div className=\"flex flex-col\">\n <SqlCellEditor\n sql={cell.data.sql}\n connector={connector}\n tableSchemas={tableSchemas}\n onChange={handleSqlChange}\n onRunQuery={handleRunQuery}\n />\n <SqlCellResults\n cellId={id}\n cellResult={cellResult}\n resultName={resultName}\n isRunning={isRunning}\n errorMessage={status?.state === 'error' ? status.message : undefined}\n resultVersion={resultVersion}\n fetchCellResultPage={fetchCellResultPage}\n />\n </div>\n );\n\n const footer = (\n <div className=\"text-muted-foreground flex items-center gap-1 px-2 py-1 text-xs\">\n <CornerDownRightIcon className=\"h-3 w-3\" />\n <SqlCellDependentsMenu\n cellId={id}\n artifactId={artifactId}\n cellsData={cellsData}\n artifacts={artifacts}\n getDownstream={getDownstream}\n />\n <SqlCellResultNameEditor\n cellId={id}\n value={resultName}\n onChange={handleResultNameChange}\n />\n </div>\n );\n\n return renderContainer({\n header: (\n <div className=\"flex w-full items-center gap-2\">\n <SqlCellConnectionSelector\n connectors={dbConnections}\n selectedConnectorId={selectedConnectorId}\n onChange={handleConnectorChange}\n />\n <SqlCellRunButton\n onRun={handleRun}\n onCancel={handleCancel}\n status={status}\n runLabel=\"Run\"\n />\n </div>\n ),\n content,\n footer,\n });\n};\n"]}
|