@sqlrooms/kepler 0.29.0-rc.6 → 0.29.0-rc.8

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 (46) hide show
  1. package/LICENSE.md +2 -1
  2. package/README.md +121 -4
  3. package/dist/KeplerSlice.d.ts +58 -2
  4. package/dist/KeplerSlice.d.ts.map +1 -1
  5. package/dist/KeplerSlice.js +152 -24
  6. package/dist/KeplerSlice.js.map +1 -1
  7. package/dist/components/CustomFilterManager.d.ts.map +1 -1
  8. package/dist/components/CustomFilterManager.js +16 -4
  9. package/dist/components/CustomFilterManager.js.map +1 -1
  10. package/dist/components/CustomLayerManager.d.ts.map +1 -1
  11. package/dist/components/CustomLayerManager.js +23 -110
  12. package/dist/components/CustomLayerManager.js.map +1 -1
  13. package/dist/components/CustomMapLegendPanel.d.ts +1 -1
  14. package/dist/components/CustomMapLegendPanel.d.ts.map +1 -1
  15. package/dist/components/CustomMapLegendPanel.js +14 -6
  16. package/dist/components/CustomMapLegendPanel.js.map +1 -1
  17. package/dist/components/CustomSourceDataSelector.d.ts +18 -0
  18. package/dist/components/CustomSourceDataSelector.d.ts.map +1 -0
  19. package/dist/components/CustomSourceDataSelector.js +130 -0
  20. package/dist/components/CustomSourceDataSelector.js.map +1 -0
  21. package/dist/components/KeplerInjector.d.ts.map +1 -1
  22. package/dist/components/KeplerInjector.js +3 -1
  23. package/dist/components/KeplerInjector.js.map +1 -1
  24. package/dist/components/KeplerMapContainer.d.ts.map +1 -1
  25. package/dist/components/KeplerMapContainer.js +9 -2
  26. package/dist/components/KeplerMapContainer.js.map +1 -1
  27. package/dist/components/KeplerProvider.d.ts.map +1 -1
  28. package/dist/components/KeplerProvider.js +3 -1
  29. package/dist/components/KeplerProvider.js.map +1 -1
  30. package/dist/components/KeplerTableSourceSelector.d.ts +20 -0
  31. package/dist/components/KeplerTableSourceSelector.d.ts.map +1 -0
  32. package/dist/components/KeplerTableSourceSelector.js +21 -0
  33. package/dist/components/KeplerTableSourceSelector.js.map +1 -0
  34. package/dist/index.d.ts +6 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +2 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/keplerTableSelection.d.ts +142 -0
  39. package/dist/keplerTableSelection.d.ts.map +1 -0
  40. package/dist/keplerTableSelection.js +231 -0
  41. package/dist/keplerTableSelection.js.map +1 -0
  42. package/dist/styles/theme.d.ts +12 -0
  43. package/dist/styles/theme.d.ts.map +1 -1
  44. package/dist/styles/theme.js +12 -0
  45. package/dist/styles/theme.js.map +1 -1
  46. package/package.json +13 -7
package/LICENSE.md CHANGED
@@ -1,6 +1,7 @@
1
1
  MIT License
2
2
 
3
- Copyright 2025 SQLRooms Contributors
3
+ Copyright 2024-2026 SQLRooms Contributors
4
+ Copyright Vis.gl contributors
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
7
 
package/README.md CHANGED
@@ -63,14 +63,18 @@ function MapPanel() {
63
63
  const mapId = useRoomStore((state) => state.kepler.config.maps[0]?.id);
64
64
  const addTableToMap = useRoomStore((state) => state.kepler.addTableToMap);
65
65
  const isTableReady = useRoomStore((state) =>
66
- Boolean(state.db.findTableByName('earthquakes')),
66
+ Boolean(state.db.findTable('earthquakes')),
67
67
  );
68
68
 
69
69
  useEffect(() => {
70
70
  if (!isTableReady || !mapId) return;
71
- void addTableToMap(mapId, 'earthquakes', {
72
- autoCreateLayers: true,
73
- centerMap: true,
71
+ void addTableToMap({
72
+ mapId,
73
+ tableName: 'earthquakes',
74
+ options: {
75
+ autoCreateLayers: true,
76
+ centerMap: true,
77
+ },
74
78
  });
75
79
  }, [isTableReady, mapId, addTableToMap]);
76
80
 
@@ -88,19 +92,132 @@ export function App() {
88
92
  }
89
93
  ```
90
94
 
95
+ ## Adding tables to maps
96
+
97
+ Use `state.kepler.addTableToMap()` to load a DuckDB table into a Kepler map. The
98
+ preferred API is an object parameter:
99
+
100
+ ```ts
101
+ await state.kepler.addTableToMap({
102
+ mapId,
103
+ tableName: 'earthquakes',
104
+ options: {
105
+ autoCreateLayers: true,
106
+ centerMap: true,
107
+ },
108
+ });
109
+ ```
110
+
111
+ `tableName` is the SQL table reference to load. It can also be a saved Kepler
112
+ dataset id when the configured table-selection policy can resolve that id back
113
+ to a DuckDB table.
114
+
115
+ For normal add-table flows, omit `datasetId`. SQLRooms derives the persisted
116
+ Kepler dataset id from the table-selection policy:
117
+
118
+ ```ts
119
+ await state.kepler.addTableToMap({
120
+ mapId,
121
+ tableName: 'main.places',
122
+ });
123
+ ```
124
+
125
+ Only pass `datasetId` when you need to load a table under an existing Kepler
126
+ `dataId`, such as when restoring a saved map config:
127
+
128
+ ```ts
129
+ await state.kepler.addTableToMap({
130
+ mapId,
131
+ tableName: savedDataId,
132
+ options: {
133
+ autoCreateLayers: false,
134
+ centerMap: false,
135
+ },
136
+ datasetId: savedDataId,
137
+ });
138
+ ```
139
+
140
+ The older positional signature is still accepted for compatibility, but new code
141
+ should use the object form so the table reference, Kepler options, config, and
142
+ dataset-id override remain clear at the call site.
143
+
91
144
  ## Common customization
92
145
 
93
146
  Pass options to `createKeplerSlice()`:
94
147
 
95
148
  ```ts
149
+ import {createKeplerTheme, type KeplerThemeOverrides} from '@sqlrooms/kepler';
150
+
96
151
  createKeplerSlice({
97
152
  basicKeplerProps: {
98
153
  mapboxApiAccessToken: import.meta.env.VITE_MAPBOX_TOKEN,
99
154
  },
155
+ keplerTheme: createKeplerTheme({
156
+ modalOverLayZ: 40,
157
+ } satisfies KeplerThemeOverrides),
158
+ modalPortalTarget: 'body',
100
159
  actionLogging: false,
101
160
  });
102
161
  ```
103
162
 
163
+ Notes:
164
+
165
+ - `basicKeplerProps` is for base Kepler registration/component props.
166
+ - `keplerTheme` (optional) sets the theme passed to Kepler `ThemeProvider`.
167
+ - `modalPortalTarget` controls modal portal placement: `'container'` (default)
168
+ or `'body'`.
169
+
170
+ ### Table selection and dataset ids
171
+
172
+ `tableSelection` controls which DuckDB tables Kepler exposes and how those
173
+ tables are represented in persisted Kepler layer and filter config.
174
+
175
+ ```ts
176
+ createKeplerSlice({
177
+ tableSelection: {
178
+ defaultDbSchema: {
179
+ database: 'project',
180
+ schema: 'main',
181
+ },
182
+ includeTable: (table) => table.table.database === 'project',
183
+ },
184
+ });
185
+ ```
186
+
187
+ By default, tables in `defaultDbSchema` use bare dataset ids such as `places`.
188
+ Tables outside that database/schema use qualified SQL table references. This
189
+ keeps common main-schema project tables readable while preserving enough
190
+ identity for tables from other schemas.
191
+
192
+ Use `includeTable` to hide tables from Kepler's Add Layer UI and to skip matching
193
+ saved dataset ids during dataset synchronization. Host apps commonly use this to
194
+ hide attached databases that will not be available when a project is reopened.
195
+
196
+ If the default dataset-id policy is not right for your app, provide both
197
+ `getDatasetIdForTable` and `findTableForDatasetId` so new layers and restored
198
+ layers agree on the same identity scheme:
199
+
200
+ ```ts
201
+ createKeplerSlice({
202
+ tableSelection: {
203
+ getDatasetIdForTable: (table) =>
204
+ `${table.table.schema}:${table.table.table}`,
205
+ findTableForDatasetId: (tables, datasetId) => {
206
+ const [schema, tableName] = datasetId.split(':');
207
+ return tables.find(
208
+ (table) =>
209
+ table.table.schema === schema && table.table.table === tableName,
210
+ );
211
+ },
212
+ getTableLabel: (table) =>
213
+ [table.table.schema, table.table.table].filter(Boolean).join('.'),
214
+ },
215
+ });
216
+ ```
217
+
218
+ `getTableLabel` only affects display labels in Kepler table selectors. It does
219
+ not change persisted dataset ids.
220
+
104
221
  ## Related packages
105
222
 
106
223
  - `@sqlrooms/artifacts` for artifact-backed map tabs
@@ -7,9 +7,12 @@ import { RoomShellSliceState, type StateCreator } from '@sqlrooms/room-shell';
7
7
  import type { AnyAction, Store as ReduxStore } from 'redux';
8
8
  import { Dispatch, Middleware } from 'redux';
9
9
  import { ReduxLoggerOptions } from 'redux-logger';
10
+ import type { DefaultTheme } from 'styled-components';
11
+ import { type KeplerTableSelectionOptions } from './keplerTableSelection';
10
12
  export type KeplerGLBasicProps = {
11
13
  mapboxApiAccessToken?: string;
12
14
  };
15
+ export type KeplerModalPortalTarget = 'body' | 'container';
13
16
  export type CreateInitialMapKeplerStateContext = {
14
17
  reason: 'initialize' | 'create-map' | 'duplicate-map' | 'register-map' | 'sync-config';
15
18
  defaultInitialMapKeplerState: Partial<KeplerGlState>;
@@ -20,9 +23,26 @@ export type CreateKeplerSliceOptions = {
20
23
  config?: Partial<KeplerSliceConfig>;
21
24
  createInitialMapKeplerState?: (context: CreateInitialMapKeplerStateContext) => Partial<KeplerGlState>;
22
25
  basicKeplerProps?: Partial<KeplerGLBasicProps>;
26
+ /**
27
+ * Theme passed to Kepler's ThemeProvider.
28
+ * Use createKeplerTheme() to merge app-level overrides into the default theme.
29
+ */
30
+ keplerTheme?: DefaultTheme;
31
+ /**
32
+ * Where the Kepler modal (Add Map Style, Export, etc.) should be portaled.
33
+ * - 'body': portals to document.body (escapes stacking contexts)
34
+ * - 'container': portals inside the kepler map container element
35
+ * @default 'container'
36
+ */
37
+ modalPortalTarget?: KeplerModalPortalTarget;
23
38
  actionLogging?: boolean | ReduxLoggerOptions;
24
39
  middlewares?: Middleware[];
25
40
  applicationConfig?: KeplerApplicationConfig;
41
+ /**
42
+ * Controls which DuckDB tables appear in Kepler's Add Layer menu and how
43
+ * those tables are represented in saved Kepler dataset ids.
44
+ */
45
+ tableSelection?: KeplerTableSelectionOptions;
26
46
  /**
27
47
  * Called when a kepler action is dispatched
28
48
  * @param mapId - The map id
@@ -45,11 +65,44 @@ export declare function hasMapId(action: KeplerAction): action is KeplerAction &
45
65
  export type KeplerGlReduxState = {
46
66
  [id: string]: KeplerGlState;
47
67
  };
68
+ export type AddTableToMapLoadOptions = {
69
+ /**
70
+ * Load the table under an explicit Kepler dataset id.
71
+ *
72
+ * Normal callers should omit this so the table-selection policy decides the
73
+ * id. Restore uses it to satisfy already-saved layer/filter dataIds.
74
+ */
75
+ datasetId?: string;
76
+ };
77
+ export type AddTableToMapParams = {
78
+ mapId: string;
79
+ /**
80
+ * Table reference to load. This can also be an existing/saved Kepler dataset
81
+ * id when the table-selection policy can resolve it back to a table.
82
+ */
83
+ tableName: string;
84
+ options?: AddDataToMapPayload['options'];
85
+ config?: AddDataToMapPayload['config'];
86
+ /**
87
+ * Explicit Kepler dataset id to write into `datasets.info.id`.
88
+ *
89
+ * Most callers should omit this so `tableSelection.getDatasetIdForTable`
90
+ * controls new ids. Restore passes it to preserve saved layer/filter dataIds.
91
+ */
92
+ datasetId?: string;
93
+ };
94
+ export type AddTableToMapFn = {
95
+ (params: AddTableToMapParams): Promise<void>;
96
+ (mapId: string, tableName: string, options?: AddDataToMapPayload['options'], config?: AddDataToMapPayload['config'], loadOptions?: AddTableToMapLoadOptions): Promise<void>;
97
+ };
48
98
  export type KeplerSliceState = {
49
99
  kepler: {
50
100
  config: KeplerSliceConfig;
51
101
  map: KeplerGlReduxState;
52
102
  basicKeplerProps?: Partial<KeplerGLBasicProps>;
103
+ keplerTheme?: DefaultTheme;
104
+ modalPortalTarget: KeplerModalPortalTarget;
105
+ tableSelection: KeplerTableSelectionOptions;
53
106
  forwardDispatch: {
54
107
  [mapId: string]: Dispatch;
55
108
  };
@@ -70,13 +123,16 @@ export type KeplerSliceState = {
70
123
  updateTooltipFields: (mapId: string, datasetId: string, fieldNames: string[]) => void;
71
124
  toggleSplitMap: (mapId: string, index?: number) => void;
72
125
  toggleLayerForMap: (mapId: string, mapIndex: number, layerId: string) => void;
73
- addTableToMap: (mapId: string, tableName: string, options?: AddDataToMapPayload['options'], config?: AddDataToMapPayload['config']) => Promise<void>;
126
+ addTableToMap: AddTableToMapFn;
74
127
  addTileSetToMap: (mapId: string, tableName: string, tileset: {
75
128
  name: string;
76
129
  type: string;
77
130
  metadata: VectorTileDatasetMetadata;
78
131
  }, tileMetadata: Record<string, any>, autoCreateLayers: boolean) => void;
79
132
  addConfigToMap: (mapId: string, config: KeplerMapSchema) => void;
133
+ isRestoringConfig: boolean;
134
+ withConfigPersistencePaused: <TResult>(fn: () => TResult | Promise<TResult>) => Promise<TResult>;
135
+ waitForConfigRestore: () => Promise<void>;
80
136
  removeDatasetFromMaps: (datasetId: string) => void;
81
137
  dispatchAction: (mapId: string, action: KeplerAction) => void;
82
138
  ensureMap: (mapId: string, name?: string) => void;
@@ -99,7 +155,7 @@ export type KeplerSliceState = {
99
155
  __reduxProviderStore: ReduxStore<KeplerGlReduxState, AnyAction> | undefined;
100
156
  };
101
157
  };
102
- export declare function createKeplerSlice({ basicKeplerProps, config: initialConfigProps, createInitialMapKeplerState, actionLogging, middlewares: additionalMiddlewares, applicationConfig, onAction, }?: CreateKeplerSliceOptions): StateCreator<KeplerSliceState>;
158
+ export declare function createKeplerSlice({ basicKeplerProps, keplerTheme, modalPortalTarget, config: initialConfigProps, createInitialMapKeplerState, actionLogging, middlewares: additionalMiddlewares, applicationConfig, tableSelection, onAction, }?: CreateKeplerSliceOptions): StateCreator<KeplerSliceState>;
103
159
  type RoomStateWithDiscuss = RoomShellSliceState & KeplerSliceState;
104
160
  export declare function useStoreWithKepler<T>(selector: (state: RoomStateWithDiscuss) => T): T;
105
161
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"KeplerSlice.d.ts","sourceRoot":"","sources":["../src/KeplerSlice.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"KeplerSlice.d.ts","sourceRoot":"","sources":["../src/KeplerSlice.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,8 @@ import { produce, setAutoFreeze } from 'immer';
14
14
  import { taskMiddleware } from 'react-palm/tasks';
15
15
  import { compose } from 'redux';
16
16
  import { createLogger } from 'redux-logger';
17
+ import { getUnqualifiedSqlIdentifier } from '@sqlrooms/duckdb-core';
18
+ import { findKeplerTableForDatasetId, getKeplerDatasetIdForTable, getKeplerTableLabel, } from './keplerTableSelection';
17
19
  setAutoFreeze(false); // Kepler attempts to mutate redux state, so we need to disable immer's auto freeze to avoid errors
18
20
  const KeplerGLSchemaManager = new KeplerGLSchemaClass();
19
21
  class DesktopKeplerTable extends KeplerTable {
@@ -29,6 +31,7 @@ function createDefaultMapKeplerState(resolvedTheme) {
29
31
  },
30
32
  uiState: {
31
33
  ...INITIAL_UI_STATE,
34
+ activeSidePanel: null,
32
35
  currentModal: null,
33
36
  mapControls: {
34
37
  visibleLayers: INITIAL_UI_STATE.mapControls.visibleLayers,
@@ -75,6 +78,25 @@ export function hasMapId(action) {
75
78
  action.payload.meta !== null &&
76
79
  '_id_' in action.payload.meta);
77
80
  }
81
+ function normalizeAddTableToMapParams(paramsOrMapId, tableName, options = {}, config = {}, loadOptions = {}) {
82
+ if (typeof paramsOrMapId === 'object') {
83
+ return {
84
+ options: {},
85
+ config: {},
86
+ ...paramsOrMapId,
87
+ };
88
+ }
89
+ if (!tableName) {
90
+ throw new Error('addTableToMap requires a tableName.');
91
+ }
92
+ return {
93
+ mapId: paramsOrMapId,
94
+ tableName,
95
+ options,
96
+ config,
97
+ datasetId: loadOptions.datasetId,
98
+ };
99
+ }
78
100
  // Auto save will be triggered in middleware on every kepler action
79
101
  // skip these actions to avoid unnecessary save
80
102
  const SKIP_AUTO_SAVE_ACTIONS = [
@@ -82,13 +104,15 @@ const SKIP_AUTO_SAVE_ACTIONS = [
82
104
  KeplerActionTypes.UPDATE_MAP,
83
105
  KeplerActionTypes.MOUSE_MOVE,
84
106
  ];
85
- export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfigProps, createInitialMapKeplerState, actionLogging = false, middlewares: additionalMiddlewares = [], applicationConfig, onAction, } = {}) {
107
+ export function createKeplerSlice({ basicKeplerProps = {}, keplerTheme, modalPortalTarget = 'container', config: initialConfigProps, createInitialMapKeplerState, actionLogging = false, middlewares: additionalMiddlewares = [], applicationConfig, tableSelection = {}, onAction, } = {}) {
86
108
  const initialConfig = createDefaultKeplerConfig(initialConfigProps);
87
109
  initApplicationConfig({
88
110
  table: DesktopKeplerTable,
89
111
  ...applicationConfig,
90
112
  });
91
113
  let syncKeplerPromise = null;
114
+ let configRestoreDepth = 0;
115
+ const configRestorePromises = new Set();
92
116
  // When a caller arrives while a sync is already in-flight, the in-flight run
93
117
  // may have captured a stale snapshot of db.tables/kepler.map (missing maps or
94
118
  // tables added by createMap, duplicateMap, etc.). Setting this flag tells the
@@ -102,6 +126,23 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
102
126
  }
103
127
  };
104
128
  return createSlice((set, get, _store) => {
129
+ function getDefaultDbSchema() {
130
+ const currentDatabase = get().db.currentDatabase;
131
+ const currentSchema = get().db.currentSchema;
132
+ if (!currentDatabase || !currentSchema) {
133
+ return undefined;
134
+ }
135
+ return {
136
+ database: currentDatabase,
137
+ schema: currentSchema,
138
+ };
139
+ }
140
+ const resolvedTableSelection = {
141
+ ...tableSelection,
142
+ };
143
+ if (!resolvedTableSelection.defaultDbSchema) {
144
+ resolvedTableSelection.defaultDbSchema = getDefaultDbSchema;
145
+ }
105
146
  function resolveInitialMapKeplerState(context) {
106
147
  const resolvedTheme = getTheme();
107
148
  const defaultInitialMapKeplerState = createDefaultMapKeplerState(resolvedTheme);
@@ -146,19 +187,29 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
146
187
  kepler: {
147
188
  config: initialConfig,
148
189
  basicKeplerProps,
190
+ keplerTheme,
191
+ modalPortalTarget,
192
+ tableSelection: resolvedTableSelection,
149
193
  map: {},
194
+ isRestoringConfig: false,
150
195
  dispatchAction: () => { },
151
196
  __reduxProviderStore: undefined,
152
197
  forwardDispatch: {},
153
198
  setConfig: (config) => {
154
- const nextConfig = KeplerSliceConfig.parse(config);
155
- set((state) => produce(state, (draft) => {
156
- draft.kepler.config = nextConfig;
157
- }));
158
- updateMapReduxStates();
159
- updateForwardDispatch();
160
- get().kepler.syncKeplerDatasets();
161
- updateMapConfigs();
199
+ void get()
200
+ .kepler.withConfigPersistencePaused(async () => {
201
+ const nextConfig = KeplerSliceConfig.parse(config);
202
+ set((state) => produce(state, (draft) => {
203
+ draft.kepler.config = nextConfig;
204
+ }));
205
+ updateMapReduxStates();
206
+ updateForwardDispatch();
207
+ updateMapConfigs();
208
+ await get().kepler.syncKeplerDatasets();
209
+ })
210
+ .catch((error) => {
211
+ console.error('setConfig: failed to restore Kepler config', error);
212
+ });
162
213
  },
163
214
  async initialize() {
164
215
  const config = get().kepler.config;
@@ -189,6 +240,7 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
189
240
  // @ts-expect-error - Symbol.observable is not defined in the Redux type definitions
190
241
  [Symbol.observable]: () => { },
191
242
  },
243
+ isRestoringConfig: get().kepler.isRestoringConfig,
192
244
  },
193
245
  });
194
246
  updateForwardDispatch();
@@ -262,13 +314,25 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
262
314
  get().kepler.registerKeplerMapIfNotExists(mapId);
263
315
  get().kepler.dispatchAction(mapId, toggleLayerForMapAction(mapIndex, layerId));
264
316
  },
265
- addTableToMap: async (mapId, tableName, options = {}, config = {}) => {
317
+ addTableToMap: (async (paramsOrMapId, legacyTableName, legacyOptions, legacyConfig, legacyLoadOptions) => {
318
+ const { mapId, tableName, options, config, datasetId: explicitDatasetId, } = normalizeAddTableToMapParams(paramsOrMapId, legacyTableName, legacyOptions, legacyConfig, legacyLoadOptions);
319
+ const tableSelection = get().kepler.tableSelection;
320
+ const table = findKeplerTableForDatasetId(get().db.tables, tableName, tableSelection);
321
+ const sqlTableName = table ? table.table.toString() : tableName;
322
+ let datasetId = explicitDatasetId;
323
+ if (!datasetId && table) {
324
+ datasetId = getKeplerDatasetIdForTable(table, tableSelection);
325
+ }
326
+ if (!datasetId) {
327
+ datasetId =
328
+ getUnqualifiedSqlIdentifier(String(sqlTableName)) ?? tableName;
329
+ }
266
330
  const connector = await get().db.getConnector();
267
331
  const duckDbColumns = await getDuckDBColumnTypes({
268
332
  query: (query) => connector.query(query).result,
269
- }, tableName);
333
+ }, sqlTableName);
270
334
  const tableDuckDBTypes = getDuckDBColumnTypesMap(duckDbColumns);
271
- const adjustedQuery = castDuckDBTypesForKepler(tableName, duckDbColumns);
335
+ const adjustedQuery = castDuckDBTypesForKepler(sqlTableName, duckDbColumns);
272
336
  const arrowResult = await connector.query(adjustedQuery).result;
273
337
  setGeoArrowWKBExtension(arrowResult, duckDbColumns);
274
338
  // TODO remove once DuckDB doesn't drop geoarrow metadata
@@ -276,14 +340,22 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
276
340
  const fields = arrowSchemaToFields(arrowResult, tableDuckDBTypes);
277
341
  const cols = Array.from({ length: arrowResult.numCols }, (_, i) => arrowResult.getChildAt(i)).filter((col) => col);
278
342
  if (fields && cols) {
343
+ let label = tableName;
344
+ if (table) {
345
+ label = getKeplerTableLabel(table, tableSelection);
346
+ }
347
+ else {
348
+ label =
349
+ getUnqualifiedSqlIdentifier(String(sqlTableName)) ?? tableName;
350
+ }
279
351
  const datasets = {
280
352
  data: { fields, cols, rows: [], arrowTable: arrowResult },
281
- info: { label: tableName, id: tableName },
282
- metadata: { tableName },
353
+ info: { label, id: datasetId },
354
+ metadata: { tableName: sqlTableName },
283
355
  };
284
356
  get().kepler.dispatchAction(mapId, addDataToMap({ datasets, options, config }));
285
357
  }
286
- },
358
+ }),
287
359
  ensureMap: (mapId, name) => {
288
360
  const now = Date.now();
289
361
  set((state) => produce(state, (draft) => {
@@ -345,15 +417,30 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
345
417
  referencedDataIds.add(dataId);
346
418
  }
347
419
  }
348
- const availableTables = new Set(get()
349
- .db.tables.filter((t) => t.table.schema === 'main')
350
- .map((t) => t.table.table));
420
+ const availableTables = get().db.tables;
351
421
  for (const dataId of referencedDataIds) {
352
- if (!keplerDatasets?.[dataId] &&
353
- availableTables.has(dataId)) {
354
- await get().kepler.addTableToMap(mapId, dataId, {
355
- autoCreateLayers: false,
356
- centerMap: false,
422
+ if (keplerDatasets?.[dataId]) {
423
+ continue;
424
+ }
425
+ const table = findKeplerTableForDatasetId(availableTables, dataId, get().kepler.tableSelection);
426
+ if (!table) {
427
+ continue;
428
+ }
429
+ try {
430
+ await get().kepler.addTableToMap({
431
+ mapId,
432
+ tableName: dataId,
433
+ options: {
434
+ autoCreateLayers: false,
435
+ centerMap: false,
436
+ },
437
+ datasetId: dataId,
438
+ });
439
+ }
440
+ catch (e) {
441
+ console.error('syncKeplerDatasets: addTableToMap failed', {
442
+ dataId,
443
+ e,
357
444
  });
358
445
  }
359
446
  }
@@ -472,6 +559,44 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
472
559
  }
473
560
  get().kepler.dispatchAction(mapId, addDataToMap({ config: parsedConfig, datasets: [] }));
474
561
  },
562
+ withConfigPersistencePaused: async (fn) => {
563
+ configRestoreDepth += 1;
564
+ if (configRestoreDepth === 1) {
565
+ set((state) => produce(state, (draft) => {
566
+ draft.kepler.isRestoringConfig = true;
567
+ }));
568
+ }
569
+ const restorePromise = (async () => {
570
+ try {
571
+ return await fn();
572
+ }
573
+ finally {
574
+ // Kepler restore actions can enqueue follow-up work through
575
+ // react-palm; let those actions settle before persisted config
576
+ // writes are allowed again.
577
+ await new Promise((resolve) => setTimeout(resolve, 0));
578
+ await new Promise((resolve) => setTimeout(resolve, 0));
579
+ configRestoreDepth -= 1;
580
+ if (configRestoreDepth === 0) {
581
+ set((state) => produce(state, (draft) => {
582
+ draft.kepler.isRestoringConfig = false;
583
+ }));
584
+ }
585
+ }
586
+ })();
587
+ configRestorePromises.add(restorePromise);
588
+ try {
589
+ return await restorePromise;
590
+ }
591
+ finally {
592
+ configRestorePromises.delete(restorePromise);
593
+ }
594
+ },
595
+ waitForConfigRestore: async () => {
596
+ while (configRestorePromises.size > 0) {
597
+ await Promise.allSettled(Array.from(configRestorePromises));
598
+ }
599
+ },
475
600
  registerKeplerMapIfNotExists(mapId) {
476
601
  if (!get().kepler.map[mapId]) {
477
602
  set({
@@ -514,7 +639,10 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
514
639
  if (!mapId)
515
640
  throw new Error('Map ID not found in action payload');
516
641
  const result = next(action);
517
- if (!SKIP_AUTO_SAVE_ACTIONS.includes(action.type) && mapId) {
642
+ if (configRestoreDepth === 0 &&
643
+ !get().kepler.isRestoringConfig &&
644
+ !SKIP_AUTO_SAVE_ACTIONS.includes(action.type) &&
645
+ mapId) {
518
646
  // save kepler config to store
519
647
  set((state) => produce(state, (draft) => {
520
648
  const mapToSave = draft.kepler.config.maps.find((map) => map.id === mapId);