@sqlrooms/deck 0.29.0-rc.4 → 0.29.0-rc.6

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 (75) hide show
  1. package/README.md +24 -2
  2. package/dist/DeckJsonMap.d.ts +1 -1
  3. package/dist/DeckJsonMap.d.ts.map +1 -1
  4. package/dist/DeckJsonMap.js +16 -11
  5. package/dist/DeckJsonMap.js.map +1 -1
  6. package/dist/LatitudeSelector.d.ts +11 -0
  7. package/dist/LatitudeSelector.d.ts.map +1 -0
  8. package/dist/LatitudeSelector.js +25 -0
  9. package/dist/LatitudeSelector.js.map +1 -0
  10. package/dist/LongitudeSelector.d.ts +11 -0
  11. package/dist/LongitudeSelector.d.ts.map +1 -0
  12. package/dist/LongitudeSelector.js +27 -0
  13. package/dist/LongitudeSelector.js.map +1 -0
  14. package/dist/MapSettings.d.ts +10 -0
  15. package/dist/MapSettings.d.ts.map +1 -0
  16. package/dist/MapSettings.js +96 -0
  17. package/dist/MapSettings.js.map +1 -0
  18. package/dist/ai.d.ts +168 -0
  19. package/dist/ai.d.ts.map +1 -0
  20. package/dist/ai.js +232 -0
  21. package/dist/ai.js.map +1 -0
  22. package/dist/dashboard.d.ts.map +1 -1
  23. package/dist/dashboard.js +72 -105
  24. package/dist/dashboard.js.map +1 -1
  25. package/dist/dashboardConfig.d.ts +22 -6
  26. package/dist/dashboardConfig.d.ts.map +1 -1
  27. package/dist/dashboardConfig.js +2 -5
  28. package/dist/dashboardConfig.js.map +1 -1
  29. package/dist/dashboardIntegration.d.ts +3 -0
  30. package/dist/dashboardIntegration.d.ts.map +1 -0
  31. package/dist/dashboardIntegration.js +16 -0
  32. package/dist/dashboardIntegration.js.map +1 -0
  33. package/dist/datasets/PreparedDatasetStore.js +2 -1
  34. package/dist/datasets/PreparedDatasetStore.js.map +1 -1
  35. package/dist/index.d.ts +8 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +5 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/json/colorScaleFunction.d.ts +1 -1
  40. package/dist/json/colorScaleFunction.d.ts.map +1 -1
  41. package/dist/json/colorScaleFunction.js +7 -1
  42. package/dist/json/colorScaleFunction.js.map +1 -1
  43. package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
  44. package/dist/json/extractColorScaleLegends.js +0 -1
  45. package/dist/json/extractColorScaleLegends.js.map +1 -1
  46. package/dist/json/layerCompatibility.d.ts.map +1 -1
  47. package/dist/json/layerCompatibility.js +2 -0
  48. package/dist/json/layerCompatibility.js.map +1 -1
  49. package/dist/mapConfigUtils.d.ts +62 -0
  50. package/dist/mapConfigUtils.d.ts.map +1 -0
  51. package/dist/mapConfigUtils.js +233 -0
  52. package/dist/mapConfigUtils.js.map +1 -0
  53. package/dist/mapDataPolicy.d.ts +4 -0
  54. package/dist/mapDataPolicy.d.ts.map +1 -0
  55. package/dist/mapDataPolicy.js +25 -0
  56. package/dist/mapDataPolicy.js.map +1 -0
  57. package/dist/mapLayerConfigUtils.d.ts +38 -0
  58. package/dist/mapLayerConfigUtils.d.ts.map +1 -0
  59. package/dist/mapLayerConfigUtils.js +185 -0
  60. package/dist/mapLayerConfigUtils.js.map +1 -0
  61. package/dist/prepare/wkbDecoder.d.ts.map +1 -1
  62. package/dist/prepare/wkbDecoder.js +266 -67
  63. package/dist/prepare/wkbDecoder.js.map +1 -1
  64. package/dist/prepare/wkbParser.d.ts +19 -0
  65. package/dist/prepare/wkbParser.d.ts.map +1 -0
  66. package/dist/prepare/wkbParser.js +115 -0
  67. package/dist/prepare/wkbParser.js.map +1 -0
  68. package/dist/types.d.ts +8 -0
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/types.js.map +1 -1
  71. package/package.json +8 -7
  72. package/dist/useDeckLayersReadyRedraw.d.ts +0 -13
  73. package/dist/useDeckLayersReadyRedraw.d.ts.map +0 -1
  74. package/dist/useDeckLayersReadyRedraw.js +0 -35
  75. package/dist/useDeckLayersReadyRedraw.js.map +0 -1
package/dist/dashboard.js CHANGED
@@ -2,13 +2,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { WebMercatorViewport } from '@deck.gl/core';
3
3
  import { escapeId, getColValAsNumber, useStoreWithDuckDb, } from '@sqlrooms/duckdb';
4
4
  import { column, sql, useMosaicClient, useStoreWithMosaicDashboard, } from '@sqlrooms/mosaic';
5
- import { Button } from '@sqlrooms/ui';
6
- import { FocusIcon, MapIcon } from 'lucide-react';
5
+ import { Button, Tooltip, TooltipContent, TooltipTrigger } from '@sqlrooms/ui';
6
+ import { FocusIcon, MapIcon, SettingsIcon } from 'lucide-react';
7
7
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
8
8
  import { DeckMapConfigPopoverEditor } from './DeckMapConfigPopoverEditor';
9
9
  import { DeckJsonMap } from './DeckJsonMap';
10
- import { asDeckJsonMapConfig, createDeckMapDashboardDatasetQuery, createDeckMapDashboardDatasets, createDeckMapDashboardPanelConfig, DECK_MAP_DASHBOARD_PANEL_TYPE, resolveDeckMapDashboardDatasetSource, } from './dashboardConfig';
11
- function DeckMapDashboardDatasetClient({ dashboard, dataset, datasetId, panel, onDatasetState, selectionName, }) {
10
+ import { MapSettingsPanel } from './MapSettings';
11
+ import { MosaicDashboardPanelLayout } from '@sqlrooms/mosaic';
12
+ import { asDeckJsonMapConfig, createDeckMapDashboardDatasetQuery, createDeckMapDashboardDatasets, DECK_MAP_DASHBOARD_PANEL_TYPE, resolveDeckMapDashboardDatasetSource, } from './dashboardConfig';
13
+ import { getDeckMapDataPolicy } from './mapDataPolicy';
14
+ import { createDeckMapDashboardPanelConfigForTable, findGeometryColumn, findLongitudeLatitudeColumns, } from './mapConfigUtils';
15
+ function DeckMapRuntimeIssuePanel({ issue }) {
16
+ const title = issue.kind === 'too-much-data'
17
+ ? 'Too much data'
18
+ : issue.kind === 'sql-error'
19
+ ? 'Map query failed'
20
+ : 'Unable to display map';
21
+ return (_jsxs("div", { className: "flex h-full min-h-[200px] flex-col items-center justify-center p-4", children: [_jsx("div", { className: "mb-2 text-center font-semibold", children: title }), _jsx("div", { className: "text-center text-sm whitespace-pre-wrap", children: issue.message })] }));
22
+ }
23
+ function DeckMapDashboardDatasetClient({ dashboard, dataset, datasetId, dataPolicy, panel, onDatasetState, runtimeIssueContext, runtimeIssueReporter, selectionName, }) {
12
24
  const source = useMemo(() => resolveDeckMapDashboardDatasetSource({
13
25
  dashboard,
14
26
  panel,
@@ -21,7 +33,10 @@ function DeckMapDashboardDatasetClient({ dashboard, dataset, datasetId, panel, o
21
33
  id: `${panel.id}:${datasetId}`,
22
34
  selectionName,
23
35
  query,
36
+ dataPolicy,
24
37
  enabled: Boolean(source),
38
+ runtimeIssueContext,
39
+ runtimeIssueReporter,
25
40
  });
26
41
  useEffect(() => {
27
42
  onDatasetState(datasetId, {
@@ -134,19 +149,35 @@ function DeckMapDashboardHeaderActions({ dashboardId, panel, }) {
134
149
  const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
135
150
  const mapConfig = asDeckJsonMapConfig(panel.config);
136
151
  const canFitView = Boolean(mapConfig?.fitToData);
152
+ const isSettingsOpen = Boolean(mapConfig?.settingsOpen);
137
153
  const handleConfigApply = useCallback((nextConfig) => {
138
154
  updatePanel(dashboardId, panel.id, {
139
155
  config: nextConfig,
140
156
  });
141
157
  }, [dashboardId, panel.id, updatePanel]);
142
- return (_jsxs("div", { className: "flex items-center gap-0.5", children: [_jsx(DeckMapConfigPopoverEditor, { value: panel.config, onApply: handleConfigApply }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", title: canFitView
158
+ const handleToggleSettings = useCallback(() => {
159
+ updatePanel(dashboardId, panel.id, {
160
+ config: { ...panel.config, settingsOpen: !isSettingsOpen },
161
+ });
162
+ }, [dashboardId, isSettingsOpen, panel.config, panel.id, updatePanel]);
163
+ return (_jsxs("div", { className: "flex items-center gap-0.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "data-[state=active]:bg-accent h-6 w-6", title: "Map settings", onClick: handleToggleSettings, "data-state": isSettingsOpen ? 'active' : 'inactive', children: _jsx(SettingsIcon, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Map settings" })] }), _jsx(DeckMapConfigPopoverEditor, { value: panel.config, onApply: handleConfigApply }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", title: canFitView
143
164
  ? 'Fit map view to data'
144
165
  : 'Fit view unavailable for this map', disabled: !canFitView, onClick: () => emitDeckMapDashboardFitRequest(panel.id), children: _jsx(FocusIcon, { className: "h-3.5 w-3.5" }) })] }));
145
166
  }
146
- function DeckMapDashboardRenderer({ dashboard, panel, selectionName, }) {
167
+ function DeckMapDashboardRenderer({ dashboard, dashboardId, panel, selectionName, }) {
147
168
  const mapConfig = asDeckJsonMapConfig(panel.config);
148
169
  const getSelection = useStoreWithMosaicDashboard((state) => state.mosaic.getSelection);
170
+ const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
171
+ const issue = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.getPanelIssue(dashboardId, panel.id));
172
+ const reportPanelIssue = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.reportPanelIssue);
173
+ const clearPanelIssue = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.clearPanelIssue);
149
174
  const executeSql = useStoreWithDuckDb((state) => state.db.executeSql);
175
+ const isSettingsOpen = Boolean(panel.config.settingsOpen);
176
+ const handleSettingsOpenChange = useCallback((isOpen) => {
177
+ updatePanel(dashboardId, panel.id, {
178
+ config: { ...panel.config, settingsOpen: isOpen },
179
+ });
180
+ }, [dashboardId, panel.config, panel.id, updatePanel]);
150
181
  const selection = useMemo(() => getSelection(selectionName, 'crossfilter'), [getSelection, selectionName]);
151
182
  const containerRef = useRef(null);
152
183
  const [datasetStates, setDatasetStates] = useState({});
@@ -163,6 +194,19 @@ function DeckMapDashboardRenderer({ dashboard, panel, selectionName, }) {
163
194
  return next;
164
195
  });
165
196
  }, []);
197
+ const dataPolicy = useMemo(() => getDeckMapDataPolicy(mapConfig), [mapConfig]);
198
+ const runtimeIssueContext = useMemo(() => ({
199
+ panelId: panel.id,
200
+ chartType: DECK_MAP_DASHBOARD_PANEL_TYPE,
201
+ }), [panel.id]);
202
+ const runtimeIssueReporter = useMemo(() => ({
203
+ reportIssue: (issueToReport) => {
204
+ reportPanelIssue(dashboardId, panel.id, issueToReport);
205
+ },
206
+ clearIssue: () => {
207
+ clearPanelIssue(dashboardId, panel.id);
208
+ },
209
+ }), [clearPanelIssue, dashboardId, panel.id, reportPanelIssue]);
166
210
  useEffect(() => {
167
211
  const container = containerRef.current;
168
212
  if (!container)
@@ -180,12 +224,6 @@ function DeckMapDashboardRenderer({ dashboard, panel, selectionName, }) {
180
224
  observer.disconnect();
181
225
  };
182
226
  }, []);
183
- const deckDatasets = useMemo(() => {
184
- if (!mapConfig) {
185
- return {};
186
- }
187
- return createDeckMapDashboardDatasets(mapConfig, datasetStates);
188
- }, [datasetStates, mapConfig]);
189
227
  const fitToData = mapConfig?.fitToData ?? null;
190
228
  const fitToDataSource = useMemo(() => fitToData
191
229
  ? resolveDeckMapDashboardDatasetSource({
@@ -354,112 +392,41 @@ function DeckMapDashboardRenderer({ dashboard, panel, selectionName, }) {
354
392
  };
355
393
  });
356
394
  }, [didAutoFit, fitStateKey, fitToData, viewState]);
357
- if (!mapConfig) {
358
- return (_jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center p-4 text-sm", children: "Invalid map panel config." }));
359
- }
360
- const datasetEntries = Object.entries(mapConfig.datasets);
361
- if (!datasetEntries.length) {
362
- return (_jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center p-4 text-sm", children: "Map panels require at least one dataset." }));
363
- }
364
- const datasetErrors = Object.entries(datasetStates).filter(([, state]) => state.error);
365
- const interactionEvent = mapConfig.interaction?.event ?? 'hover';
366
- const interactionDeckProps = mapConfig.interaction
367
- ? interactionEvent === 'click'
368
- ? { onClick: handleBrushEvent }
369
- : { onHover: handleBrushEvent }
370
- : {};
371
- return (_jsxs("div", { ref: containerRef, className: "relative h-full w-full", children: [datasetEntries.map(([datasetId, dataset]) => (_jsx(DeckMapDashboardDatasetClient, { dashboard: dashboard, dataset: dataset, datasetId: datasetId, panel: panel, onDatasetState: handleDatasetState, selectionName: selectionName }, datasetId))), datasetErrors.length ? (_jsx("div", { className: "bg-background/90 text-destructive absolute inset-x-4 top-4 z-10 rounded-md border p-3 text-sm shadow", children: datasetErrors.map(([datasetId, state]) => (_jsxs("div", { children: ["Failed to load dataset \"", datasetId, "\":", ' ', state.error?.message] }, datasetId))) })) : null, _jsx(DeckJsonMap, { className: "h-full w-full", spec: mapConfig.spec, datasets: deckDatasets, mapStyle: mapConfig.mapStyle, mapProps: mapConfig.mapProps, showLegends: mapConfig.showLegends, deckProps: {
395
+ const settingsContent = (_jsx(MapSettingsPanel, { dashboardId: dashboardId, panel: panel, onClose: () => handleSettingsOpenChange(false) }));
396
+ const mapContent = !mapConfig ? (_jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center p-4 text-sm", children: "Invalid map panel config." })) : issue ? (_jsx(DeckMapRuntimeIssuePanel, { issue: issue })) : Object.entries(mapConfig.datasets).length === 0 ? (_jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center p-4 text-sm", children: "Map panels require at least one dataset." })) : (_jsxs("div", { ref: containerRef, className: "relative h-full w-full", children: [Object.entries(mapConfig.datasets).map(([datasetId, dataset]) => (_jsx(DeckMapDashboardDatasetClient, { dashboard: dashboard, dataset: dataset, datasetId: datasetId, dataPolicy: dataPolicy, panel: panel, onDatasetState: handleDatasetState, runtimeIssueContext: runtimeIssueContext, runtimeIssueReporter: runtimeIssueReporter, selectionName: selectionName }, datasetId))), Object.entries(datasetStates)
397
+ .filter(([, state]) => state.error)
398
+ .map(([datasetId, state]) => (_jsxs("div", { className: "bg-background/90 text-destructive absolute inset-x-4 top-4 z-10 rounded-md border p-3 text-sm shadow", children: ["Failed to load dataset \"", datasetId, "\":", ' ', state.error?.message] }, datasetId))), _jsx(DeckJsonMap, { className: "h-full w-full", spec: mapConfig.spec, datasets: mapConfig
399
+ ? createDeckMapDashboardDatasets(mapConfig, datasetStates)
400
+ : {}, mapStyle: mapConfig.mapStyle, mapProps: mapConfig.mapProps, showLegends: mapConfig.showLegends, deckProps: {
372
401
  controller: true,
373
402
  ...(viewState ? { viewState } : {}),
374
403
  onViewStateChange: handleViewStateChange,
375
- ...interactionDeckProps,
404
+ ...(mapConfig.interaction
405
+ ? (mapConfig.interaction.event ?? 'hover') === 'click'
406
+ ? { onClick: handleBrushEvent }
407
+ : { onHover: handleBrushEvent }
408
+ : {}),
376
409
  } })] }));
410
+ return (_jsx("div", { className: "h-full min-h-0", children: _jsx(MosaicDashboardPanelLayout, { isOpen: isSettingsOpen, onIsOpenChange: handleSettingsOpenChange, settings: settingsContent, content: mapContent }) }));
377
411
  }
378
412
  export const deckMapDashboardPanelRenderer = {
379
413
  component: DeckMapDashboardRenderer,
380
414
  headerActions: DeckMapDashboardHeaderActions,
381
415
  icon: MapIcon,
382
416
  };
383
- const LONGITUDE_COLUMN_NAMES = ['longitude', 'lon', 'lng', 'long', 'x'];
384
- const LATITUDE_COLUMN_NAMES = ['latitude', 'lat', 'y'];
385
- function findColumnByName(table, candidates) {
386
- const candidateSet = new Set(candidates);
387
- return table.columns.find((column) => candidateSet.has(column.name.toLowerCase()))?.name;
388
- }
389
- function findLongitudeLatitudeColumns(table) {
390
- if (!table)
391
- return null;
392
- const longitudeColumn = findColumnByName(table, LONGITUDE_COLUMN_NAMES);
393
- const latitudeColumn = findColumnByName(table, LATITUDE_COLUMN_NAMES);
394
- return longitudeColumn && latitudeColumn
395
- ? { longitudeColumn, latitudeColumn }
396
- : null;
397
- }
398
- function quoteSqlIdentifier(identifier) {
399
- return `"${identifier.replace(/"/g, '""')}"`;
400
- }
401
- function quoteTableReference(table) {
402
- const qualifiedName = table.table;
403
- return [qualifiedName.database, qualifiedName.schema, qualifiedName.table]
404
- .filter((part) => Boolean(part))
405
- .map(quoteSqlIdentifier)
406
- .join('.');
407
- }
408
- function createDeckMapPanelForTable(table) {
409
- const coordinates = findLongitudeLatitudeColumns(table);
410
- if (!coordinates)
411
- return undefined;
412
- const { longitudeColumn, latitudeColumn } = coordinates;
413
- const datasetId = table.tableName;
414
- const geometryColumn = '__sqlrooms_geom';
415
- const quotedLongitude = quoteSqlIdentifier(longitudeColumn);
416
- const quotedLatitude = quoteSqlIdentifier(latitudeColumn);
417
- return createDeckMapDashboardPanelConfig({
418
- title: `${table.tableName} map`,
419
- source: { tableName: table.tableName },
420
- spec: {
421
- initialViewState: { longitude: 0, latitude: 20, zoom: 1.5 },
422
- layers: [
423
- {
424
- '@@type': 'GeoArrowScatterplotLayer',
425
- id: datasetId,
426
- _sqlroomsBinding: { dataset: datasetId },
427
- filled: true,
428
- stroked: false,
429
- pickable: true,
430
- radiusUnits: 'pixels',
431
- getRadius: 4,
432
- getFillColor: [56, 189, 248, 180],
433
- },
434
- ],
435
- },
436
- datasets: {
437
- [datasetId]: {
438
- source: {
439
- sqlQuery: [
440
- `SELECT *, ST_AsWKB(ST_Point(${quotedLongitude}, ${quotedLatitude})) AS ${quoteSqlIdentifier(geometryColumn)}`,
441
- `FROM ${quoteTableReference(table)}`,
442
- `WHERE ${quotedLongitude} IS NOT NULL AND ${quotedLatitude} IS NOT NULL`,
443
- ].join(' '),
444
- },
445
- geometryColumn,
446
- geometryEncodingHint: 'wkb',
447
- },
448
- },
449
- fitToData: {
450
- dataset: datasetId,
451
- longitudeColumn,
452
- latitudeColumn,
453
- padding: 40,
454
- maxZoom: 12,
455
- },
456
- });
457
- }
458
417
  export const deckMapDashboardAddPanelAction = {
459
418
  type: DECK_MAP_DASHBOARD_PANEL_TYPE,
460
419
  label: 'Map',
461
420
  icon: MapIcon,
462
- isEnabled: ({ selectedTable }) => Boolean(findLongitudeLatitudeColumns(selectedTable)),
463
- createPanel: ({ selectedTable }) => selectedTable ? createDeckMapPanelForTable(selectedTable) : undefined,
421
+ isEnabled: ({ selectedTable }) => Boolean(findLongitudeLatitudeColumns(selectedTable) ??
422
+ findGeometryColumn(selectedTable)),
423
+ createPanel: ({ selectedTable }) => selectedTable
424
+ ? createDeckMapDashboardPanelConfigForTable({
425
+ title: `${selectedTable.tableName} map`,
426
+ tableName: selectedTable.tableName,
427
+ columns: selectedTable.columns,
428
+ tableReference: selectedTable.table,
429
+ })
430
+ : undefined,
464
431
  };
465
432
  //# sourceMappingURL=dashboard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.tsx"],"names":[],"mappings":"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","sourcesContent":["import {WebMercatorViewport} from '@deck.gl/core';\nimport type {ComponentProps} from 'react';\nimport type DeckGLReact from '@deck.gl/react';\n\ntype DeckProps = ComponentProps<typeof DeckGLReact>;\nimport {\n escapeId,\n getColValAsNumber,\n useStoreWithDuckDb,\n type DataTable,\n} from '@sqlrooms/duckdb';\nimport {\n column,\n type MosaicDashboardEntryType,\n type MosaicDashboardPanelConfigType,\n type MosaicDashboardPanelRenderer,\n type MosaicDashboardPanelRendererProps,\n sql,\n useMosaicClient,\n useStoreWithMosaicDashboard,\n} from '@sqlrooms/mosaic';\nimport {Button} from '@sqlrooms/ui';\nimport type {MosaicClient} from '@uwdata/mosaic-core';\nimport type {Selection} from '@uwdata/mosaic-core';\nimport type {Table as ArrowTable} from 'apache-arrow';\nimport {FocusIcon, MapIcon} from 'lucide-react';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {DeckMapConfigPopoverEditor} from './DeckMapConfigPopoverEditor';\nimport {DeckJsonMap} from './DeckJsonMap';\nimport type {DeckJsonMapProps} from './types';\nimport {\n asDeckJsonMapConfig,\n createDeckMapDashboardDatasetQuery,\n createDeckMapDashboardDatasets,\n createDeckMapDashboardPanelConfig,\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n resolveDeckMapDashboardDatasetSource,\n type DeckMapDashboardFitToDataConfig,\n type DeckMapDashboardDatasetClientState,\n type DeckMapDashboardDatasetConfig,\n type DeckMapDashboardInteractionConfig,\n} from './dashboardConfig';\n\nfunction DeckMapDashboardDatasetClient({\n dashboard,\n dataset,\n datasetId,\n panel,\n onDatasetState,\n selectionName,\n}: {\n dashboard: MosaicDashboardEntryType;\n dataset: DeckMapDashboardDatasetConfig;\n datasetId: string;\n panel: MosaicDashboardPanelConfigType;\n onDatasetState: (\n datasetId: string,\n state: DeckMapDashboardDatasetClientState | undefined,\n ) => void;\n selectionName: string;\n}) {\n const source = useMemo(\n () =>\n resolveDeckMapDashboardDatasetSource({\n dashboard,\n panel,\n dataset,\n }),\n [dashboard, dataset, panel],\n );\n const query = useCallback(\n (filter: unknown) =>\n source\n ? createDeckMapDashboardDatasetQuery(source, filter)\n : createDeckMapDashboardDatasetQuery(\n {tableName: '__missing_dashboard_map_dataset__'},\n filter,\n ),\n [source],\n );\n const {data, error, isLoading, client} = useMosaicClient({\n id: `${panel.id}:${datasetId}`,\n selectionName,\n query,\n enabled: Boolean(source),\n });\n\n useEffect(() => {\n onDatasetState(datasetId, {\n arrowTable: data ?? undefined,\n error,\n isLoading,\n client,\n });\n\n return () => {\n onDatasetState(datasetId, undefined);\n };\n }, [client, data, datasetId, error, isLoading, onDatasetState]);\n\n return null;\n}\n\nfunction createPointRadiusPredicate(\n interaction: DeckMapDashboardInteractionConfig,\n coordinate: [number, number],\n) {\n const [longitude, latitude] = coordinate;\n const radiusMeters = interaction.radiusMeters ?? 500;\n const metersPerDegree = 111_320;\n const cosLatitude = Math.cos(latitude * (Math.PI / 180));\n const radiusSquared = radiusMeters * radiusMeters;\n\n return sql`(\n pow((${column(interaction.longitudeColumn)} - ${longitude}) * ${\n cosLatitude * metersPerDegree\n }, 2) +\n pow((${column(interaction.latitudeColumn)} - ${latitude}) * ${\n metersPerDegree\n }, 2)\n ) < ${radiusSquared}`;\n}\n\ntype DeckMapInteractionEvent = {\n coordinate?: number[] | null;\n object?: unknown;\n index?: number;\n picked?: boolean;\n};\n\nfunction getCoordinate(\n info: DeckMapInteractionEvent,\n): [number, number] | undefined {\n return info.coordinate && info.coordinate.length >= 2\n ? [info.coordinate[0]!, info.coordinate[1]!]\n : undefined;\n}\n\nfunction isPickedMapFeature(info: DeckMapInteractionEvent) {\n return Boolean(info.picked || info.object || (info.index ?? -1) >= 0);\n}\n\nfunction createDeckMapBoundsQuery(options: {\n source: {tableName?: string; sqlQuery?: string};\n fitToData: DeckMapDashboardFitToDataConfig;\n}) {\n const {source, fitToData} = options;\n const baseSourceSql = source.sqlQuery\n ? `SELECT * FROM (${source.sqlQuery}) AS \"__sqlrooms_dashboard_map_source\"`\n : `SELECT * FROM ${(source.tableName ?? '')\n .split('.')\n .map(escapeId)\n .join('.')}`;\n const longitudeColumn = escapeId(fitToData.longitudeColumn);\n const latitudeColumn = escapeId(fitToData.latitudeColumn);\n\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(ST_Point(${longitudeColumn}, ${latitudeColumn})) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_points\"\n WHERE ${longitudeColumn} IS NOT NULL AND ${latitudeColumn} IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n}\n\nfunction readBoundsFromExtentResult(result: ArrowTable) {\n const minLongitude = getColValAsNumber(result, 'min_longitude');\n const minLatitude = getColValAsNumber(result, 'min_latitude');\n const maxLongitude = getColValAsNumber(result, 'max_longitude');\n const maxLatitude = getColValAsNumber(result, 'max_latitude');\n if (\n !Number.isFinite(minLongitude) ||\n !Number.isFinite(minLatitude) ||\n !Number.isFinite(maxLongitude) ||\n !Number.isFinite(maxLatitude)\n ) {\n return null;\n }\n\n return [\n [\n minLongitude === maxLongitude ? minLongitude - 0.01 : minLongitude,\n minLatitude === maxLatitude ? minLatitude - 0.01 : minLatitude,\n ],\n [\n minLongitude === maxLongitude ? maxLongitude + 0.01 : maxLongitude,\n minLatitude === maxLatitude ? maxLatitude + 0.01 : maxLatitude,\n ],\n ] as const;\n}\n\nfunction fitViewStateToBounds(options: {\n bounds: readonly [readonly [number, number], readonly [number, number]];\n width: number;\n height: number;\n padding?: number;\n maxZoom?: number;\n}) {\n const {bounds, width, height, padding = 40, maxZoom = 12} = options;\n const viewport = new WebMercatorViewport({\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n });\n const fitted = viewport.fitBounds(\n [\n [bounds[0][0], bounds[0][1]],\n [bounds[1][0], bounds[1][1]],\n ],\n {padding},\n ) as WebMercatorViewport & {\n longitude: number;\n latitude: number;\n zoom: number;\n };\n\n return {\n longitude: fitted.longitude,\n latitude: fitted.latitude,\n zoom: Math.min(fitted.zoom, maxZoom),\n };\n}\n\nconst deckMapDashboardFitRequestTarget = new EventTarget();\n\nfunction emitDeckMapDashboardFitRequest(panelId: string) {\n deckMapDashboardFitRequestTarget.dispatchEvent(\n new CustomEvent('fit-view', {detail: {panelId}}),\n );\n}\n\ntype DeckMapDashboardFitState = {\n key: string;\n viewState: DeckProps['viewState'];\n didAutoFit: boolean;\n fitRequestVersion: number;\n handledFitRequestVersion: number;\n};\n\nfunction createInitialDeckMapDashboardFitState(\n key: string,\n): DeckMapDashboardFitState {\n return {\n key,\n viewState: undefined,\n didAutoFit: false,\n fitRequestVersion: 0,\n handledFitRequestVersion: 0,\n };\n}\n\nfunction DeckMapDashboardHeaderActions({\n dashboardId,\n panel,\n}: MosaicDashboardPanelRendererProps) {\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n const mapConfig = asDeckJsonMapConfig(panel.config);\n const canFitView = Boolean(mapConfig?.fitToData);\n const handleConfigApply = useCallback(\n (nextConfig: Record<string, unknown>) => {\n updatePanel(dashboardId, panel.id, {\n config: nextConfig,\n });\n },\n [dashboardId, panel.id, updatePanel],\n );\n\n return (\n <div className=\"flex items-center gap-0.5\">\n <DeckMapConfigPopoverEditor\n value={panel.config}\n onApply={handleConfigApply}\n />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n title={\n canFitView\n ? 'Fit map view to data'\n : 'Fit view unavailable for this map'\n }\n disabled={!canFitView}\n onClick={() => emitDeckMapDashboardFitRequest(panel.id)}\n >\n <FocusIcon className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n );\n}\n\nfunction DeckMapDashboardRenderer({\n dashboard,\n panel,\n selectionName,\n}: MosaicDashboardPanelRendererProps) {\n const mapConfig = asDeckJsonMapConfig(panel.config);\n const getSelection = useStoreWithMosaicDashboard(\n (state) => state.mosaic.getSelection,\n );\n const executeSql = useStoreWithDuckDb((state) => state.db.executeSql);\n const selection = useMemo<Selection>(\n () => getSelection(selectionName, 'crossfilter'),\n [getSelection, selectionName],\n );\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [datasetStates, setDatasetStates] = useState<\n Record<string, DeckMapDashboardDatasetClientState>\n >({});\n const [containerSize, setContainerSize] = useState({width: 0, height: 0});\n\n const handleDatasetState = useCallback(\n (\n datasetId: string,\n state: DeckMapDashboardDatasetClientState | undefined,\n ) => {\n setDatasetStates((current) => {\n const next = {...current};\n if (state) {\n next[datasetId] = state;\n } else {\n delete next[datasetId];\n }\n return next;\n });\n },\n [],\n );\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const updateSize = () => {\n setContainerSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n };\n\n updateSize();\n const observer = new ResizeObserver(updateSize);\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n const deckDatasets = useMemo<DeckJsonMapProps['datasets']>(() => {\n if (!mapConfig) {\n return {};\n }\n\n return createDeckMapDashboardDatasets(mapConfig, datasetStates);\n }, [datasetStates, mapConfig]);\n const fitToData = mapConfig?.fitToData ?? null;\n const fitToDataSource = useMemo(\n () =>\n fitToData\n ? resolveDeckMapDashboardDatasetSource({\n dashboard,\n panel,\n dataset: mapConfig?.datasets[fitToData.dataset],\n })\n : undefined,\n [dashboard, fitToData, mapConfig?.datasets, panel],\n );\n const fitToDataKey = useMemo(\n () =>\n fitToData && fitToDataSource\n ? JSON.stringify({\n source: fitToDataSource,\n fitToData,\n })\n : null,\n [fitToData, fitToDataSource],\n );\n const fitStateKey = useMemo(\n () => JSON.stringify({panelId: panel.id, fitToDataKey}),\n [fitToDataKey, panel.id],\n );\n const [fitState, setFitState] = useState<DeckMapDashboardFitState>(() =>\n createInitialDeckMapDashboardFitState(fitStateKey),\n );\n const activeFitState =\n fitState.key === fitStateKey\n ? fitState\n : createInitialDeckMapDashboardFitState(fitStateKey);\n const {didAutoFit, fitRequestVersion, handledFitRequestVersion, viewState} =\n activeFitState;\n\n useEffect(() => {\n const handleFitRequest = (event: Event) => {\n const detail = (event as CustomEvent<{panelId?: string}>).detail;\n if (detail?.panelId === panel.id) {\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n fitRequestVersion: scoped.fitRequestVersion + 1,\n };\n });\n }\n };\n\n deckMapDashboardFitRequestTarget.addEventListener(\n 'fit-view',\n handleFitRequest,\n );\n return () => {\n deckMapDashboardFitRequestTarget.removeEventListener(\n 'fit-view',\n handleFitRequest,\n );\n };\n }, [fitStateKey, panel.id]);\n\n useEffect(() => {\n const hasManualFitRequest = fitRequestVersion > handledFitRequestVersion;\n if (\n !fitToData ||\n !fitToDataSource ||\n containerSize.width <= 0 ||\n containerSize.height <= 0 ||\n (!hasManualFitRequest && didAutoFit)\n ) {\n return;\n }\n\n let isCancelled = false;\n\n const fitToDataBounds = async () => {\n try {\n const handle = await executeSql(\n createDeckMapBoundsQuery({\n source: fitToDataSource,\n fitToData,\n }),\n );\n const result = handle ? await handle : null;\n if (isCancelled || !result) {\n return;\n }\n\n const bounds = readBoundsFromExtentResult(result);\n if (!bounds) {\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n didAutoFit: true,\n handledFitRequestVersion: fitRequestVersion,\n };\n });\n return;\n }\n\n const nextViewState = fitViewStateToBounds({\n bounds,\n width: containerSize.width,\n height: containerSize.height,\n padding: fitToData.padding,\n maxZoom: fitToData.maxZoom,\n });\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n viewState: nextViewState,\n didAutoFit: true,\n handledFitRequestVersion: fitRequestVersion,\n };\n });\n } catch {\n if (!isCancelled) {\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n didAutoFit: true,\n handledFitRequestVersion: fitRequestVersion,\n };\n });\n }\n }\n };\n\n void fitToDataBounds();\n\n return () => {\n isCancelled = true;\n };\n }, [\n containerSize.height,\n containerSize.width,\n didAutoFit,\n executeSql,\n fitRequestVersion,\n fitStateKey,\n fitToData,\n fitToDataSource,\n handledFitRequestVersion,\n ]);\n\n const handleBrushEvent = useCallback(\n (info: DeckMapInteractionEvent) => {\n const interaction = mapConfig?.interaction;\n if (!interaction) {\n return;\n }\n\n const client = datasetStates[interaction.dataset]?.client as\n | MosaicClient\n | null\n | undefined;\n if (!client) {\n return;\n }\n const coordinate = getCoordinate(info);\n if (!coordinate) {\n return;\n }\n if (interaction.event !== 'click' && !isPickedMapFeature(info)) {\n selection.reset(\n selection.clauses.filter((clause) => clause.source === client),\n );\n return;\n }\n\n const radiusMeters = interaction.radiusMeters ?? 500;\n selection.update({\n source: client,\n clients: new Set([client]),\n value: [coordinate[0], coordinate[1], radiusMeters],\n predicate: createPointRadiusPredicate(interaction, coordinate),\n });\n },\n [datasetStates, mapConfig?.interaction, selection],\n );\n\n const handleViewStateChange = useCallback(\n ({\n viewState: nextViewState,\n interactionState,\n }: {\n viewState: any;\n interactionState?: any;\n }) => {\n const hasUserInteraction = Boolean(\n interactionState &&\n ['isDragging', 'isPanning', 'isRotating', 'isZooming'].some((key) =>\n Boolean(interactionState[key]),\n ),\n );\n if (\n fitToData &&\n !didAutoFit &&\n viewState === null &&\n !hasUserInteraction\n ) {\n return;\n }\n\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n viewState: nextViewState,\n didAutoFit: hasUserInteraction || scoped.didAutoFit || !fitToData,\n };\n });\n },\n [didAutoFit, fitStateKey, fitToData, viewState],\n );\n\n if (!mapConfig) {\n return (\n <div className=\"text-muted-foreground flex h-full items-center justify-center p-4 text-sm\">\n Invalid map panel config.\n </div>\n );\n }\n\n const datasetEntries = Object.entries(mapConfig.datasets);\n if (!datasetEntries.length) {\n return (\n <div className=\"text-muted-foreground flex h-full items-center justify-center p-4 text-sm\">\n Map panels require at least one dataset.\n </div>\n );\n }\n const datasetErrors = Object.entries(datasetStates).filter(\n ([, state]) => state.error,\n );\n\n const interactionEvent = mapConfig.interaction?.event ?? 'hover';\n const interactionDeckProps: DeckJsonMapProps['deckProps'] =\n mapConfig.interaction\n ? interactionEvent === 'click'\n ? {onClick: handleBrushEvent}\n : {onHover: handleBrushEvent}\n : {};\n\n return (\n <div ref={containerRef} className=\"relative h-full w-full\">\n {datasetEntries.map(([datasetId, dataset]) => (\n <DeckMapDashboardDatasetClient\n key={datasetId}\n dashboard={dashboard}\n dataset={dataset}\n datasetId={datasetId}\n panel={panel}\n onDatasetState={handleDatasetState}\n selectionName={selectionName}\n />\n ))}\n {datasetErrors.length ? (\n <div className=\"bg-background/90 text-destructive absolute inset-x-4 top-4 z-10 rounded-md border p-3 text-sm shadow\">\n {datasetErrors.map(([datasetId, state]) => (\n <div key={datasetId}>\n Failed to load dataset &quot;{datasetId}&quot;:{' '}\n {state.error?.message}\n </div>\n ))}\n </div>\n ) : null}\n <DeckJsonMap\n className=\"h-full w-full\"\n spec={mapConfig.spec}\n datasets={deckDatasets}\n mapStyle={mapConfig.mapStyle}\n mapProps={mapConfig.mapProps}\n showLegends={mapConfig.showLegends}\n deckProps={{\n controller: true,\n ...(viewState ? {viewState} : {}),\n onViewStateChange: handleViewStateChange,\n ...interactionDeckProps,\n }}\n />\n </div>\n );\n}\n\nexport const deckMapDashboardPanelRenderer: MosaicDashboardPanelRenderer = {\n component: DeckMapDashboardRenderer,\n headerActions: DeckMapDashboardHeaderActions,\n icon: MapIcon,\n};\n\nconst LONGITUDE_COLUMN_NAMES = ['longitude', 'lon', 'lng', 'long', 'x'];\nconst LATITUDE_COLUMN_NAMES = ['latitude', 'lat', 'y'];\n\nfunction findColumnByName(table: DataTable, candidates: string[]) {\n const candidateSet = new Set(candidates);\n return table.columns.find((column) =>\n candidateSet.has(column.name.toLowerCase()),\n )?.name;\n}\n\nfunction findLongitudeLatitudeColumns(table?: DataTable) {\n if (!table) return null;\n const longitudeColumn = findColumnByName(table, LONGITUDE_COLUMN_NAMES);\n const latitudeColumn = findColumnByName(table, LATITUDE_COLUMN_NAMES);\n return longitudeColumn && latitudeColumn\n ? {longitudeColumn, latitudeColumn}\n : null;\n}\n\nfunction quoteSqlIdentifier(identifier: string) {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction quoteTableReference(table: DataTable) {\n const qualifiedName = table.table;\n return [qualifiedName.database, qualifiedName.schema, qualifiedName.table]\n .filter((part): part is string => Boolean(part))\n .map(quoteSqlIdentifier)\n .join('.');\n}\n\nfunction createDeckMapPanelForTable(table: DataTable) {\n const coordinates = findLongitudeLatitudeColumns(table);\n if (!coordinates) return undefined;\n\n const {longitudeColumn, latitudeColumn} = coordinates;\n const datasetId = table.tableName;\n const geometryColumn = '__sqlrooms_geom';\n const quotedLongitude = quoteSqlIdentifier(longitudeColumn);\n const quotedLatitude = quoteSqlIdentifier(latitudeColumn);\n\n return createDeckMapDashboardPanelConfig({\n title: `${table.tableName} map`,\n source: {tableName: table.tableName},\n spec: {\n initialViewState: {longitude: 0, latitude: 20, zoom: 1.5},\n layers: [\n {\n '@@type': 'GeoArrowScatterplotLayer',\n id: datasetId,\n _sqlroomsBinding: {dataset: datasetId},\n filled: true,\n stroked: false,\n pickable: true,\n radiusUnits: 'pixels',\n getRadius: 4,\n getFillColor: [56, 189, 248, 180],\n },\n ],\n },\n datasets: {\n [datasetId]: {\n source: {\n sqlQuery: [\n `SELECT *, ST_AsWKB(ST_Point(${quotedLongitude}, ${quotedLatitude})) AS ${quoteSqlIdentifier(geometryColumn)}`,\n `FROM ${quoteTableReference(table)}`,\n `WHERE ${quotedLongitude} IS NOT NULL AND ${quotedLatitude} IS NOT NULL`,\n ].join(' '),\n },\n geometryColumn,\n geometryEncodingHint: 'wkb',\n },\n },\n fitToData: {\n dataset: datasetId,\n longitudeColumn,\n latitudeColumn,\n padding: 40,\n maxZoom: 12,\n },\n });\n}\n\nexport const deckMapDashboardAddPanelAction: import('@sqlrooms/mosaic').MosaicDashboardAddPanelAction =\n {\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n label: 'Map',\n icon: MapIcon,\n isEnabled: ({selectedTable}) =>\n Boolean(findLongitudeLatitudeColumns(selectedTable)),\n createPanel: ({selectedTable}) =>\n selectedTable ? createDeckMapPanelForTable(selectedTable) : undefined,\n };\n"]}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.tsx"],"names":[],"mappings":"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","sourcesContent":["import {WebMercatorViewport} from '@deck.gl/core';\nimport type {ComponentProps} from 'react';\nimport type DeckGLReact from '@deck.gl/react';\n\ntype DeckProps = ComponentProps<typeof DeckGLReact>;\nimport {\n escapeId,\n getColValAsNumber,\n useStoreWithDuckDb,\n} from '@sqlrooms/duckdb';\nimport {\n column,\n type MosaicDashboardEntryType,\n type MosaicDashboardPanelConfigType,\n type MosaicDashboardPanelRenderer,\n type MosaicDashboardPanelRendererProps,\n sql,\n type ChartDataPolicy,\n type ChartRuntimeIssue,\n type ChartRuntimeIssueContext,\n type ChartRuntimeIssueReporter,\n useMosaicClient,\n useStoreWithMosaicDashboard,\n} from '@sqlrooms/mosaic';\nimport {Button, Tooltip, TooltipContent, TooltipTrigger} from '@sqlrooms/ui';\nimport type {MosaicClient} from '@uwdata/mosaic-core';\nimport type {Selection} from '@uwdata/mosaic-core';\nimport type {Table as ArrowTable} from 'apache-arrow';\nimport {FocusIcon, MapIcon, SettingsIcon} from 'lucide-react';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {DeckMapConfigPopoverEditor} from './DeckMapConfigPopoverEditor';\nimport {DeckJsonMap} from './DeckJsonMap';\nimport {MapSettingsPanel} from './MapSettings';\nimport {MosaicDashboardPanelLayout} from '@sqlrooms/mosaic';\nimport {\n asDeckJsonMapConfig,\n createDeckMapDashboardDatasetQuery,\n createDeckMapDashboardDatasets,\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n resolveDeckMapDashboardDatasetSource,\n type DeckMapDashboardFitToDataConfig,\n type DeckMapDashboardDatasetClientState,\n type DeckMapDashboardDatasetConfig,\n type DeckMapDashboardInteractionConfig,\n type DeckMapDashboardPanelConfig,\n} from './dashboardConfig';\nimport {getDeckMapDataPolicy} from './mapDataPolicy';\nimport {\n createDeckMapDashboardPanelConfigForTable,\n findGeometryColumn,\n findLongitudeLatitudeColumns,\n} from './mapConfigUtils';\n\nfunction DeckMapRuntimeIssuePanel({issue}: {issue: ChartRuntimeIssue}) {\n const title =\n issue.kind === 'too-much-data'\n ? 'Too much data'\n : issue.kind === 'sql-error'\n ? 'Map query failed'\n : 'Unable to display map';\n\n return (\n <div className=\"flex h-full min-h-[200px] flex-col items-center justify-center p-4\">\n <div className=\"mb-2 text-center font-semibold\">{title}</div>\n <div className=\"text-center text-sm whitespace-pre-wrap\">\n {issue.message}\n </div>\n </div>\n );\n}\n\nfunction DeckMapDashboardDatasetClient({\n dashboard,\n dataset,\n datasetId,\n dataPolicy,\n panel,\n onDatasetState,\n runtimeIssueContext,\n runtimeIssueReporter,\n selectionName,\n}: {\n dashboard: MosaicDashboardEntryType;\n dataset: DeckMapDashboardDatasetConfig;\n datasetId: string;\n dataPolicy?: ChartDataPolicy | null;\n panel: MosaicDashboardPanelConfigType;\n onDatasetState: (\n datasetId: string,\n state: DeckMapDashboardDatasetClientState | undefined,\n ) => void;\n runtimeIssueContext?: ChartRuntimeIssueContext;\n runtimeIssueReporter?: ChartRuntimeIssueReporter;\n selectionName: string;\n}) {\n const source = useMemo(\n () =>\n resolveDeckMapDashboardDatasetSource({\n dashboard,\n panel,\n dataset,\n }),\n [dashboard, dataset, panel],\n );\n const query = useCallback(\n (filter: unknown) =>\n source\n ? createDeckMapDashboardDatasetQuery(source, filter)\n : createDeckMapDashboardDatasetQuery(\n {tableName: '__missing_dashboard_map_dataset__'},\n filter,\n ),\n [source],\n );\n const {data, error, isLoading, client} = useMosaicClient({\n id: `${panel.id}:${datasetId}`,\n selectionName,\n query,\n dataPolicy,\n enabled: Boolean(source),\n runtimeIssueContext,\n runtimeIssueReporter,\n });\n\n useEffect(() => {\n onDatasetState(datasetId, {\n arrowTable: data ?? undefined,\n error,\n isLoading,\n client,\n });\n\n return () => {\n onDatasetState(datasetId, undefined);\n };\n }, [client, data, datasetId, error, isLoading, onDatasetState]);\n\n return null;\n}\n\nfunction createPointRadiusPredicate(\n interaction: DeckMapDashboardInteractionConfig,\n coordinate: [number, number],\n) {\n const [longitude, latitude] = coordinate;\n const radiusMeters = interaction.radiusMeters ?? 500;\n const metersPerDegree = 111_320;\n const cosLatitude = Math.cos(latitude * (Math.PI / 180));\n const radiusSquared = radiusMeters * radiusMeters;\n\n return sql`(\n pow((${column(interaction.longitudeColumn)} - ${longitude}) * ${\n cosLatitude * metersPerDegree\n }, 2) +\n pow((${column(interaction.latitudeColumn)} - ${latitude}) * ${\n metersPerDegree\n }, 2)\n ) < ${radiusSquared}`;\n}\n\ntype DeckMapInteractionEvent = {\n coordinate?: number[] | null;\n object?: unknown;\n index?: number;\n picked?: boolean;\n};\n\nfunction getCoordinate(\n info: DeckMapInteractionEvent,\n): [number, number] | undefined {\n return info.coordinate && info.coordinate.length >= 2\n ? [info.coordinate[0]!, info.coordinate[1]!]\n : undefined;\n}\n\nfunction isPickedMapFeature(info: DeckMapInteractionEvent) {\n return Boolean(info.picked || info.object || (info.index ?? -1) >= 0);\n}\n\nfunction createDeckMapBoundsQuery(options: {\n source: {tableName?: string; sqlQuery?: string};\n fitToData: DeckMapDashboardFitToDataConfig;\n}) {\n const {source, fitToData} = options;\n const baseSourceSql = source.sqlQuery\n ? `SELECT * FROM (${source.sqlQuery}) AS \"__sqlrooms_dashboard_map_source\"`\n : `SELECT * FROM ${(source.tableName ?? '')\n .split('.')\n .map(escapeId)\n .join('.')}`;\n const longitudeColumn = escapeId(fitToData.longitudeColumn);\n const latitudeColumn = escapeId(fitToData.latitudeColumn);\n\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(ST_Point(${longitudeColumn}, ${latitudeColumn})) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_points\"\n WHERE ${longitudeColumn} IS NOT NULL AND ${latitudeColumn} IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n}\n\nfunction readBoundsFromExtentResult(result: ArrowTable) {\n const minLongitude = getColValAsNumber(result, 'min_longitude');\n const minLatitude = getColValAsNumber(result, 'min_latitude');\n const maxLongitude = getColValAsNumber(result, 'max_longitude');\n const maxLatitude = getColValAsNumber(result, 'max_latitude');\n if (\n !Number.isFinite(minLongitude) ||\n !Number.isFinite(minLatitude) ||\n !Number.isFinite(maxLongitude) ||\n !Number.isFinite(maxLatitude)\n ) {\n return null;\n }\n\n return [\n [\n minLongitude === maxLongitude ? minLongitude - 0.01 : minLongitude,\n minLatitude === maxLatitude ? minLatitude - 0.01 : minLatitude,\n ],\n [\n minLongitude === maxLongitude ? maxLongitude + 0.01 : maxLongitude,\n minLatitude === maxLatitude ? maxLatitude + 0.01 : maxLatitude,\n ],\n ] as const;\n}\n\nfunction fitViewStateToBounds(options: {\n bounds: readonly [readonly [number, number], readonly [number, number]];\n width: number;\n height: number;\n padding?: number;\n maxZoom?: number;\n}) {\n const {bounds, width, height, padding = 40, maxZoom = 12} = options;\n const viewport = new WebMercatorViewport({\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n });\n const fitted = viewport.fitBounds(\n [\n [bounds[0][0], bounds[0][1]],\n [bounds[1][0], bounds[1][1]],\n ],\n {padding},\n ) as WebMercatorViewport & {\n longitude: number;\n latitude: number;\n zoom: number;\n };\n\n return {\n longitude: fitted.longitude,\n latitude: fitted.latitude,\n zoom: Math.min(fitted.zoom, maxZoom),\n };\n}\n\nconst deckMapDashboardFitRequestTarget = new EventTarget();\n\nfunction emitDeckMapDashboardFitRequest(panelId: string) {\n deckMapDashboardFitRequestTarget.dispatchEvent(\n new CustomEvent('fit-view', {detail: {panelId}}),\n );\n}\n\ntype DeckMapDashboardFitState = {\n key: string;\n viewState: DeckProps['viewState'];\n didAutoFit: boolean;\n fitRequestVersion: number;\n handledFitRequestVersion: number;\n};\n\nfunction createInitialDeckMapDashboardFitState(\n key: string,\n): DeckMapDashboardFitState {\n return {\n key,\n viewState: undefined,\n didAutoFit: false,\n fitRequestVersion: 0,\n handledFitRequestVersion: 0,\n };\n}\n\nfunction DeckMapDashboardHeaderActions({\n dashboardId,\n panel,\n}: MosaicDashboardPanelRendererProps) {\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n const mapConfig = asDeckJsonMapConfig(panel.config);\n const canFitView = Boolean(mapConfig?.fitToData);\n\n const isSettingsOpen = Boolean(mapConfig?.settingsOpen);\n\n const handleConfigApply = useCallback(\n (nextConfig: Record<string, unknown>) => {\n updatePanel(dashboardId, panel.id, {\n config: nextConfig,\n });\n },\n [dashboardId, panel.id, updatePanel],\n );\n\n const handleToggleSettings = useCallback(() => {\n updatePanel(dashboardId, panel.id, {\n config: {...panel.config, settingsOpen: !isSettingsOpen},\n });\n }, [dashboardId, isSettingsOpen, panel.config, panel.id, updatePanel]);\n\n return (\n <div className=\"flex items-center gap-0.5\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"data-[state=active]:bg-accent h-6 w-6\"\n title=\"Map settings\"\n onClick={handleToggleSettings}\n data-state={isSettingsOpen ? 'active' : 'inactive'}\n >\n <SettingsIcon className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Map settings</TooltipContent>\n </Tooltip>\n <DeckMapConfigPopoverEditor\n value={panel.config}\n onApply={handleConfigApply}\n />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n title={\n canFitView\n ? 'Fit map view to data'\n : 'Fit view unavailable for this map'\n }\n disabled={!canFitView}\n onClick={() => emitDeckMapDashboardFitRequest(panel.id)}\n >\n <FocusIcon className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n );\n}\n\nfunction DeckMapDashboardRenderer({\n dashboard,\n dashboardId,\n panel,\n selectionName,\n}: MosaicDashboardPanelRendererProps) {\n const mapConfig = asDeckJsonMapConfig(panel.config);\n const getSelection = useStoreWithMosaicDashboard(\n (state) => state.mosaic.getSelection,\n );\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n const issue = useStoreWithMosaicDashboard((state) =>\n state.mosaicDashboard.getPanelIssue(dashboardId, panel.id),\n );\n const reportPanelIssue = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.reportPanelIssue,\n );\n const clearPanelIssue = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.clearPanelIssue,\n );\n const executeSql = useStoreWithDuckDb((state) => state.db.executeSql);\n\n const isSettingsOpen = Boolean(\n (panel.config as DeckMapDashboardPanelConfig).settingsOpen,\n );\n\n const handleSettingsOpenChange = useCallback(\n (isOpen: boolean) => {\n updatePanel(dashboardId, panel.id, {\n config: {...panel.config, settingsOpen: isOpen},\n });\n },\n [dashboardId, panel.config, panel.id, updatePanel],\n );\n const selection = useMemo<Selection>(\n () => getSelection(selectionName, 'crossfilter'),\n [getSelection, selectionName],\n );\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [datasetStates, setDatasetStates] = useState<\n Record<string, DeckMapDashboardDatasetClientState>\n >({});\n const [containerSize, setContainerSize] = useState({width: 0, height: 0});\n\n const handleDatasetState = useCallback(\n (\n datasetId: string,\n state: DeckMapDashboardDatasetClientState | undefined,\n ) => {\n setDatasetStates((current) => {\n const next = {...current};\n if (state) {\n next[datasetId] = state;\n } else {\n delete next[datasetId];\n }\n return next;\n });\n },\n [],\n );\n\n const dataPolicy = useMemo<ChartDataPolicy>(\n () => getDeckMapDataPolicy(mapConfig),\n [mapConfig],\n );\n const runtimeIssueContext = useMemo(\n () => ({\n panelId: panel.id,\n chartType: DECK_MAP_DASHBOARD_PANEL_TYPE,\n }),\n [panel.id],\n );\n const runtimeIssueReporter = useMemo<ChartRuntimeIssueReporter>(\n () => ({\n reportIssue: (issueToReport) => {\n reportPanelIssue(dashboardId, panel.id, issueToReport);\n },\n clearIssue: () => {\n clearPanelIssue(dashboardId, panel.id);\n },\n }),\n [clearPanelIssue, dashboardId, panel.id, reportPanelIssue],\n );\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const updateSize = () => {\n setContainerSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n };\n\n updateSize();\n const observer = new ResizeObserver(updateSize);\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n const fitToData = mapConfig?.fitToData ?? null;\n const fitToDataSource = useMemo(\n () =>\n fitToData\n ? resolveDeckMapDashboardDatasetSource({\n dashboard,\n panel,\n dataset: mapConfig?.datasets[fitToData.dataset],\n })\n : undefined,\n [dashboard, fitToData, mapConfig?.datasets, panel],\n );\n const fitToDataKey = useMemo(\n () =>\n fitToData && fitToDataSource\n ? JSON.stringify({\n source: fitToDataSource,\n fitToData,\n })\n : null,\n [fitToData, fitToDataSource],\n );\n const fitStateKey = useMemo(\n () => JSON.stringify({panelId: panel.id, fitToDataKey}),\n [fitToDataKey, panel.id],\n );\n const [fitState, setFitState] = useState<DeckMapDashboardFitState>(() =>\n createInitialDeckMapDashboardFitState(fitStateKey),\n );\n const activeFitState =\n fitState.key === fitStateKey\n ? fitState\n : createInitialDeckMapDashboardFitState(fitStateKey);\n const {didAutoFit, fitRequestVersion, handledFitRequestVersion, viewState} =\n activeFitState;\n\n useEffect(() => {\n const handleFitRequest = (event: Event) => {\n const detail = (event as CustomEvent<{panelId?: string}>).detail;\n if (detail?.panelId === panel.id) {\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n fitRequestVersion: scoped.fitRequestVersion + 1,\n };\n });\n }\n };\n\n deckMapDashboardFitRequestTarget.addEventListener(\n 'fit-view',\n handleFitRequest,\n );\n return () => {\n deckMapDashboardFitRequestTarget.removeEventListener(\n 'fit-view',\n handleFitRequest,\n );\n };\n }, [fitStateKey, panel.id]);\n\n useEffect(() => {\n const hasManualFitRequest = fitRequestVersion > handledFitRequestVersion;\n if (\n !fitToData ||\n !fitToDataSource ||\n containerSize.width <= 0 ||\n containerSize.height <= 0 ||\n (!hasManualFitRequest && didAutoFit)\n ) {\n return;\n }\n\n let isCancelled = false;\n\n const fitToDataBounds = async () => {\n try {\n const handle = await executeSql(\n createDeckMapBoundsQuery({\n source: fitToDataSource,\n fitToData,\n }),\n );\n const result = handle ? await handle : null;\n if (isCancelled || !result) {\n return;\n }\n\n const bounds = readBoundsFromExtentResult(result);\n if (!bounds) {\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n didAutoFit: true,\n handledFitRequestVersion: fitRequestVersion,\n };\n });\n return;\n }\n\n const nextViewState = fitViewStateToBounds({\n bounds,\n width: containerSize.width,\n height: containerSize.height,\n padding: fitToData.padding,\n maxZoom: fitToData.maxZoom,\n });\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n viewState: nextViewState,\n didAutoFit: true,\n handledFitRequestVersion: fitRequestVersion,\n };\n });\n } catch {\n if (!isCancelled) {\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n didAutoFit: true,\n handledFitRequestVersion: fitRequestVersion,\n };\n });\n }\n }\n };\n\n void fitToDataBounds();\n\n return () => {\n isCancelled = true;\n };\n }, [\n containerSize.height,\n containerSize.width,\n didAutoFit,\n executeSql,\n fitRequestVersion,\n fitStateKey,\n fitToData,\n fitToDataSource,\n handledFitRequestVersion,\n ]);\n\n const handleBrushEvent = useCallback(\n (info: DeckMapInteractionEvent) => {\n const interaction = mapConfig?.interaction;\n if (!interaction) {\n return;\n }\n\n const client = datasetStates[interaction.dataset]?.client as\n | MosaicClient\n | null\n | undefined;\n if (!client) {\n return;\n }\n const coordinate = getCoordinate(info);\n if (!coordinate) {\n return;\n }\n if (interaction.event !== 'click' && !isPickedMapFeature(info)) {\n selection.reset(\n selection.clauses.filter((clause) => clause.source === client),\n );\n return;\n }\n\n const radiusMeters = interaction.radiusMeters ?? 500;\n selection.update({\n source: client,\n clients: new Set([client]),\n value: [coordinate[0], coordinate[1], radiusMeters],\n predicate: createPointRadiusPredicate(interaction, coordinate),\n });\n },\n [datasetStates, mapConfig?.interaction, selection],\n );\n\n const handleViewStateChange = useCallback(\n ({\n viewState: nextViewState,\n interactionState,\n }: {\n viewState: any;\n interactionState?: any;\n }) => {\n const hasUserInteraction = Boolean(\n interactionState &&\n ['isDragging', 'isPanning', 'isRotating', 'isZooming'].some((key) =>\n Boolean(interactionState[key]),\n ),\n );\n if (\n fitToData &&\n !didAutoFit &&\n viewState === null &&\n !hasUserInteraction\n ) {\n return;\n }\n\n setFitState((current) => {\n const scoped =\n current.key === fitStateKey\n ? current\n : createInitialDeckMapDashboardFitState(fitStateKey);\n return {\n ...scoped,\n viewState: nextViewState,\n didAutoFit: hasUserInteraction || scoped.didAutoFit || !fitToData,\n };\n });\n },\n [didAutoFit, fitStateKey, fitToData, viewState],\n );\n\n const settingsContent = (\n <MapSettingsPanel\n dashboardId={dashboardId}\n panel={panel}\n onClose={() => handleSettingsOpenChange(false)}\n />\n );\n\n const mapContent = !mapConfig ? (\n <div className=\"text-muted-foreground flex h-full items-center justify-center p-4 text-sm\">\n Invalid map panel config.\n </div>\n ) : issue ? (\n <DeckMapRuntimeIssuePanel issue={issue} />\n ) : Object.entries(mapConfig.datasets).length === 0 ? (\n <div className=\"text-muted-foreground flex h-full items-center justify-center p-4 text-sm\">\n Map panels require at least one dataset.\n </div>\n ) : (\n <div ref={containerRef} className=\"relative h-full w-full\">\n {Object.entries(mapConfig.datasets).map(([datasetId, dataset]) => (\n <DeckMapDashboardDatasetClient\n key={datasetId}\n dashboard={dashboard}\n dataset={dataset}\n datasetId={datasetId}\n dataPolicy={dataPolicy}\n panel={panel}\n onDatasetState={handleDatasetState}\n runtimeIssueContext={runtimeIssueContext}\n runtimeIssueReporter={runtimeIssueReporter}\n selectionName={selectionName}\n />\n ))}\n {Object.entries(datasetStates)\n .filter(([, state]) => state.error)\n .map(([datasetId, state]) => (\n <div\n key={datasetId}\n className=\"bg-background/90 text-destructive absolute inset-x-4 top-4 z-10 rounded-md border p-3 text-sm shadow\"\n >\n Failed to load dataset &quot;{datasetId}&quot;:{' '}\n {state.error?.message}\n </div>\n ))}\n <DeckJsonMap\n className=\"h-full w-full\"\n spec={mapConfig.spec}\n datasets={\n mapConfig\n ? createDeckMapDashboardDatasets(mapConfig, datasetStates)\n : {}\n }\n mapStyle={mapConfig.mapStyle}\n mapProps={mapConfig.mapProps}\n showLegends={mapConfig.showLegends}\n deckProps={{\n controller: true,\n ...(viewState ? {viewState} : {}),\n onViewStateChange: handleViewStateChange,\n ...(mapConfig.interaction\n ? (mapConfig.interaction.event ?? 'hover') === 'click'\n ? {onClick: handleBrushEvent}\n : {onHover: handleBrushEvent}\n : {}),\n }}\n />\n </div>\n );\n\n return (\n <div className=\"h-full min-h-0\">\n <MosaicDashboardPanelLayout\n isOpen={isSettingsOpen}\n onIsOpenChange={handleSettingsOpenChange}\n settings={settingsContent}\n content={mapContent}\n />\n </div>\n );\n}\n\nexport const deckMapDashboardPanelRenderer: MosaicDashboardPanelRenderer = {\n component: DeckMapDashboardRenderer,\n headerActions: DeckMapDashboardHeaderActions,\n icon: MapIcon,\n};\n\nexport const deckMapDashboardAddPanelAction: import('@sqlrooms/mosaic').MosaicDashboardAddPanelAction =\n {\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n label: 'Map',\n icon: MapIcon,\n isEnabled: ({selectedTable}) =>\n Boolean(\n findLongitudeLatitudeColumns(selectedTable) ??\n findGeometryColumn(selectedTable),\n ),\n createPanel: ({selectedTable}) =>\n selectedTable\n ? createDeckMapDashboardPanelConfigForTable({\n title: `${selectedTable.tableName} map`,\n tableName: selectedTable.tableName,\n columns: selectedTable.columns,\n tableReference: selectedTable.table,\n })\n : undefined,\n };\n"]}
@@ -1,9 +1,18 @@
1
- import { type MosaicDashboardEntryType, type MosaicDashboardPanelConfigType, type MosaicDashboardPanelSourceType } from '@sqlrooms/mosaic';
1
+ import { type MosaicDashboardEntryType, type MosaicDashboardPanelConfigType } from '@sqlrooms/mosaic';
2
2
  import type { Table as ArrowTable } from 'apache-arrow';
3
3
  import type { DeckJsonMapProps, DeckSqlDatasetInput } from './types';
4
4
  export declare const DECK_MAP_DASHBOARD_PANEL_TYPE = "deck-json-map";
5
+ export declare const DEFAULT_DECK_MAP_MAX_DATA_POINTS = 100000;
6
+ export type DeckMapDataPolicyOverride = {
7
+ disabled?: boolean;
8
+ maxRows?: number;
9
+ reason?: string;
10
+ };
5
11
  export type DeckMapDashboardDatasetConfig = Omit<DeckSqlDatasetInput, 'sqlQuery'> & {
6
- source?: MosaicDashboardPanelSourceType;
12
+ source?: {
13
+ tableName?: string;
14
+ sqlQuery?: string;
15
+ };
7
16
  };
8
17
  export type DeckMapDashboardInteractionConfig = {
9
18
  type: 'point-radius-brush';
@@ -28,10 +37,11 @@ export type DeckMapDashboardPanelConfig = {
28
37
  showLegends?: boolean;
29
38
  interaction?: DeckMapDashboardInteractionConfig;
30
39
  fitToData?: DeckMapDashboardFitToDataConfig;
40
+ dataPolicy?: DeckMapDataPolicyOverride;
41
+ settingsOpen?: boolean;
31
42
  };
32
43
  export type CreateDeckMapDashboardPanelConfigOptions = DeckMapDashboardPanelConfig & {
33
44
  title?: string;
34
- source?: MosaicDashboardPanelSourceType;
35
45
  };
36
46
  export type DeckMapDashboardDatasetClientState = {
37
47
  arrowTable?: ArrowTable;
@@ -40,12 +50,18 @@ export type DeckMapDashboardDatasetClientState = {
40
50
  client: unknown;
41
51
  };
42
52
  export declare function asDeckJsonMapConfig(config: Record<string, unknown>): DeckMapDashboardPanelConfig | null;
43
- export declare function createDeckMapDashboardPanelConfig(options: CreateDeckMapDashboardPanelConfigOptions): MosaicDashboardPanelConfigType;
53
+ export declare function createDeckMapDashboardPanelConfig(options: CreateDeckMapDashboardPanelConfigOptions): any;
44
54
  export declare function resolveDeckMapDashboardDatasetSource(options: {
45
55
  dashboard: MosaicDashboardEntryType;
46
56
  panel: MosaicDashboardPanelConfigType;
47
57
  dataset?: DeckMapDashboardDatasetConfig;
48
- }): MosaicDashboardPanelSourceType | undefined;
49
- export declare function createDeckMapDashboardDatasetQuery(source: MosaicDashboardPanelSourceType, filter: unknown): import("@uwdata/mosaic-sql").SelectQuery;
58
+ }): {
59
+ tableName?: string;
60
+ sqlQuery?: string;
61
+ } | undefined;
62
+ export declare function createDeckMapDashboardDatasetQuery(source: {
63
+ tableName?: string;
64
+ sqlQuery?: string;
65
+ }, filter: unknown): import("@uwdata/mosaic-sql").SelectQuery;
50
66
  export declare function createDeckMapDashboardDatasets(mapConfig: DeckMapDashboardPanelConfig, datasetStates: Record<string, Pick<DeckMapDashboardDatasetClientState, 'arrowTable'>>): DeckJsonMapProps['datasets'];
51
67
  //# sourceMappingURL=dashboardConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboardConfig.d.ts","sourceRoot":"","sources":["../src/dashboardConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,8BAA8B,EACnC,KAAK,8BAA8B,EAEpC,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EAAC,KAAK,IAAI,UAAU,EAAC,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAC,gBAAgB,EAAE,mBAAmB,EAAC,MAAM,SAAS,CAAC;AAEnE,eAAO,MAAM,6BAA6B,kBAAkB,CAAC;AAE7D,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAC9C,mBAAmB,EACnB,UAAU,CACX,GAAG;IACF,MAAM,CAAC,EAAE,8BAA8B,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,oBAAoB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,iCAAiC,CAAC;IAChD,SAAS,CAAC,EAAE,+BAA+B,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,wCAAwC,GAClD,2BAA2B,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,8BAA8B,CAAC;CACzC,CAAC;AAEJ,MAAM,MAAM,kCAAkC,GAAG;IAC/C,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,2BAA2B,GAAG,IAAI,CAWpC;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,wCAAwC,GAChD,8BAA8B,CAShC;AAED,wBAAgB,oCAAoC,CAAC,OAAO,EAAE;IAC5D,SAAS,EAAE,wBAAwB,CAAC;IACpC,KAAK,EAAE,8BAA8B,CAAC;IACtC,OAAO,CAAC,EAAE,6BAA6B,CAAC;CACzC,GAAG,8BAA8B,GAAG,SAAS,CAW7C;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,8BAA8B,EACtC,MAAM,EAAE,OAAO,4CAShB;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,2BAA2B,EACtC,aAAa,EAAE,MAAM,CACnB,MAAM,EACN,IAAI,CAAC,kCAAkC,EAAE,YAAY,CAAC,CACvD,GACA,gBAAgB,CAAC,UAAU,CAAC,CAW9B"}
1
+ {"version":3,"file":"dashboardConfig.d.ts","sourceRoot":"","sources":["../src/dashboardConfig.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { Query, } from '@sqlrooms/mosaic';
2
2
  import { createId } from '@paralleldrive/cuid2';
3
3
  import { verbatim } from '@uwdata/mosaic-sql';
4
4
  export const DECK_MAP_DASHBOARD_PANEL_TYPE = 'deck-json-map';
5
+ export const DEFAULT_DECK_MAP_MAX_DATA_POINTS = 100_000;
5
6
  export function asDeckJsonMapConfig(config) {
6
7
  if (!config.spec ||
7
8
  !config.datasets ||
@@ -12,12 +13,11 @@ export function asDeckJsonMapConfig(config) {
12
13
  return config;
13
14
  }
14
15
  export function createDeckMapDashboardPanelConfig(options) {
15
- const { title, source, ...config } = options;
16
+ const { title, ...config } = options;
16
17
  return {
17
18
  id: createId(),
18
19
  type: DECK_MAP_DASHBOARD_PANEL_TYPE,
19
20
  title: title ?? 'Map',
20
- ...(source ? { source } : {}),
21
21
  config: JSON.parse(JSON.stringify(config)),
22
22
  };
23
23
  }
@@ -26,9 +26,6 @@ export function resolveDeckMapDashboardDatasetSource(options) {
26
26
  if (datasetSource?.sqlQuery || datasetSource?.tableName) {
27
27
  return datasetSource;
28
28
  }
29
- if (options.panel.source?.sqlQuery || options.panel.source?.tableName) {
30
- return options.panel.source;
31
- }
32
29
  return options.dashboard.selectedTable
33
30
  ? { tableName: options.dashboard.selectedTable }
34
31
  : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboardConfig.js","sourceRoot":"","sources":["../src/dashboardConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,GACN,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAI5C,MAAM,CAAC,MAAM,6BAA6B,GAAG,eAAe,CAAC;AAiD7D,MAAM,UAAU,mBAAmB,CACjC,MAA+B;IAE/B,IACE,CAAC,MAAM,CAAC,IAAI;QACZ,CAAC,MAAM,CAAC,QAAQ;QAChB,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACnC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAC9B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAqC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,OAAiD;IAEjD,MAAM,EAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAC,GAAG,OAAO,CAAC;IAC3C,OAAO;QACL,EAAE,EAAE,QAAQ,EAAE;QACd,IAAI,EAAE,6BAA6B;QACnC,KAAK,EAAE,KAAK,IAAI,KAAK;QACrB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAC,MAAM,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAA4B;KACtE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oCAAoC,CAAC,OAIpD;IACC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC;IAC9C,IAAI,aAAa,EAAE,QAAQ,IAAI,aAAa,EAAE,SAAS,EAAE,CAAC;QACxD,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;QACtE,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;IAC9B,CAAC;IACD,OAAO,OAAO,CAAC,SAAS,CAAC,aAAa;QACpC,CAAC,CAAC,EAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,aAAa,EAAC;QAC9C,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,kCAAkC,CAChD,MAAsC,EACtC,MAAe;IAEf,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ;QAC3B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YACT,uBAAuB,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC;SAC1D,CAAC;QACJ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAEvC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAe,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,SAAsC,EACtC,aAGC;IAED,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;QAC/D,SAAS;QACT;YACE,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE,UAAU;YAChD,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;SACnD;KACF,CAAC,CACH,CAAC;AACJ,CAAC","sourcesContent":["import {\n type MosaicDashboardEntryType,\n type MosaicDashboardPanelConfigType,\n type MosaicDashboardPanelSourceType,\n Query,\n} from '@sqlrooms/mosaic';\nimport {createId} from '@paralleldrive/cuid2';\nimport {verbatim} from '@uwdata/mosaic-sql';\nimport type {Table as ArrowTable} from 'apache-arrow';\nimport type {DeckJsonMapProps, DeckSqlDatasetInput} from './types';\n\nexport const DECK_MAP_DASHBOARD_PANEL_TYPE = 'deck-json-map';\n\nexport type DeckMapDashboardDatasetConfig = Omit<\n DeckSqlDatasetInput,\n 'sqlQuery'\n> & {\n source?: MosaicDashboardPanelSourceType;\n};\n\nexport type DeckMapDashboardInteractionConfig = {\n type: 'point-radius-brush';\n dataset: string;\n longitudeColumn: string;\n latitudeColumn: string;\n radiusMeters?: number;\n event?: 'hover' | 'click';\n};\n\nexport type DeckMapDashboardFitToDataConfig = {\n dataset: string;\n longitudeColumn: string;\n latitudeColumn: string;\n padding?: number;\n maxZoom?: number;\n};\n\nexport type DeckMapDashboardPanelConfig = {\n spec: DeckJsonMapProps['spec'];\n datasets: Record<string, DeckMapDashboardDatasetConfig>;\n mapStyle?: string;\n mapProps?: Record<string, unknown>;\n showLegends?: boolean;\n interaction?: DeckMapDashboardInteractionConfig;\n fitToData?: DeckMapDashboardFitToDataConfig;\n};\n\nexport type CreateDeckMapDashboardPanelConfigOptions =\n DeckMapDashboardPanelConfig & {\n title?: string;\n source?: MosaicDashboardPanelSourceType;\n };\n\nexport type DeckMapDashboardDatasetClientState = {\n arrowTable?: ArrowTable;\n isLoading: boolean;\n error?: Error;\n client: unknown;\n};\n\nexport function asDeckJsonMapConfig(\n config: Record<string, unknown>,\n): DeckMapDashboardPanelConfig | null {\n if (\n !config.spec ||\n !config.datasets ||\n typeof config.datasets !== 'object' ||\n Array.isArray(config.datasets)\n ) {\n return null;\n }\n\n return config as DeckMapDashboardPanelConfig;\n}\n\nexport function createDeckMapDashboardPanelConfig(\n options: CreateDeckMapDashboardPanelConfigOptions,\n): MosaicDashboardPanelConfigType {\n const {title, source, ...config} = options;\n return {\n id: createId(),\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n title: title ?? 'Map',\n ...(source ? {source} : {}),\n config: JSON.parse(JSON.stringify(config)) as Record<string, unknown>,\n };\n}\n\nexport function resolveDeckMapDashboardDatasetSource(options: {\n dashboard: MosaicDashboardEntryType;\n panel: MosaicDashboardPanelConfigType;\n dataset?: DeckMapDashboardDatasetConfig;\n}): MosaicDashboardPanelSourceType | undefined {\n const datasetSource = options.dataset?.source;\n if (datasetSource?.sqlQuery || datasetSource?.tableName) {\n return datasetSource;\n }\n if (options.panel.source?.sqlQuery || options.panel.source?.tableName) {\n return options.panel.source;\n }\n return options.dashboard.selectedTable\n ? {tableName: options.dashboard.selectedTable}\n : undefined;\n}\n\nexport function createDeckMapDashboardDatasetQuery(\n source: MosaicDashboardPanelSourceType,\n filter: unknown,\n) {\n const query = source.sqlQuery\n ? Query.from({\n __dashboard_map_dataset: verbatim(`(${source.sqlQuery})`),\n })\n : Query.from(source.tableName ?? '');\n\n return query.select('*').where(filter as never);\n}\n\nexport function createDeckMapDashboardDatasets(\n mapConfig: DeckMapDashboardPanelConfig,\n datasetStates: Record<\n string,\n Pick<DeckMapDashboardDatasetClientState, 'arrowTable'>\n >,\n): DeckJsonMapProps['datasets'] {\n return Object.fromEntries(\n Object.entries(mapConfig.datasets).map(([datasetId, dataset]) => [\n datasetId,\n {\n arrowTable: datasetStates[datasetId]?.arrowTable,\n geometryColumn: dataset.geometryColumn,\n geometryEncodingHint: dataset.geometryEncodingHint,\n },\n ]),\n );\n}\n"]}
1
+ {"version":3,"file":"dashboardConfig.js","sourceRoot":"","sources":["../src/dashboardConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,GACN,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAI5C,MAAM,CAAC,MAAM,6BAA6B,GAAG,eAAe,CAAC;AAC7D,MAAM,CAAC,MAAM,gCAAgC,GAAG,OAAO,CAAC;AAwDxD,MAAM,UAAU,mBAAmB,CACjC,MAA+B;IAE/B,IACE,CAAC,MAAM,CAAC,IAAI;QACZ,CAAC,MAAM,CAAC,QAAQ;QAChB,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACnC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAC9B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAqC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,OAAiD;IAEjD,MAAM,EAAC,KAAK,EAAE,GAAG,MAAM,EAAC,GAAG,OAAO,CAAC;IACnC,OAAO;QACL,EAAE,EAAE,QAAQ,EAAE;QACd,IAAI,EAAE,6BAA6B;QACnC,KAAK,EAAE,KAAK,IAAI,KAAK;QACrB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAA4B;KACtE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oCAAoC,CAAC,OAIpD;IACC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC;IAC9C,IAAI,aAAa,EAAE,QAAQ,IAAI,aAAa,EAAE,SAAS,EAAE,CAAC;QACxD,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,OAAO,OAAO,CAAC,SAAS,CAAC,aAAa;QACpC,CAAC,CAAC,EAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,aAAa,EAAC;QAC9C,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,kCAAkC,CAChD,MAA+C,EAC/C,MAAe;IAEf,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ;QAC3B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YACT,uBAAuB,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC;SAC1D,CAAC;QACJ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAEvC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAe,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,SAAsC,EACtC,aAGC;IAED,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;QAC/D,SAAS;QACT;YACE,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE,UAAU;YAChD,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;SACnD;KACF,CAAC,CACH,CAAC;AACJ,CAAC","sourcesContent":["import {\n type MosaicDashboardEntryType,\n type MosaicDashboardPanelConfigType,\n Query,\n} from '@sqlrooms/mosaic';\nimport {createId} from '@paralleldrive/cuid2';\nimport {verbatim} from '@uwdata/mosaic-sql';\nimport type {Table as ArrowTable} from 'apache-arrow';\nimport type {DeckJsonMapProps, DeckSqlDatasetInput} from './types';\n\nexport const DECK_MAP_DASHBOARD_PANEL_TYPE = 'deck-json-map';\nexport const DEFAULT_DECK_MAP_MAX_DATA_POINTS = 100_000;\n\nexport type DeckMapDataPolicyOverride = {\n disabled?: boolean;\n maxRows?: number;\n reason?: string;\n};\n\nexport type DeckMapDashboardDatasetConfig = Omit<\n DeckSqlDatasetInput,\n 'sqlQuery'\n> & {\n source?: {tableName?: string; sqlQuery?: string};\n};\n\nexport type DeckMapDashboardInteractionConfig = {\n type: 'point-radius-brush';\n dataset: string;\n longitudeColumn: string;\n latitudeColumn: string;\n radiusMeters?: number;\n event?: 'hover' | 'click';\n};\n\nexport type DeckMapDashboardFitToDataConfig = {\n dataset: string;\n longitudeColumn: string;\n latitudeColumn: string;\n padding?: number;\n maxZoom?: number;\n};\n\nexport type DeckMapDashboardPanelConfig = {\n spec: DeckJsonMapProps['spec'];\n datasets: Record<string, DeckMapDashboardDatasetConfig>;\n mapStyle?: string;\n mapProps?: Record<string, unknown>;\n showLegends?: boolean;\n interaction?: DeckMapDashboardInteractionConfig;\n fitToData?: DeckMapDashboardFitToDataConfig;\n dataPolicy?: DeckMapDataPolicyOverride;\n settingsOpen?: boolean;\n};\n\nexport type CreateDeckMapDashboardPanelConfigOptions =\n DeckMapDashboardPanelConfig & {\n title?: string;\n };\n\nexport type DeckMapDashboardDatasetClientState = {\n arrowTable?: ArrowTable;\n isLoading: boolean;\n error?: Error;\n client: unknown;\n};\n\nexport function asDeckJsonMapConfig(\n config: Record<string, unknown>,\n): DeckMapDashboardPanelConfig | null {\n if (\n !config.spec ||\n !config.datasets ||\n typeof config.datasets !== 'object' ||\n Array.isArray(config.datasets)\n ) {\n return null;\n }\n\n return config as DeckMapDashboardPanelConfig;\n}\n\nexport function createDeckMapDashboardPanelConfig(\n options: CreateDeckMapDashboardPanelConfigOptions,\n): any {\n const {title, ...config} = options;\n return {\n id: createId(),\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n title: title ?? 'Map',\n config: JSON.parse(JSON.stringify(config)) as Record<string, unknown>,\n };\n}\n\nexport function resolveDeckMapDashboardDatasetSource(options: {\n dashboard: MosaicDashboardEntryType;\n panel: MosaicDashboardPanelConfigType;\n dataset?: DeckMapDashboardDatasetConfig;\n}): {tableName?: string; sqlQuery?: string} | undefined {\n const datasetSource = options.dataset?.source;\n if (datasetSource?.sqlQuery || datasetSource?.tableName) {\n return datasetSource;\n }\n return options.dashboard.selectedTable\n ? {tableName: options.dashboard.selectedTable}\n : undefined;\n}\n\nexport function createDeckMapDashboardDatasetQuery(\n source: {tableName?: string; sqlQuery?: string},\n filter: unknown,\n) {\n const query = source.sqlQuery\n ? Query.from({\n __dashboard_map_dataset: verbatim(`(${source.sqlQuery})`),\n })\n : Query.from(source.tableName ?? '');\n\n return query.select('*').where(filter as never);\n}\n\nexport function createDeckMapDashboardDatasets(\n mapConfig: DeckMapDashboardPanelConfig,\n datasetStates: Record<\n string,\n Pick<DeckMapDashboardDatasetClientState, 'arrowTable'>\n >,\n): DeckJsonMapProps['datasets'] {\n return Object.fromEntries(\n Object.entries(mapConfig.datasets).map(([datasetId, dataset]) => [\n datasetId,\n {\n arrowTable: datasetStates[datasetId]?.arrowTable,\n geometryColumn: dataset.geometryColumn,\n geometryEncodingHint: dataset.geometryEncodingHint,\n },\n ]),\n );\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { type CreateMosaicDashboardSliceProps } from '@sqlrooms/mosaic';
2
+ export declare function createDeckMapDashboardSliceOptions(): CreateMosaicDashboardSliceProps;
3
+ //# sourceMappingURL=dashboardIntegration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboardIntegration.d.ts","sourceRoot":"","sources":["../src/dashboardIntegration.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,+BAA+B,EACrC,MAAM,kBAAkB,CAAC;AAO1B,wBAAgB,kCAAkC,IAAI,+BAA+B,CAWpF"}
@@ -0,0 +1,16 @@
1
+ import { createDefaultChartTypes, createDefaultMosaicDashboardPanelRenderers, defaultAddPanelActions, } from '@sqlrooms/mosaic';
2
+ import { deckMapDashboardAddPanelAction, deckMapDashboardPanelRenderer, } from './dashboard';
3
+ import { DECK_MAP_DASHBOARD_PANEL_TYPE } from './dashboardConfig';
4
+ export function createDeckMapDashboardSliceOptions() {
5
+ return {
6
+ panelRenderers: createDefaultMosaicDashboardPanelRenderers({
7
+ [DECK_MAP_DASHBOARD_PANEL_TYPE]: deckMapDashboardPanelRenderer,
8
+ }),
9
+ addPanelActions: [
10
+ ...defaultAddPanelActions,
11
+ deckMapDashboardAddPanelAction,
12
+ ],
13
+ chartTypes: createDefaultChartTypes(),
14
+ };
15
+ }
16
+ //# sourceMappingURL=dashboardIntegration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboardIntegration.js","sourceRoot":"","sources":["../src/dashboardIntegration.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,0CAA0C,EAC1C,sBAAsB,GAEvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAC,6BAA6B,EAAC,MAAM,mBAAmB,CAAC;AAEhE,MAAM,UAAU,kCAAkC;IAChD,OAAO;QACL,cAAc,EAAE,0CAA0C,CAAC;YACzD,CAAC,6BAA6B,CAAC,EAAE,6BAA6B;SAC/D,CAAC;QACF,eAAe,EAAE;YACf,GAAG,sBAAsB;YACzB,8BAA8B;SAC/B;QACD,UAAU,EAAE,uBAAuB,EAAE;KACtC,CAAC;AACJ,CAAC","sourcesContent":["import {\n createDefaultChartTypes,\n createDefaultMosaicDashboardPanelRenderers,\n defaultAddPanelActions,\n type CreateMosaicDashboardSliceProps,\n} from '@sqlrooms/mosaic';\nimport {\n deckMapDashboardAddPanelAction,\n deckMapDashboardPanelRenderer,\n} from './dashboard';\nimport {DECK_MAP_DASHBOARD_PANEL_TYPE} from './dashboardConfig';\n\nexport function createDeckMapDashboardSliceOptions(): CreateMosaicDashboardSliceProps {\n return {\n panelRenderers: createDefaultMosaicDashboardPanelRenderers({\n [DECK_MAP_DASHBOARD_PANEL_TYPE]: deckMapDashboardPanelRenderer,\n }),\n addPanelActions: [\n ...defaultAddPanelActions,\n deckMapDashboardAddPanelAction,\n ],\n chartTypes: createDefaultChartTypes(),\n };\n}\n"]}
@@ -173,7 +173,8 @@ export function createPreparedDatasetStore(options = {}) {
173
173
  }
174
174
  nextEntries[cacheKey] = cloneEntryWithConsumers(entry, consumers);
175
175
  }
176
- const { [consumerId]: _removedConsumer, ...nextConsumerKeys } = state.consumerKeys;
176
+ const nextConsumerKeys = { ...state.consumerKeys };
177
+ delete nextConsumerKeys[consumerId];
177
178
  return {
178
179
  ...state,
179
180
  consumerKeys: nextConsumerKeys,