@sqlrooms/pivot 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.
Files changed (66) hide show
  1. package/README.md +3 -0
  2. package/dist/PivotCellContent.d.ts +10 -0
  3. package/dist/PivotCellContent.d.ts.map +1 -0
  4. package/dist/PivotCellContent.js +37 -0
  5. package/dist/PivotCellContent.js.map +1 -0
  6. package/dist/PivotCoreSlice.d.ts +73 -0
  7. package/dist/PivotCoreSlice.d.ts.map +1 -0
  8. package/dist/PivotCoreSlice.js +175 -0
  9. package/dist/PivotCoreSlice.js.map +1 -0
  10. package/dist/PivotEditor.d.ts +66 -0
  11. package/dist/PivotEditor.d.ts.map +1 -0
  12. package/dist/PivotEditor.js +341 -0
  13. package/dist/PivotEditor.js.map +1 -0
  14. package/dist/PivotResults.d.ts +15 -0
  15. package/dist/PivotResults.d.ts.map +1 -0
  16. package/dist/PivotResults.js +102 -0
  17. package/dist/PivotResults.js.map +1 -0
  18. package/dist/PivotSlice.d.ts +7 -0
  19. package/dist/PivotSlice.d.ts.map +1 -0
  20. package/dist/PivotSlice.js +353 -0
  21. package/dist/PivotSlice.js.map +1 -0
  22. package/dist/PivotView.d.ts +3 -0
  23. package/dist/PivotView.d.ts.map +1 -0
  24. package/dist/PivotView.js +39 -0
  25. package/dist/PivotView.js.map +1 -0
  26. package/dist/TableRenderer.d.ts +14 -0
  27. package/dist/TableRenderer.d.ts.map +1 -0
  28. package/dist/TableRenderer.js +100 -0
  29. package/dist/TableRenderer.js.map +1 -0
  30. package/dist/TsvRenderer.d.ts +7 -0
  31. package/dist/TsvRenderer.d.ts.map +1 -0
  32. package/dist/TsvRenderer.js +26 -0
  33. package/dist/TsvRenderer.js.map +1 -0
  34. package/dist/aggregators.d.ts +24 -0
  35. package/dist/aggregators.d.ts.map +1 -0
  36. package/dist/aggregators.js +232 -0
  37. package/dist/aggregators.js.map +1 -0
  38. package/dist/helpers.d.ts +85 -0
  39. package/dist/helpers.d.ts.map +1 -0
  40. package/dist/helpers.js +348 -0
  41. package/dist/helpers.js.map +1 -0
  42. package/dist/index.d.ts +20 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +17 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/pivotCellRegistryEntry.d.ts +4 -0
  47. package/dist/pivotCellRegistryEntry.d.ts.map +1 -0
  48. package/dist/pivotCellRegistryEntry.js +137 -0
  49. package/dist/pivotCellRegistryEntry.js.map +1 -0
  50. package/dist/pivotCellTypes.d.ts +23 -0
  51. package/dist/pivotCellTypes.d.ts.map +1 -0
  52. package/dist/pivotCellTypes.js +14 -0
  53. package/dist/pivotCellTypes.js.map +1 -0
  54. package/dist/pivotExecution.d.ts +16 -0
  55. package/dist/pivotExecution.d.ts.map +1 -0
  56. package/dist/pivotExecution.js +49 -0
  57. package/dist/pivotExecution.js.map +1 -0
  58. package/dist/sql.d.ts +17 -0
  59. package/dist/sql.d.ts.map +1 -0
  60. package/dist/sql.js +278 -0
  61. package/dist/sql.js.map +1 -0
  62. package/dist/types.d.ts +513 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +107 -0
  65. package/dist/types.js.map +1 -0
  66. package/package.json +58 -0
@@ -0,0 +1,341 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { DndContext, DragOverlay, PointerSensor, closestCenter, useDroppable, useSensor, useSensors, } from '@dnd-kit/core';
3
+ import { SortableContext, rectSortingStrategy, useSortable, } from '@dnd-kit/sortable';
4
+ import { arrowTableToJson, useSql } from '@sqlrooms/duckdb';
5
+ import { Badge, Button, Card, CardContent, CardHeader, CardTitle, Checkbox, Input, Label, Popover, PopoverContent, PopoverTrigger, ScrollArea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, cn, } from '@sqlrooms/ui';
6
+ import { ArrowDownWideNarrowIcon, ArrowUpAZIcon, ArrowUpNarrowWideIcon, Columns2Icon, FilterIcon, GripVerticalIcon, Rows3Icon, TablePropertiesIcon, } from 'lucide-react';
7
+ import React, { createContext, useContext, useEffect, useMemo, useRef, useState, } from 'react';
8
+ import { useStore } from 'zustand';
9
+ import { PIVOT_AGGREGATORS, getPivotAggregator } from './aggregators';
10
+ import { createPivotCoreStore, } from './PivotCoreSlice';
11
+ import { PivotResults } from './PivotResults';
12
+ import { buildDistinctValuesQuery } from './sql';
13
+ import { PIVOT_RENDERER_NAMES, } from './types';
14
+ const PivotEditorStoreContext = createContext(null);
15
+ function usePivotEditorStore(selector) {
16
+ const store = useContext(PivotEditorStoreContext);
17
+ if (!store) {
18
+ throw new Error('PivotEditor store context is missing');
19
+ }
20
+ return useStore(store, selector);
21
+ }
22
+ function usePivotEditorStoreApi() {
23
+ const store = useContext(PivotEditorStoreContext);
24
+ if (!store) {
25
+ throw new Error('PivotEditor store context is missing');
26
+ }
27
+ return store;
28
+ }
29
+ const CONTAINER_ID_PREFIX = 'pivot-container:';
30
+ const numericTypePattern = /INT|DECIMAL|FLOAT|DOUBLE|REAL|HUGEINT|BIGINT/i;
31
+ const EMPTY_FILTER_VALUES = Object.freeze({});
32
+ function getContainerId(zone) {
33
+ return `${CONTAINER_ID_PREFIX}${zone}`;
34
+ }
35
+ function parseContainerId(id) {
36
+ if (!id.startsWith(CONTAINER_ID_PREFIX)) {
37
+ return null;
38
+ }
39
+ return id.replace(CONTAINER_ID_PREFIX, '');
40
+ }
41
+ function getSortIcon(order) {
42
+ switch (order) {
43
+ case 'value_a_to_z':
44
+ return ArrowDownWideNarrowIcon;
45
+ case 'value_z_to_a':
46
+ return ArrowUpNarrowWideIcon;
47
+ default:
48
+ return ArrowUpAZIcon;
49
+ }
50
+ }
51
+ function useVisibleFields() {
52
+ const fields = usePivotEditorStore((state) => state.fields);
53
+ const hiddenAttributes = usePivotEditorStore((state) => state.config.hiddenAttributes);
54
+ return useMemo(() => fields.filter((field) => !hiddenAttributes.includes(field.name)), [fields, hiddenAttributes]);
55
+ }
56
+ function useZoneFields(zone) {
57
+ const visibleFields = useVisibleFields();
58
+ const rows = usePivotEditorStore((state) => state.config.rows);
59
+ const cols = usePivotEditorStore((state) => state.config.cols);
60
+ const hiddenFromDragDrop = usePivotEditorStore((state) => state.config.hiddenFromDragDrop);
61
+ const unusedOrder = usePivotEditorStore((state) => state.config.unusedOrder);
62
+ return useMemo(() => {
63
+ if (zone === 'rows') {
64
+ return rows
65
+ .map((name) => visibleFields.find((field) => field.name === name))
66
+ .filter((field) => Boolean(field));
67
+ }
68
+ if (zone === 'cols') {
69
+ return cols
70
+ .map((name) => visibleFields.find((field) => field.name === name))
71
+ .filter((field) => Boolean(field));
72
+ }
73
+ const used = new Set([...rows, ...cols]);
74
+ const candidates = visibleFields.filter((field) => !used.has(field.name) && !hiddenFromDragDrop.includes(field.name));
75
+ const orderedNames = [
76
+ ...unusedOrder.filter((name) => candidates.some((field) => field.name === name)),
77
+ ...candidates
78
+ .map((field) => field.name)
79
+ .filter((name) => !unusedOrder.includes(name)),
80
+ ];
81
+ return orderedNames
82
+ .map((name) => candidates.find((field) => field.name === name))
83
+ .filter((field) => Boolean(field));
84
+ }, [zone, rows, cols, hiddenFromDragDrop, unusedOrder, visibleFields]);
85
+ }
86
+ function AutoRunEffect({ enabled, debounceMs, }) {
87
+ const store = usePivotEditorStoreApi();
88
+ const source = usePivotEditorStore((state) => state.source);
89
+ const config = usePivotEditorStore((state) => state.config);
90
+ const stale = usePivotEditorStore((state) => state.status.stale);
91
+ const runState = usePivotEditorStore((state) => state.status.state);
92
+ const timeoutRef = useRef(null);
93
+ useEffect(() => {
94
+ if (!enabled || !source || !stale || runState === 'running') {
95
+ return;
96
+ }
97
+ timeoutRef.current = setTimeout(() => {
98
+ void store.getState().run();
99
+ }, debounceMs);
100
+ return () => {
101
+ if (timeoutRef.current) {
102
+ clearTimeout(timeoutRef.current);
103
+ }
104
+ };
105
+ }, [config, debounceMs, enabled, runState, source, stale, store]);
106
+ return null;
107
+ }
108
+ const PivotEditorRoot = ({ store, source, config, status, querySource, fields, availableTables, callbacks, autoRun = false, autoRunDebounceMs = 300, className, children, }) => {
109
+ const [internalStore] = useState(() => store
110
+ ? null
111
+ : createPivotCoreStore({
112
+ source,
113
+ config,
114
+ status,
115
+ querySource,
116
+ fields,
117
+ availableTables,
118
+ callbacks,
119
+ }));
120
+ const resolvedStore = store ?? internalStore;
121
+ if (!resolvedStore) {
122
+ return null;
123
+ }
124
+ return (_jsxs(PivotEditorStoreContext.Provider, { value: resolvedStore, children: [_jsx(AutoRunEffect, { enabled: autoRun, debounceMs: autoRunDebounceMs }), _jsx(PivotEditorDndProvider, { className: className, children: children ?? _jsx(DefaultPivotEditorLayout, {}) })] }));
125
+ };
126
+ const PivotEditorDndProvider = ({ className, children }) => {
127
+ const moveField = usePivotEditorStore((state) => state.moveField);
128
+ const rowFields = useZoneFields('rows');
129
+ const colFields = useZoneFields('cols');
130
+ const unusedFields = useZoneFields('unused');
131
+ const sensors = useSensors(useSensor(PointerSensor, {
132
+ activationConstraint: { distance: 6 },
133
+ }));
134
+ const zoneItems = {
135
+ unused: unusedFields.map((field) => field.name),
136
+ rows: rowFields.map((field) => field.name),
137
+ cols: colFields.map((field) => field.name),
138
+ };
139
+ const [activeDragField, setActiveDragField] = useState(null);
140
+ const handleDragStart = (event) => {
141
+ setActiveDragField(String(event.active.id));
142
+ };
143
+ const handleDragEnd = (event) => {
144
+ const activeId = String(event.active.id);
145
+ const overId = event.over ? String(event.over.id) : '';
146
+ setActiveDragField(null);
147
+ if (!overId) {
148
+ return;
149
+ }
150
+ const directContainerId = parseContainerId(overId);
151
+ const sortableContainerId = parseContainerId(String(event.over?.data.current?.sortable?.containerId ?? ''));
152
+ const destination = directContainerId ??
153
+ sortableContainerId ??
154
+ Object.entries(zoneItems).find(([, items]) => items.includes(overId))?.[0];
155
+ if (!destination) {
156
+ return;
157
+ }
158
+ const index = directContainerId
159
+ ? zoneItems[destination].length
160
+ : zoneItems[destination].indexOf(overId);
161
+ moveField(activeId, destination, index);
162
+ };
163
+ return (_jsx("div", { className: cn('bg-muted/10 flex h-full flex-col gap-4 overflow-auto p-4', className), children: _jsxs(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragStart: handleDragStart, onDragEnd: handleDragEnd, onDragCancel: () => setActiveDragField(null), children: [children, _jsx(DragOverlay, { dropAnimation: null, children: activeDragField ? (_jsxs("div", { className: "bg-background flex items-center gap-1 rounded-md border px-2 py-1 text-sm shadow-md", children: [_jsx(GripVerticalIcon, { className: "text-muted-foreground h-4 w-4" }), _jsx("span", { className: "truncate", children: activeDragField })] })) : null })] }) }));
164
+ };
165
+ const PivotSourceSection = ({ children, }) => (_jsx(Card, { children: _jsx(CardContent, { className: "grid gap-4 pt-6 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto]", children: children ?? (_jsxs(_Fragment, { children: [_jsx(PivotTableSelector, {}), _jsx(PivotRendererSelector, {}), _jsx(PivotAggregatorSelector, {}), _jsx(PivotValues, {})] })) }) }));
166
+ const PivotToolbar = ({ children }) => (_jsx("div", { className: "flex items-center justify-between gap-3", children: children }));
167
+ const PivotTableSelector = () => {
168
+ const source = usePivotEditorStore((state) => state.source);
169
+ const availableTables = usePivotEditorStore((state) => state.availableTables);
170
+ const setSource = usePivotEditorStore((state) => state.setSource);
171
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Table" }), _jsxs(Select, { value: source?.kind === 'table' ? source.tableName : undefined, onValueChange: (tableName) => setSource({ kind: 'table', tableName }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Select a table" }) }), _jsx(SelectContent, { children: availableTables.map((tableName) => (_jsx(SelectItem, { value: tableName, children: tableName }, tableName))) })] })] }));
172
+ };
173
+ const PivotRunButton = () => {
174
+ const run = usePivotEditorStore((state) => state.run);
175
+ const status = usePivotEditorStore((state) => state.status);
176
+ return (_jsx(Button, { size: "sm", variant: "secondary", onClick: () => void run(), disabled: status.state === 'running', children: status.state === 'running' ? 'Running…' : 'Run' }));
177
+ };
178
+ const PivotRendererSelector = () => {
179
+ const value = usePivotEditorStore((state) => state.config.rendererName);
180
+ const setRendererName = usePivotEditorStore((state) => state.setRendererName);
181
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Renderer" }), _jsxs(Select, { value: value, onValueChange: setRendererName, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: PIVOT_RENDERER_NAMES.map((rendererName) => (_jsx(SelectItem, { value: rendererName, children: rendererName }, rendererName))) })] })] }));
182
+ };
183
+ const PivotAggregatorSelector = () => {
184
+ const value = usePivotEditorStore((state) => state.config.aggregatorName);
185
+ const setAggregatorName = usePivotEditorStore((state) => state.setAggregatorName);
186
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Aggregator" }), _jsxs(Select, { value: value, onValueChange: setAggregatorName, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: Object.keys(PIVOT_AGGREGATORS).map((aggregatorName) => (_jsx(SelectItem, { value: aggregatorName, children: aggregatorName }, aggregatorName))) })] })] }));
187
+ };
188
+ const PivotValuesSelect = ({ index }) => {
189
+ const visibleFields = useVisibleFields();
190
+ const config = usePivotEditorStore((state) => state.config);
191
+ const setVals = usePivotEditorStore((state) => state.setVals);
192
+ const aggregator = useMemo(() => getPivotAggregator(config.aggregatorName), [config.aggregatorName]);
193
+ return (_jsxs(Select, { value: config.vals[index], onValueChange: (value) => {
194
+ const nextValues = [...config.vals];
195
+ nextValues[index] = value;
196
+ setVals(nextValues.slice(0, aggregator.numInputs));
197
+ }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: `Value ${index + 1}` }) }), _jsx(SelectContent, { children: visibleFields
198
+ .filter((field) => !config.hiddenFromAggregators.includes(field.name) &&
199
+ (aggregator.valueRequirement !== 'numeric' ||
200
+ numericTypePattern.test(field.type)))
201
+ .map((field) => (_jsx(SelectItem, { value: field.name, children: field.name }, field.name))) })] }));
202
+ };
203
+ const PivotValuesBase = ({ children, }) => {
204
+ const aggregatorName = usePivotEditorStore((state) => state.config.aggregatorName);
205
+ const aggregator = useMemo(() => getPivotAggregator(aggregatorName), [aggregatorName]);
206
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Values" }), _jsxs("div", { className: "flex flex-col gap-2", children: [children ??
207
+ Array.from({ length: aggregator.numInputs }).map((_, index) => (_jsx(PivotValuesSelect, { index: index }, `value-select-${index}`))), aggregator.numInputs === 0 ? (_jsx("div", { className: "text-muted-foreground text-xs", children: "This aggregation does not require measure columns." })) : null] })] }));
208
+ };
209
+ const PivotFieldFilter = ({ field, children }) => {
210
+ const querySource = usePivotEditorStore((state) => state.querySource);
211
+ const menuLimit = usePivotEditorStore((state) => state.config.menuLimit);
212
+ const rawFilterValues = usePivotEditorStore((state) => state.config.valueFilter[field.name]);
213
+ const filterValues = rawFilterValues ?? EMPTY_FILTER_VALUES;
214
+ const setFilterValues = usePivotEditorStore((state) => state.setAttributeFilterValues);
215
+ const addFilters = usePivotEditorStore((state) => state.addAttributeFilterValues);
216
+ const removeFilters = usePivotEditorStore((state) => state.removeAttributeFilterValues);
217
+ const clearFilter = usePivotEditorStore((state) => state.clearAttributeFilter);
218
+ const [open, setOpen] = useState(false);
219
+ const [search, setSearch] = useState('');
220
+ const query = useMemo(() => querySource
221
+ ? buildDistinctValuesQuery(querySource, field.name, menuLimit)
222
+ : '', [field.name, menuLimit, querySource]);
223
+ const valuesResult = useSql({ query, enabled: open && Boolean(query) });
224
+ const valuesData = valuesResult.data;
225
+ const values = useMemo(() => valuesData?.arrowTable
226
+ ? arrowTableToJson(valuesData.arrowTable)
227
+ : [], [valuesData]);
228
+ const shownValues = values.filter((item) => String(item.value).toLowerCase().includes(search.trim().toLowerCase()));
229
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: children }), _jsx(PopoverContent, { align: "start", className: "w-80 p-3", onOpenAutoFocus: (event) => event.preventDefault(), children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: field.name }), _jsx("div", { className: "text-muted-foreground text-xs", children: "Filter values" })] }), Object.keys(filterValues).length > 0 ? (_jsxs(Badge, { variant: "secondary", children: [Object.keys(filterValues).length, " excluded"] })) : null] }), _jsx(Input, { value: search, onChange: (event) => setSearch(event.target.value), placeholder: "Search values", className: "h-8" }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { size: "xs", variant: "outline", onClick: () => removeFilters(field.name, shownValues.map((item) => String(item.value))), children: "Select shown" }), _jsx(Button, { size: "xs", variant: "outline", onClick: () => addFilters(field.name, shownValues.map((item) => String(item.value))), children: "Deselect shown" }), _jsx(Button, { size: "xs", variant: "ghost", onClick: () => clearFilter(field.name), children: "Clear" })] }), _jsx(ScrollArea, { className: "h-64 rounded-md border", children: _jsx("div", { className: "space-y-1 p-2", children: valuesResult.isLoading ? (_jsx("div", { className: "text-muted-foreground text-xs", children: "Loading values\u2026" })) : shownValues.length === 0 ? (_jsx("div", { className: "text-muted-foreground text-xs", children: "No matching values." })) : (shownValues.map((item) => {
230
+ const value = String(item.value);
231
+ const included = !(value in filterValues);
232
+ return (_jsxs("div", { className: "hover:bg-muted flex items-center justify-between gap-2 rounded-sm px-2 py-1", children: [_jsxs("label", { className: "flex min-w-0 flex-1 items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: included, onCheckedChange: (checked) => {
233
+ if (checked) {
234
+ removeFilters(field.name, [value]);
235
+ }
236
+ else {
237
+ addFilters(field.name, [value]);
238
+ }
239
+ } }), _jsx("span", { className: "truncate", children: value || 'null' }), _jsxs("span", { className: "text-muted-foreground text-xs", children: ["(", item.count, ")"] })] }), _jsx(Button, { size: "xs", variant: "ghost", onClick: () => setFilterValues(field.name, values
240
+ .map((candidate) => String(candidate.value))
241
+ .filter((candidate) => candidate !== value)), children: "only" })] }, value));
242
+ })) }) })] }) })] }));
243
+ };
244
+ const PivotFieldChip = ({ field }) => {
245
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: field.name });
246
+ const isFiltered = usePivotEditorStore((state) => Boolean(state.config.valueFilter[field.name]));
247
+ return (_jsx("div", { ref: setNodeRef, style: {
248
+ transform: transform
249
+ ? `translate3d(${transform.x}px, ${transform.y}px, 0)`
250
+ : undefined,
251
+ transition,
252
+ opacity: isDragging ? 0.5 : 1,
253
+ }, className: "max-w-full", ...attributes, children: _jsxs("div", { className: cn('bg-background flex max-w-full items-center gap-1 rounded-md border px-2 py-1 text-sm shadow-xs', isFiltered && 'border-primary text-primary'), children: [_jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground cursor-grab", ...listeners, children: _jsx(GripVerticalIcon, { className: "h-4 w-4" }) }), _jsx("span", { className: "truncate", children: field.name }), _jsx(PivotFieldFilter, { field: field, children: _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "h-6 w-6 shrink-0", children: _jsx(FilterIcon, { className: "h-3.5 w-3.5" }) }) })] }) }));
254
+ };
255
+ const PivotZone = ({ zone, title, description, framed = true }) => {
256
+ const items = useZoneFields(zone);
257
+ const { setNodeRef, isOver } = useDroppable({ id: getContainerId(zone) });
258
+ const content = (_jsxs(_Fragment, { children: [framed ? (_jsxs(CardHeader, { className: "space-y-1 pb-3", children: [_jsx(CardTitle, { className: "text-sm", children: title }), _jsx("div", { className: "text-muted-foreground text-xs", children: description })] })) : null, framed ? _jsx(CardContent, { children: renderZone() }) : renderZone()] }));
259
+ function renderZone() {
260
+ return (_jsxs("div", { ref: setNodeRef, id: getContainerId(zone), className: cn('bg-muted/30 flex min-h-20 flex-wrap items-start gap-2 rounded-md border border-dashed p-3', isOver && 'border-primary bg-primary/5'), children: [_jsx(SortableContext, { id: getContainerId(zone), items: items.map((field) => field.name), strategy: rectSortingStrategy, children: items.map((field) => (_jsx(PivotFieldChip, { field: field }, field.name))) }), items.length === 0 ? (_jsx("div", { className: "text-muted-foreground text-xs", children: "Drop fields here." })) : null] }));
261
+ }
262
+ return framed ? _jsx(Card, { children: content }) : _jsx(_Fragment, { children: content });
263
+ };
264
+ const PivotRowsHeader = () => {
265
+ const cycleRowOrder = usePivotEditorStore((state) => state.cycleRowOrder);
266
+ const rowOrder = usePivotEditorStore((state) => state.config.rowOrder);
267
+ const icon = getSortIcon(rowOrder);
268
+ return (_jsxs(CardHeader, { className: "flex flex-row items-center justify-between gap-2 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-sm", children: "Rows" }), _jsx("div", { className: "text-muted-foreground text-xs", children: "Drag fields to define row groups." })] }), _jsx(Button, { size: "icon", variant: "ghost", onClick: cycleRowOrder, children: React.createElement(icon, { className: 'h-4 w-4' }) })] }));
269
+ };
270
+ const PivotRowsZone = () => (_jsx(CardContent, { className: "pt-0", children: _jsx(PivotZone, { zone: "rows", title: "Rows", description: "Drag fields to define row groups.", framed: false }) }));
271
+ const PivotRowsBase = ({ children }) => (_jsx(Card, { children: children ?? (_jsxs(_Fragment, { children: [_jsx(PivotRowsHeader, {}), _jsx(PivotRowsZone, {})] })) }));
272
+ const PivotColumnsHeader = () => {
273
+ const cycleColOrder = usePivotEditorStore((state) => state.cycleColOrder);
274
+ const colOrder = usePivotEditorStore((state) => state.config.colOrder);
275
+ const icon = getSortIcon(colOrder);
276
+ return (_jsxs(CardHeader, { className: "flex flex-row items-center justify-between gap-2 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-sm", children: "Columns" }), _jsx("div", { className: "text-muted-foreground text-xs", children: "Drag fields to define column groups." })] }), _jsx(Button, { size: "icon", variant: "ghost", onClick: cycleColOrder, children: React.createElement(icon, { className: 'h-4 w-4' }) })] }));
277
+ };
278
+ const PivotColumnsZone = () => (_jsx(CardContent, { className: "pt-0", children: _jsx(PivotZone, { zone: "cols", title: "Columns", description: "Drag fields to define column groups.", framed: false }) }));
279
+ const PivotColumnsBase = ({ children, }) => (_jsx(Card, { children: children ?? (_jsxs(_Fragment, { children: [_jsx(PivotColumnsHeader, {}), _jsx(PivotColumnsZone, {})] })) }));
280
+ const PivotAvailableFieldsZone = () => (_jsx(PivotZone, { zone: "unused", title: "Available fields", description: "Drag fields into rows or columns." }));
281
+ const PivotAvailableFieldsBase = ({ children, }) => children ?? _jsx(PivotAvailableFieldsZone, {});
282
+ const PivotResultsView = () => {
283
+ const config = usePivotEditorStore((state) => state.config);
284
+ const status = usePivotEditorStore((state) => state.status);
285
+ const querySource = usePivotEditorStore((state) => state.querySource);
286
+ if (!querySource && !status.relations?.cells) {
287
+ return (_jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center p-6 text-sm", children: "Add or load a table to start pivoting data." }));
288
+ }
289
+ return (_jsx(PivotResults, { config: config, source: querySource, relations: status.relations, runState: status.state, stale: status.stale, lastError: status.lastError }));
290
+ };
291
+ const PivotTableOutput = () => _jsx(PivotResultsView, {});
292
+ const PivotChartOutput = () => _jsx(PivotResultsView, {});
293
+ const PivotTsvOutput = () => _jsx(PivotResultsView, {});
294
+ const PivotOutputHeader = () => {
295
+ const config = usePivotEditorStore((state) => state.config);
296
+ const aggregator = useMemo(() => getPivotAggregator(config.aggregatorName), [config.aggregatorName]);
297
+ return (_jsxs(CardHeader, { className: "flex flex-row items-center justify-between gap-2 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-sm", children: "Pivot output" }), _jsx("div", { className: "text-muted-foreground text-xs", children: "DuckDB computes the aggregation; charts render with Vega-Lite." })] }), _jsxs("div", { className: "text-muted-foreground flex items-center gap-3 text-xs", children: [_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(Rows3Icon, { className: "h-3.5 w-3.5" }), " ", config.rows.length, " rows"] }), _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(Columns2Icon, { className: "h-3.5 w-3.5" }), " ", config.cols.length, " cols"] }), _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(TablePropertiesIcon, { className: "h-3.5 w-3.5" }), aggregator.name] })] })] }));
298
+ };
299
+ const PivotOutputBody = () => (_jsx(CardContent, { className: "min-h-0", children: _jsx(PivotResultsView, {}) }));
300
+ const PivotOutputBase = ({ children, }) => (_jsx(Card, { className: "min-h-0", children: children ?? (_jsxs(_Fragment, { children: [_jsx(PivotOutputHeader, {}), _jsx(PivotOutputBody, {})] })) }));
301
+ const DefaultPivotEditorLayout = () => {
302
+ return (_jsxs(_Fragment, { children: [_jsx(PivotSourceSection, {}), _jsxs("div", { className: "grid min-h-0 flex-1 gap-4 xl:grid-cols-[380px_minmax(0,1fr)]", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2 xl:grid-cols-1", children: [_jsx(PivotRows, {}), _jsx(PivotColumns, {})] }), _jsx(PivotAvailableFields, {})] }), _jsx(PivotOutput, {})] })] }));
303
+ };
304
+ const PivotValues = Object.assign(PivotValuesBase, {
305
+ Select: PivotValuesSelect,
306
+ });
307
+ const PivotRows = Object.assign(PivotRowsBase, {
308
+ Header: PivotRowsHeader,
309
+ Zone: PivotRowsZone,
310
+ });
311
+ const PivotColumns = Object.assign(PivotColumnsBase, {
312
+ Header: PivotColumnsHeader,
313
+ Zone: PivotColumnsZone,
314
+ });
315
+ const PivotAvailableFields = Object.assign(PivotAvailableFieldsBase, {
316
+ Zone: PivotAvailableFieldsZone,
317
+ });
318
+ const PivotOutput = Object.assign(PivotOutputBase, {
319
+ Header: PivotOutputHeader,
320
+ Body: PivotOutputBody,
321
+ });
322
+ export const PivotEditor = Object.assign(PivotEditorRoot, {
323
+ Source: PivotSourceSection,
324
+ Toolbar: PivotToolbar,
325
+ TableSelector: PivotTableSelector,
326
+ RunButton: PivotRunButton,
327
+ RendererSelector: PivotRendererSelector,
328
+ AggregatorSelector: PivotAggregatorSelector,
329
+ Values: PivotValues,
330
+ Rows: PivotRows,
331
+ Columns: PivotColumns,
332
+ AvailableFields: PivotAvailableFields,
333
+ FieldChip: PivotFieldChip,
334
+ FieldFilter: PivotFieldFilter,
335
+ Output: PivotOutput,
336
+ Results: PivotResultsView,
337
+ TableOutput: PivotTableOutput,
338
+ ChartOutput: PivotChartOutput,
339
+ TsvOutput: PivotTsvOutput,
340
+ });
341
+ //# sourceMappingURL=PivotEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PivotEditor.js","sourceRoot":"","sources":["../src/PivotEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n DndContext,\n type DragEndEvent,\n DragOverlay,\n type DragStartEvent,\n PointerSensor,\n closestCenter,\n useDroppable,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport {\n SortableContext,\n rectSortingStrategy,\n useSortable,\n} from '@dnd-kit/sortable';\nimport {arrowTableToJson, useSql} from '@sqlrooms/duckdb';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Checkbox,\n Input,\n Label,\n Popover,\n PopoverContent,\n PopoverTrigger,\n ScrollArea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n cn,\n} from '@sqlrooms/ui';\nimport {\n ArrowDownWideNarrowIcon,\n ArrowUpAZIcon,\n ArrowUpNarrowWideIcon,\n Columns2Icon,\n FilterIcon,\n GripVerticalIcon,\n Rows3Icon,\n TablePropertiesIcon,\n} from 'lucide-react';\nimport React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {useStore} from 'zustand';\nimport {PIVOT_AGGREGATORS, getPivotAggregator} from './aggregators';\nimport {\n type CreatePivotCoreStoreProps,\n type PivotInstanceState,\n type PivotInstanceStore,\n createPivotCoreStore,\n} from './PivotCoreSlice';\nimport {PivotResults} from './PivotResults';\nimport {buildDistinctValuesQuery} from './sql';\nimport {\n PIVOT_RENDERER_NAMES,\n type PivotDropZone,\n type PivotField,\n} from './types';\n\ntype PivotEditorProps = CreatePivotCoreStoreProps & {\n store?: PivotInstanceStore;\n autoRun?: boolean;\n autoRunDebounceMs?: number;\n className?: string;\n children?: React.ReactNode;\n};\n\nconst PivotEditorStoreContext = createContext<PivotInstanceStore | null>(null);\n\nfunction usePivotEditorStore<T>(selector: (state: PivotInstanceState) => T): T {\n const store = useContext(PivotEditorStoreContext);\n if (!store) {\n throw new Error('PivotEditor store context is missing');\n }\n return useStore(store, selector);\n}\n\nfunction usePivotEditorStoreApi() {\n const store = useContext(PivotEditorStoreContext);\n if (!store) {\n throw new Error('PivotEditor store context is missing');\n }\n return store;\n}\n\nconst CONTAINER_ID_PREFIX = 'pivot-container:';\nconst numericTypePattern = /INT|DECIMAL|FLOAT|DOUBLE|REAL|HUGEINT|BIGINT/i;\nconst EMPTY_FILTER_VALUES: Record<string, boolean> = Object.freeze({});\n\nfunction getContainerId(zone: PivotDropZone) {\n return `${CONTAINER_ID_PREFIX}${zone}`;\n}\n\nfunction parseContainerId(id: string): PivotDropZone | null {\n if (!id.startsWith(CONTAINER_ID_PREFIX)) {\n return null;\n }\n return id.replace(CONTAINER_ID_PREFIX, '') as PivotDropZone;\n}\n\nfunction getSortIcon(order: PivotInstanceState['config']['rowOrder']) {\n switch (order) {\n case 'value_a_to_z':\n return ArrowDownWideNarrowIcon;\n case 'value_z_to_a':\n return ArrowUpNarrowWideIcon;\n default:\n return ArrowUpAZIcon;\n }\n}\n\nfunction useVisibleFields() {\n const fields = usePivotEditorStore((state) => state.fields);\n const hiddenAttributes = usePivotEditorStore(\n (state) => state.config.hiddenAttributes,\n );\n return useMemo(\n () => fields.filter((field) => !hiddenAttributes.includes(field.name)),\n [fields, hiddenAttributes],\n );\n}\n\nfunction useZoneFields(zone: PivotDropZone) {\n const visibleFields = useVisibleFields();\n const rows = usePivotEditorStore((state) => state.config.rows);\n const cols = usePivotEditorStore((state) => state.config.cols);\n const hiddenFromDragDrop = usePivotEditorStore(\n (state) => state.config.hiddenFromDragDrop,\n );\n const unusedOrder = usePivotEditorStore((state) => state.config.unusedOrder);\n\n return useMemo(() => {\n if (zone === 'rows') {\n return rows\n .map((name) => visibleFields.find((field) => field.name === name))\n .filter((field): field is PivotField => Boolean(field));\n }\n\n if (zone === 'cols') {\n return cols\n .map((name) => visibleFields.find((field) => field.name === name))\n .filter((field): field is PivotField => Boolean(field));\n }\n\n const used = new Set([...rows, ...cols]);\n const candidates = visibleFields.filter(\n (field) =>\n !used.has(field.name) && !hiddenFromDragDrop.includes(field.name),\n );\n const orderedNames = [\n ...unusedOrder.filter((name) =>\n candidates.some((field) => field.name === name),\n ),\n ...candidates\n .map((field) => field.name)\n .filter((name) => !unusedOrder.includes(name)),\n ];\n return orderedNames\n .map((name) => candidates.find((field) => field.name === name))\n .filter((field): field is PivotField => Boolean(field));\n }, [zone, rows, cols, hiddenFromDragDrop, unusedOrder, visibleFields]);\n}\n\nfunction AutoRunEffect({\n enabled,\n debounceMs,\n}: {\n enabled: boolean;\n debounceMs: number;\n}) {\n const store = usePivotEditorStoreApi();\n const source = usePivotEditorStore((state) => state.source);\n const config = usePivotEditorStore((state) => state.config);\n const stale = usePivotEditorStore((state) => state.status.stale);\n const runState = usePivotEditorStore((state) => state.status.state);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (!enabled || !source || !stale || runState === 'running') {\n return;\n }\n\n timeoutRef.current = setTimeout(() => {\n void store.getState().run();\n }, debounceMs);\n\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, [config, debounceMs, enabled, runState, source, stale, store]);\n\n return null;\n}\n\ntype PivotEditorComponent = React.FC<PivotEditorProps> & {\n Source: React.FC<{children?: React.ReactNode}>;\n Toolbar: React.FC<{children?: React.ReactNode}>;\n TableSelector: React.FC;\n RunButton: React.FC;\n RendererSelector: React.FC;\n AggregatorSelector: React.FC;\n Values: React.FC<{children?: React.ReactNode}> & {\n Select: React.FC<{index: number}>;\n };\n Rows: React.FC<{children?: React.ReactNode}> & {\n Header: React.FC;\n Zone: React.FC;\n };\n Columns: React.FC<{children?: React.ReactNode}> & {\n Header: React.FC;\n Zone: React.FC;\n };\n AvailableFields: React.FC<{children?: React.ReactNode}> & {\n Zone: React.FC;\n };\n FieldChip: React.FC<{field: PivotField}>;\n FieldFilter: React.FC<{\n field: PivotField;\n children: React.ReactNode;\n }>;\n Output: React.FC<{children?: React.ReactNode}> & {\n Header: React.FC;\n Body: React.FC;\n };\n Results: React.FC;\n TableOutput: React.FC;\n ChartOutput: React.FC;\n TsvOutput: React.FC;\n};\n\nconst PivotEditorRoot: React.FC<PivotEditorProps> = ({\n store,\n source,\n config,\n status,\n querySource,\n fields,\n availableTables,\n callbacks,\n autoRun = false,\n autoRunDebounceMs = 300,\n className,\n children,\n}) => {\n const [internalStore] = useState(() =>\n store\n ? null\n : createPivotCoreStore({\n source,\n config,\n status,\n querySource,\n fields,\n availableTables,\n callbacks,\n }),\n );\n\n const resolvedStore = store ?? internalStore;\n if (!resolvedStore) {\n return null;\n }\n\n return (\n <PivotEditorStoreContext.Provider value={resolvedStore}>\n <AutoRunEffect enabled={autoRun} debounceMs={autoRunDebounceMs} />\n <PivotEditorDndProvider className={className}>\n {children ?? <DefaultPivotEditorLayout />}\n </PivotEditorDndProvider>\n </PivotEditorStoreContext.Provider>\n );\n};\n\nconst PivotEditorDndProvider: React.FC<{\n className?: string;\n children: React.ReactNode;\n}> = ({className, children}) => {\n const moveField = usePivotEditorStore((state) => state.moveField);\n const rowFields = useZoneFields('rows');\n const colFields = useZoneFields('cols');\n const unusedFields = useZoneFields('unused');\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {distance: 6},\n }),\n );\n\n const zoneItems: Record<PivotDropZone, string[]> = {\n unused: unusedFields.map((field) => field.name),\n rows: rowFields.map((field) => field.name),\n cols: colFields.map((field) => field.name),\n };\n\n const [activeDragField, setActiveDragField] = useState<string | null>(null);\n\n const handleDragStart = (event: DragStartEvent) => {\n setActiveDragField(String(event.active.id));\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n const activeId = String(event.active.id);\n const overId = event.over ? String(event.over.id) : '';\n setActiveDragField(null);\n if (!overId) {\n return;\n }\n\n const directContainerId = parseContainerId(overId);\n const sortableContainerId = parseContainerId(\n String(event.over?.data.current?.sortable?.containerId ?? ''),\n );\n const destination =\n directContainerId ??\n sortableContainerId ??\n (Object.entries(zoneItems).find(([, items]) =>\n items.includes(overId),\n )?.[0] as PivotDropZone | undefined);\n\n if (!destination) {\n return;\n }\n\n const index = directContainerId\n ? zoneItems[destination].length\n : zoneItems[destination].indexOf(overId);\n moveField(activeId, destination, index);\n };\n\n return (\n <div\n className={cn(\n 'bg-muted/10 flex h-full flex-col gap-4 overflow-auto p-4',\n className,\n )}\n >\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n onDragCancel={() => setActiveDragField(null)}\n >\n {children}\n <DragOverlay dropAnimation={null}>\n {activeDragField ? (\n <div className=\"bg-background flex items-center gap-1 rounded-md border px-2 py-1 text-sm shadow-md\">\n <GripVerticalIcon className=\"text-muted-foreground h-4 w-4\" />\n <span className=\"truncate\">{activeDragField}</span>\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n </div>\n );\n};\n\nconst PivotSourceSection: React.FC<{children?: React.ReactNode}> = ({\n children,\n}) => (\n <Card>\n <CardContent className=\"grid gap-4 pt-6 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto]\">\n {children ?? (\n <>\n <PivotTableSelector />\n <PivotRendererSelector />\n <PivotAggregatorSelector />\n <PivotValues />\n </>\n )}\n </CardContent>\n </Card>\n);\n\nconst PivotToolbar: React.FC<{children?: React.ReactNode}> = ({children}) => (\n <div className=\"flex items-center justify-between gap-3\">{children}</div>\n);\n\nconst PivotTableSelector: React.FC = () => {\n const source = usePivotEditorStore((state) => state.source);\n const availableTables = usePivotEditorStore((state) => state.availableTables);\n const setSource = usePivotEditorStore((state) => state.setSource);\n\n return (\n <div className=\"space-y-2\">\n <Label>Table</Label>\n <Select\n value={source?.kind === 'table' ? source.tableName : undefined}\n onValueChange={(tableName) => setSource({kind: 'table', tableName})}\n >\n <SelectTrigger>\n <SelectValue placeholder=\"Select a table\" />\n </SelectTrigger>\n <SelectContent>\n {availableTables.map((tableName) => (\n <SelectItem key={tableName} value={tableName}>\n {tableName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n );\n};\n\nconst PivotRunButton: React.FC = () => {\n const run = usePivotEditorStore((state) => state.run);\n const status = usePivotEditorStore((state) => state.status);\n return (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => void run()}\n disabled={status.state === 'running'}\n >\n {status.state === 'running' ? 'Running…' : 'Run'}\n </Button>\n );\n};\n\nconst PivotRendererSelector: React.FC = () => {\n const value = usePivotEditorStore((state) => state.config.rendererName);\n const setRendererName = usePivotEditorStore((state) => state.setRendererName);\n\n return (\n <div className=\"space-y-2\">\n <Label>Renderer</Label>\n <Select value={value} onValueChange={setRendererName}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PIVOT_RENDERER_NAMES.map((rendererName) => (\n <SelectItem key={rendererName} value={rendererName}>\n {rendererName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n );\n};\n\nconst PivotAggregatorSelector: React.FC = () => {\n const value = usePivotEditorStore((state) => state.config.aggregatorName);\n const setAggregatorName = usePivotEditorStore(\n (state) => state.setAggregatorName,\n );\n\n return (\n <div className=\"space-y-2\">\n <Label>Aggregator</Label>\n <Select value={value} onValueChange={setAggregatorName}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(PIVOT_AGGREGATORS).map((aggregatorName) => (\n <SelectItem key={aggregatorName} value={aggregatorName}>\n {aggregatorName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n );\n};\n\nconst PivotValuesSelect: React.FC<{index: number}> = ({index}) => {\n const visibleFields = useVisibleFields();\n const config = usePivotEditorStore((state) => state.config);\n const setVals = usePivotEditorStore((state) => state.setVals);\n const aggregator = useMemo(\n () => getPivotAggregator(config.aggregatorName),\n [config.aggregatorName],\n );\n\n return (\n <Select\n value={config.vals[index]}\n onValueChange={(value) => {\n const nextValues = [...config.vals];\n nextValues[index] = value;\n setVals(nextValues.slice(0, aggregator.numInputs));\n }}\n >\n <SelectTrigger>\n <SelectValue placeholder={`Value ${index + 1}`} />\n </SelectTrigger>\n <SelectContent>\n {visibleFields\n .filter(\n (field) =>\n !config.hiddenFromAggregators.includes(field.name) &&\n (aggregator.valueRequirement !== 'numeric' ||\n numericTypePattern.test(field.type)),\n )\n .map((field) => (\n <SelectItem key={field.name} value={field.name}>\n {field.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n};\n\nconst PivotValuesBase: React.FC<{children?: React.ReactNode}> = ({\n children,\n}) => {\n const aggregatorName = usePivotEditorStore(\n (state) => state.config.aggregatorName,\n );\n const aggregator = useMemo(\n () => getPivotAggregator(aggregatorName),\n [aggregatorName],\n );\n\n return (\n <div className=\"space-y-2\">\n <Label>Values</Label>\n <div className=\"flex flex-col gap-2\">\n {children ??\n Array.from({length: aggregator.numInputs}).map((_, index) => (\n <PivotValuesSelect key={`value-select-${index}`} index={index} />\n ))}\n {aggregator.numInputs === 0 ? (\n <div className=\"text-muted-foreground text-xs\">\n This aggregation does not require measure columns.\n </div>\n ) : null}\n </div>\n </div>\n );\n};\n\nconst PivotFieldFilter: React.FC<{\n field: PivotField;\n children: React.ReactNode;\n}> = ({field, children}) => {\n const querySource = usePivotEditorStore((state) => state.querySource);\n const menuLimit = usePivotEditorStore((state) => state.config.menuLimit);\n const rawFilterValues = usePivotEditorStore(\n (state) => state.config.valueFilter[field.name],\n );\n const filterValues = rawFilterValues ?? EMPTY_FILTER_VALUES;\n const setFilterValues = usePivotEditorStore(\n (state) => state.setAttributeFilterValues,\n );\n const addFilters = usePivotEditorStore(\n (state) => state.addAttributeFilterValues,\n );\n const removeFilters = usePivotEditorStore(\n (state) => state.removeAttributeFilterValues,\n );\n const clearFilter = usePivotEditorStore(\n (state) => state.clearAttributeFilter,\n );\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState('');\n const query = useMemo(\n () =>\n querySource\n ? buildDistinctValuesQuery(querySource, field.name, menuLimit)\n : '',\n [field.name, menuLimit, querySource],\n );\n const valuesResult = useSql({query, enabled: open && Boolean(query)});\n const valuesData = valuesResult.data;\n const values = useMemo(\n () =>\n valuesData?.arrowTable\n ? (arrowTableToJson(valuesData.arrowTable) as Array<{\n value: string;\n count: number;\n }>)\n : [],\n [valuesData],\n );\n const shownValues = values.filter((item) =>\n String(item.value).toLowerCase().includes(search.trim().toLowerCase()),\n );\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"w-80 p-3\"\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <div>\n <div className=\"text-sm font-medium\">{field.name}</div>\n <div className=\"text-muted-foreground text-xs\">Filter values</div>\n </div>\n {Object.keys(filterValues).length > 0 ? (\n <Badge variant=\"secondary\">\n {Object.keys(filterValues).length} excluded\n </Badge>\n ) : null}\n </div>\n <Input\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n placeholder=\"Search values\"\n className=\"h-8\"\n />\n <div className=\"flex flex-wrap gap-2\">\n <Button\n size=\"xs\"\n variant=\"outline\"\n onClick={() =>\n removeFilters(\n field.name,\n shownValues.map((item) => String(item.value)),\n )\n }\n >\n Select shown\n </Button>\n <Button\n size=\"xs\"\n variant=\"outline\"\n onClick={() =>\n addFilters(\n field.name,\n shownValues.map((item) => String(item.value)),\n )\n }\n >\n Deselect shown\n </Button>\n <Button\n size=\"xs\"\n variant=\"ghost\"\n onClick={() => clearFilter(field.name)}\n >\n Clear\n </Button>\n </div>\n <ScrollArea className=\"h-64 rounded-md border\">\n <div className=\"space-y-1 p-2\">\n {valuesResult.isLoading ? (\n <div className=\"text-muted-foreground text-xs\">\n Loading values…\n </div>\n ) : shownValues.length === 0 ? (\n <div className=\"text-muted-foreground text-xs\">\n No matching values.\n </div>\n ) : (\n shownValues.map((item) => {\n const value = String(item.value);\n const included = !(value in filterValues);\n return (\n <div\n key={value}\n className=\"hover:bg-muted flex items-center justify-between gap-2 rounded-sm px-2 py-1\"\n >\n <label className=\"flex min-w-0 flex-1 items-center gap-2 text-sm\">\n <Checkbox\n checked={included}\n onCheckedChange={(checked) => {\n if (checked) {\n removeFilters(field.name, [value]);\n } else {\n addFilters(field.name, [value]);\n }\n }}\n />\n <span className=\"truncate\">{value || 'null'}</span>\n <span className=\"text-muted-foreground text-xs\">\n ({item.count})\n </span>\n </label>\n <Button\n size=\"xs\"\n variant=\"ghost\"\n onClick={() =>\n setFilterValues(\n field.name,\n values\n .map((candidate) => String(candidate.value))\n .filter((candidate) => candidate !== value),\n )\n }\n >\n only\n </Button>\n </div>\n );\n })\n )}\n </div>\n </ScrollArea>\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\nconst PivotFieldChip: React.FC<{field: PivotField}> = ({field}) => {\n const {attributes, listeners, setNodeRef, transform, transition, isDragging} =\n useSortable({id: field.name});\n const isFiltered = usePivotEditorStore((state) =>\n Boolean(state.config.valueFilter[field.name]),\n );\n\n return (\n <div\n ref={setNodeRef}\n style={{\n transform: transform\n ? `translate3d(${transform.x}px, ${transform.y}px, 0)`\n : undefined,\n transition,\n opacity: isDragging ? 0.5 : 1,\n }}\n className=\"max-w-full\"\n {...attributes}\n >\n <div\n className={cn(\n 'bg-background flex max-w-full items-center gap-1 rounded-md border px-2 py-1 text-sm shadow-xs',\n isFiltered && 'border-primary text-primary',\n )}\n >\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:text-foreground cursor-grab\"\n {...listeners}\n >\n <GripVerticalIcon className=\"h-4 w-4\" />\n </button>\n <span className=\"truncate\">{field.name}</span>\n <PivotFieldFilter field={field}>\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-6 w-6 shrink-0\"\n >\n <FilterIcon className=\"h-3.5 w-3.5\" />\n </Button>\n </PivotFieldFilter>\n </div>\n </div>\n );\n};\n\nconst PivotZone: React.FC<{\n zone: PivotDropZone;\n title: string;\n description: string;\n framed?: boolean;\n}> = ({zone, title, description, framed = true}) => {\n const items = useZoneFields(zone);\n const {setNodeRef, isOver} = useDroppable({id: getContainerId(zone)});\n\n const content = (\n <>\n {framed ? (\n <CardHeader className=\"space-y-1 pb-3\">\n <CardTitle className=\"text-sm\">{title}</CardTitle>\n <div className=\"text-muted-foreground text-xs\">{description}</div>\n </CardHeader>\n ) : null}\n {framed ? <CardContent>{renderZone()}</CardContent> : renderZone()}\n </>\n );\n\n function renderZone() {\n return (\n <div\n ref={setNodeRef}\n id={getContainerId(zone)}\n className={cn(\n 'bg-muted/30 flex min-h-20 flex-wrap items-start gap-2 rounded-md border border-dashed p-3',\n isOver && 'border-primary bg-primary/5',\n )}\n >\n <SortableContext\n id={getContainerId(zone)}\n items={items.map((field) => field.name)}\n strategy={rectSortingStrategy}\n >\n {items.map((field) => (\n <PivotFieldChip key={field.name} field={field} />\n ))}\n </SortableContext>\n {items.length === 0 ? (\n <div className=\"text-muted-foreground text-xs\">Drop fields here.</div>\n ) : null}\n </div>\n );\n }\n\n return framed ? <Card>{content}</Card> : <>{content}</>;\n};\n\nconst PivotRowsHeader: React.FC = () => {\n const cycleRowOrder = usePivotEditorStore((state) => state.cycleRowOrder);\n const rowOrder = usePivotEditorStore((state) => state.config.rowOrder);\n const icon = getSortIcon(rowOrder);\n\n return (\n <CardHeader className=\"flex flex-row items-center justify-between gap-2 pb-3\">\n <div>\n <CardTitle className=\"text-sm\">Rows</CardTitle>\n <div className=\"text-muted-foreground text-xs\">\n Drag fields to define row groups.\n </div>\n </div>\n <Button size=\"icon\" variant=\"ghost\" onClick={cycleRowOrder}>\n {React.createElement(icon, {className: 'h-4 w-4'})}\n </Button>\n </CardHeader>\n );\n};\n\nconst PivotRowsZone: React.FC = () => (\n <CardContent className=\"pt-0\">\n <PivotZone\n zone=\"rows\"\n title=\"Rows\"\n description=\"Drag fields to define row groups.\"\n framed={false}\n />\n </CardContent>\n);\n\nconst PivotRowsBase: React.FC<{children?: React.ReactNode}> = ({children}) => (\n <Card>\n {children ?? (\n <>\n <PivotRowsHeader />\n <PivotRowsZone />\n </>\n )}\n </Card>\n);\n\nconst PivotColumnsHeader: React.FC = () => {\n const cycleColOrder = usePivotEditorStore((state) => state.cycleColOrder);\n const colOrder = usePivotEditorStore((state) => state.config.colOrder);\n const icon = getSortIcon(colOrder);\n\n return (\n <CardHeader className=\"flex flex-row items-center justify-between gap-2 pb-3\">\n <div>\n <CardTitle className=\"text-sm\">Columns</CardTitle>\n <div className=\"text-muted-foreground text-xs\">\n Drag fields to define column groups.\n </div>\n </div>\n <Button size=\"icon\" variant=\"ghost\" onClick={cycleColOrder}>\n {React.createElement(icon, {className: 'h-4 w-4'})}\n </Button>\n </CardHeader>\n );\n};\n\nconst PivotColumnsZone: React.FC = () => (\n <CardContent className=\"pt-0\">\n <PivotZone\n zone=\"cols\"\n title=\"Columns\"\n description=\"Drag fields to define column groups.\"\n framed={false}\n />\n </CardContent>\n);\n\nconst PivotColumnsBase: React.FC<{children?: React.ReactNode}> = ({\n children,\n}) => (\n <Card>\n {children ?? (\n <>\n <PivotColumnsHeader />\n <PivotColumnsZone />\n </>\n )}\n </Card>\n);\n\nconst PivotAvailableFieldsZone: React.FC = () => (\n <PivotZone\n zone=\"unused\"\n title=\"Available fields\"\n description=\"Drag fields into rows or columns.\"\n />\n);\n\nconst PivotAvailableFieldsBase: React.FC<{children?: React.ReactNode}> = ({\n children,\n}) => children ?? <PivotAvailableFieldsZone />;\n\nconst PivotResultsView: React.FC = () => {\n const config = usePivotEditorStore((state) => state.config);\n const status = usePivotEditorStore((state) => state.status);\n const querySource = usePivotEditorStore((state) => state.querySource);\n\n if (!querySource && !status.relations?.cells) {\n return (\n <div className=\"text-muted-foreground flex h-full items-center justify-center p-6 text-sm\">\n Add or load a table to start pivoting data.\n </div>\n );\n }\n\n return (\n <PivotResults\n config={config}\n source={querySource}\n relations={status.relations}\n runState={status.state}\n stale={status.stale}\n lastError={status.lastError}\n />\n );\n};\n\nconst PivotTableOutput: React.FC = () => <PivotResultsView />;\nconst PivotChartOutput: React.FC = () => <PivotResultsView />;\nconst PivotTsvOutput: React.FC = () => <PivotResultsView />;\n\nconst PivotOutputHeader: React.FC = () => {\n const config = usePivotEditorStore((state) => state.config);\n const aggregator = useMemo(\n () => getPivotAggregator(config.aggregatorName),\n [config.aggregatorName],\n );\n\n return (\n <CardHeader className=\"flex flex-row items-center justify-between gap-2 pb-3\">\n <div>\n <CardTitle className=\"text-sm\">Pivot output</CardTitle>\n <div className=\"text-muted-foreground text-xs\">\n DuckDB computes the aggregation; charts render with Vega-Lite.\n </div>\n </div>\n <div className=\"text-muted-foreground flex items-center gap-3 text-xs\">\n <span className=\"inline-flex items-center gap-1\">\n <Rows3Icon className=\"h-3.5 w-3.5\" /> {config.rows.length} rows\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Columns2Icon className=\"h-3.5 w-3.5\" /> {config.cols.length} cols\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <TablePropertiesIcon className=\"h-3.5 w-3.5\" />\n {aggregator.name}\n </span>\n </div>\n </CardHeader>\n );\n};\n\nconst PivotOutputBody: React.FC = () => (\n <CardContent className=\"min-h-0\">\n <PivotResultsView />\n </CardContent>\n);\n\nconst PivotOutputBase: React.FC<{children?: React.ReactNode}> = ({\n children,\n}) => (\n <Card className=\"min-h-0\">\n {children ?? (\n <>\n <PivotOutputHeader />\n <PivotOutputBody />\n </>\n )}\n </Card>\n);\n\nconst DefaultPivotEditorLayout: React.FC = () => {\n return (\n <>\n <PivotSourceSection />\n <div className=\"grid min-h-0 flex-1 gap-4 xl:grid-cols-[380px_minmax(0,1fr)]\">\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-1\">\n <PivotRows />\n <PivotColumns />\n </div>\n <PivotAvailableFields />\n </div>\n <PivotOutput />\n </div>\n </>\n );\n};\n\nconst PivotValues = Object.assign(PivotValuesBase, {\n Select: PivotValuesSelect,\n});\n\nconst PivotRows = Object.assign(PivotRowsBase, {\n Header: PivotRowsHeader,\n Zone: PivotRowsZone,\n});\n\nconst PivotColumns = Object.assign(PivotColumnsBase, {\n Header: PivotColumnsHeader,\n Zone: PivotColumnsZone,\n});\n\nconst PivotAvailableFields = Object.assign(PivotAvailableFieldsBase, {\n Zone: PivotAvailableFieldsZone,\n});\n\nconst PivotOutput = Object.assign(PivotOutputBase, {\n Header: PivotOutputHeader,\n Body: PivotOutputBody,\n});\n\nexport const PivotEditor = Object.assign(PivotEditorRoot, {\n Source: PivotSourceSection,\n Toolbar: PivotToolbar,\n TableSelector: PivotTableSelector,\n RunButton: PivotRunButton,\n RendererSelector: PivotRendererSelector,\n AggregatorSelector: PivotAggregatorSelector,\n Values: PivotValues,\n Rows: PivotRows,\n Columns: PivotColumns,\n AvailableFields: PivotAvailableFields,\n FieldChip: PivotFieldChip,\n FieldFilter: PivotFieldFilter,\n Output: PivotOutput,\n Results: PivotResultsView,\n TableOutput: PivotTableOutput,\n ChartOutput: PivotChartOutput,\n TsvOutput: PivotTsvOutput,\n}) as PivotEditorComponent;\n"]}
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { createPivotQuerySourceFromTable } from './sql';
3
+ import { type PivotConfig, type PivotQuerySource, type PivotRelationViews } from './types';
4
+ type PivotResultsProps = {
5
+ config: PivotConfig;
6
+ source?: PivotQuerySource;
7
+ table?: Parameters<typeof createPivotQuerySourceFromTable>[0];
8
+ relations?: PivotRelationViews;
9
+ runState?: 'idle' | 'running' | 'success' | 'cancel' | 'error';
10
+ stale?: boolean;
11
+ lastError?: string;
12
+ };
13
+ export declare const PivotResults: React.FC<PivotResultsProps>;
14
+ export {};
15
+ //# sourceMappingURL=PivotResults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PivotResults.d.ts","sourceRoot":"","sources":["../src/PivotResults.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAOrC,OAAO,EAML,+BAA+B,EAChC,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACxB,MAAM,SAAS,CAAC;AAEjB,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAuMpD,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useSql } from '@sqlrooms/duckdb';
3
+ import { ErrorPane, SpinnerPane } from '@sqlrooms/ui';
4
+ import { VegaLiteChart } from '@sqlrooms/vega';
5
+ import { useMemo } from 'react';
6
+ import { getDefaultValuesForAggregator } from './aggregators';
7
+ import { buildChartSpec, getUniqueStringColumnValues, } from './helpers';
8
+ import { buildCellsQuery, buildColTotalsQuery, buildGrandTotalQuery, buildPivotExportQuery, buildRowTotalsQuery, createPivotQuerySourceFromTable, } from './sql';
9
+ import { TableRenderer } from './TableRenderer';
10
+ import { TsvRenderer } from './TsvRenderer';
11
+ export const PivotResults = ({ config, source, table, relations, runState, stale, lastError, }) => {
12
+ const querySource = useMemo(() => source ?? (table ? createPivotQuerySourceFromTable(table) : undefined), [source, table]);
13
+ const resolvedConfig = useMemo(() => {
14
+ const nextVals = getDefaultValuesForAggregator({
15
+ aggregatorName: config.aggregatorName,
16
+ fields: (querySource?.columns ?? []).filter((column) => !config.hiddenFromAggregators.includes(column.name)),
17
+ currentValues: config.vals,
18
+ });
19
+ if (JSON.stringify(nextVals) === JSON.stringify(config.vals)) {
20
+ return config;
21
+ }
22
+ return {
23
+ ...config,
24
+ vals: nextVals,
25
+ };
26
+ }, [config, querySource?.columns]);
27
+ const directCellsQuery = useMemo(() => (querySource ? buildCellsQuery(resolvedConfig, querySource) : ''), [querySource, resolvedConfig]);
28
+ const directRowTotalsQuery = useMemo(() => (querySource ? buildRowTotalsQuery(resolvedConfig, querySource) : ''), [querySource, resolvedConfig]);
29
+ const directColTotalsQuery = useMemo(() => (querySource ? buildColTotalsQuery(resolvedConfig, querySource) : ''), [querySource, resolvedConfig]);
30
+ const directGrandTotalQuery = useMemo(() => querySource ? buildGrandTotalQuery(resolvedConfig, querySource) : '', [querySource, resolvedConfig]);
31
+ const materializedRelations = useMemo(() => !querySource && runState === 'success' && !stale ? relations : undefined, [querySource, relations, runState, stale]);
32
+ const matCells = materializedRelations?.cells;
33
+ const matRowTotals = materializedRelations?.rowTotals;
34
+ const matColTotals = materializedRelations?.colTotals;
35
+ const matGrandTotal = materializedRelations?.grandTotal;
36
+ const matExport = materializedRelations?.export;
37
+ const cellsQuery = useMemo(() => (matCells ? `SELECT * FROM ${matCells}` : directCellsQuery), [directCellsQuery, matCells]);
38
+ const rowTotalsQuery = useMemo(() => matRowTotals ? `SELECT * FROM ${matRowTotals}` : directRowTotalsQuery, [directRowTotalsQuery, matRowTotals]);
39
+ const colTotalsQuery = useMemo(() => matColTotals ? `SELECT * FROM ${matColTotals}` : directColTotalsQuery, [directColTotalsQuery, matColTotals]);
40
+ const grandTotalQuery = useMemo(() => matGrandTotal ? `SELECT * FROM ${matGrandTotal}` : directGrandTotalQuery, [directGrandTotalQuery, matGrandTotal]);
41
+ const enabled = Boolean(matCells || matRowTotals || matColTotals || matGrandTotal || querySource);
42
+ const cellsResult = useSql({ query: cellsQuery, enabled });
43
+ const rowTotalsResult = useSql({ query: rowTotalsQuery, enabled });
44
+ const colTotalsResult = useSql({ query: colTotalsQuery, enabled });
45
+ const grandTotalResult = useSql({ query: grandTotalQuery, enabled });
46
+ const grandTotal = useMemo(() => {
47
+ return grandTotalResult.data?.arrowTable?.getChild('value')?.get(0) ?? null;
48
+ }, [grandTotalResult.data?.arrowTable]);
49
+ const chartRenderer = resolvedConfig.rendererName.includes('Chart');
50
+ const numericOutput = !['List Unique Values', 'First', 'Last'].includes(resolvedConfig.aggregatorName);
51
+ const chartSpec = useMemo(() => buildChartSpec(resolvedConfig, resolvedConfig.rendererName), [resolvedConfig]);
52
+ const cellsArrowTable = cellsResult.data?.arrowTable;
53
+ const chartExportQuery = useMemo(() => {
54
+ const colLabels = getUniqueStringColumnValues(cellsArrowTable, 'col_label');
55
+ if (matExport) {
56
+ return `SELECT * FROM ${matExport}`;
57
+ }
58
+ return querySource
59
+ ? buildPivotExportQuery(resolvedConfig, querySource, colLabels)
60
+ : '';
61
+ }, [cellsArrowTable, matExport, querySource, resolvedConfig]);
62
+ if (!enabled) {
63
+ return (_jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center p-6 text-sm", children: "Select a pivot source to preview results." }));
64
+ }
65
+ if (runState === 'error' && lastError) {
66
+ return _jsx(ErrorPane, { error: new Error(lastError) });
67
+ }
68
+ if (cellsResult.error ||
69
+ rowTotalsResult.error ||
70
+ colTotalsResult.error ||
71
+ grandTotalResult.error) {
72
+ return (_jsx(ErrorPane, { error: cellsResult.error ||
73
+ rowTotalsResult.error ||
74
+ colTotalsResult.error ||
75
+ grandTotalResult.error ||
76
+ new Error('Unknown pivot error') }));
77
+ }
78
+ if (cellsResult.isLoading ||
79
+ rowTotalsResult.isLoading ||
80
+ colTotalsResult.isLoading ||
81
+ grandTotalResult.isLoading) {
82
+ return _jsx(SpinnerPane, { className: "h-80" });
83
+ }
84
+ if (resolvedConfig.rendererName === 'Exportable TSV') {
85
+ return _jsx(TsvRenderer, { query: chartExportQuery });
86
+ }
87
+ if (chartRenderer) {
88
+ if (!numericOutput) {
89
+ return (_jsx(ErrorPane, { error: new Error('The selected renderer requires a numeric aggregation.') }));
90
+ }
91
+ return (_jsx("div", { className: "bg-background rounded-md border p-4", children: _jsx(VegaLiteChart.ArrowChart, { aspectRatio: 16 / 8, arrowTable: cellsResult.data?.arrowTable, spec: chartSpec }) }));
92
+ }
93
+ const heatmapMode = resolvedConfig.rendererName === 'Table Heatmap'
94
+ ? 'full'
95
+ : resolvedConfig.rendererName === 'Table Row Heatmap'
96
+ ? 'row'
97
+ : resolvedConfig.rendererName === 'Table Col Heatmap'
98
+ ? 'col'
99
+ : undefined;
100
+ return (_jsx(TableRenderer, { config: resolvedConfig, cellRows: cellsResult.data?.arrowTable, rowTotals: rowTotalsResult.data?.arrowTable, colTotals: colTotalsResult.data?.arrowTable, grandTotal: grandTotal, heatmapMode: heatmapMode }));
101
+ };
102
+ //# sourceMappingURL=PivotResults.js.map