@sqlrooms/cells 0.29.0-rc.1 → 0.29.0-rc.2
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/dist/cellsSlice.d.ts.map +1 -1
- package/dist/cellsSlice.js +191 -73
- 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 +11 -0
- package/dist/components/CellSourceSelector.d.ts.map +1 -0
- package/dist/components/CellSourceSelector.js +35 -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/SheetsTabBar.d.ts.map +1 -1
- package/dist/components/SheetsTabBar.js +2 -1
- package/dist/components/SheetsTabBar.js.map +1 -1
- package/dist/components/SqlCellBody.d.ts +6 -0
- package/dist/components/SqlCellBody.d.ts.map +1 -0
- package/dist/components/SqlCellBody.js +12 -0
- package/dist/components/SqlCellBody.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 +29 -154
- 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 +31 -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/crdt.d.ts +61 -0
- package/dist/crdt.d.ts.map +1 -0
- package/dist/crdt.js +82 -0
- package/dist/crdt.js.map +1 -0
- package/dist/dagSlice.d.ts +3 -0
- package/dist/dagSlice.d.ts.map +1 -0
- package/dist/dagSlice.js +51 -0
- package/dist/dagSlice.js.map +1 -0
- package/dist/dagUtils.d.ts +2 -1
- package/dist/dagUtils.d.ts.map +1 -1
- package/dist/dagUtils.js +35 -11
- package/dist/dagUtils.js.map +1 -1
- package/dist/defaultCellRegistry.d.ts.map +1 -1
- package/dist/defaultCellRegistry.js +63 -24
- package/dist/defaultCellRegistry.js.map +1 -1
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +2 -1
- package/dist/execution.js.map +1 -1
- package/dist/helpers.d.ts +14 -2
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +56 -2
- 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 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/sqlHelpers.d.ts +3 -3
- package/dist/sqlHelpers.d.ts.map +1 -1
- package/dist/sqlHelpers.js +9 -5
- package/dist/sqlHelpers.js.map +1 -1
- package/dist/typeGuards.d.ts +2 -0
- package/dist/typeGuards.d.ts.map +1 -0
- package/dist/typeGuards.js +4 -0
- package/dist/typeGuards.js.map +1 -0
- package/dist/types.d.ts +97 -26
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -2
- 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 +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +16 -0
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +16 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +40 -0
- package/dist/validation.js.map +1 -0
- 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
|
@@ -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":"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","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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SheetsTabBar.d.ts","sourceRoot":"","sources":["../../src/components/SheetsTabBar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SheetsTabBar.d.ts","sourceRoot":"","sources":["../../src/components/SheetsTabBar.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAK5D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AASF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmIpD,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, TabStrip, } from '@sqlrooms/ui';
|
|
3
|
-
import { AppWindow, FileText, LayoutDashboard, PencilIcon, PlusIcon, TrashIcon, } from 'lucide-react';
|
|
3
|
+
import { AppWindow, BarChart3, FileText, LayoutDashboard, PencilIcon, PlusIcon, TrashIcon, } from 'lucide-react';
|
|
4
4
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
5
5
|
import { useCellsStore } from '../hooks';
|
|
6
6
|
import { DeleteSheetModal } from './DeleteSheetModal';
|
|
@@ -8,6 +8,7 @@ const TYPE_ICONS = {
|
|
|
8
8
|
notebook: FileText,
|
|
9
9
|
canvas: LayoutDashboard,
|
|
10
10
|
app: AppWindow,
|
|
11
|
+
dashboard: BarChart3,
|
|
11
12
|
};
|
|
12
13
|
export const SheetsTabBar = ({ className }) => {
|
|
13
14
|
const sheetOrder = useCellsStore((s) => s.cells.config.sheetOrder);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SheetsTabBar.js","sourceRoot":"","sources":["../../src/components/SheetsTabBar.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n TabStrip,\n TabDescriptor,\n} from '@sqlrooms/ui';\nimport {\n AppWindow,\n FileText,\n LayoutDashboard,\n PencilIcon,\n PlusIcon,\n TrashIcon,\n} from 'lucide-react';\nimport React, {useCallback, useMemo, useState} from 'react';\nimport {useCellsStore} from '../hooks';\nimport {SheetType} from '../types';\nimport {DeleteSheetModal} from './DeleteSheetModal';\n\nexport type SheetsTabBarProps = {\n className?: string;\n};\n\nconst TYPE_ICONS: Record<SheetType, React.ElementType> = {\n notebook: FileText,\n canvas: LayoutDashboard,\n app: AppWindow,\n};\n\nexport const SheetsTabBar: React.FC<SheetsTabBarProps> = ({className}) => {\n const sheetOrder = useCellsStore((s) => s.cells.config.sheetOrder);\n const sheets = useCellsStore((s) => s.cells.config.sheets);\n const currentSheetId = useCellsStore((s) => s.cells.config.currentSheetId);\n const supportedTypes = useCellsStore((s) => s.cells.supportedSheetTypes);\n const addSheet = useCellsStore((s) => s.cells.addSheet);\n const removeSheet = useCellsStore((s) => s.cells.removeSheet);\n const closeSheet = useCellsStore((s) => s.cells.closeSheet);\n const openSheet = useCellsStore((s) => s.cells.openSheet);\n const setSheetOrder = useCellsStore((s) => s.cells.setSheetOrder);\n const renameSheet = useCellsStore((s) => s.cells.renameSheet);\n const setCurrentSheet = useCellsStore((s) => s.cells.setCurrentSheet);\n\n const [sheetToDelete, setSheetToDelete] = useState<string | null>(null);\n\n const handleDeleteRequest = useCallback(\n (sheetId: string) => {\n const sheet = sheets[sheetId];\n if (sheet && sheet.cellIds.length === 0) {\n removeSheet(sheetId);\n } else {\n setSheetToDelete(sheetId);\n }\n },\n [sheets, removeSheet],\n );\n\n const handleConfirmDelete = useCallback(() => {\n if (sheetToDelete) {\n removeSheet(sheetToDelete);\n setSheetToDelete(null);\n }\n }, [sheetToDelete, removeSheet]);\n\n const tabs = useMemo(\n () =>\n Object.values(sheets).map((sheet) => ({\n id: sheet.id,\n name: sheet.title || 'Untitled',\n type: sheet.type || 'notebook',\n })),\n [sheets],\n );\n\n return (\n <TabStrip\n className={className}\n tabs={tabs}\n openTabs={sheetOrder}\n selectedTabId={currentSheetId}\n onSelect={setCurrentSheet}\n onRename={renameSheet}\n onClose={closeSheet}\n onOpenTabsChange={setSheetOrder}\n renderTabTitle={(tab: TabDescriptor) => {\n const Icon = TYPE_ICONS[tab.type as SheetType] || FileText;\n return (\n <div className=\"flex min-w-0 items-center gap-2\">\n <Icon className=\"text-muted-foreground h-3.5 w-3.5 shrink-0\" />\n <div className=\"truncate text-sm\">{tab.name}</div>\n </div>\n );\n }}\n renderTabMenu={(tab) => (\n <>\n <TabStrip.MenuItem onClick={() => renameSheet(tab.id, tab.name)}>\n <PencilIcon className=\"mr-2 h-4 w-4\" />\n Rename\n </TabStrip.MenuItem>\n <TabStrip.MenuSeparator />\n <TabStrip.MenuItem\n variant=\"destructive\"\n onClick={() => handleDeleteRequest(tab.id)}\n >\n <TrashIcon className=\"mr-2 h-4 w-4\" />\n Delete\n </TabStrip.MenuItem>\n </>\n )}\n renderSearchItemActions={(tab) => (\n <>\n <TabStrip.SearchItemAction\n icon={<PencilIcon className=\"h-3 w-3\" />}\n aria-label={`Rename ${tab.name}`}\n onClick={() => renameSheet(tab.id, tab.name)}\n />\n <TabStrip.SearchItemAction\n icon={<TrashIcon className=\"h-3 w-3\" />}\n aria-label={`Delete ${tab.name}`}\n onClick={() => handleDeleteRequest(tab.id)}\n />\n </>\n )}\n >\n <TabStrip.SearchDropdown />\n <TabStrip.Tabs tabClassName=\"pl-2\" />\n\n {supportedTypes.length === 1 ? (\n <AddNewSheetButton\n onClick={() => addSheet(undefined, supportedTypes[0])}\n />\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <AddNewSheetButton />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {supportedTypes.map((type) => {\n const Icon = TYPE_ICONS[type];\n return (\n <DropdownMenuItem\n key={type}\n onClick={() => addSheet(undefined, type)}\n className=\"capitalize\"\n >\n <Icon className=\"mr-2 h-4 w-4\" />\n New {type}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n <DeleteSheetModal\n isOpen={sheetToDelete !== null}\n onClose={() => setSheetToDelete(null)}\n onConfirm={handleConfirmDelete}\n sheetTitle={sheetToDelete ? sheets[sheetToDelete]?.title : undefined}\n />\n </TabStrip>\n );\n};\n\nconst AddNewSheetButton = React.forwardRef<\n HTMLButtonElement,\n React.ComponentPropsWithoutRef<typeof Button>\n>(({className, ...props}, ref) => {\n return (\n <Button\n ref={ref}\n size=\"icon\"\n variant=\"ghost\"\n className={`hover:bg-primary/10 h-full w-8 rounded-none ${className ?? ''}`}\n {...props}\n >\n <PlusIcon className=\"h-4 w-4\" />\n </Button>\n );\n});\nAddNewSheetButton.displayName = 'AddNewSheetButton';\n"]}
|
|
1
|
+
{"version":3,"file":"SheetsTabBar.js","sourceRoot":"","sources":["../../src/components/SheetsTabBar.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n TabStrip,\n TabDescriptor,\n} from '@sqlrooms/ui';\nimport {\n AppWindow,\n BarChart3,\n FileText,\n LayoutDashboard,\n PencilIcon,\n PlusIcon,\n TrashIcon,\n} from 'lucide-react';\nimport React, {useCallback, useMemo, useState} from 'react';\nimport {useCellsStore} from '../hooks';\nimport {SheetType} from '../types';\nimport {DeleteSheetModal} from './DeleteSheetModal';\n\nexport type SheetsTabBarProps = {\n className?: string;\n};\n\nconst TYPE_ICONS: Record<SheetType, React.ElementType> = {\n notebook: FileText,\n canvas: LayoutDashboard,\n app: AppWindow,\n dashboard: BarChart3,\n};\n\nexport const SheetsTabBar: React.FC<SheetsTabBarProps> = ({className}) => {\n const sheetOrder = useCellsStore((s) => s.cells.config.sheetOrder);\n const sheets = useCellsStore((s) => s.cells.config.sheets);\n const currentSheetId = useCellsStore((s) => s.cells.config.currentSheetId);\n const supportedTypes = useCellsStore((s) => s.cells.supportedSheetTypes);\n const addSheet = useCellsStore((s) => s.cells.addSheet);\n const removeSheet = useCellsStore((s) => s.cells.removeSheet);\n const closeSheet = useCellsStore((s) => s.cells.closeSheet);\n const openSheet = useCellsStore((s) => s.cells.openSheet);\n const setSheetOrder = useCellsStore((s) => s.cells.setSheetOrder);\n const renameSheet = useCellsStore((s) => s.cells.renameSheet);\n const setCurrentSheet = useCellsStore((s) => s.cells.setCurrentSheet);\n\n const [sheetToDelete, setSheetToDelete] = useState<string | null>(null);\n\n const handleDeleteRequest = useCallback(\n (sheetId: string) => {\n const sheet = sheets[sheetId];\n if (sheet && sheet.cellIds.length === 0) {\n removeSheet(sheetId);\n } else {\n setSheetToDelete(sheetId);\n }\n },\n [sheets, removeSheet],\n );\n\n const handleConfirmDelete = useCallback(() => {\n if (sheetToDelete) {\n removeSheet(sheetToDelete);\n setSheetToDelete(null);\n }\n }, [sheetToDelete, removeSheet]);\n\n const tabs = useMemo(\n () =>\n Object.values(sheets).map((sheet) => ({\n id: sheet.id,\n name: sheet.title || 'Untitled',\n type: sheet.type || 'notebook',\n })),\n [sheets],\n );\n\n return (\n <TabStrip\n className={className}\n tabs={tabs}\n openTabs={sheetOrder}\n selectedTabId={currentSheetId}\n onSelect={setCurrentSheet}\n onRename={renameSheet}\n onClose={closeSheet}\n onOpenTabsChange={setSheetOrder}\n renderTabTitle={(tab: TabDescriptor) => {\n const Icon = TYPE_ICONS[tab.type as SheetType] || FileText;\n return (\n <div className=\"flex min-w-0 items-center gap-2\">\n <Icon className=\"text-muted-foreground h-3.5 w-3.5 shrink-0\" />\n <div className=\"truncate text-sm\">{tab.name}</div>\n </div>\n );\n }}\n renderTabMenu={(tab) => (\n <>\n <TabStrip.MenuItem onClick={() => renameSheet(tab.id, tab.name)}>\n <PencilIcon className=\"mr-2 h-4 w-4\" />\n Rename\n </TabStrip.MenuItem>\n <TabStrip.MenuSeparator />\n <TabStrip.MenuItem\n variant=\"destructive\"\n onClick={() => handleDeleteRequest(tab.id)}\n >\n <TrashIcon className=\"mr-2 h-4 w-4\" />\n Delete\n </TabStrip.MenuItem>\n </>\n )}\n renderSearchItemActions={(tab) => (\n <>\n <TabStrip.SearchItemAction\n icon={<PencilIcon className=\"h-3 w-3\" />}\n aria-label={`Rename ${tab.name}`}\n onClick={() => renameSheet(tab.id, tab.name)}\n />\n <TabStrip.SearchItemAction\n icon={<TrashIcon className=\"h-3 w-3\" />}\n aria-label={`Delete ${tab.name}`}\n onClick={() => handleDeleteRequest(tab.id)}\n />\n </>\n )}\n >\n <TabStrip.SearchDropdown />\n <TabStrip.Tabs tabClassName=\"pl-2\" />\n\n {supportedTypes.length === 1 ? (\n <AddNewSheetButton\n onClick={() => addSheet(undefined, supportedTypes[0])}\n />\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <AddNewSheetButton />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {supportedTypes.map((type) => {\n const Icon = TYPE_ICONS[type];\n return (\n <DropdownMenuItem\n key={type}\n onClick={() => addSheet(undefined, type)}\n className=\"capitalize\"\n >\n <Icon className=\"mr-2 h-4 w-4\" />\n New {type}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n <DeleteSheetModal\n isOpen={sheetToDelete !== null}\n onClose={() => setSheetToDelete(null)}\n onConfirm={handleConfirmDelete}\n sheetTitle={sheetToDelete ? sheets[sheetToDelete]?.title : undefined}\n />\n </TabStrip>\n );\n};\n\nconst AddNewSheetButton = React.forwardRef<\n HTMLButtonElement,\n React.ComponentPropsWithoutRef<typeof Button>\n>(({className, ...props}, ref) => {\n return (\n <Button\n ref={ref}\n size=\"icon\"\n variant=\"ghost\"\n className={`hover:bg-primary/10 h-full w-8 rounded-none ${className ?? ''}`}\n {...props}\n >\n <PlusIcon className=\"h-4 w-4\" />\n </Button>\n );\n});\nAddNewSheetButton.displayName = 'AddNewSheetButton';\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SqlCellBodyProps } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Editable SQL cell body with controls and optional result rendering.
|
|
4
|
+
*/
|
|
5
|
+
export declare function SqlCellBody({ sql, onSqlChange, onRun, onCancel, status, resultName, renderResult, runLabel, disabled, }: SqlCellBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
//# sourceMappingURL=SqlCellBody.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlCellBody.d.ts","sourceRoot":"","sources":["../../src/components/SqlCellBody.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,UAAU,CAAC;AAG/C;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,WAAW,EACX,KAAK,EACL,QAAQ,EACR,MAAM,EACN,UAAU,EACV,YAAY,EACZ,QAAgB,EAChB,QAAQ,GACT,EAAE,gBAAgB,2CAmClB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { QueryDataTable } from '@sqlrooms/data-table';
|
|
3
|
+
import { SqlMonacoEditor } from '@sqlrooms/sql-editor';
|
|
4
|
+
import { SqlCellRunButton } from './SqlCellRunButton';
|
|
5
|
+
/**
|
|
6
|
+
* Editable SQL cell body with controls and optional result rendering.
|
|
7
|
+
*/
|
|
8
|
+
export function SqlCellBody({ sql, onSqlChange, onRun, onCancel, status, resultName, renderResult, runLabel = 'Run', disabled, }) {
|
|
9
|
+
const showResultTable = !renderResult && resultName && status?.state === 'success';
|
|
10
|
+
return (_jsxs("div", { className: "flex w-full flex-col gap-2", children: [_jsx("div", { className: "p-2", children: _jsx(SqlCellRunButton, { onRun: onRun, onCancel: onCancel, status: status, runLabel: runLabel, disabled: disabled }) }), _jsxs("div", { className: "relative flex min-h-[200px] flex-col", children: [_jsx("div", { children: _jsx(SqlMonacoEditor, { className: "absolute inset-0 h-full w-full", value: sql, onChange: (v) => onSqlChange(v || ''), options: { minimap: { enabled: false } } }) }), renderResult, showResultTable && (_jsx("div", { className: "overflow-hidden border-t", children: _jsx(QueryDataTable, { query: `SELECT * FROM ${resultName}`, fontSize: "text-xs" }) }))] })] }));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=SqlCellBody.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlCellBody.js","sourceRoot":"","sources":["../../src/components/SqlCellBody.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAEpD;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,GAAG,EACH,WAAW,EACX,KAAK,EACL,QAAQ,EACR,MAAM,EACN,UAAU,EACV,YAAY,EACZ,QAAQ,GAAG,KAAK,EAChB,QAAQ,GACS;IACjB,MAAM,eAAe,GACnB,CAAC,YAAY,IAAI,UAAU,IAAI,MAAM,EAAE,KAAK,KAAK,SAAS,CAAC;IAC7D,OAAO,CACL,eAAK,SAAS,EAAC,4BAA4B,aACzC,cAAK,SAAS,EAAC,KAAK,YAClB,KAAC,gBAAgB,IACf,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,GAClB,GACE,EACN,eAAK,SAAS,EAAC,sCAAsC,aACnD,wBACE,KAAC,eAAe,IACd,SAAS,EAAC,gCAAgC,EAC1C,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,EACrC,OAAO,EAAE,EAAC,OAAO,EAAE,EAAC,OAAO,EAAE,KAAK,EAAC,EAAC,GACpC,GACE,EACL,YAAY,EACZ,eAAe,IAAI,CAClB,cAAK,SAAS,EAAC,0BAA0B,YACvC,KAAC,cAAc,IACb,KAAK,EAAE,iBAAiB,UAAU,EAAE,EACpC,QAAQ,EAAC,SAAS,GAClB,GACE,CACP,IACG,IACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["import {QueryDataTable} from '@sqlrooms/data-table';\nimport {SqlMonacoEditor} from '@sqlrooms/sql-editor';\nimport type {SqlCellBodyProps} from '../types';\nimport {SqlCellRunButton} from './SqlCellRunButton';\n\n/**\n * Editable SQL cell body with controls and optional result rendering.\n */\nexport function SqlCellBody({\n sql,\n onSqlChange,\n onRun,\n onCancel,\n status,\n resultName,\n renderResult,\n runLabel = 'Run',\n disabled,\n}: SqlCellBodyProps) {\n const showResultTable =\n !renderResult && resultName && status?.state === 'success';\n return (\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"p-2\">\n <SqlCellRunButton\n onRun={onRun}\n onCancel={onCancel}\n status={status}\n runLabel={runLabel}\n disabled={disabled}\n />\n </div>\n <div className=\"relative flex min-h-[200px] flex-col\">\n <div>\n <SqlMonacoEditor\n className=\"absolute inset-0 h-full w-full\"\n value={sql}\n onChange={(v) => onSqlChange(v || '')}\n options={{minimap: {enabled: false}}}\n />\n </div>\n {renderResult}\n {showResultTable && (\n <div className=\"overflow-hidden border-t\">\n <QueryDataTable\n query={`SELECT * FROM ${resultName}`}\n fontSize=\"text-xs\"\n />\n </div>\n )}\n </div>\n </div>\n );\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();
|
|
@@ -26,10 +26,12 @@ export const SqlCellContent = ({ id, cell, renderContainer, }) => {
|
|
|
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, currentSheetId: currentSheetId, cellsData: cellsData, sheets: sheets, 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
|
});
|