@sqlrooms/kepler 0.29.0-rc.7 → 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.
- package/LICENSE.md +2 -1
- package/README.md +121 -4
- package/dist/KeplerSlice.d.ts +55 -2
- package/dist/KeplerSlice.d.ts.map +1 -1
- package/dist/KeplerSlice.js +92 -15
- package/dist/KeplerSlice.js.map +1 -1
- package/dist/components/CustomFilterManager.d.ts.map +1 -1
- package/dist/components/CustomFilterManager.js +16 -4
- package/dist/components/CustomFilterManager.js.map +1 -1
- package/dist/components/CustomLayerManager.d.ts.map +1 -1
- package/dist/components/CustomLayerManager.js +23 -110
- package/dist/components/CustomLayerManager.js.map +1 -1
- package/dist/components/CustomMapLegendPanel.d.ts +1 -1
- package/dist/components/CustomMapLegendPanel.d.ts.map +1 -1
- package/dist/components/CustomMapLegendPanel.js +14 -6
- package/dist/components/CustomMapLegendPanel.js.map +1 -1
- package/dist/components/CustomSourceDataSelector.d.ts +18 -0
- package/dist/components/CustomSourceDataSelector.d.ts.map +1 -0
- package/dist/components/CustomSourceDataSelector.js +130 -0
- package/dist/components/CustomSourceDataSelector.js.map +1 -0
- package/dist/components/KeplerInjector.d.ts.map +1 -1
- package/dist/components/KeplerInjector.js +3 -1
- package/dist/components/KeplerInjector.js.map +1 -1
- package/dist/components/KeplerMapContainer.d.ts.map +1 -1
- package/dist/components/KeplerMapContainer.js +9 -2
- package/dist/components/KeplerMapContainer.js.map +1 -1
- package/dist/components/KeplerProvider.d.ts.map +1 -1
- package/dist/components/KeplerProvider.js +3 -1
- package/dist/components/KeplerProvider.js.map +1 -1
- package/dist/components/KeplerTableSourceSelector.d.ts +20 -0
- package/dist/components/KeplerTableSourceSelector.d.ts.map +1 -0
- package/dist/components/KeplerTableSourceSelector.js +21 -0
- package/dist/components/KeplerTableSourceSelector.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/keplerTableSelection.d.ts +142 -0
- package/dist/keplerTableSelection.d.ts.map +1 -0
- package/dist/keplerTableSelection.js +231 -0
- package/dist/keplerTableSelection.js.map +1 -0
- package/dist/styles/theme.d.ts +12 -0
- package/dist/styles/theme.d.ts.map +1 -1
- package/dist/styles/theme.js +12 -0
- package/dist/styles/theme.js.map +1 -1
- package/package.json +13 -7
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
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.
|
|
66
|
+
Boolean(state.db.findTable('earthquakes')),
|
|
67
67
|
);
|
|
68
68
|
|
|
69
69
|
useEffect(() => {
|
|
70
70
|
if (!isTableReady || !mapId) return;
|
|
71
|
-
void addTableToMap(
|
|
72
|
-
|
|
73
|
-
|
|
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
|
package/dist/KeplerSlice.d.ts
CHANGED
|
@@ -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,7 +123,7 @@ 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:
|
|
126
|
+
addTableToMap: AddTableToMapFn;
|
|
74
127
|
addTileSetToMap: (mapId: string, tableName: string, tileset: {
|
|
75
128
|
name: string;
|
|
76
129
|
type: string;
|
|
@@ -102,7 +155,7 @@ export type KeplerSliceState = {
|
|
|
102
155
|
__reduxProviderStore: ReduxStore<KeplerGlReduxState, AnyAction> | undefined;
|
|
103
156
|
};
|
|
104
157
|
};
|
|
105
|
-
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>;
|
|
106
159
|
type RoomStateWithDiscuss = RoomShellSliceState & KeplerSliceState;
|
|
107
160
|
export declare function useStoreWithKepler<T>(selector: (state: RoomStateWithDiscuss) => T): T;
|
|
108
161
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeplerSlice.d.ts","sourceRoot":"","sources":["../src/KeplerSlice.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAkB,yBAAyB,EAAC,MAAM,sBAAsB,CAAC;AAShF,OAAO,EAGL,aAAa,EAEd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAGL,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAC,eAAe,EAAE,iBAAiB,EAAC,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAIL,mBAAmB,EAEnB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EAEV,SAAS,EAET,KAAK,IAAI,UAAU,EACpB,MAAM,OAAO,CAAC;AACf,OAAO,EAAU,QAAQ,EAAE,UAAU,EAAC,MAAM,OAAO,CAAC;AACpD,OAAO,EAAe,kBAAkB,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"KeplerSlice.d.ts","sourceRoot":"","sources":["../src/KeplerSlice.ts"],"names":[],"mappings":"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"}
|
package/dist/KeplerSlice.js
CHANGED
|
@@ -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,7 +104,7 @@ 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,
|
|
@@ -104,6 +126,23 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
|
|
|
104
126
|
}
|
|
105
127
|
};
|
|
106
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
|
+
}
|
|
107
146
|
function resolveInitialMapKeplerState(context) {
|
|
108
147
|
const resolvedTheme = getTheme();
|
|
109
148
|
const defaultInitialMapKeplerState = createDefaultMapKeplerState(resolvedTheme);
|
|
@@ -148,6 +187,9 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
|
|
|
148
187
|
kepler: {
|
|
149
188
|
config: initialConfig,
|
|
150
189
|
basicKeplerProps,
|
|
190
|
+
keplerTheme,
|
|
191
|
+
modalPortalTarget,
|
|
192
|
+
tableSelection: resolvedTableSelection,
|
|
151
193
|
map: {},
|
|
152
194
|
isRestoringConfig: false,
|
|
153
195
|
dispatchAction: () => { },
|
|
@@ -272,13 +314,25 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
|
|
|
272
314
|
get().kepler.registerKeplerMapIfNotExists(mapId);
|
|
273
315
|
get().kepler.dispatchAction(mapId, toggleLayerForMapAction(mapIndex, layerId));
|
|
274
316
|
},
|
|
275
|
-
addTableToMap: async (
|
|
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
|
+
}
|
|
276
330
|
const connector = await get().db.getConnector();
|
|
277
331
|
const duckDbColumns = await getDuckDBColumnTypes({
|
|
278
332
|
query: (query) => connector.query(query).result,
|
|
279
|
-
},
|
|
333
|
+
}, sqlTableName);
|
|
280
334
|
const tableDuckDBTypes = getDuckDBColumnTypesMap(duckDbColumns);
|
|
281
|
-
const adjustedQuery = castDuckDBTypesForKepler(
|
|
335
|
+
const adjustedQuery = castDuckDBTypesForKepler(sqlTableName, duckDbColumns);
|
|
282
336
|
const arrowResult = await connector.query(adjustedQuery).result;
|
|
283
337
|
setGeoArrowWKBExtension(arrowResult, duckDbColumns);
|
|
284
338
|
// TODO remove once DuckDB doesn't drop geoarrow metadata
|
|
@@ -286,14 +340,22 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
|
|
|
286
340
|
const fields = arrowSchemaToFields(arrowResult, tableDuckDBTypes);
|
|
287
341
|
const cols = Array.from({ length: arrowResult.numCols }, (_, i) => arrowResult.getChildAt(i)).filter((col) => col);
|
|
288
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
|
+
}
|
|
289
351
|
const datasets = {
|
|
290
352
|
data: { fields, cols, rows: [], arrowTable: arrowResult },
|
|
291
|
-
info: { label
|
|
292
|
-
metadata: { tableName },
|
|
353
|
+
info: { label, id: datasetId },
|
|
354
|
+
metadata: { tableName: sqlTableName },
|
|
293
355
|
};
|
|
294
356
|
get().kepler.dispatchAction(mapId, addDataToMap({ datasets, options, config }));
|
|
295
357
|
}
|
|
296
|
-
},
|
|
358
|
+
}),
|
|
297
359
|
ensureMap: (mapId, name) => {
|
|
298
360
|
const now = Date.now();
|
|
299
361
|
set((state) => produce(state, (draft) => {
|
|
@@ -355,15 +417,30 @@ export function createKeplerSlice({ basicKeplerProps = {}, config: initialConfig
|
|
|
355
417
|
referencedDataIds.add(dataId);
|
|
356
418
|
}
|
|
357
419
|
}
|
|
358
|
-
const availableTables =
|
|
359
|
-
.db.tables.filter((t) => t.table.schema === 'main')
|
|
360
|
-
.map((t) => t.table.table));
|
|
420
|
+
const availableTables = get().db.tables;
|
|
361
421
|
for (const dataId of referencedDataIds) {
|
|
362
|
-
if (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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,
|
|
367
444
|
});
|
|
368
445
|
}
|
|
369
446
|
}
|