@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VegaCellContent.d.ts","sourceRoot":"","sources":["../../src/components/VegaCellContent.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VegaCellContent.d.ts","sourceRoot":"","sources":["../../src/components/VegaCellContent.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,kBAAkB,EAAE,QAAQ,EAAC,MAAM,UAAU,CAAC;AAa3D,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,CA6J1D,CAAC"}
|
|
@@ -1,63 +1,77 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useDebouncedValue } from '@sqlrooms/ui';
|
|
3
3
|
import { VegaLiteChart } from '@sqlrooms/vega';
|
|
4
4
|
import { produce } from 'immer';
|
|
5
|
-
import { useCallback,
|
|
5
|
+
import { useCallback, useState } from 'react';
|
|
6
6
|
import { useCellsStore } from '../hooks';
|
|
7
|
+
import { useVegaCellQuery } from '../hooks/useVegaCellQuery';
|
|
8
|
+
import { useVegaCellDataSource } from '../hooks/useVegaCellDataSource';
|
|
9
|
+
import { SelectionListener } from './SelectionListener';
|
|
7
10
|
import { VegaConfigPanel } from './VegaConfigPanel';
|
|
11
|
+
import { VegaCellHeader } from './VegaCellHeader';
|
|
12
|
+
import { toDataSourceCell, toDataSourceTable } from '../helpers';
|
|
13
|
+
const DEFAULT_ASPECT_RATIO = 3 / 2;
|
|
14
|
+
const DEFAULT_SPEC = {
|
|
15
|
+
data: { name: 'queryResult' },
|
|
16
|
+
mark: 'bar',
|
|
17
|
+
padding: 20,
|
|
18
|
+
};
|
|
8
19
|
export const VegaCellContent = ({ id, cell, renderContainer, }) => {
|
|
9
20
|
const updateCell = useCellsStore((s) => s.cells.updateCell);
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
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
|
-
});
|
|
21
|
+
const crossFilterEnabled = cell.data.crossFilter?.enabled !== false;
|
|
22
|
+
const brushField = cell.data.crossFilter?.brushField;
|
|
23
|
+
const brushFieldType = cell.data.crossFilter?.brushFieldType;
|
|
31
24
|
const [isEditing, setIsEditing] = useState(false);
|
|
32
|
-
|
|
33
|
-
|
|
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) => {
|
|
25
|
+
// Local state with debounced persistence
|
|
26
|
+
const [localSpec, handleSpecChange] = useDebouncedValue(cell.data.vegaSpec ?? DEFAULT_SPEC, (spec) => {
|
|
41
27
|
updateCell(id, (c) => produce(c, (draft) => {
|
|
42
28
|
if (draft.type === 'vega')
|
|
43
|
-
draft.data.
|
|
29
|
+
draft.data.vegaSpec = spec;
|
|
44
30
|
}));
|
|
45
|
-
};
|
|
46
|
-
const
|
|
31
|
+
}, 300);
|
|
32
|
+
const { selectedSqlId, selectedTableRef, selectedSqlStatus, baseSqlQuery, lastRunTime, hasDataSource, } = useVegaCellDataSource(cell);
|
|
33
|
+
const { selectedSqlQuery, crossFilterPredicate } = useVegaCellQuery({
|
|
34
|
+
cellId: id,
|
|
35
|
+
baseSqlQuery,
|
|
36
|
+
selectedSqlId,
|
|
37
|
+
crossFilterEnabled,
|
|
38
|
+
});
|
|
39
|
+
// Encode selection value: "cell:<id>" or "table:<schema.table>"
|
|
40
|
+
const selectValue = selectedSqlId
|
|
41
|
+
? toDataSourceCell(selectedSqlId)
|
|
42
|
+
: selectedTableRef
|
|
43
|
+
? toDataSourceTable(selectedTableRef)
|
|
44
|
+
: undefined;
|
|
45
|
+
const handleCrossFilterToggle = useCallback((enabled) => {
|
|
47
46
|
updateCell(id, (c) => produce(c, (draft) => {
|
|
48
|
-
if (draft.type === 'vega')
|
|
49
|
-
draft.data.
|
|
47
|
+
if (draft.type === 'vega') {
|
|
48
|
+
if (!draft.data.crossFilter)
|
|
49
|
+
draft.data.crossFilter = {};
|
|
50
|
+
draft.data.crossFilter.enabled = enabled;
|
|
51
|
+
}
|
|
52
|
+
}));
|
|
53
|
+
}, [id, updateCell]);
|
|
54
|
+
const handleBrushFieldChange = useCallback((field) => {
|
|
55
|
+
updateCell(id, (c) => produce(c, (draft) => {
|
|
56
|
+
if (draft.type === 'vega') {
|
|
57
|
+
if (!draft.data.crossFilter)
|
|
58
|
+
draft.data.crossFilter = {};
|
|
59
|
+
draft.data.crossFilter.brushField = field;
|
|
60
|
+
}
|
|
61
|
+
}));
|
|
62
|
+
}, [id, updateCell]);
|
|
63
|
+
const handleBrushFieldTypeChange = useCallback((fieldType) => {
|
|
64
|
+
updateCell(id, (c) => produce(c, (draft) => {
|
|
65
|
+
if (draft.type === 'vega') {
|
|
66
|
+
if (!draft.data.crossFilter)
|
|
67
|
+
draft.data.crossFilter = {};
|
|
68
|
+
draft.data.crossFilter.brushFieldType = fieldType;
|
|
69
|
+
}
|
|
50
70
|
}));
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const content = (_jsxs("div", { className: "flex h-[400px]", children: [isEditing && (_jsx(VegaConfigPanel, { sqlQuery:
|
|
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 })) })] }));
|
|
71
|
+
}, [id, updateCell]);
|
|
72
|
+
const header = (_jsx(VegaCellHeader, { cellId: id, selectValue: selectValue, onEditToggle: () => setIsEditing((prev) => !prev), hasDataSource: hasDataSource, crossFilterEnabled: crossFilterEnabled, brushField: brushField, crossFilterPredicate: crossFilterPredicate }));
|
|
73
|
+
const showSelectionListener = crossFilterEnabled && brushField && selectedSqlId && selectedSqlStatus;
|
|
74
|
+
const content = (_jsxs("div", { className: "flex h-[400px]", children: [isEditing && (_jsx(VegaConfigPanel, { sqlQuery: baseSqlQuery, lastRunTime: lastRunTime, spec: localSpec, crossFilterEnabled: crossFilterEnabled, onSpecChange: handleSpecChange, onCrossFilterToggle: handleCrossFilterToggle, onBrushFieldChange: handleBrushFieldChange, onBrushFieldTypeChange: handleBrushFieldTypeChange })), _jsx("div", { onDoubleClick: () => hasDataSource && setIsEditing((prev) => !prev), className: "flex h-full w-full p-2", children: !hasDataSource ? (_jsx("div", { className: "flex h-full w-full items-center justify-center text-gray-400", children: "Please select a data source first." })) : !selectedSqlStatus && !selectedTableRef ? (_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, spec: localSpec, className: "h-full w-full", aspectRatio: isEditing ? undefined : DEFAULT_ASPECT_RATIO, children: showSelectionListener && (_jsx(SelectionListener, { cellId: id, sqlId: selectedSqlId, brushField: brushField, brushFieldType: brushFieldType })) })) })] }));
|
|
61
75
|
return renderContainer({
|
|
62
76
|
header,
|
|
63
77
|
content,
|
|
@@ -1 +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"]}
|
|
1
|
+
{"version":3,"file":"VegaCellContent.js","sourceRoot":"","sources":["../../src/components/VegaCellContent.tsx"],"names":[],"mappings":"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","sourcesContent":["import {useDebouncedValue} from '@sqlrooms/ui';\nimport {VegaLiteChart} from '@sqlrooms/vega';\nimport {produce} from 'immer';\nimport {useCallback, useState} from 'react';\nimport {useCellsStore} from '../hooks';\nimport {useVegaCellQuery} from '../hooks/useVegaCellQuery';\nimport {useVegaCellDataSource} from '../hooks/useVegaCellDataSource';\nimport type {CellContainerProps, VegaCell} from '../types';\nimport {SelectionListener} from './SelectionListener';\nimport {VegaConfigPanel} from './VegaConfigPanel';\nimport {VegaCellHeader} from './VegaCellHeader';\nimport {toDataSourceCell, toDataSourceTable} from '../helpers';\n\nconst DEFAULT_ASPECT_RATIO = 3 / 2;\nconst DEFAULT_SPEC = {\n data: {name: 'queryResult'},\n mark: 'bar',\n padding: 20,\n} as const;\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\n const crossFilterEnabled = cell.data.crossFilter?.enabled !== false;\n const brushField = cell.data.crossFilter?.brushField;\n const brushFieldType = cell.data.crossFilter?.brushFieldType;\n\n const [isEditing, setIsEditing] = useState(false);\n\n // Local state with debounced persistence\n const [localSpec, handleSpecChange] = useDebouncedValue(\n cell.data.vegaSpec ?? DEFAULT_SPEC,\n (spec) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'vega') draft.data.vegaSpec = spec;\n }),\n );\n },\n 300,\n );\n\n const {\n selectedSqlId,\n selectedTableRef,\n selectedSqlStatus,\n baseSqlQuery,\n lastRunTime,\n hasDataSource,\n } = useVegaCellDataSource(cell);\n\n const {selectedSqlQuery, crossFilterPredicate} = useVegaCellQuery({\n cellId: id,\n baseSqlQuery,\n selectedSqlId,\n crossFilterEnabled,\n });\n\n // Encode selection value: \"cell:<id>\" or \"table:<schema.table>\"\n const selectValue = selectedSqlId\n ? toDataSourceCell(selectedSqlId)\n : selectedTableRef\n ? toDataSourceTable(selectedTableRef)\n : undefined;\n\n const handleCrossFilterToggle = useCallback(\n (enabled: boolean) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'vega') {\n if (!draft.data.crossFilter) draft.data.crossFilter = {};\n draft.data.crossFilter.enabled = enabled;\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const handleBrushFieldChange = useCallback(\n (field: string | undefined) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'vega') {\n if (!draft.data.crossFilter) draft.data.crossFilter = {};\n draft.data.crossFilter.brushField = field;\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const handleBrushFieldTypeChange = useCallback(\n (fieldType: string | undefined) => {\n updateCell(id, (c) =>\n produce(c, (draft) => {\n if (draft.type === 'vega') {\n if (!draft.data.crossFilter) draft.data.crossFilter = {};\n draft.data.crossFilter.brushFieldType = fieldType;\n }\n }),\n );\n },\n [id, updateCell],\n );\n\n const header = (\n <VegaCellHeader\n cellId={id}\n selectValue={selectValue}\n onEditToggle={() => setIsEditing((prev) => !prev)}\n hasDataSource={hasDataSource}\n crossFilterEnabled={crossFilterEnabled}\n brushField={brushField}\n crossFilterPredicate={crossFilterPredicate}\n />\n );\n\n const showSelectionListener =\n crossFilterEnabled && brushField && selectedSqlId && selectedSqlStatus;\n\n const content = (\n <div className=\"flex h-[400px]\">\n {isEditing && (\n <VegaConfigPanel\n sqlQuery={baseSqlQuery}\n lastRunTime={lastRunTime}\n spec={localSpec}\n crossFilterEnabled={crossFilterEnabled}\n onSpecChange={handleSpecChange}\n onCrossFilterToggle={handleCrossFilterToggle}\n onBrushFieldChange={handleBrushFieldChange}\n onBrushFieldTypeChange={handleBrushFieldTypeChange}\n />\n )}\n <div\n onDoubleClick={() => hasDataSource && setIsEditing((prev) => !prev)}\n className=\"flex h-full w-full p-2\"\n >\n {!hasDataSource ? (\n <div className=\"flex h-full w-full items-center justify-center text-gray-400\">\n Please select a data source first.\n </div>\n ) : !selectedSqlStatus && !selectedTableRef ? (\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 spec={localSpec}\n className=\"h-full w-full\"\n aspectRatio={isEditing ? undefined : DEFAULT_ASPECT_RATIO}\n >\n {showSelectionListener && (\n <SelectionListener\n cellId={id}\n sqlId={selectedSqlId}\n brushField={brushField}\n brushFieldType={brushFieldType}\n />\n )}\n </VegaLiteChart>\n )}\n </div>\n </div>\n );\n\n return renderContainer({\n header,\n content,\n });\n};\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type VegaCellHeaderProps = {
|
|
2
|
+
cellId: string;
|
|
3
|
+
selectValue: string | undefined;
|
|
4
|
+
onEditToggle: () => void;
|
|
5
|
+
hasDataSource: boolean;
|
|
6
|
+
crossFilterEnabled: boolean;
|
|
7
|
+
brushField: string | undefined;
|
|
8
|
+
crossFilterPredicate: string | null;
|
|
9
|
+
};
|
|
10
|
+
export declare const VegaCellHeader: React.FC<VegaCellHeaderProps>;
|
|
11
|
+
//# sourceMappingURL=VegaCellHeader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VegaCellHeader.d.ts","sourceRoot":"","sources":["../../src/components/VegaCellHeader.tsx"],"names":[],"mappings":"AAOA,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAmExD,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Tooltip, TooltipContent, TooltipTrigger } from '@sqlrooms/ui';
|
|
3
|
+
import { produce } from 'immer';
|
|
4
|
+
import { Filter, Settings } from 'lucide-react';
|
|
5
|
+
import { fromDataSourceCell, fromDataSourceTable } from '../helpers';
|
|
6
|
+
import { CellSourceSelector } from './CellSourceSelector';
|
|
7
|
+
import { useCellsStore } from '../hooks';
|
|
8
|
+
export const VegaCellHeader = ({ cellId, selectValue, onEditToggle, hasDataSource, crossFilterEnabled, brushField, crossFilterPredicate, }) => {
|
|
9
|
+
const updateCell = useCellsStore((s) => s.cells.updateCell);
|
|
10
|
+
const handleDataSourceChange = (value) => {
|
|
11
|
+
updateCell(cellId, (c) => produce(c, (draft) => {
|
|
12
|
+
if (draft.type !== 'vega') {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const cellIdFromValue = fromDataSourceCell(value);
|
|
16
|
+
const tableRef = fromDataSourceTable(value);
|
|
17
|
+
if (cellIdFromValue) {
|
|
18
|
+
draft.data.sqlId = cellIdFromValue;
|
|
19
|
+
delete draft.data.tableRef;
|
|
20
|
+
}
|
|
21
|
+
else if (tableRef) {
|
|
22
|
+
draft.data.tableRef = tableRef;
|
|
23
|
+
delete draft.data.sqlId;
|
|
24
|
+
}
|
|
25
|
+
}));
|
|
26
|
+
};
|
|
27
|
+
return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CellSourceSelector, { value: selectValue, onValueChange: handleDataSourceChange }), _jsx(Button, { size: "xs", variant: "secondary", className: "h-6", onClick: onEditToggle, disabled: !hasDataSource, children: _jsx(Settings, { className: "h-4 w-4" }) }), crossFilterEnabled && brushField && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { className: "flex items-center", children: _jsx(Filter, { className: `h-3.5 w-3.5 ${crossFilterPredicate ? 'text-blue-500' : 'text-gray-400'}` }) }) }), _jsx(TooltipContent, { side: "bottom", children: _jsx("p", { className: "text-xs", children: crossFilterPredicate
|
|
28
|
+
? `Filtered: ${crossFilterPredicate}`
|
|
29
|
+
: `Cross-filter on ${brushField}` }) })] }))] }));
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=VegaCellHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VegaCellHeader.js","sourceRoot":"","sources":["../../src/components/VegaCellHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAC,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAC,kBAAkB,EAAE,mBAAmB,EAAC,MAAM,YAAY,CAAC;AACnE,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AAYvC,MAAM,CAAC,MAAM,cAAc,GAAkC,CAAC,EAC5D,MAAM,EACN,WAAW,EACX,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,oBAAoB,GACrB,EAAE,EAAE;IACH,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAE5D,MAAM,sBAAsB,GAAG,CAAC,KAAa,EAAE,EAAE;QAC/C,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CACvB,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC1B,OAAO;YACT,CAAC;YAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAE5C,IAAI,eAAe,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC;gBACnC,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC7B,CAAC;iBAAM,IAAI,QAAQ,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBAC/B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,kBAAkB,IACjB,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,sBAAsB,GACrC,EACF,KAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,OAAO,EAAC,WAAW,EACnB,SAAS,EAAC,KAAK,EACf,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,CAAC,aAAa,YAExB,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,GAAG,GACzB,EACR,kBAAkB,IAAI,UAAU,IAAI,CACnC,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,cAAK,SAAS,EAAC,mBAAmB,YAChC,KAAC,MAAM,IACL,SAAS,EAAE,eAAe,oBAAoB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,EAAE,GACpF,GACE,GACS,EACjB,KAAC,cAAc,IAAC,IAAI,EAAC,QAAQ,YAC3B,YAAG,SAAS,EAAC,SAAS,YACnB,oBAAoB;gCACnB,CAAC,CAAC,aAAa,oBAAoB,EAAE;gCACrC,CAAC,CAAC,mBAAmB,UAAU,EAAE,GACjC,GACW,IACT,CACX,IACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {Button, Tooltip, TooltipContent, TooltipTrigger} from '@sqlrooms/ui';\nimport {produce} from 'immer';\nimport {Filter, Settings} from 'lucide-react';\nimport {fromDataSourceCell, fromDataSourceTable} from '../helpers';\nimport {CellSourceSelector} from './CellSourceSelector';\nimport {useCellsStore} from '../hooks';\n\nexport type VegaCellHeaderProps = {\n cellId: string;\n selectValue: string | undefined;\n onEditToggle: () => void;\n hasDataSource: boolean;\n crossFilterEnabled: boolean;\n brushField: string | undefined;\n crossFilterPredicate: string | null;\n};\n\nexport const VegaCellHeader: React.FC<VegaCellHeaderProps> = ({\n cellId,\n selectValue,\n onEditToggle,\n hasDataSource,\n crossFilterEnabled,\n brushField,\n crossFilterPredicate,\n}) => {\n const updateCell = useCellsStore((s) => s.cells.updateCell);\n\n const handleDataSourceChange = (value: string) => {\n updateCell(cellId, (c) =>\n produce(c, (draft) => {\n if (draft.type !== 'vega') {\n return;\n }\n\n const cellIdFromValue = fromDataSourceCell(value);\n const tableRef = fromDataSourceTable(value);\n\n if (cellIdFromValue) {\n draft.data.sqlId = cellIdFromValue;\n delete draft.data.tableRef;\n } else if (tableRef) {\n draft.data.tableRef = tableRef;\n delete draft.data.sqlId;\n }\n }),\n );\n };\n\n return (\n <div className=\"flex items-center gap-2\">\n <CellSourceSelector\n value={selectValue}\n onValueChange={handleDataSourceChange}\n />\n <Button\n size=\"xs\"\n variant=\"secondary\"\n className=\"h-6\"\n onClick={onEditToggle}\n disabled={!hasDataSource}\n >\n <Settings className=\"h-4 w-4\" />\n </Button>\n {crossFilterEnabled && brushField && (\n <Tooltip>\n <TooltipTrigger asChild>\n <div className=\"flex items-center\">\n <Filter\n className={`h-3.5 w-3.5 ${crossFilterPredicate ? 'text-blue-500' : 'text-gray-400'}`}\n />\n </div>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">\n <p className=\"text-xs\">\n {crossFilterPredicate\n ? `Filtered: ${crossFilterPredicate}`\n : `Cross-filter on ${brushField}`}\n </p>\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n );\n};\n"]}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { BrushFieldType } from '../types';
|
|
2
3
|
export declare const VegaConfigPanel: React.FC<{
|
|
3
4
|
spec: any;
|
|
4
5
|
sqlQuery: string;
|
|
5
6
|
lastRunTime?: number;
|
|
7
|
+
crossFilterEnabled: boolean;
|
|
6
8
|
onSpecChange: (spec: any) => void;
|
|
9
|
+
onCrossFilterToggle: (enabled: boolean) => void;
|
|
10
|
+
onBrushFieldChange: (field: string | undefined) => void;
|
|
11
|
+
onBrushFieldTypeChange: (fieldType: BrushFieldType | undefined) => void;
|
|
7
12
|
}>;
|
|
8
13
|
//# sourceMappingURL=VegaConfigPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VegaConfigPanel.d.ts","sourceRoot":"","sources":["../../src/components/VegaConfigPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"VegaConfigPanel.d.ts","sourceRoot":"","sources":["../../src/components/VegaConfigPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,UAAU,CAAC;AAW7C,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,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAClC,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACxD,sBAAsB,EAAE,CAAC,SAAS,EAAE,cAAc,GAAG,SAAS,KAAK,IAAI,CAAC;CACzE,CAyJA,CAAC"}
|
|
@@ -1,72 +1,62 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger, Label, Separator, Switch, } from '@sqlrooms/ui';
|
|
3
3
|
import { useSql } from '@sqlrooms/duckdb';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{ value: '#00A972', label: 'Green' },
|
|
12
|
-
{ value: '#85b6b2', label: 'Teal' },
|
|
13
|
-
{ value: '#919191', label: 'Gray' },
|
|
14
|
-
];
|
|
15
|
-
const aggregationOptions = [
|
|
16
|
-
{ value: 'sum', label: 'Sum' },
|
|
17
|
-
{ value: 'mean', label: 'Mean' },
|
|
18
|
-
{ value: 'count', label: 'Count' },
|
|
19
|
-
];
|
|
20
|
-
export const VegaConfigPanel = ({ sqlQuery, lastRunTime, spec, onSpecChange }) => {
|
|
4
|
+
import { getArrowColumnTypeCategory } from '@sqlrooms/duckdb';
|
|
5
|
+
import { readSpecValues, buildCrossFilterSpec, buildFlatSpec, } from '../vegaSpecBuilder';
|
|
6
|
+
import { FieldSelector } from './FieldSelector';
|
|
7
|
+
import { ColorSelector, colorOptions } from './ColorSelector';
|
|
8
|
+
import { ChartTypeSelector } from './ChartTypeSelector';
|
|
9
|
+
import { AggregationSelector } from './AggregationSelector';
|
|
10
|
+
export const VegaConfigPanel = ({ sqlQuery, lastRunTime, spec, crossFilterEnabled, onSpecChange, onCrossFilterToggle, onBrushFieldChange, onBrushFieldTypeChange, }) => {
|
|
21
11
|
const result = useSql({ query: sqlQuery, version: lastRunTime });
|
|
22
12
|
const arrowTable = result.data?.arrowTable;
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
13
|
+
const fields = arrowTable?.schema?.fields || [];
|
|
14
|
+
const detectBrushFieldType = (fieldName) => {
|
|
15
|
+
const arrowField = arrowTable?.schema?.fields?.find((field) => field.name === fieldName);
|
|
16
|
+
if (!arrowField) {
|
|
17
|
+
return 'numeric';
|
|
18
|
+
}
|
|
19
|
+
const category = getArrowColumnTypeCategory(arrowField.type);
|
|
20
|
+
if (category === 'datetime')
|
|
21
|
+
return 'temporal';
|
|
22
|
+
if (category === 'string')
|
|
23
|
+
return 'string';
|
|
24
|
+
return 'numeric';
|
|
29
25
|
};
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
const current = readSpecValues(spec);
|
|
27
|
+
const rebuild = (overrides, cfEnabled = crossFilterEnabled) => {
|
|
28
|
+
const merged = { ...current, ...overrides };
|
|
29
|
+
const builder = cfEnabled ? buildCrossFilterSpec : buildFlatSpec;
|
|
30
|
+
onSpecChange(builder({
|
|
31
|
+
mark: merged.mark ?? 'bar',
|
|
32
|
+
xField: merged.xField,
|
|
33
|
+
xFieldType: merged.xField
|
|
34
|
+
? detectBrushFieldType(merged.xField)
|
|
35
|
+
: undefined,
|
|
36
|
+
yField: merged.yField,
|
|
37
|
+
yAggregate: merged.yAggregate,
|
|
38
|
+
color: merged.color ?? colorOptions[0]?.value,
|
|
39
|
+
}));
|
|
40
|
+
if ('xField' in overrides) {
|
|
41
|
+
onBrushFieldChange(cfEnabled ? overrides.xField : undefined);
|
|
42
|
+
onBrushFieldTypeChange(cfEnabled && overrides.xField
|
|
43
|
+
? detectBrushFieldType(overrides.xField)
|
|
44
|
+
: undefined);
|
|
45
|
+
}
|
|
38
46
|
};
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const handleMarkChange = (mark) => rebuild({ mark });
|
|
48
|
+
const handleXFieldChange = (field) => rebuild({ xField: field });
|
|
49
|
+
const handleYFieldChange = (field) => rebuild({ yField: field, yAggregate: current.yAggregate ?? 'sum' });
|
|
50
|
+
const handleYAggregationChange = (aggregate) => rebuild({ yAggregate: aggregate });
|
|
51
|
+
const handleColorChange = (color) => rebuild({ color });
|
|
52
|
+
const handleCrossFilterToggle = (enabled) => {
|
|
53
|
+
onCrossFilterToggle(enabled);
|
|
54
|
+
rebuild({}, enabled);
|
|
55
|
+
onBrushFieldChange(enabled ? current.xField : undefined);
|
|
56
|
+
onBrushFieldTypeChange(enabled && current.xField
|
|
57
|
+
? detectBrushFieldType(current.xField)
|
|
58
|
+
: undefined);
|
|
51
59
|
};
|
|
52
|
-
|
|
53
|
-
onSpecChange({
|
|
54
|
-
...spec,
|
|
55
|
-
encoding: {
|
|
56
|
-
...spec?.encoding,
|
|
57
|
-
y: { ...spec?.encoding?.y, aggregate },
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
const handleColorChange = (color) => {
|
|
62
|
-
onSpecChange({
|
|
63
|
-
...spec,
|
|
64
|
-
encoding: {
|
|
65
|
-
...spec?.encoding,
|
|
66
|
-
color: { value: color },
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
};
|
|
70
|
-
return (_jsx("div", { className: "w-80 border-r p-4 text-xs", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "text-xs font-medium text-gray-400", children: "Type" }), _jsxs(Select, { value: spec?.mark, onValueChange: handleMarkChange, children: [_jsx(SelectTrigger, { className: "h-8 text-xs", children: _jsx(SelectValue, { placeholder: "Select chart type" }) }), _jsx(SelectContent, { onCloseAutoFocus: (e) => e.preventDefault(), children: markOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] }), _jsx(Separator, {}), _jsxs(Tabs, { defaultValue: "general", className: "w-full", children: [_jsxs(TabsList, { className: "grid w-full grid-cols-2", children: [_jsx(TabsTrigger, { value: "general", className: "text-xs", children: "General" }), _jsx(TabsTrigger, { value: "styles", className: "text-xs", children: "Styles" })] }), _jsxs(TabsContent, { value: "general", className: "mt-4 space-y-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs font-medium text-gray-400", children: "X-Axis" }), _jsxs(Select, { value: spec?.encoding?.x?.field || '', onValueChange: handleXFieldChange, children: [_jsx(SelectTrigger, { className: "h-8 text-xs", children: _jsx(SelectValue, { placeholder: "Select field" }) }), _jsx(SelectContent, { onCloseAutoFocus: (e) => e.preventDefault(), children: fieldNames.map((field) => (_jsx(SelectItem, { value: field, children: field }, field))) })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs font-medium text-gray-400", children: "Y-Axis" }), _jsxs("div", { className: "grid grid-cols-[2fr_1fr] gap-2", children: [_jsxs(Select, { value: spec?.encoding?.y?.field || '', onValueChange: handleYFieldChange, children: [_jsx(SelectTrigger, { className: "h-8 text-xs", children: _jsx(SelectValue, { placeholder: "Select field" }) }), _jsx(SelectContent, { onCloseAutoFocus: (e) => e.preventDefault(), children: fieldNames.map((field) => (_jsx(SelectItem, { value: field, children: field }, field))) })] }), _jsxs(Select, { value: spec?.encoding?.y?.aggregate, onValueChange: handleYAggregationChange, children: [_jsx(SelectTrigger, { className: "h-8 text-xs", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { onCloseAutoFocus: (e) => e.preventDefault(), children: aggregationOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] })] })] }), _jsx(TabsContent, { value: "styles", className: "mt-4 space-y-4", children: _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "font-medium", children: "Color" }), _jsxs(Select, { value: spec?.encoding?.color?.value, onValueChange: handleColorChange, children: [_jsx(SelectTrigger, { className: "h-8 text-xs", children: _jsx(SelectValue, { placeholder: "Select color" }) }), _jsx(SelectContent, { onCloseAutoFocus: (e) => e.preventDefault(), children: colorOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] }) })] })] }) }));
|
|
60
|
+
return (_jsx("div", { className: "w-80 border-r p-4 text-xs", children: _jsxs("div", { className: "space-y-3", children: [_jsx(ChartTypeSelector, { value: current.mark, onValueChange: handleMarkChange }), _jsx(Separator, {}), _jsxs(Tabs, { defaultValue: "general", className: "w-full", children: [_jsxs(TabsList, { className: "grid w-full grid-cols-2", children: [_jsx(TabsTrigger, { value: "general", className: "text-xs", children: "General" }), _jsx(TabsTrigger, { value: "styles", className: "text-xs", children: "Styles" })] }), _jsxs(TabsContent, { value: "general", className: "mt-4 space-y-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs font-medium text-gray-400", children: "X-Axis" }), _jsx(FieldSelector, { value: current.xField, fields: fields, onValueChange: handleXFieldChange })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs font-medium text-gray-400", children: "Y-Axis" }), _jsxs("div", { className: "grid grid-cols-[2fr_1fr] gap-2", children: [_jsx(FieldSelector, { value: current.yField, fields: fields, onValueChange: handleYFieldChange }), _jsx(AggregationSelector, { value: current.yAggregate, onValueChange: handleYAggregationChange })] })] }), _jsx(Separator, {}), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs font-medium text-gray-400", children: "Cross-filter" }), _jsx(Switch, { checked: crossFilterEnabled, onCheckedChange: handleCrossFilterToggle })] })] }), _jsx(TabsContent, { value: "styles", className: "mt-4 space-y-4", children: _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs font-medium text-gray-400", children: "Color" }), _jsx(ColorSelector, { value: current.color, onValueChange: handleColorChange })] }) })] })] }) }));
|
|
71
61
|
};
|
|
72
62
|
//# sourceMappingURL=VegaConfigPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VegaConfigPanel.js","sourceRoot":"","sources":["../../src/components/VegaConfigPanel.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Label,\n Separator,\n} from '@sqlrooms/ui';\nimport {useSql} from '@sqlrooms/duckdb';\n\nconst markOptions = [\n {value: 'bar', label: 'Bar'},\n {value: 'line', label: 'Line'},\n];\n\nconst colorOptions = [\n {value: '#077A9D', label: 'Blue'},\n {value: '#FFAB00', label: 'Orange'},\n {value: '#00A972', label: 'Green'},\n {value: '#85b6b2', label: 'Teal'},\n {value: '#919191', label: 'Gray'},\n];\n\nconst aggregationOptions = [\n {value: 'sum', label: 'Sum'},\n {value: 'mean', label: 'Mean'},\n {value: 'count', label: 'Count'},\n];\n\nexport const VegaConfigPanel: React.FC<{\n spec: any;\n sqlQuery: string;\n lastRunTime?: number;\n onSpecChange: (spec: any) => void;\n}> = ({sqlQuery, lastRunTime, spec, onSpecChange}) => {\n const result = useSql({query: sqlQuery, version: lastRunTime});\n const arrowTable = result.data?.arrowTable;\n const fieldNames =\n arrowTable?.schema?.fields?.map((field: any) => field.name) || [];\n\n const handleMarkChange = (mark: string) => {\n onSpecChange({\n ...spec,\n mark,\n });\n };\n\n const handleXFieldChange = (field: string) => {\n onSpecChange({\n ...spec,\n encoding: {\n ...spec?.encoding,\n x: {...spec?.encoding?.x, field},\n },\n });\n };\n\n const handleYFieldChange = (field: string) => {\n onSpecChange({\n ...spec,\n encoding: {\n ...spec?.encoding,\n y: {\n ...spec?.encoding?.y,\n field,\n aggregate: spec?.encoding?.y?.aggregate ?? 'sum',\n },\n },\n });\n };\n\n const handleYAggregationChange = (aggregate: string) => {\n onSpecChange({\n ...spec,\n encoding: {\n ...spec?.encoding,\n y: {...spec?.encoding?.y, aggregate},\n },\n });\n };\n\n const handleColorChange = (color: string) => {\n onSpecChange({\n ...spec,\n encoding: {\n ...spec?.encoding,\n color: {value: color},\n },\n });\n };\n\n return (\n <div className=\"w-80 border-r p-4 text-xs\">\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-xs font-medium text-gray-400\">Type</Label>\n <Select value={spec?.mark} onValueChange={handleMarkChange}>\n <SelectTrigger className=\"h-8 text-xs\">\n <SelectValue placeholder=\"Select chart type\" />\n </SelectTrigger>\n <SelectContent onCloseAutoFocus={(e) => e.preventDefault()}>\n {markOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <Separator />\n\n <Tabs defaultValue=\"general\" className=\"w-full\">\n <TabsList className=\"grid w-full grid-cols-2\">\n <TabsTrigger value=\"general\" className=\"text-xs\">\n General\n </TabsTrigger>\n <TabsTrigger value=\"styles\" className=\"text-xs\">\n Styles\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"general\" className=\"mt-4 space-y-4\">\n <div className=\"space-y-1\">\n <Label className=\"text-xs font-medium text-gray-400\">\n X-Axis\n </Label>\n <Select\n value={spec?.encoding?.x?.field || ''}\n onValueChange={handleXFieldChange}\n >\n <SelectTrigger className=\"h-8 text-xs\">\n <SelectValue placeholder=\"Select field\" />\n </SelectTrigger>\n <SelectContent onCloseAutoFocus={(e) => e.preventDefault()}>\n {fieldNames.map((field: string) => (\n <SelectItem key={field} value={field}>\n {field}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1\">\n <Label className=\"text-xs font-medium text-gray-400\">\n Y-Axis\n </Label>\n <div className=\"grid grid-cols-[2fr_1fr] gap-2\">\n <Select\n value={spec?.encoding?.y?.field || ''}\n onValueChange={handleYFieldChange}\n >\n <SelectTrigger className=\"h-8 text-xs\">\n <SelectValue placeholder=\"Select field\" />\n </SelectTrigger>\n <SelectContent onCloseAutoFocus={(e) => e.preventDefault()}>\n {fieldNames.map((field: string) => (\n <SelectItem key={field} value={field}>\n {field}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n <Select\n value={spec?.encoding?.y?.aggregate}\n onValueChange={handleYAggregationChange}\n >\n <SelectTrigger className=\"h-8 text-xs\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent onCloseAutoFocus={(e) => e.preventDefault()}>\n {aggregationOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n </TabsContent>\n\n <TabsContent value=\"styles\" className=\"mt-4 space-y-4\">\n <div className=\"space-y-1\">\n <Label className=\"font-medium\">Color</Label>\n <Select\n value={spec?.encoding?.color?.value}\n onValueChange={handleColorChange}\n >\n <SelectTrigger className=\"h-8 text-xs\">\n <SelectValue placeholder=\"Select color\" />\n </SelectTrigger>\n <SelectContent onCloseAutoFocus={(e) => e.preventDefault()}>\n {colorOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </TabsContent>\n </Tabs>\n </div>\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"VegaConfigPanel.js","sourceRoot":"","sources":["../../src/components/VegaConfigPanel.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport {\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Label,\n Separator,\n Switch,\n} from '@sqlrooms/ui';\nimport {useSql} from '@sqlrooms/duckdb';\nimport {getArrowColumnTypeCategory} from '@sqlrooms/duckdb';\nimport type {BrushFieldType} from '../types';\nimport {\n readSpecValues,\n buildCrossFilterSpec,\n buildFlatSpec,\n} from '../vegaSpecBuilder';\nimport {FieldSelector} from './FieldSelector';\nimport {ColorSelector, colorOptions} from './ColorSelector';\nimport {ChartTypeSelector} from './ChartTypeSelector';\nimport {AggregationSelector} from './AggregationSelector';\n\nexport const VegaConfigPanel: React.FC<{\n spec: any;\n sqlQuery: string;\n lastRunTime?: number;\n crossFilterEnabled: boolean;\n onSpecChange: (spec: any) => void;\n onCrossFilterToggle: (enabled: boolean) => void;\n onBrushFieldChange: (field: string | undefined) => void;\n onBrushFieldTypeChange: (fieldType: BrushFieldType | undefined) => void;\n}> = ({\n sqlQuery,\n lastRunTime,\n spec,\n crossFilterEnabled,\n onSpecChange,\n onCrossFilterToggle,\n onBrushFieldChange,\n onBrushFieldTypeChange,\n}) => {\n const result = useSql({query: sqlQuery, version: lastRunTime});\n const arrowTable = result.data?.arrowTable;\n const fields = arrowTable?.schema?.fields || [];\n\n const detectBrushFieldType = (fieldName: string): BrushFieldType => {\n const arrowField = arrowTable?.schema?.fields?.find(\n (field) => field.name === fieldName,\n );\n\n if (!arrowField) {\n return 'numeric';\n }\n\n const category = getArrowColumnTypeCategory(arrowField.type);\n if (category === 'datetime') return 'temporal';\n if (category === 'string') return 'string';\n return 'numeric';\n };\n\n const current = readSpecValues(spec);\n\n const rebuild = (\n overrides: Partial<ReturnType<typeof readSpecValues>>,\n cfEnabled = crossFilterEnabled,\n ) => {\n const merged = {...current, ...overrides};\n const builder = cfEnabled ? buildCrossFilterSpec : buildFlatSpec;\n onSpecChange(\n builder({\n mark: merged.mark ?? 'bar',\n xField: merged.xField,\n xFieldType: merged.xField\n ? detectBrushFieldType(merged.xField)\n : undefined,\n yField: merged.yField,\n yAggregate: merged.yAggregate,\n color: merged.color ?? colorOptions[0]?.value,\n }),\n );\n if ('xField' in overrides) {\n onBrushFieldChange(cfEnabled ? overrides.xField : undefined);\n onBrushFieldTypeChange(\n cfEnabled && overrides.xField\n ? detectBrushFieldType(overrides.xField)\n : undefined,\n );\n }\n };\n\n const handleMarkChange = (mark: string) => rebuild({mark});\n const handleXFieldChange = (field: string) => rebuild({xField: field});\n const handleYFieldChange = (field: string) =>\n rebuild({yField: field, yAggregate: current.yAggregate ?? 'sum'});\n const handleYAggregationChange = (aggregate: string) =>\n rebuild({yAggregate: aggregate});\n const handleColorChange = (color: string) => rebuild({color});\n\n const handleCrossFilterToggle = (enabled: boolean) => {\n onCrossFilterToggle(enabled);\n rebuild({}, enabled);\n onBrushFieldChange(enabled ? current.xField : undefined);\n onBrushFieldTypeChange(\n enabled && current.xField\n ? detectBrushFieldType(current.xField)\n : undefined,\n );\n };\n\n return (\n <div className=\"w-80 border-r p-4 text-xs\">\n <div className=\"space-y-3\">\n <ChartTypeSelector\n value={current.mark}\n onValueChange={handleMarkChange}\n />\n\n <Separator />\n\n <Tabs defaultValue=\"general\" className=\"w-full\">\n <TabsList className=\"grid w-full grid-cols-2\">\n <TabsTrigger value=\"general\" className=\"text-xs\">\n General\n </TabsTrigger>\n <TabsTrigger value=\"styles\" className=\"text-xs\">\n Styles\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"general\" className=\"mt-4 space-y-4\">\n <div className=\"space-y-1\">\n <Label className=\"text-xs font-medium text-gray-400\">\n X-Axis\n </Label>\n <FieldSelector\n value={current.xField}\n fields={fields}\n onValueChange={handleXFieldChange}\n />\n </div>\n <div className=\"space-y-1\">\n <Label className=\"text-xs font-medium text-gray-400\">\n Y-Axis\n </Label>\n <div className=\"grid grid-cols-[2fr_1fr] gap-2\">\n <FieldSelector\n value={current.yField}\n fields={fields}\n onValueChange={handleYFieldChange}\n />\n\n <AggregationSelector\n value={current.yAggregate}\n onValueChange={handleYAggregationChange}\n />\n </div>\n </div>\n\n <Separator />\n\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-xs font-medium text-gray-400\">\n Cross-filter\n </Label>\n <Switch\n checked={crossFilterEnabled}\n onCheckedChange={handleCrossFilterToggle}\n />\n </div>\n </TabsContent>\n\n <TabsContent value=\"styles\" className=\"mt-4 space-y-4\">\n <div className=\"space-y-1\">\n <Label className=\"text-xs font-medium text-gray-400\">Color</Label>\n <ColorSelector\n value={current.color}\n onValueChange={handleColorChange}\n />\n </div>\n </TabsContent>\n </Tabs>\n </div>\n </div>\n );\n};\n"]}
|
package/dist/crdt.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { CrdtMirror } from '@sqlrooms/crdt';
|
|
2
|
+
import { type CellsSliceState } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Mirror schema for syncing the `@sqlrooms/cells` slice via `@sqlrooms/crdt`.
|
|
5
|
+
*
|
|
6
|
+
* Syncs: data (cells), sheets, sheetOrder, edges
|
|
7
|
+
* Keeps local: status, currentSheetId, abortControllers
|
|
8
|
+
*/
|
|
9
|
+
export declare const cellsMirrorSchema: import("loro-mirror").LoroMapSchema<{
|
|
10
|
+
config: import("loro-mirror").LoroMapSchema<{
|
|
11
|
+
data: /*elided*/ any;
|
|
12
|
+
sheets: /*elided*/ any;
|
|
13
|
+
sheetOrder: /*elided*/ any;
|
|
14
|
+
}> & {
|
|
15
|
+
options: {};
|
|
16
|
+
} & {
|
|
17
|
+
catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
|
|
18
|
+
data: /*elided*/ any;
|
|
19
|
+
sheets: /*elided*/ any;
|
|
20
|
+
sheetOrder: /*elided*/ any;
|
|
21
|
+
}, C>;
|
|
22
|
+
};
|
|
23
|
+
}> & {
|
|
24
|
+
options: {};
|
|
25
|
+
} & {
|
|
26
|
+
catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
|
|
27
|
+
config: import("loro-mirror").LoroMapSchema<{
|
|
28
|
+
data: /*elided*/ any;
|
|
29
|
+
sheets: /*elided*/ any;
|
|
30
|
+
sheetOrder: /*elided*/ any;
|
|
31
|
+
}> & {
|
|
32
|
+
options: {};
|
|
33
|
+
} & {
|
|
34
|
+
catchall: <C_1 extends import("loro-mirror").SchemaType>(catchallSchema: C_1) => import("loro-mirror").LoroMapSchemaWithCatchall<{
|
|
35
|
+
data: /*elided*/ any;
|
|
36
|
+
sheets: /*elided*/ any;
|
|
37
|
+
sheetOrder: /*elided*/ any;
|
|
38
|
+
}, C_1>;
|
|
39
|
+
};
|
|
40
|
+
}, C>;
|
|
41
|
+
};
|
|
42
|
+
export type CellsMirrorSchema = typeof cellsMirrorSchema;
|
|
43
|
+
/**
|
|
44
|
+
* Default initial mirror state for the cells CRDT schema.
|
|
45
|
+
*/
|
|
46
|
+
export declare const cellsMirrorInitialState: {
|
|
47
|
+
config: {
|
|
48
|
+
data: never[];
|
|
49
|
+
sheets: never[];
|
|
50
|
+
sheetOrder: never[];
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Creates a CRDT mirror bundle for the cells slice.
|
|
55
|
+
*/
|
|
56
|
+
export declare function createCellsCrdtMirror<S extends CellsSliceState = CellsSliceState>(): CrdtMirror<S, typeof cellsMirrorSchema>;
|
|
57
|
+
/**
|
|
58
|
+
* @deprecated Use `createCellsCrdtMirror` instead.
|
|
59
|
+
*/
|
|
60
|
+
export declare const createCellsCrdtModule: typeof createCellsCrdtMirror;
|
|
61
|
+
//# sourceMappingURL=crdt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crdt.d.ts","sourceRoot":"","sources":["../src/crdt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAmB,KAAK,eAAe,EAAC,MAAM,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B5B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,OAAO,iBAAiB,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;CAMnC,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,eAAe,GAAG,eAAe,KACxC,UAAU,CAAC,CAAC,EAAE,OAAO,iBAAiB,CAAC,CAoD3C;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,8BAAwB,CAAC"}
|
package/dist/crdt.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { schema } from 'loro-mirror';
|
|
2
|
+
import { CellsSliceConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Mirror schema for syncing the `@sqlrooms/cells` slice via `@sqlrooms/crdt`.
|
|
5
|
+
*
|
|
6
|
+
* Syncs: data (cells), sheets, sheetOrder, edges
|
|
7
|
+
* Keeps local: status, currentSheetId, abortControllers
|
|
8
|
+
*/
|
|
9
|
+
export const cellsMirrorSchema = schema.LoroMap({
|
|
10
|
+
config: schema.LoroMap({
|
|
11
|
+
data: schema.LoroList(schema.LoroMap({
|
|
12
|
+
id: schema.String(),
|
|
13
|
+
type: schema.String(),
|
|
14
|
+
data: schema.Any(), // Cell-specific data varies by type
|
|
15
|
+
}), (cell) => cell.id),
|
|
16
|
+
sheets: schema.LoroList(schema.LoroMap({
|
|
17
|
+
id: schema.String(),
|
|
18
|
+
type: schema.String(),
|
|
19
|
+
title: schema.String(),
|
|
20
|
+
cellIds: schema.LoroList(schema.String()),
|
|
21
|
+
edges: schema.LoroList(schema.LoroMap({
|
|
22
|
+
id: schema.String(),
|
|
23
|
+
source: schema.String(),
|
|
24
|
+
target: schema.String(),
|
|
25
|
+
}), (edge) => edge.id),
|
|
26
|
+
}), (sheet) => sheet.id),
|
|
27
|
+
sheetOrder: schema.LoroList(schema.String()),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Default initial mirror state for the cells CRDT schema.
|
|
32
|
+
*/
|
|
33
|
+
export const cellsMirrorInitialState = {
|
|
34
|
+
config: {
|
|
35
|
+
data: [],
|
|
36
|
+
sheets: [],
|
|
37
|
+
sheetOrder: [],
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Creates a CRDT mirror bundle for the cells slice.
|
|
42
|
+
*/
|
|
43
|
+
export function createCellsCrdtMirror() {
|
|
44
|
+
return {
|
|
45
|
+
schema: cellsMirrorSchema,
|
|
46
|
+
initialState: cellsMirrorInitialState,
|
|
47
|
+
select: (state) => ({
|
|
48
|
+
config: {
|
|
49
|
+
data: Object.values(state.cells.config.data),
|
|
50
|
+
sheets: Object.values(state.cells.config.sheets).map((sheet) => ({
|
|
51
|
+
...sheet,
|
|
52
|
+
edges: sheet.edges || [],
|
|
53
|
+
})),
|
|
54
|
+
sheetOrder: state.cells.config.sheetOrder,
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
apply: (value, set, get) => {
|
|
58
|
+
if (!value?.config)
|
|
59
|
+
return;
|
|
60
|
+
const configValue = value.config;
|
|
61
|
+
const newData = Object.fromEntries((configValue.data || []).map((c) => [c.id, c]));
|
|
62
|
+
const newSheets = Object.fromEntries((configValue.sheets || []).map((s) => [s.id, s]));
|
|
63
|
+
set((state) => ({
|
|
64
|
+
...state,
|
|
65
|
+
cells: {
|
|
66
|
+
...state.cells,
|
|
67
|
+
config: CellsSliceConfig.parse({
|
|
68
|
+
...state.cells.config,
|
|
69
|
+
data: newData,
|
|
70
|
+
sheets: newSheets,
|
|
71
|
+
sheetOrder: configValue.sheetOrder,
|
|
72
|
+
}),
|
|
73
|
+
},
|
|
74
|
+
}));
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @deprecated Use `createCellsCrdtMirror` instead.
|
|
80
|
+
*/
|
|
81
|
+
export const createCellsCrdtModule = createCellsCrdtMirror;
|
|
82
|
+
//# sourceMappingURL=crdt.js.map
|