@sqlrooms/cells 0.29.0-rc.1

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.
Files changed (99) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +32 -0
  3. package/dist/cellsSlice.d.ts +3 -0
  4. package/dist/cellsSlice.d.ts.map +1 -0
  5. package/dist/cellsSlice.js +602 -0
  6. package/dist/cellsSlice.js.map +1 -0
  7. package/dist/components/DeleteSheetModal.d.ts +9 -0
  8. package/dist/components/DeleteSheetModal.d.ts.map +1 -0
  9. package/dist/components/DeleteSheetModal.js +6 -0
  10. package/dist/components/DeleteSheetModal.js.map +1 -0
  11. package/dist/components/Input/ConfigPanel/DropdownConfig.d.ts +2 -0
  12. package/dist/components/Input/ConfigPanel/DropdownConfig.d.ts.map +1 -0
  13. package/dist/components/Input/ConfigPanel/DropdownConfig.js +44 -0
  14. package/dist/components/Input/ConfigPanel/DropdownConfig.js.map +1 -0
  15. package/dist/components/Input/ConfigPanel/InputConfigPanel.d.ts +11 -0
  16. package/dist/components/Input/ConfigPanel/InputConfigPanel.d.ts.map +1 -0
  17. package/dist/components/Input/ConfigPanel/InputConfigPanel.js +65 -0
  18. package/dist/components/Input/ConfigPanel/InputConfigPanel.js.map +1 -0
  19. package/dist/components/Input/ConfigPanel/SliderConfig.d.ts +2 -0
  20. package/dist/components/Input/ConfigPanel/SliderConfig.d.ts.map +1 -0
  21. package/dist/components/Input/ConfigPanel/SliderConfig.js +19 -0
  22. package/dist/components/Input/ConfigPanel/SliderConfig.js.map +1 -0
  23. package/dist/components/Input/ConfigPanel/TextConfig.d.ts +2 -0
  24. package/dist/components/Input/ConfigPanel/TextConfig.d.ts.map +1 -0
  25. package/dist/components/Input/ConfigPanel/TextConfig.js +8 -0
  26. package/dist/components/Input/ConfigPanel/TextConfig.js.map +1 -0
  27. package/dist/components/Input/helpers.d.ts +3 -0
  28. package/dist/components/Input/helpers.d.ts.map +1 -0
  29. package/dist/components/Input/helpers.js +28 -0
  30. package/dist/components/Input/helpers.js.map +1 -0
  31. package/dist/components/InputCellContent.d.ts +9 -0
  32. package/dist/components/InputCellContent.d.ts.map +1 -0
  33. package/dist/components/InputCellContent.js +38 -0
  34. package/dist/components/InputCellContent.js.map +1 -0
  35. package/dist/components/SheetsTabBar.d.ts +6 -0
  36. package/dist/components/SheetsTabBar.d.ts.map +1 -0
  37. package/dist/components/SheetsTabBar.js +57 -0
  38. package/dist/components/SheetsTabBar.js.map +1 -0
  39. package/dist/components/SqlCellContent.d.ts +9 -0
  40. package/dist/components/SqlCellContent.d.ts.map +1 -0
  41. package/dist/components/SqlCellContent.js +222 -0
  42. package/dist/components/SqlCellContent.js.map +1 -0
  43. package/dist/components/SqlCellRunButton.d.ts +17 -0
  44. package/dist/components/SqlCellRunButton.d.ts.map +1 -0
  45. package/dist/components/SqlCellRunButton.js +11 -0
  46. package/dist/components/SqlCellRunButton.js.map +1 -0
  47. package/dist/components/TextCellContent.d.ts +9 -0
  48. package/dist/components/TextCellContent.d.ts.map +1 -0
  49. package/dist/components/TextCellContent.js +27 -0
  50. package/dist/components/TextCellContent.js.map +1 -0
  51. package/dist/components/VegaCellContent.d.ts +9 -0
  52. package/dist/components/VegaCellContent.d.ts.map +1 -0
  53. package/dist/components/VegaCellContent.js +66 -0
  54. package/dist/components/VegaCellContent.js.map +1 -0
  55. package/dist/components/VegaConfigPanel.d.ts +8 -0
  56. package/dist/components/VegaConfigPanel.d.ts.map +1 -0
  57. package/dist/components/VegaConfigPanel.js +72 -0
  58. package/dist/components/VegaConfigPanel.js.map +1 -0
  59. package/dist/dagUtils.d.ts +20 -0
  60. package/dist/dagUtils.d.ts.map +1 -0
  61. package/dist/dagUtils.js +233 -0
  62. package/dist/dagUtils.js.map +1 -0
  63. package/dist/defaultCellRegistry.d.ts +3 -0
  64. package/dist/defaultCellRegistry.d.ts.map +1 -0
  65. package/dist/defaultCellRegistry.js +177 -0
  66. package/dist/defaultCellRegistry.js.map +1 -0
  67. package/dist/execution.d.ts +9 -0
  68. package/dist/execution.d.ts.map +1 -0
  69. package/dist/execution.js +195 -0
  70. package/dist/execution.js.map +1 -0
  71. package/dist/helpers.d.ts +45 -0
  72. package/dist/helpers.d.ts.map +1 -0
  73. package/dist/helpers.js +124 -0
  74. package/dist/helpers.js.map +1 -0
  75. package/dist/hooks.d.ts +11 -0
  76. package/dist/hooks.d.ts.map +1 -0
  77. package/dist/hooks.js +9 -0
  78. package/dist/hooks.js.map +1 -0
  79. package/dist/index.d.ts +27 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +26 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/resultRelationPolicy.d.ts +74 -0
  84. package/dist/resultRelationPolicy.d.ts.map +1 -0
  85. package/dist/resultRelationPolicy.js +74 -0
  86. package/dist/resultRelationPolicy.js.map +1 -0
  87. package/dist/sqlHelpers.d.ts +41 -0
  88. package/dist/sqlHelpers.d.ts.map +1 -0
  89. package/dist/sqlHelpers.js +190 -0
  90. package/dist/sqlHelpers.js.map +1 -0
  91. package/dist/types.d.ts +501 -0
  92. package/dist/types.d.ts.map +1 -0
  93. package/dist/types.js +144 -0
  94. package/dist/types.js.map +1 -0
  95. package/dist/utils.d.ts +17 -0
  96. package/dist/utils.d.ts.map +1 -0
  97. package/dist/utils.js +35 -0
  98. package/dist/utils.js.map +1 -0
  99. package/package.json +57 -0
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, TabStrip, } from '@sqlrooms/ui';
3
+ import { AppWindow, FileText, LayoutDashboard, PencilIcon, PlusIcon, TrashIcon, } from 'lucide-react';
4
+ import React, { useCallback, useMemo, useState } from 'react';
5
+ import { useCellsStore } from '../hooks';
6
+ import { DeleteSheetModal } from './DeleteSheetModal';
7
+ const TYPE_ICONS = {
8
+ notebook: FileText,
9
+ canvas: LayoutDashboard,
10
+ app: AppWindow,
11
+ };
12
+ export const SheetsTabBar = ({ className }) => {
13
+ const sheetOrder = useCellsStore((s) => s.cells.config.sheetOrder);
14
+ const sheets = useCellsStore((s) => s.cells.config.sheets);
15
+ const currentSheetId = useCellsStore((s) => s.cells.config.currentSheetId);
16
+ const supportedTypes = useCellsStore((s) => s.cells.supportedSheetTypes);
17
+ const addSheet = useCellsStore((s) => s.cells.addSheet);
18
+ const removeSheet = useCellsStore((s) => s.cells.removeSheet);
19
+ const closeSheet = useCellsStore((s) => s.cells.closeSheet);
20
+ const openSheet = useCellsStore((s) => s.cells.openSheet);
21
+ const setSheetOrder = useCellsStore((s) => s.cells.setSheetOrder);
22
+ const renameSheet = useCellsStore((s) => s.cells.renameSheet);
23
+ const setCurrentSheet = useCellsStore((s) => s.cells.setCurrentSheet);
24
+ const [sheetToDelete, setSheetToDelete] = useState(null);
25
+ const handleDeleteRequest = useCallback((sheetId) => {
26
+ const sheet = sheets[sheetId];
27
+ if (sheet && sheet.cellIds.length === 0) {
28
+ removeSheet(sheetId);
29
+ }
30
+ else {
31
+ setSheetToDelete(sheetId);
32
+ }
33
+ }, [sheets, removeSheet]);
34
+ const handleConfirmDelete = useCallback(() => {
35
+ if (sheetToDelete) {
36
+ removeSheet(sheetToDelete);
37
+ setSheetToDelete(null);
38
+ }
39
+ }, [sheetToDelete, removeSheet]);
40
+ const tabs = useMemo(() => Object.values(sheets).map((sheet) => ({
41
+ id: sheet.id,
42
+ name: sheet.title || 'Untitled',
43
+ type: sheet.type || 'notebook',
44
+ })), [sheets]);
45
+ return (_jsxs(TabStrip, { className: className, tabs: tabs, openTabs: sheetOrder, selectedTabId: currentSheetId, onSelect: setCurrentSheet, onRename: renameSheet, onClose: closeSheet, onOpenTabsChange: setSheetOrder, renderTabTitle: (tab) => {
46
+ const Icon = TYPE_ICONS[tab.type] || FileText;
47
+ return (_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Icon, { className: "text-muted-foreground h-3.5 w-3.5 shrink-0" }), _jsx("div", { className: "truncate text-sm", children: tab.name })] }));
48
+ }, renderTabMenu: (tab) => (_jsxs(_Fragment, { children: [_jsxs(TabStrip.MenuItem, { onClick: () => renameSheet(tab.id, tab.name), children: [_jsx(PencilIcon, { className: "mr-2 h-4 w-4" }), "Rename"] }), _jsx(TabStrip.MenuSeparator, {}), _jsxs(TabStrip.MenuItem, { variant: "destructive", onClick: () => handleDeleteRequest(tab.id), children: [_jsx(TrashIcon, { className: "mr-2 h-4 w-4" }), "Delete"] })] })), renderSearchItemActions: (tab) => (_jsxs(_Fragment, { children: [_jsx(TabStrip.SearchItemAction, { icon: _jsx(PencilIcon, { className: "h-3 w-3" }), "aria-label": `Rename ${tab.name}`, onClick: () => renameSheet(tab.id, tab.name) }), _jsx(TabStrip.SearchItemAction, { icon: _jsx(TrashIcon, { className: "h-3 w-3" }), "aria-label": `Delete ${tab.name}`, onClick: () => handleDeleteRequest(tab.id) })] })), children: [_jsx(TabStrip.SearchDropdown, {}), _jsx(TabStrip.Tabs, { tabClassName: "pl-2" }), supportedTypes.length === 1 ? (_jsx(AddNewSheetButton, { onClick: () => addSheet(undefined, supportedTypes[0]) })) : (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(AddNewSheetButton, {}) }), _jsx(DropdownMenuContent, { align: "start", children: supportedTypes.map((type) => {
49
+ const Icon = TYPE_ICONS[type];
50
+ return (_jsxs(DropdownMenuItem, { onClick: () => addSheet(undefined, type), className: "capitalize", children: [_jsx(Icon, { className: "mr-2 h-4 w-4" }), "New ", type] }, type));
51
+ }) })] })), _jsx(DeleteSheetModal, { isOpen: sheetToDelete !== null, onClose: () => setSheetToDelete(null), onConfirm: handleConfirmDelete, sheetTitle: sheetToDelete ? sheets[sheetToDelete]?.title : undefined })] }));
52
+ };
53
+ const AddNewSheetButton = React.forwardRef(({ className, ...props }, ref) => {
54
+ return (_jsx(Button, { ref: ref, size: "icon", variant: "ghost", className: `hover:bg-primary/10 h-full w-8 rounded-none ${className ?? ''}`, ...props, children: _jsx(PlusIcon, { className: "h-4 w-4" }) }));
55
+ });
56
+ AddNewSheetButton.displayName = 'AddNewSheetButton';
57
+ //# sourceMappingURL=SheetsTabBar.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { CellContainerProps, SqlCell } from '../types';
3
+ export type SqlCellContentProps = {
4
+ id: string;
5
+ cell: SqlCell;
6
+ renderContainer: (props: CellContainerProps) => React.ReactElement;
7
+ };
8
+ export declare const SqlCellContent: React.FC<SqlCellContentProps>;
9
+ //# sourceMappingURL=SqlCellContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqlCellContent.d.ts","sourceRoot":"","sources":["../../src/components/SqlCellContent.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAE/E,OAAO,KAAK,EAAC,kBAAkB,EAAkB,OAAO,EAAC,MAAM,UAAU,CAAC;AAI1E,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,CAqZxD,CAAC"}
@@ -0,0 +1,222 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DataTablePaginated, QueryDataTableActionsMenu, useArrowDataTable, } from '@sqlrooms/data-table';
3
+ import { getCoreDuckDbConnectionId } from '@sqlrooms/db';
4
+ 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
+ import { produce } from 'immer';
9
+ import { CornerDownRightIcon } from 'lucide-react';
10
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
+ import { useCellsStore } from '../hooks';
12
+ import { getEffectiveResultName, isValidSqlIdentifier } from '../utils';
13
+ import { SqlCellRunButton } from './SqlCellRunButton';
14
+ export const SqlCellContent = ({ id, cell, renderContainer, }) => {
15
+ const storeApi = useRoomStoreApi();
16
+ const updateCell = useCellsStore((s) => s.cells.updateCell);
17
+ const runCell = useCellsStore((s) => s.cells.runCell);
18
+ const cancelCell = useCellsStore((s) => s.cells.cancelCell);
19
+ const getDownstream = useCellsStore((s) => s.cells.getDownstream);
20
+ const currentSheetId = useCellsStore((s) => s.cells.config.currentSheetId);
21
+ const cellsData = useCellsStore((s) => s.cells.config.data);
22
+ const sheets = useCellsStore((s) => s.cells.config.sheets);
23
+ const cellStatus = useCellsStore((s) => s.cells.status[id]);
24
+ const resultVersion = useCellsStore((s) => s.cells.resultVersion?.[id] ?? 0);
25
+ const pageVersion = useCellsStore((s) => s.cells.pageVersion?.[id] ?? 0);
26
+ const getCellResult = useCellsStore((s) => s.cells.getCellResult);
27
+ const fetchCellResultPage = useCellsStore((s) => s.cells.fetchCellResultPage);
28
+ const dbConnections = useCellsStore((s) => s.db.config.connections);
29
+ // Re-read the cache whenever resultVersion or pageVersion changes
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31
+ const cellResult = useMemo(() => getCellResult(id), [getCellResult, id, resultVersion, pageVersion]);
32
+ const arrowTableData = useArrowDataTable(cellResult?.arrowTable);
33
+ const handleSqlChange = useCallback((v) => {
34
+ updateCell(id, (c) => produce(c, (draft) => {
35
+ if (draft.type === 'sql') {
36
+ draft.data.sql = v || '';
37
+ }
38
+ }));
39
+ }, [id, updateCell]);
40
+ const handleRun = useCallback(() => {
41
+ runCell(id);
42
+ }, [id, runCell]);
43
+ const handleConnectorChange = useCallback((connectorId) => {
44
+ updateCell(id, (c) => produce(c, (draft) => {
45
+ if (draft.type === 'sql') {
46
+ draft.data.connectorId = connectorId || undefined;
47
+ }
48
+ }));
49
+ }, [id, updateCell]);
50
+ const handleCancel = useCallback(() => {
51
+ cancelCell(id);
52
+ }, [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
+ const handleResultNameChange = useCallback((value) => {
61
+ const nextValue = value.trim();
62
+ if (!validateResultName(nextValue)) {
63
+ setIsResultNameInvalid(true);
64
+ return;
65
+ }
66
+ updateCell(id, (c) => produce(c, (draft) => {
67
+ if (draft.type === 'sql') {
68
+ draft.data.resultName = nextValue;
69
+ }
70
+ }));
71
+ setIsResultNameInvalid(false);
72
+ }, [id, updateCell, validateResultName]);
73
+ const effectiveResultName = getEffectiveResultName(cell.data, convertToValidColumnOrTableName);
74
+ const explicitResultName = cell.data.resultName || '';
75
+ 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
+ const status = cellStatus?.type === 'sql'
115
+ ? {
116
+ state: cellStatus.status,
117
+ message: cellStatus.lastError,
118
+ resultName: cellStatus.resultView || cellStatus.resultName,
119
+ lastRunTime: cellStatus.lastRunTime,
120
+ }
121
+ : undefined;
122
+ const resultName = status?.resultName;
123
+ 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
+ const handleRunRef = useRef(handleRun);
175
+ useEffect(() => {
176
+ handleRunRef.current = handleRun;
177
+ }, [handleRun]);
178
+ const handleSqlEditorMount = useCallback((editor, monaco) => {
179
+ // Use onKeyDown instead of addCommand to scope the shortcut
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" }) })] })] }));
216
+ return renderContainer({
217
+ header: (_jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx("div", { className: "flex-1", children: _jsx("select", { className: "border-input bg-background text-foreground h-7 rounded border px-2 text-xs", value: selectedConnectorId, onChange: (e) => handleConnectorChange(e.target.value), children: connectionOptions.map((connection) => (_jsx("option", { value: connection.id, children: connection.title }, connection.id))) }) }), _jsx(SqlCellRunButton, { onRun: handleRun, onCancel: handleCancel, status: status, runLabel: "Run" })] })),
218
+ content,
219
+ footer,
220
+ });
221
+ };
222
+ //# sourceMappingURL=SqlCellContent.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,17 @@
1
+ import { SqlCellRunStatus } from '../types';
2
+ /**
3
+ * Props for the standalone run/cancel control used by SQL cells.
4
+ */
5
+ type SqlCellRunButtonProps = {
6
+ onRun: () => void;
7
+ onCancel?: () => void;
8
+ status?: SqlCellRunStatus;
9
+ runLabel?: string;
10
+ disabled?: boolean;
11
+ };
12
+ /**
13
+ * Renders the run/cancel control for a SQL cell and shows error feedback.
14
+ */
15
+ export declare function SqlCellRunButton({ onRun, onCancel, status, runLabel, disabled, }: SqlCellRunButtonProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
17
+ //# sourceMappingURL=SqlCellRunButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqlCellRunButton.d.ts","sourceRoot":"","sources":["../../src/components/SqlCellRunButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,gBAAgB,EAAC,MAAM,UAAU,CAAC;AAE1C;;GAEG;AACH,KAAK,qBAAqB,GAAG;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AACF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAgB,EAChB,QAAQ,GACT,EAAE,qBAAqB,2CA6BvB"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Spinner } from '@sqlrooms/ui';
3
+ import { Play } from 'lucide-react';
4
+ /**
5
+ * Renders the run/cancel control for a SQL cell and shows error feedback.
6
+ */
7
+ export function SqlCellRunButton({ onRun, onCancel, status, runLabel = 'Run', disabled, }) {
8
+ const showCancel = status?.state === 'running' && Boolean(onCancel);
9
+ return (_jsx("div", { className: "flex items-center gap-2", children: showCancel ? (_jsxs(Button, { size: "xs", variant: "destructive", className: "flex h-7 w-20 gap-1", onClick: onCancel, children: [_jsx(Spinner, {}), "Cancel"] })) : (_jsxs(Button, { size: "xs", variant: "secondary", className: "flex h-7 w-20 gap-1", onClick: onRun, disabled: disabled, children: [_jsx(Play, { className: "h-3 w-3" }), runLabel] })) }));
10
+ }
11
+ //# sourceMappingURL=SqlCellRunButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqlCellRunButton.js","sourceRoot":"","sources":["../../src/components/SqlCellRunButton.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,OAAO,EAAC,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAC,IAAI,EAAC,MAAM,cAAc,CAAC;AAalC;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,GAAG,KAAK,EAChB,QAAQ,GACc;IACtB,MAAM,UAAU,GAAG,MAAM,EAAE,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEpE,OAAO,CACL,cAAK,SAAS,EAAC,yBAAyB,YACrC,UAAU,CAAC,CAAC,CAAC,CACZ,MAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,OAAO,EAAC,aAAa,EACrB,SAAS,EAAC,qBAAqB,EAC/B,OAAO,EAAE,QAAQ,aAEjB,KAAC,OAAO,KAAG,cAEJ,CACV,CAAC,CAAC,CAAC,CACF,MAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,OAAO,EAAC,WAAW,EACnB,SAAS,EAAC,qBAAqB,EAC/B,OAAO,EAAE,KAAK,EACd,QAAQ,EAAE,QAAQ,aAElB,KAAC,IAAI,IAAC,SAAS,EAAC,SAAS,GAAG,EAC3B,QAAQ,IACF,CACV,GACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["import {Button, Spinner} from '@sqlrooms/ui';\nimport {Play} from 'lucide-react';\nimport {SqlCellRunStatus} from '../types';\n\n/**\n * Props for the standalone run/cancel control used by SQL cells.\n */\ntype SqlCellRunButtonProps = {\n onRun: () => void;\n onCancel?: () => void;\n status?: SqlCellRunStatus;\n runLabel?: string;\n disabled?: boolean;\n};\n/**\n * Renders the run/cancel control for a SQL cell and shows error feedback.\n */\nexport function SqlCellRunButton({\n onRun,\n onCancel,\n status,\n runLabel = 'Run',\n disabled,\n}: SqlCellRunButtonProps) {\n const showCancel = status?.state === 'running' && Boolean(onCancel);\n\n return (\n <div className=\"flex items-center gap-2\">\n {showCancel ? (\n <Button\n size=\"xs\"\n variant=\"destructive\"\n className=\"flex h-7 w-20 gap-1\"\n onClick={onCancel}\n >\n <Spinner />\n Cancel\n </Button>\n ) : (\n <Button\n size=\"xs\"\n variant=\"secondary\"\n className=\"flex h-7 w-20 gap-1\"\n onClick={onRun}\n disabled={disabled}\n >\n <Play className=\"h-3 w-3\" />\n {runLabel}\n </Button>\n )}\n </div>\n );\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { CellContainerProps, TextCell } from '../types';
3
+ export type TextCellContentProps = {
4
+ id: string;
5
+ cell: TextCell;
6
+ renderContainer: (props: CellContainerProps) => React.ReactElement;
7
+ };
8
+ export declare const TextCellContent: React.FC<TextCellContentProps>;
9
+ //# sourceMappingURL=TextCellContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextCellContent.d.ts","sourceRoot":"","sources":["../../src/components/TextCellContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,OAAO,KAAK,EAAC,kBAAkB,EAAE,QAAQ,EAAC,MAAM,UAAU,CAAC;AAG3D,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,KAAK,CAAC,YAAY,CAAC;CACpE,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgE1D,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback } from 'react';
3
+ import Markdown from 'react-markdown';
4
+ import remarkGfm from 'remark-gfm';
5
+ import { Button } from '@sqlrooms/ui';
6
+ import { useCellsStore } from '../hooks';
7
+ import { produce } from 'immer';
8
+ export const TextCellContent = ({ id, cell, renderContainer, }) => {
9
+ const updateCell = useCellsStore((s) => s.cells.updateCell);
10
+ const [isEditing, setIsEditing] = useState(false);
11
+ const [draftText, setDraftText] = useState(cell.data.text);
12
+ const saveText = useCallback(() => {
13
+ updateCell(id, (c) => produce(c, (draft) => {
14
+ if (draft.type === 'text') {
15
+ draft.data.text = draftText;
16
+ }
17
+ }));
18
+ setIsEditing(false);
19
+ }, [id, draftText, updateCell]);
20
+ const header = (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { size: "xs", variant: "secondary", className: "h-6", onClick: () => (isEditing ? saveText() : setIsEditing(true)), children: isEditing ? 'Save' : 'Edit text' }), _jsx("span", { className: "text-[10px] font-bold uppercase text-gray-400", children: "Text" })] }));
21
+ const content = (_jsxs("div", { className: "flex min-h-[100px] flex-col divide-y dark:divide-gray-800", onDoubleClick: () => setIsEditing((prev) => !prev), children: [isEditing && (_jsx("textarea", { className: "bg-accent min-h-[100px] w-full p-3 text-xs outline-none", value: draftText, onChange: (e) => setDraftText(e.target.value), placeholder: "Write text... (Markdown supported)", autoFocus: true })), !isEditing && (_jsx("div", { className: "prose dark:prose-invert max-w-none flex-1 p-3 text-sm", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], children: cell.data.text || '_No content yet. Double click to edit._' }) }))] }));
22
+ return renderContainer({
23
+ header,
24
+ content,
25
+ });
26
+ };
27
+ //# sourceMappingURL=TextCellContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextCellContent.js","sourceRoot":"","sources":["../../src/components/TextCellContent.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,QAAQ,EAAE,WAAW,EAAC,MAAM,OAAO,CAAC;AACnD,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,EAAC,MAAM,EAAK,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AAEvC,OAAO,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AAQ9B,MAAM,CAAC,MAAM,eAAe,GAAmC,CAAC,EAC9D,EAAE,EACF,IAAI,EACJ,eAAe,GAChB,EAAE,EAAE;IACH,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE3D,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QACF,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAEhC,MAAM,MAAM,GAAG,CACb,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,OAAO,EAAC,WAAW,EACnB,SAAS,EAAC,KAAK,EACf,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,YAE3D,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,GAC1B,EACT,eAAM,SAAS,EAAC,+CAA+C,qBAExD,IACH,CACP,CAAC;IAEF,MAAM,OAAO,GAAG,CACd,eACE,SAAS,EAAC,2DAA2D,EACrE,aAAa,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,aAEjD,SAAS,IAAI,CACZ,mBACE,SAAS,EAAC,yDAAyD,EACnE,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC7C,WAAW,EAAC,oCAAoC,EAChD,SAAS,SACT,CACH,EACA,CAAC,SAAS,IAAI,CACb,cAAK,SAAS,EAAC,uDAAuD,YACpE,KAAC,QAAQ,IAAC,aAAa,EAAE,CAAC,SAAS,CAAC,YACjC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,yCAAyC,GACnD,GACP,CACP,IACG,CACP,CAAC;IAEF,OAAO,eAAe,CAAC;QACrB,MAAM;QACN,OAAO;KACR,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import React, {useState, useCallback} from 'react';\nimport Markdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport {Button, cn} from '@sqlrooms/ui';\nimport {useCellsStore} from '../hooks';\nimport type {CellContainerProps, TextCell} from '../types';\nimport {produce} from 'immer';\n\nexport type TextCellContentProps = {\n id: string;\n cell: TextCell;\n renderContainer: (props: CellContainerProps) => React.ReactElement;\n};\n\nexport const TextCellContent: React.FC<TextCellContentProps> = ({\n id,\n cell,\n renderContainer,\n}) => {\n const updateCell = useCellsStore((s) => s.cells.updateCell);\n const [isEditing, setIsEditing] = useState(false);\n const [draftText, setDraftText] = useState(cell.data.text);\n\n const saveText = useCallback(() => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'text') {\n draft.data.text = draftText;\n }\n }),\n );\n setIsEditing(false);\n }, [id, draftText, updateCell]);\n\n const header = (\n <div className=\"flex items-center gap-2\">\n <Button\n size=\"xs\"\n variant=\"secondary\"\n className=\"h-6\"\n onClick={() => (isEditing ? saveText() : setIsEditing(true))}\n >\n {isEditing ? 'Save' : 'Edit text'}\n </Button>\n <span className=\"text-[10px] font-bold uppercase text-gray-400\">\n Text\n </span>\n </div>\n );\n\n const content = (\n <div\n className=\"flex min-h-[100px] flex-col divide-y dark:divide-gray-800\"\n onDoubleClick={() => setIsEditing((prev) => !prev)}\n >\n {isEditing && (\n <textarea\n className=\"bg-accent min-h-[100px] w-full p-3 text-xs outline-none\"\n value={draftText}\n onChange={(e) => setDraftText(e.target.value)}\n placeholder=\"Write text... (Markdown supported)\"\n autoFocus\n />\n )}\n {!isEditing && (\n <div className=\"prose dark:prose-invert max-w-none flex-1 p-3 text-sm\">\n <Markdown remarkPlugins={[remarkGfm]}>\n {cell.data.text || '_No content yet. Double click to edit._'}\n </Markdown>\n </div>\n )}\n </div>\n );\n\n return renderContainer({\n header,\n content,\n });\n};\n"]}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { CellContainerProps, VegaCell } from '../types';
3
+ export type VegaCellContentProps = {
4
+ id: string;
5
+ cell: VegaCell;
6
+ renderContainer: (props: CellContainerProps) => React.ReactElement;
7
+ };
8
+ export declare const VegaCellContent: React.FC<VegaCellContentProps>;
9
+ //# sourceMappingURL=VegaCellContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VegaCellContent.d.ts","sourceRoot":"","sources":["../../src/components/VegaCellContent.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAO,kBAAkB,EAAE,QAAQ,EAAC,MAAM,UAAU,CAAC;AAGjE,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,KAAK,CAAC,YAAY,CAAC;CACpE,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAyI1D,CAAC"}
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@sqlrooms/ui';
3
+ import { VegaLiteChart } from '@sqlrooms/vega';
4
+ import { produce } from 'immer';
5
+ import { useCallback, useMemo, useState } from 'react';
6
+ import { useCellsStore } from '../hooks';
7
+ import { VegaConfigPanel } from './VegaConfigPanel';
8
+ export const VegaCellContent = ({ id, cell, renderContainer, }) => {
9
+ const updateCell = useCellsStore((s) => s.cells.updateCell);
10
+ const cellsData = useCellsStore((s) => s.cells.config.data);
11
+ const cellsStatus = useCellsStore((s) => s.cells.status);
12
+ // Find available SQL cells in the same sheet
13
+ const currentSheetId = useCellsStore((s) => s.cells.config.currentSheetId);
14
+ const sheetCellIds = useCellsStore((s) => currentSheetId ? s.cells.config.sheets[currentSheetId]?.cellIds : undefined);
15
+ const availableSqlCells = useMemo(() => {
16
+ if (!sheetCellIds)
17
+ return [];
18
+ return sheetCellIds
19
+ .map((cid) => cellsData[cid])
20
+ .filter((c) => c?.type === 'sql');
21
+ }, [sheetCellIds, cellsData]);
22
+ const selectedSqlId = cell.data.sqlId;
23
+ const selectedSqlStatus = selectedSqlId
24
+ ? cellsStatus[selectedSqlId]
25
+ : undefined;
26
+ const [draftSpec, setDraftSpec] = useState(cell.data.vegaSpec ?? {
27
+ data: { name: 'queryResult' },
28
+ mark: 'bar',
29
+ padding: 20,
30
+ });
31
+ const [isEditing, setIsEditing] = useState(false);
32
+ const selectedSqlQuery = selectedSqlStatus?.type === 'sql' && selectedSqlStatus.resultView
33
+ ? `SELECT * FROM ${selectedSqlStatus.resultView}`
34
+ : selectedSqlId && cellsData[selectedSqlId]?.type === 'sql'
35
+ ? cellsData[selectedSqlId].data.sql
36
+ : '';
37
+ const lastRunTime = selectedSqlStatus?.type === 'sql'
38
+ ? selectedSqlStatus.lastRunTime
39
+ : undefined;
40
+ const handleSqlIdChange = (value) => {
41
+ updateCell(id, (c) => produce(c, (draft) => {
42
+ if (draft.type === 'vega')
43
+ draft.data.sqlId = value;
44
+ }));
45
+ };
46
+ const saveSpec = useCallback(() => {
47
+ updateCell(id, (c) => produce(c, (draft) => {
48
+ if (draft.type === 'vega')
49
+ draft.data.vegaSpec = draftSpec;
50
+ }));
51
+ setIsEditing(false);
52
+ }, [id, draftSpec, updateCell]);
53
+ const header = (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Select, { value: selectedSqlId, onValueChange: handleSqlIdChange, children: [_jsx(SelectTrigger, { className: "h-6 w-[150px] text-xs shadow-none", children: _jsx(SelectValue, { placeholder: "Select data source" }) }), _jsx(SelectContent, { onCloseAutoFocus: (e) => e.preventDefault(), children: availableSqlCells.map((sql) => (_jsx(SelectItem, { className: "text-xs", value: sql.id, children: sql.data.title }, sql.id))) })] }), _jsx(Button, { size: "xs", variant: "secondary", className: "h-6", onClick: () => (isEditing ? saveSpec() : setIsEditing(true)), disabled: !selectedSqlId, children: isEditing ? 'Save' : 'Edit chart' }), _jsx("span", { className: "text-[10px] font-bold uppercase text-gray-400", children: "Vega" })] }));
54
+ const content = (_jsxs("div", { className: "flex h-[400px]", children: [isEditing && (_jsx(VegaConfigPanel, { sqlQuery: selectedSqlQuery, lastRunTime: lastRunTime, spec: draftSpec, onSpecChange: setDraftSpec })), _jsx("div", { onDoubleClick: () => selectedSqlId && setIsEditing((prev) => !prev), className: "flex h-full w-full p-2", children: !selectedSqlId ? (_jsx("div", { className: "flex h-full w-full items-center justify-center text-gray-400", children: "Please select a SQL data source first." })) : !selectedSqlStatus ? (_jsx("div", { className: "flex h-full w-full items-center justify-center text-gray-400", children: "No chart data available, please run the SQL cell first." })) : (_jsx(VegaLiteChart, { sqlQuery: selectedSqlQuery,
55
+ // isLoading={
56
+ // selectedSqlStatus?.type === 'sql' &&
57
+ // selectedSqlStatus.status === 'running'
58
+ // }
59
+ // lastRunTime={lastRunTime}
60
+ spec: draftSpec, className: "h-full w-full", aspectRatio: isEditing ? undefined : 3 / 2 })) })] }));
61
+ return renderContainer({
62
+ header,
63
+ content,
64
+ });
65
+ };
66
+ //# sourceMappingURL=VegaCellContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VegaCellContent.js","sourceRoot":"","sources":["../../src/components/VegaCellContent.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Button,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@sqlrooms/ui';\nimport {VegaLiteChart} from '@sqlrooms/vega';\nimport {produce} from 'immer';\nimport React, {useCallback, useMemo, useState} from 'react';\nimport {useCellsStore} from '../hooks';\nimport type {Cell, CellContainerProps, VegaCell} from '../types';\nimport {VegaConfigPanel} from './VegaConfigPanel';\n\nexport type VegaCellContentProps = {\n id: string;\n cell: VegaCell;\n renderContainer: (props: CellContainerProps) => React.ReactElement;\n};\n\nexport const VegaCellContent: React.FC<VegaCellContentProps> = ({\n id,\n cell,\n renderContainer,\n}) => {\n const updateCell = useCellsStore((s) => s.cells.updateCell);\n const cellsData = useCellsStore((s) => s.cells.config.data);\n const cellsStatus = useCellsStore((s) => s.cells.status);\n\n // Find available SQL cells in the same sheet\n const currentSheetId = useCellsStore((s) => s.cells.config.currentSheetId);\n const sheetCellIds = useCellsStore((s) =>\n currentSheetId ? s.cells.config.sheets[currentSheetId]?.cellIds : undefined,\n );\n\n const availableSqlCells = useMemo(() => {\n if (!sheetCellIds) return [];\n return sheetCellIds\n .map((cid) => cellsData[cid])\n .filter((c): c is Cell & {type: 'sql'} => c?.type === 'sql');\n }, [sheetCellIds, cellsData]);\n\n const selectedSqlId = cell.data.sqlId;\n const selectedSqlStatus = selectedSqlId\n ? cellsStatus[selectedSqlId]\n : undefined;\n\n const [draftSpec, setDraftSpec] = useState(\n cell.data.vegaSpec ?? {\n data: {name: 'queryResult'},\n mark: 'bar',\n padding: 20,\n },\n );\n const [isEditing, setIsEditing] = useState(false);\n\n const selectedSqlQuery =\n selectedSqlStatus?.type === 'sql' && selectedSqlStatus.resultView\n ? `SELECT * FROM ${selectedSqlStatus.resultView}`\n : selectedSqlId && cellsData[selectedSqlId]?.type === 'sql'\n ? (cellsData[selectedSqlId] as any).data.sql\n : '';\n\n const lastRunTime =\n selectedSqlStatus?.type === 'sql'\n ? selectedSqlStatus.lastRunTime\n : undefined;\n\n const handleSqlIdChange = (value: string) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'vega') draft.data.sqlId = value;\n }),\n );\n };\n\n const saveSpec = useCallback(() => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'vega') draft.data.vegaSpec = draftSpec;\n }),\n );\n setIsEditing(false);\n }, [id, draftSpec, updateCell]);\n\n const header = (\n <div className=\"flex items-center gap-2\">\n <Select value={selectedSqlId} onValueChange={handleSqlIdChange}>\n <SelectTrigger className=\"h-6 w-[150px] text-xs shadow-none\">\n <SelectValue placeholder=\"Select data source\" />\n </SelectTrigger>\n <SelectContent onCloseAutoFocus={(e) => e.preventDefault()}>\n {availableSqlCells.map((sql) => (\n <SelectItem className=\"text-xs\" key={sql.id} value={sql.id}>\n {sql.data.title}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Button\n size=\"xs\"\n variant=\"secondary\"\n className=\"h-6\"\n onClick={() => (isEditing ? saveSpec() : setIsEditing(true))}\n disabled={!selectedSqlId}\n >\n {isEditing ? 'Save' : 'Edit chart'}\n </Button>\n <span className=\"text-[10px] font-bold uppercase text-gray-400\">\n Vega\n </span>\n </div>\n );\n\n const content = (\n <div className=\"flex h-[400px]\">\n {isEditing && (\n <VegaConfigPanel\n sqlQuery={selectedSqlQuery}\n lastRunTime={lastRunTime}\n spec={draftSpec}\n onSpecChange={setDraftSpec}\n />\n )}\n <div\n onDoubleClick={() => selectedSqlId && setIsEditing((prev) => !prev)}\n className=\"flex h-full w-full p-2\"\n >\n {!selectedSqlId ? (\n <div className=\"flex h-full w-full items-center justify-center text-gray-400\">\n Please select a SQL data source first.\n </div>\n ) : !selectedSqlStatus ? (\n <div className=\"flex h-full w-full items-center justify-center text-gray-400\">\n No chart data available, please run the SQL cell first.\n </div>\n ) : (\n <VegaLiteChart\n sqlQuery={selectedSqlQuery}\n // isLoading={\n // selectedSqlStatus?.type === 'sql' &&\n // selectedSqlStatus.status === 'running'\n // }\n // lastRunTime={lastRunTime}\n spec={draftSpec}\n className=\"h-full w-full\"\n aspectRatio={isEditing ? undefined : 3 / 2}\n />\n )}\n </div>\n </div>\n );\n\n return renderContainer({\n header,\n content,\n });\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export declare const VegaConfigPanel: React.FC<{
3
+ spec: any;
4
+ sqlQuery: string;
5
+ lastRunTime?: number;
6
+ onSpecChange: (spec: any) => void;
7
+ }>;
8
+ //# sourceMappingURL=VegaConfigPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VegaConfigPanel.d.ts","sourceRoot":"","sources":["../../src/components/VegaConfigPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAmC1B,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;CACnC,CA6KA,CAAC"}