@@ -73,7 +73,7 @@ User can import a specific action handler in their root reducer and use it to di
Here is an example how you can listen to an app action `QUERY_SUCCESS` and call `updateVisDataUpdater` to load data into kepler.gl.
```js
-import keplerGlReducer, {visStateUpdaters} from 'kepler.gl/reducers';
+import keplerGlReducer, {visStateUpdaters} from '@kepler.gl/reducers';
// Root Reducer
const reducers = combineReducers({
diff --git a/docs/api-reference/reducers/combine.md b/docs/api-reference/reducers/combine.md
index 48dd1889d7..46c8537f4f 100644
--- a/docs/api-reference/reducers/combine.md
+++ b/docs/api-reference/reducers/combine.md
@@ -2,8 +2,8 @@
### Table of Contents
-- [combinedUpdaters][1]
- - [addDataToMapUpdater][3]
+- [combinedUpdaters](#combinedupdaters)
+ - [addDataToMapUpdater](#adddatatomapupdater)
## combinedUpdaters
@@ -14,7 +14,7 @@ as the first argument. Read more about [Using updaters][5]
**Examples**
```javascript
-import keplerGlReducer, {combinedUpdaters} from 'kepler.gl/reducers';
+import keplerGlReducer, {combinedUpdaters} from '@kepler.gl/reducers';
// Root Reducer
const reducers = combineReducers({
keplerGl: keplerGlReducer,
@@ -58,7 +58,7 @@ Combine data and full configuration update in a single action
**Parameters**
- `state` **[Object][7]** kepler.gl instance state, containing all subreducer state
-- `action` **[Object][7]**
+- `action` **[Object][7]**
- `action.payload` **[Object][7]** `{datasets, options, config}`
- `action.payload.datasets` **([Array][8]<[Object][7]> | [Object][7])** **\*required** datasets can be a dataset or an array of datasets
Each dataset object needs to have `info` and `data` property.
diff --git a/docs/api-reference/reducers/map-state.md b/docs/api-reference/reducers/map-state.md
index 2ce9ccf1c0..53b601ce8f 100644
--- a/docs/api-reference/reducers/map-state.md
+++ b/docs/api-reference/reducers/map-state.md
@@ -2,14 +2,15 @@
### Table of Contents
-- [mapStateUpdaters][1]
- - [fitBoundsUpdater][3]
- - [INITIAL_MAP_STATE][5]
- - [receiveMapConfigUpdater][7]
- - [resetMapConfigUpdater][9]
- - [togglePerspectiveUpdater][11]
- - [toggleSplitMapUpdater][13]
- - [updateMapUpdater][15]
+- [mapStateUpdaters](#mapstateupdaters)
+ - [fitBoundsUpdater](#fitboundsupdater)
+ - [INITIAL\_MAP\_STATE](#initial_map_state)
+ - [Properties](#properties)
+ - [receiveMapConfigUpdater](#receivemapconfigupdater)
+ - [resetMapConfigUpdater](#resetmapconfigupdater)
+ - [togglePerspectiveUpdater](#toggleperspectiveupdater)
+ - [toggleSplitMapUpdater](#togglesplitmapupdater)
+ - [updateMapUpdater](#updatemapupdater)
## mapStateUpdaters
@@ -19,7 +20,7 @@ Read more about [Using updaters][17]
**Examples**
```javascript
-import keplerGlReducer, {mapStateUpdaters} from 'kepler.gl/reducers';
+import keplerGlReducer, {mapStateUpdaters} from '@kepler.gl/reducers';
// Root Reducer
const reducers = combineReducers({
keplerGl: keplerGlReducer,
@@ -57,8 +58,8 @@ Fit map viewport to bounds
**Parameters**
-- `state` **[Object][19]**
-- `action` **[Object][19]**
+- `state` **[Object][19]**
+- `action` **[Object][19]**
- `action.payload` **[Array][20]<[number][21]>** bounds as `[lngMin, latMin, lngMax, latMax]`
Returns **[Object][19]** nextState
@@ -87,8 +88,8 @@ Update `mapState` to propagate a new config
**Parameters**
-- `state` **[Object][19]**
-- `action` **[Object][19]**
+- `state` **[Object][19]**
+- `action` **[Object][19]**
- `action.payload` **[Object][19]** saved map config
- `action.payload.config` (optional, default `{}`)
- `action.payload.options` (optional, default `{}`)
@@ -116,7 +117,7 @@ Toggle between 3d and 2d map.
**Parameters**
-- `state` **[Object][19]**
+- `state` **[Object][19]**
Returns **[Object][19]** nextState
@@ -128,7 +129,7 @@ Toggle between one or split maps
**Parameters**
-- `state` **[Object][19]**
+- `state` **[Object][19]**
Returns **[Object][19]** nextState
@@ -140,8 +141,8 @@ Update map viewport
**Parameters**
-- `state` **[Object][19]**
-- `action` **[Object][19]**
+- `state` **[Object][19]**
+- `action` **[Object][19]**
- `action.payload` **[Object][19]** viewport
Returns **[Object][19]** nextState
diff --git a/docs/api-reference/reducers/map-style.md b/docs/api-reference/reducers/map-style.md
index 1c5db37494..5e71853898 100644
--- a/docs/api-reference/reducers/map-style.md
+++ b/docs/api-reference/reducers/map-style.md
@@ -2,16 +2,17 @@
### Table of Contents
-- [mapStyleUpdaters][1]
- - [INITIAL_MAP_STYLE][3]
- - [initMapStyleUpdater][5]
- - [inputMapStyleUpdater][7]
- - [loadCustomMapStyleUpdater][9]
- - [loadMapStyleErrUpdater][11]
- - [loadMapStylesUpdater][13]
- - [mapConfigChangeUpdater][15]
- - [mapStyleChangeUpdater][17]
- - [resetMapConfigMapStyleUpdater][19]
+- [mapStyleUpdaters](#mapstyleupdaters)
+ - [INITIAL\_MAP\_STYLE](#initial_map_style)
+ - [Properties](#properties)
+ - [initMapStyleUpdater](#initmapstyleupdater)
+ - [inputMapStyleUpdater](#inputmapstyleupdater)
+ - [loadCustomMapStyleUpdater](#loadcustommapstyleupdater)
+ - [loadMapStyleErrUpdater](#loadmapstyleerrupdater)
+ - [loadMapStylesUpdater](#loadmapstylesupdater)
+ - [mapConfigChangeUpdater](#mapconfigchangeupdater)
+ - [mapStyleChangeUpdater](#mapstylechangeupdater)
+ - [resetMapConfigMapStyleUpdater](#resetmapconfigmapstyleupdater)
## mapStyleUpdaters
@@ -21,7 +22,7 @@ Read more about [Using updaters][21]
**Examples**
```javascript
-import keplerGlReducer, {mapStyleUpdaters} from 'kepler.gl/reducers';
+import keplerGlReducer, {mapStyleUpdaters} from '@kepler.gl/reducers';
// Root Reducer
const reducers = combineReducers({
keplerGl: keplerGlReducer,
@@ -76,10 +77,10 @@ populate mapStyles.
**Parameters**
-- `state` **[Object][23]**
-- `action` **[Object][23]**
- - `action.payload` **[Object][23]**
- - `action.payload.mapboxApiAccessToken` **[string][22]**
+- `state` **[Object][23]**
+- `action` **[Object][23]**
+ - `action.payload` **[Object][23]**
+ - `action.payload.mapboxApiAccessToken` **[string][22]**
Returns **[Object][23]** nextState
@@ -100,8 +101,8 @@ Input a custom map style object
- `action.payload.name` **[string][22]** style name
- `action.payload.layerGroups` **[Object][23]** layer groups that can be used to set map layer visibility
- `action.payload.icon` **[Object][23]** icon image data url
- - `action.payload.inputStyle`
- - `action.payload.mapState`
+ - `action.payload.inputStyle`
+ - `action.payload.mapState`
Returns **[Object][23]** nextState
@@ -114,14 +115,14 @@ Callback when a custom map style object is received
**Parameters**
- `state` **[Object][23]** `mapStyle`
-- `action` **[Object][23]**
- - `action.payload` **[Object][23]**
- - `action.payload.icon` **[string][22]**
- - `action.payload.style` **[Object][23]**
- - `action.payload.error` **any**
- - `action.payload.icon`
- - `action.payload.style`
- - `action.payload.error`
+- `action` **[Object][23]**
+ - `action.payload` **[Object][23]**
+ - `action.payload.icon` **[string][22]**
+ - `action.payload.style` **[Object][23]**
+ - `action.payload.error` **any**
+ - `action.payload.icon`
+ - `action.payload.style`
+ - `action.payload.error`
Returns **[Object][23]** nextState
@@ -134,7 +135,7 @@ Callback when load map style error
**Parameters**
- `state` **[Object][23]** `mapStyle`
-- `action` **[Object][23]**
+- `action` **[Object][23]**
- `action.payload` **any** error
Returns **[Object][23]** nextState
@@ -148,7 +149,7 @@ Callback when load map style success
**Parameters**
- `state` **[Object][23]** `mapStyle`
-- `action` **[Object][23]**
+- `action` **[Object][23]**
- `action.payload` **[Object][23]** a `{[id]: style}` mapping
Returns **[Object][23]** nextState
@@ -162,7 +163,7 @@ Update `visibleLayerGroups`to change layer group visibility
**Parameters**
- `state` **[Object][23]** `mapStyle`
-- `action` **[Object][23]**
+- `action` **[Object][23]**
- `action.payload` **[Object][23]** new config `{visibleLayerGroups: {label: false, road: true, background: true}}`
Returns **[Object][23]** nextState
@@ -176,8 +177,8 @@ Change to another map style. The selected style should already been loaded into
**Parameters**
- `state` **[Object][23]** `mapStyle`
-- `action` **[Object][23]**
- - `action.payload` **[string][22]**
+- `action` **[Object][23]**
+ - `action.payload` **[string][22]**
Returns **[Object][23]** nextState
diff --git a/docs/api-reference/reducers/reducers.md b/docs/api-reference/reducers/reducers.md
index 54055fdcce..46eb2d2d36 100644
--- a/docs/api-reference/reducers/reducers.md
+++ b/docs/api-reference/reducers/reducers.md
@@ -2,14 +2,14 @@
### Table of Contents
-- [keplerGlReducer][1]
- - [keplerGlReducer.initialState][3]
- - [keplerGlReducer.plugin][6]
-- [mapStateLens][9]
-- [mapStyleLens][11]
-- [providerStateLens][13]
-- [uiStateLens][15]
-- [visStateLens][17]
+- [keplerGlReducer](#keplerglreducer)
+ - [keplerGlReducer.initialState](#keplerglreducerinitialstate)
+ - [keplerGlReducer.plugin](#keplerglreducerplugin)
+- [mapStateLens](#mapstatelens)
+- [mapStyleLens](#mapstylelens)
+- [providerStateLens](#providerstatelens)
+- [uiStateLens](#uistatelens)
+- [visStateLens](#visstatelens)
## keplerGlReducer
@@ -19,7 +19,7 @@ to mount it at another address e.g. `foo` you will need to specify it when you m
**Examples**
```javascript
-import keplerGlReducer from 'kepler.gl/reducers';
+import keplerGlReducer from '@kepler.gl/reducers';
import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
import {taskMiddleware} from 'react-palm/tasks';
@@ -109,7 +109,7 @@ Connect subreducer `mapState`, used with `injectComponents`. Learn more at
**Parameters**
-- `reduxState` **any**
+- `reduxState` **any**
## mapStyleLens
@@ -118,7 +118,7 @@ Connect subreducer `mapStyle`, used with `injectComponents`. Learn more at
**Parameters**
-- `reduxState` **any**
+- `reduxState` **any**
## providerStateLens
@@ -127,7 +127,7 @@ Connect subreducer `providerState`, used with `injectComponents`. Learn more at
**Parameters**
-- `reduxState` **any**
+- `reduxState` **any**
## uiStateLens
@@ -136,7 +136,7 @@ Connect subreducer `uiState`, used with `injectComponents`. Learn more at
**Parameters**
-- `reduxState` **any**
+- `reduxState` **any**
## visStateLens
@@ -145,7 +145,7 @@ Connect subreducer `visState`, used with `injectComponents`. Learn more at
**Parameters**
-- `reduxState` **any**
+- `reduxState` **any**
[1]: #keplerglreducer
diff --git a/docs/api-reference/reducers/ui-state.md b/docs/api-reference/reducers/ui-state.md
index adb525131e..ba90d510aa 100644
--- a/docs/api-reference/reducers/ui-state.md
+++ b/docs/api-reference/reducers/ui-state.md
@@ -2,32 +2,37 @@
### Table of Contents
-- [uiStateUpdaters][1]
- - [addNotificationUpdater][3]
- - [cleanupExportImage][5]
- - [DEFAULT_EXPORT_DATA][7]
- - [DEFAULT_EXPORT_IMAGE][9]
- - [DEFAULT_MAP_CONTROLS_FEATURES][11]
- - [hideExportDropdownUpdater][13]
- - [INITIAL_UI_STATE][15]
- - [loadFilesErrUpdater][17]
- - [loadFilesUpdater][19]
- - [openDeleteModalUpdater][21]
- - [removeNotificationUpdater][23]
- - [setExportDataTypeUpdater][25]
- - [setExportDataUpdater][27]
- - [setExportFilteredUpdater][29]
- - [setExportImageDataUri][31]
- - [setExportImageSetting][33]
- - [setExportSelectedDatasetUpdater][35]
- - [showExportDropdownUpdater][37]
- - [startExportingImage][39]
- - [toggleMapControlUpdater][41]
- - [toggleModalUpdater][43]
- - [toggleSidePanelUpdater][45]
- - [toggleSplitMapUpdater][47]
-- [DEFAULT_EXPORT_HTML][49]
-- [setUserMapboxAccessTokenUpdater][51]
+- [uiStateUpdaters](#uistateupdaters)
+ - [addNotificationUpdater](#addnotificationupdater)
+ - [cleanupExportImage](#cleanupexportimage)
+ - [DEFAULT\_EXPORT\_DATA](#default_export_data)
+ - [Properties](#properties)
+ - [DEFAULT\_EXPORT\_IMAGE](#default_export_image)
+ - [Properties](#properties-1)
+ - [DEFAULT\_MAP\_CONTROLS\_FEATURES](#default_map_controls_features)
+ - [Properties](#properties-2)
+ - [hideExportDropdownUpdater](#hideexportdropdownupdater)
+ - [INITIAL\_UI\_STATE](#initial_ui_state)
+ - [Properties](#properties-3)
+ - [loadFilesErrUpdater](#loadfileserrupdater)
+ - [loadFilesUpdater](#loadfilesupdater)
+ - [openDeleteModalUpdater](#opendeletemodalupdater)
+ - [removeNotificationUpdater](#removenotificationupdater)
+ - [setExportDataTypeUpdater](#setexportdatatypeupdater)
+ - [setExportDataUpdater](#setexportdataupdater)
+ - [setExportFilteredUpdater](#setexportfilteredupdater)
+ - [setExportImageDataUri](#setexportimagedatauri)
+ - [setExportImageSetting](#setexportimagesetting)
+ - [setExportSelectedDatasetUpdater](#setexportselecteddatasetupdater)
+ - [showExportDropdownUpdater](#showexportdropdownupdater)
+ - [startExportingImage](#startexportingimage)
+ - [toggleMapControlUpdater](#togglemapcontrolupdater)
+ - [toggleModalUpdater](#togglemodalupdater)
+ - [toggleSidePanelUpdater](#togglesidepanelupdater)
+ - [toggleSplitMapUpdater](#togglesplitmapupdater)
+- [DEFAULT\_EXPORT\_HTML](#default_export_html)
+ - [Properties](#properties-4)
+- [setUserMapboxAccessTokenUpdater](#setusermapboxaccesstokenupdater)
## uiStateUpdaters
@@ -37,7 +42,7 @@ Read more about [Using updaters][53]
**Examples**
```javascript
-import keplerGlReducer, {uiStateUpdaters} from 'kepler.gl/reducers';
+import keplerGlReducer, {uiStateUpdaters} from '@kepler.gl/reducers';
// Root Reducer
const reducers = combineReducers({
keplerGl: keplerGlReducer,
@@ -77,8 +82,8 @@ Existing notification is going to be updated in case of matching ids.
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
- - `action.payload` **[Object][55]**
+- `action` **[Object][55]**
+ - `action.payload` **[Object][55]**
Returns **[Object][55]** nextState
@@ -174,9 +179,9 @@ Handles load file error and set fileLoading property to false
**Parameters**
-- `state`
-- `error` **[Object][55]**
- - `error.error`
+- `state`
+- `error` **[Object][55]**
+ - `error.error`
Returns **[Object][55]** nextState
@@ -201,7 +206,7 @@ Toggle active map control panel
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **[string][57]** dataset id
Returns **[Object][55]** nextState
@@ -215,7 +220,7 @@ Remove a notification
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **[String][57]** id of the notification to be removed
Returns **[Object][55]** nextState
@@ -229,7 +234,7 @@ Set data format for exporting data
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **[string][57]** one of `'text/csv'`
Returns **[Object][55]** nextState
@@ -255,8 +260,8 @@ Whether to export filtered data, `true` or `false`
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
- - `action.payload` **[boolean][58]**
+- `action` **[Object][55]**
+ - `action.payload` **[boolean][58]**
Returns **[Object][55]** nextState
@@ -269,7 +274,7 @@ Set `exportImage.setExportImageDataUri` to a image dataUri
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **[string][57]** export image data uri
Returns **[Object][55]** nextState
@@ -283,8 +288,8 @@ Set `exportImage.legend` to `true` or `false`
**Parameters**
- `state` **[Object][55]** `uiState`
-- `$1` **[Object][55]**
- - `$1.payload`
+- `$1` **[Object][55]**
+ - `$1.payload`
Returns **[Object][55]** nextState
@@ -297,7 +302,7 @@ Set selected dataset for export
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **[string][57]** dataset id
Returns **[Object][55]** nextState
@@ -311,7 +316,7 @@ Hide and show side panel header dropdown, activated by clicking the share link o
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **[string][57]** id of the dropdown
Returns **[Object][55]** nextState
@@ -339,7 +344,7 @@ Toggle active map control panel
- `state` **[Object][55]** `uiState`
- `action` **[Object][55]** action
- `action.payload` **[string][57]** map control panel id, one of the keys of: [`DEFAULT_MAP_CONTROLS`][60]
- - `action.payload.panelId`
+ - `action.payload.panelId`
- `action.payload.index` (optional, default `0`)
Returns **[Object][55]** nextState
@@ -353,7 +358,7 @@ Show and hide modal dialog
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **([string][57] | null)** id of modal to be shown, null to hide modals. One of:- [`DATA_TABLE_ID`][76]
- [`DELETE_DATA_ID`][77]
- [`ADD_DATA_ID`][78]
@@ -372,7 +377,7 @@ Toggle active side panel
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
+- `action` **[Object][55]**
- `action.payload` **([string][57] | null)** id of side panel to be shown, one of `layer`, `filter`, `interaction`, `map`. close side panel if `null`
Returns **[Object][55]** nextState
@@ -385,7 +390,7 @@ Handles toggle map split and reset all map control index to 0
**Parameters**
-- `state`
+- `state`
Returns **[Object][55]** nextState
@@ -407,8 +412,8 @@ whether to export a mapbox access to HTML single page
**Parameters**
- `state` **[Object][55]** `uiState`
-- `action` **[Object][55]**
- - `action.payload` **[string][57]**
+- `action` **[Object][55]**
+ - `action.payload` **[string][57]**
Returns **[Object][55]** nextState
diff --git a/docs/api-reference/reducers/vis-state.md b/docs/api-reference/reducers/vis-state.md
index d51bb329e2..10ca6e4c16 100644
--- a/docs/api-reference/reducers/vis-state.md
+++ b/docs/api-reference/reducers/vis-state.md
@@ -2,39 +2,40 @@
### Table of Contents
-- [visStateUpdaters][1]
- - [addFilterUpdater][3]
- - [addLayerUpdater][5]
- - [applyCPUFilterUpdater][7]
- - [enlargeFilterUpdater][9]
- - [INITIAL_VIS_STATE][11]
- - [interactionConfigChangeUpdater][13]
- - [layerClickUpdater][15]
- - [layerHoverUpdater][17]
- - [layerTypeChangeUpdater][19]
- - [layerVisConfigChangeUpdater][21]
- - [layerVisualChannelChangeUpdater][23]
- - [loadFilesErrUpdater][25]
- - [loadFilesUpdater][27]
- - [mapClickUpdater][29]
- - [receiveMapConfigUpdater][31]
- - [removeDatasetUpdater][33]
- - [removeFilterUpdater][35]
- - [removeLayerUpdater][37]
- - [reorderLayerUpdater][39]
- - [resetMapConfigUpdater][41]
- - [setFilterPlotUpdater][43]
- - [setFilterUpdater][45]
- - [setMapInfoUpdater][47]
- - [showDatasetTableUpdater][49]
- - [toggleFilterAnimationUpdater][51]
- - [toggleLayerForMapUpdater][53]
- - [toggleSplitMapUpdater][55]
- - [updateAnimationTimeUpdater][57]
- - [updateFilterAnimationSpeedUpdater][59]
- - [updateLayerAnimationSpeedUpdater][61]
- - [updateLayerBlendingUpdater][63]
- - [updateVisDataUpdater][65]
+- [visStateUpdaters](#visstateupdaters)
+ - [addFilterUpdater](#addfilterupdater)
+ - [addLayerUpdater](#addlayerupdater)
+ - [applyCPUFilterUpdater](#applycpufilterupdater)
+ - [enlargeFilterUpdater](#enlargefilterupdater)
+ - [INITIAL\_VIS\_STATE](#initial_vis_state)
+ - [Properties](#properties)
+ - [interactionConfigChangeUpdater](#interactionconfigchangeupdater)
+ - [layerClickUpdater](#layerclickupdater)
+ - [layerHoverUpdater](#layerhoverupdater)
+ - [layerTypeChangeUpdater](#layertypechangeupdater)
+ - [layerVisConfigChangeUpdater](#layervisconfigchangeupdater)
+ - [layerVisualChannelChangeUpdater](#layervisualchannelchangeupdater)
+ - [loadFilesErrUpdater](#loadfileserrupdater)
+ - [loadFilesUpdater](#loadfilesupdater)
+ - [mapClickUpdater](#mapclickupdater)
+ - [receiveMapConfigUpdater](#receivemapconfigupdater)
+ - [removeDatasetUpdater](#removedatasetupdater)
+ - [removeFilterUpdater](#removefilterupdater)
+ - [removeLayerUpdater](#removelayerupdater)
+ - [reorderLayerUpdater](#reorderlayerupdater)
+ - [resetMapConfigUpdater](#resetmapconfigupdater)
+ - [setFilterPlotUpdater](#setfilterplotupdater)
+ - [setFilterUpdater](#setfilterupdater)
+ - [setMapInfoUpdater](#setmapinfoupdater)
+ - [showDatasetTableUpdater](#showdatasettableupdater)
+ - [toggleFilterAnimationUpdater](#togglefilteranimationupdater)
+ - [toggleLayerForMapUpdater](#togglelayerformapupdater)
+ - [toggleSplitMapUpdater](#togglesplitmapupdater)
+ - [updateAnimationTimeUpdater](#updateanimationtimeupdater)
+ - [updateFilterAnimationSpeedUpdater](#updatefilteranimationspeedupdater)
+ - [updateLayerAnimationSpeedUpdater](#updatelayeranimationspeedupdater)
+ - [updateLayerBlendingUpdater](#updatelayerblendingupdater)
+ - [updateVisDataUpdater](#updatevisdataupdater)
## visStateUpdaters
@@ -44,7 +45,7 @@ Read more about [Using updaters][67]
**Examples**
```javascript
-import keplerGlReducer, {visStateUpdaters} from 'kepler.gl/reducers';
+import keplerGlReducer, {visStateUpdaters} from '@kepler.gl/reducers';
// Root Reducer
const reducers = combineReducers({
keplerGl: keplerGlReducer,
@@ -111,7 +112,7 @@ When select dataset for export, apply cpu filter to selected dataset
**Parameters**
- `state` **[Object][69]** `visState`
-- `action` **[Object][69]**
+- `action` **[Object][69]**
- `action.dataId` **[string][70]** dataset id
Returns **[Object][69]** nextState
@@ -138,24 +139,24 @@ Type: [Object][69]
#### Properties
-- `layers` **[Array][75]**
-- `layerData` **[Array][75]**
-- `layerToBeMerged` **[Array][75]**
-- `layerOrder` **[Array][75]**
-- `filters` **[Array][75]**
-- `filterToBeMerged` **[Array][75]**
-- `datasets` **[Array][75]**
-- `editingDataset` **[string][70]**
-- `interactionConfig` **[Object][69]**
-- `interactionToBeMerged` **[Object][69]**
-- `layerBlending` **[string][70]**
-- `hoverInfo` **[Object][69]**
-- `clicked` **[Object][69]**
-- `mousePos` **[Object][69]**
+- `layers` **[Array][75]**
+- `layerData` **[Array][75]**
+- `layerToBeMerged` **[Array][75]**
+- `layerOrder` **[Array][75]**
+- `filters` **[Array][75]**
+- `filterToBeMerged` **[Array][75]**
+- `datasets` **[Array][75]**
+- `editingDataset` **[string][70]**
+- `interactionConfig` **[Object][69]**
+- `interactionToBeMerged` **[Object][69]**
+- `layerBlending` **[string][70]**
+- `hoverInfo` **[Object][69]**
+- `clicked` **[Object][69]**
+- `mousePos` **[Object][69]**
- `splitMaps` **[Array][75]** a list of objects of layer availabilities and visibilities for each map
-- `layerClasses` **[Object][69]**
-- `animationConfig` **[Object][69]**
-- `editor` **[Object][69]**
+- `layerClasses` **[Object][69]**
+- `animationConfig` **[Object][69]**
+- `editor` **[Object][69]**
### interactionConfigChangeUpdater
@@ -255,7 +256,7 @@ Trigger loading file error
- `state` **[Object][69]** `visState`
- `action` **[Object][69]** action
- - `action.error` **any**
+ - `action.error` **any**
Returns **[Object][69]** nextState
@@ -381,7 +382,7 @@ Set the property of a filter plot
- `state` **[Object][69]** `visState`
- `action` **[Object][69]** action
- - `action.idx` **[Number][74]**
+ - `action.idx` **[Number][74]**
- `action.newProp` **[Object][69]** key value mapping of new prop `{yAxis: 'histogram'}`
Returns **[Object][69]** nextState
@@ -453,8 +454,8 @@ Toggle visibility of a layer in a split map
**Parameters**
-- `state` **[Object][69]**
-- `action` **[Object][69]**
+- `state` **[Object][69]**
+- `action` **[Object][69]**
- `action.mapIndex` **[Number][74]** index of the split map
- `action.layerId` **[string][70]** id of the layer
diff --git a/examples/demo-app/package.json b/examples/demo-app/package.json
index 43e43dd1fa..a0530c634b 100644
--- a/examples/demo-app/package.json
+++ b/examples/demo-app/package.json
@@ -44,6 +44,7 @@
"react-virtualized": "^9.21.0",
"redux": "^4.2.1",
"redux-actions": "^2.2.1",
+ "redux-logger": "^3.0.6",
"redux-thunk": "^1.0.0",
"styled-components": "^4.1.3"
},
diff --git a/examples/demo-app/src/app.js b/examples/demo-app/src/app.tsx
similarity index 62%
rename from examples/demo-app/src/app.js
rename to examples/demo-app/src/app.tsx
index 8be0057a41..500c076993 100644
--- a/examples/demo-app/src/app.js
+++ b/examples/demo-app/src/app.tsx
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
-import React, {Component} from 'react';
+import React, {useCallback, useEffect, useMemo, useState} from 'react';
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
import styled, {ThemeProvider} from 'styled-components';
import window from 'global/window';
-import {connect} from 'react-redux';
+import {connect, useDispatch} from 'react-redux';
import cloneDeep from 'lodash.clonedeep';
import {ScreenshotWrapper} from 'react-ai-assist';
@@ -30,7 +30,7 @@ import {
onLoadCloudMapSuccess
} from './actions';
-import {loadCloudMap, addDataToMap, addNotification, replaceDataInMap} from '@kepler.gl/actions';
+import {loadCloudMap, addDataToMap, replaceDataInMap} from '@kepler.gl/actions';
import {CLOUD_PROVIDERS} from './cloud-providers';
const KeplerGl = require('@kepler.gl/components').injectComponents([
@@ -48,7 +48,7 @@ import sampleGeojsonConfig from './data/sample-geojson-config';
import sampleH3Data, {config as h3MapConfig} from './data/sample-hex-id-csv';
import sampleS2Data, {config as s2MapConfig, dataId as s2DataId} from './data/sample-s2-data';
import sampleAnimateTrip, {animateTripDataId} from './data/sample-animate-trip-data';
-import sampleIconCsv, {config as savedMapConfig} from './data/sample-icon-csv';
+import sampleIconCsv from './data/sample-icon-csv';
import sampleGpsData from './data/sample-gps-data';
import sampleRowData, {config as rowDataConfig} from './data/sample-row-data';
import {processCsvData, processGeojson, processRowObject} from '@kepler.gl/processors';
@@ -93,24 +93,23 @@ const CONTAINER_STYLE = {
width: '100%',
height: '100%',
left: 0,
- top: 0
+ top: 0,
+ display: 'flex',
+ flexDirection: 'row'
};
-class App extends Component {
- state = {
- showBanner: false,
- width: window.innerWidth,
- height: window.innerHeight
- };
+const App = props => {
+ const [showBanner, toggleShowBanner] = useState(false);
+ const {params: {id, provider} = {}, location: {query = {}} = {}} = props;
+ const dispatch = useDispatch();
- componentDidMount() {
+ useEffect(() => {
// if we pass an id as part of the url
// we ry to fetch along map configurations
- const {params: {id, provider} = {}, location: {query = {}} = {}} = this.props;
const cloudProvider = CLOUD_PROVIDERS.find(c => c.name === provider);
if (cloudProvider) {
- this.props.dispatch(
+ dispatch(
loadCloudMap({
loadParams: query,
provider: cloudProvider,
@@ -122,83 +121,56 @@ class App extends Component {
// Load sample using its id
if (id) {
- this.props.dispatch(loadSampleConfigurations(id));
+ dispatch(loadSampleConfigurations(id));
}
// Load map using a custom
if (query.mapUrl) {
// TODO?: validate map url
- this.props.dispatch(loadRemoteMap({dataUrl: query.mapUrl}));
+ dispatch(loadRemoteMap({dataUrl: query.mapUrl}));
}
// delay zs to show the banner
// if (!window.localStorage.getItem(BannerKey)) {
- // window.setTimeout(this._showBanner, 3000);
+ // window.setTimeout(_showBanner, 3000);
// }
// load sample data
- // this._loadSampleData();
+ // _loadSampleData();
// Notifications
- // this._loadMockNotifications();
- }
-
- _setStartScreenCapture = flag => {
- this.props.dispatch(setStartScreenCapture(flag));
- };
+ // _loadMockNotifications();
+ }, [dispatch, id, provider, query]);
+
+ const _setStartScreenCapture = useCallback(
+ flag => {
+ dispatch(setStartScreenCapture(flag));
+ },
+ [dispatch]
+ );
- _setScreenCaptured = screenshot => {
- this.props.dispatch(setScreenCaptured(screenshot));
- };
+ const _setScreenCaptured = useCallback(
+ screenshot => {
+ dispatch(setScreenCaptured(screenshot));
+ },
+ [dispatch]
+ );
- _showBanner = () => {
- this.setState({showBanner: true});
- };
+ // eslint-disable-next-line no-unused-vars
+ const _showBanner = useCallback(() => {
+ toggleShowBanner(true);
+ }, [toggleShowBanner]);
- _hideBanner = () => {
- this.setState({showBanner: false});
- };
+ const hideBanner = useCallback(() => {
+ toggleShowBanner(false);
+ }, [toggleShowBanner]);
- _disableBanner = () => {
- this._hideBanner();
+ const _disableBanner = useCallback(() => {
+ hideBanner();
window.localStorage.setItem(BannerKey, 'true');
- };
-
- _loadMockNotifications = () => {
- const notifications = [
- [{message: 'Welcome to Kepler.gl'}, 3000],
- [{message: 'Something is wrong', type: 'error'}, 1000],
- [{message: 'I am getting better', type: 'warning'}, 1000],
- [{message: 'Everything is fine', type: 'success'}, 1000]
- ];
-
- this._addNotifications(notifications);
- };
-
- _addNotifications(notifications) {
- if (notifications && notifications.length) {
- const [notification, timeout] = notifications[0];
-
- window.setTimeout(() => {
- this.props.dispatch(addNotification(notification));
- this._addNotifications(notifications.slice(1));
- }, timeout);
- }
- }
+ }, [hideBanner]);
- _loadSampleData() {
- // this._loadPointData();
- // this._loadGeojsonData();
- // this._loadTripGeoJson();
- // this._loadIconData();
- // this._loadH3HexagonData();
- // this._loadS2Data();
- // this._loadScenegraphLayer();
- // this._loadGpsData();
- // this._loadRowData();
- }
-
- _loadRowData() {
- this.props.dispatch(
+ const _loadRowData = useCallback(() => {
+ dispatch(
addDataToMap({
datasets: [
{
@@ -212,10 +184,10 @@ class App extends Component {
config: rowDataConfig
})
);
- }
+ }, [dispatch]);
- _loadPointData() {
- this.props.dispatch(
+ const _loadPointData = useCallback(() => {
+ dispatch(
addDataToMap({
datasets: [
{
@@ -248,10 +220,10 @@ class App extends Component {
config: sampleTripDataConfig
})
);
- }
+ }, [dispatch]);
- _loadScenegraphLayer() {
- this.props.dispatch(
+ const _loadScenegraphLayer = useCallback(() => {
+ dispatch(
addDataToMap({
datasets: {
info: {
@@ -282,11 +254,11 @@ class App extends Component {
}
})
);
- }
+ }, [dispatch]);
- _loadIconData() {
+ const _loadIconData = useCallback(() => {
// load icon data and config and process csv file
- this.props.dispatch(
+ dispatch(
addDataToMap({
datasets: [
{
@@ -299,10 +271,10 @@ class App extends Component {
]
})
);
- }
+ }, [dispatch]);
- _loadTripGeoJson() {
- this.props.dispatch(
+ const _loadTripGeoJson = useCallback(() => {
+ dispatch(
addDataToMap({
datasets: [
{
@@ -312,17 +284,45 @@ class App extends Component {
]
})
);
- }
+ }, [dispatch]);
- _replaceData = () => {
+ const _loadGeojsonData = useCallback(() => {
+ // load geojson
+ const geojsonPoints = processGeojson(sampleGeojsonPoints);
+ const geojsonZip = processGeojson(sampleGeojson);
+ dispatch(
+ addDataToMap({
+ datasets: [
+ geojsonPoints
+ ? {
+ info: {label: 'Bart Stops Geo', id: 'bart-stops-geo'},
+ data: geojsonPoints
+ }
+ : null,
+ geojsonZip
+ ? {
+ info: {label: 'SF Zip Geo', id: 'sf-zip-geo'},
+ data: geojsonZip
+ }
+ : null
+ ].filter(d => d !== null),
+ options: {
+ keepExistingConfig: true
+ },
+ config: sampleGeojsonConfig
+ })
+ );
+ }, [dispatch]);
+
+ const _replaceData = useCallback(() => {
// add geojson data
const sliceData = processGeojson({
type: 'FeatureCollection',
features: sampleGeojsonPoints.features.slice(0, 5)
});
- this._loadGeojsonData();
+ _loadGeojsonData();
window.setTimeout(() => {
- this.props.dispatch(
+ dispatch(
replaceDataInMap({
datasetToReplaceId: 'bart-stops-geo',
datasetToUse: {
@@ -332,33 +332,11 @@ class App extends Component {
})
);
}, 1000);
- };
-
- _loadGeojsonData() {
- // load geojson
- this.props.dispatch(
- addDataToMap({
- datasets: [
- {
- info: {label: 'Bart Stops Geo', id: 'bart-stops-geo'},
- data: processGeojson(sampleGeojsonPoints)
- }
- // {
- // info: {label: 'SF Zip Geo', id: 'sf-zip-geo'},
- // data: processGeojson(sampleGeojson)
- // }
- ],
- options: {
- keepExistingConfig: true
- },
- config: sampleGeojsonConfig
- })
- );
- }
+ }, [dispatch, _loadGeojsonData]);
- _loadH3HexagonData() {
+ const _loadH3HexagonData = useCallback(() => {
// load h3 hexagon
- this.props.dispatch(
+ dispatch(
addDataToMap({
datasets: [
{
@@ -375,11 +353,11 @@ class App extends Component {
}
})
);
- }
+ }, [dispatch]);
- _loadS2Data() {
+ const _loadS2Data = useCallback(() => {
// load s2
- this.props.dispatch(
+ dispatch(
addDataToMap({
datasets: [
{
@@ -396,10 +374,10 @@ class App extends Component {
}
})
);
- }
+ }, [dispatch]);
- _loadGpsData() {
- this.props.dispatch(
+ const _loadGpsData = useCallback(() => {
+ dispatch(
addDataToMap({
datasets: [
{
@@ -415,66 +393,66 @@ class App extends Component {
}
})
);
- }
- _toggleCloudModal = () => {
- // TODO: this lives only in the demo hence we use the state for now
- // REFCOTOR using redux
- this.setState({
- cloudModalOpen: !this.state.cloudModalOpen
- });
- };
-
- _getMapboxRef = mapbox => {
- if (!mapbox) {
- // The ref has been unset.
- // https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
- // console.log(`Map ${index} has closed`);
- } else {
- // We expect an Map created by KeplerGl's MapContainer.
- // https://visgl.github.io/react-map-gl/docs/api-reference/map
- const map = mapbox.getMap();
- map.on('zoomend', () => {
- // console.log(`Map ${index} zoom level: ${e.target.style.z}`);
- });
- }
- };
-
- combinedMessages = Object.keys(messages).reduce(
- (acc, language) => ({
- ...acc,
- [language]: {
- ...(messages[language] || {}),
- ...(aiAssistantMessages[language] || {})
- }
- }),
- {}
- );
-
- render() {
- return (
-
- {
- node ? (this.root = node) : null;
- }}
+ }, [dispatch]);
+
+ const combinedMessages = useMemo(() => {
+ return Object.keys(messages).reduce(
+ (acc, language) => ({
+ ...acc,
+ [language]: {
+ ...(messages[language] || {}),
+ ...(aiAssistantMessages[language] || {})
+ }
+ }),
+ {}
+ );
+ }, []);
+
+ // eslint-disable-next-line no-unused-vars
+ const _loadSampleData = useCallback(() => {
+ // _loadPointData();
+ // _loadGeojsonData();
+ // _loadTripGeoJson();
+ // _loadIconData();
+ // _loadH3HexagonData();
+ // _loadS2Data();
+ // _loadScenegraphLayer();
+ // _loadGpsData();
+ // _loadRowData();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [
+ _loadPointData,
+ _loadGeojsonData,
+ _loadTripGeoJson,
+ _loadIconData,
+ _loadH3HexagonData,
+ _loadS2Data,
+ _loadScenegraphLayer,
+ _loadGpsData,
+ _loadRowData,
+ _replaceData
+ ]);
+
+ return (
+
+ {
+ // node ? (this.root = node) : null;
+ // }}
+ >
+
-
-
-
-
-
+
+
+
+
+
+
+
+ );
+};
const mapStateToProps = state => state;
const dispatchToProps = dispatch => ({dispatch});
diff --git a/examples/demo-app/src/store.js b/examples/demo-app/src/store.js
index 50841d8cc8..fba46ea6cc 100644
--- a/examples/demo-app/src/store.js
+++ b/examples/demo-app/src/store.js
@@ -6,7 +6,7 @@ import {routerReducer, routerMiddleware} from 'react-router-redux';
import {browserHistory} from 'react-router';
import {createLogger} from 'redux-logger';
import {enhanceReduxMiddleware} from '@kepler.gl/reducers';
-import thunk from 'redux-thunk';
+import {createLogger} from 'redux-logger';
// eslint-disable-next-line no-unused-vars
import window from 'global/window';
diff --git a/package.json b/package.json
index 68cd97c61c..906f66aa45 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "kepler.gl",
"author": "Shan He
",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl is a webgl based application to visualize large scale location data in the browser",
"license": "MIT",
"main": "dist/index.js",
@@ -18,6 +18,7 @@
"workspaces": [
"./src/types",
"./src/constants",
+ "./src/common-utils",
"./src/utils",
"./src/styles",
"./src/localization",
@@ -102,7 +103,7 @@
"@deck.gl/mapbox": "^8.9.27",
"@hubble.gl/core": "1.2.0-alpha.6",
"@hubble.gl/react": "1.2.0-alpha.6",
- "@kepler.gl/components": "3.0.0",
+ "@kepler.gl/components": "3.1.0-alpha.0",
"@loaders.gl/polyfills": "^4.3.2",
"@types/mapbox__geo-viewport": "^0.4.1",
"html-webpack-plugin": "^4.3.0",
diff --git a/src/actions/package.json b/src/actions/package.json
index b945bd38e8..e15d30c7d3 100644
--- a/src/actions/package.json
+++ b/src/actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/actions",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -31,11 +31,11 @@
],
"dependencies": {
"@deck.gl/core": "^8.9.27",
- "@kepler.gl/cloud-providers": "3.0.0",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/layers": "3.0.0",
- "@kepler.gl/processors": "3.0.0",
- "@kepler.gl/types": "3.0.0",
+ "@kepler.gl/cloud-providers": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/layers": "3.1.0-alpha.0",
+ "@kepler.gl/processors": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
"@reduxjs/toolkit": "^1.7.2",
"@types/lodash.curry": "^4.1.7",
"@types/react-redux": "^7.1.23",
diff --git a/src/actions/src/action-types.ts b/src/actions/src/action-types.ts
index dfa8f59651..f9e0cf0dc8 100644
--- a/src/actions/src/action-types.ts
+++ b/src/actions/src/action-types.ts
@@ -43,6 +43,7 @@ export const ActionTypes = {
ADD_DATA: `${ACTION_PREFIX}ADD_DATA`,
ADD_FILTER: `${ACTION_PREFIX}ADD_FILTER`,
CREATE_OR_UPDATE_FILTER: `${ACTION_PREFIX}CREATE_OR_UPDATE_FILTER`,
+ CREATE_NEW_DATASET_SUCCESS: `${ACTION_PREFIX}CREATE_NEW_DATASET_SUCCESS`,
ADD_LAYER: `${ACTION_PREFIX}ADD_LAYER`,
APPLY_LAYER_CONFIG: `${ACTION_PREFIX}APPLY_LAYER_CONFIG`,
DUPLICATE_LAYER: `${ACTION_PREFIX}DUPLICATE_LAYER`,
@@ -190,6 +191,7 @@ export const ActionTypes = {
};
// eslint-disable-next-line prettier/prettier
-const assignType = (obj: T): { [K in keyof T]: `${typeof ACTION_PREFIX}${string & K}`; } => obj as any
+const assignType = (obj: T): {[K in keyof T]: `${typeof ACTION_PREFIX}${string & K}`} =>
+ obj as any;
export default assignType(ActionTypes);
diff --git a/src/actions/src/vis-state-actions.ts b/src/actions/src/vis-state-actions.ts
index 2775d91ec4..73c2b77740 100644
--- a/src/actions/src/vis-state-actions.ts
+++ b/src/actions/src/vis-state-actions.ts
@@ -23,6 +23,9 @@ import {
EffectPropsPartial,
SyncTimelineMode
} from '@kepler.gl/types';
+import {createAction} from '@reduxjs/toolkit';
+
+import {KeplerTable} from '@kepler.gl/table';
// TODO - import LoaderObject type from @loaders.gl/core when supported
// TODO - import LoadOptions type from @loaders.gl/core when supported
@@ -1596,6 +1599,21 @@ export function setTimeFilterSyncTimelineMode({
};
}
+export type CreateNewDatasetSuccessPayload = {
+ results: (PromiseFulfilledResult> | PromiseRejectedResult)[];
+ addToMapOptions: AddDataToMapPayload['options'];
+};
+
+/**
+ * Called when a new dataset is created successfully via async table methods
+ * @param payload
+ * @param payload.results - results of promises.allSettlted
+ * @returns
+ */
+export const createNewDatasetSuccess = createAction(
+ ActionTypes.CREATE_NEW_DATASET_SUCCESS
+);
+
/**
* This declaration is needed to group actions in docs
*/
diff --git a/src/ai-assistant/package.json b/src/ai-assistant/package.json
index 565b8ab921..4b382a392c 100644
--- a/src/ai-assistant/package.json
+++ b/src/ai-assistant/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/ai-assistant",
"author": "Xun Li",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl AI assistant",
"license": "MIT",
"main": "dist/index.js",
@@ -30,11 +30,11 @@
"umd"
],
"dependencies": {
- "@kepler.gl/components": "3.0.0",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/layers": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/components": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/layers": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"global": "^4.3.0",
"react-ai-assist": "0.0.14"
},
diff --git a/src/cloud-providers/package.json b/src/cloud-providers/package.json
index fca083c37e..237ef37adc 100644
--- a/src/cloud-providers/package.json
+++ b/src/cloud-providers/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/cloud-providers",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,7 +30,7 @@
"umd"
],
"dependencies": {
- "@kepler.gl/types": "3.0.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
"react": "^18.2.0"
},
"nyc": {
diff --git a/src/common-utils/babel.config.js b/src/common-utils/babel.config.js
new file mode 100644
index 0000000000..eb16706b69
--- /dev/null
+++ b/src/common-utils/babel.config.js
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MIT
+// Copyright contributors to the kepler.gl project
+
+const KeplerPackage = require('./package');
+
+const PRESETS = ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'];
+const PLUGINS = [
+ ['@babel/plugin-transform-typescript', {isTSX: true, allowDeclareFields: true}],
+ '@babel/plugin-transform-modules-commonjs',
+ '@babel/plugin-transform-class-properties',
+ '@babel/plugin-transform-optional-chaining',
+ '@babel/plugin-transform-logical-assignment-operators',
+ '@babel/plugin-transform-nullish-coalescing-operator',
+ '@babel/plugin-transform-export-namespace-from',
+ [
+ '@babel/transform-runtime',
+ {
+ regenerator: true
+ }
+ ],
+ [
+ 'search-and-replace',
+ {
+ rules: [
+ {
+ search: '__PACKAGE_VERSION__',
+ replace: KeplerPackage.version
+ }
+ ]
+ }
+ ]
+];
+const ENV = {
+ test: {
+ plugins: ['istanbul']
+ },
+ debug: {
+ sourceMaps: 'inline',
+ retainLines: true
+ }
+};
+
+module.exports = function babel(api) {
+ api.cache(true);
+
+ return {
+ presets: PRESETS,
+ plugins: PLUGINS,
+ env: ENV
+ };
+};
diff --git a/src/common-utils/package.json b/src/common-utils/package.json
new file mode 100644
index 0000000000..7f9aff0250
--- /dev/null
+++ b/src/common-utils/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@kepler.gl/common-utils",
+ "author": "Shan He ",
+ "version": "3.1.0-alpha.0",
+ "description": "kepler.gl common utils",
+ "license": "MIT",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "keywords": [
+ "babel",
+ "es6",
+ "react",
+ "webgl",
+ "visualization",
+ "deck.gl"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/keplergl/kepler.gl.git"
+ },
+ "scripts": {
+ "build": "rm -fr dist && babel src --out-dir dist --source-maps inline --extensions '.ts,.tsx,.js,.jsx' --ignore '**/*.d.ts'",
+ "build:umd": "NODE_OPTIONS=--openssl-legacy-provider webpack --config ./webpack/umd.js --progress --env.prod",
+ "build:types": "tsc --project ./tsconfig.production.json",
+ "prepublish": "babel-node ../../scripts/license-header/bin --license ../../FILE-HEADER && yarn build && yarn build:types",
+ "stab": "mkdir -p dist && touch dist/index.js"
+ },
+ "files": [
+ "dist",
+ "umd"
+ ],
+ "dependencies": {
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "d3-array": "^2.8.0",
+ "global": "^4.3.0",
+ "type-analyzer": "0.4.0"
+ },
+ "nyc": {
+ "sourceMap": false,
+ "instrument": false
+ },
+ "maintainers": [
+ "Shan He ",
+ "Igor Dykhta "
+ ],
+ "engines": {
+ "node": ">=18"
+ },
+ "volta": {
+ "node": "18.18.2",
+ "yarn": "4.4.0"
+ },
+ "packageManager": "yarn@4.4.0"
+}
diff --git a/src/common-utils/src/data-type.ts b/src/common-utils/src/data-type.ts
new file mode 100644
index 0000000000..19740e6831
--- /dev/null
+++ b/src/common-utils/src/data-type.ts
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: MIT
+// Copyright contributors to the kepler.gl project
+
+import {Analyzer, DATA_TYPES as AnalyzerDATA_TYPES} from 'type-analyzer';
+import {RowData, Field} from '@kepler.gl/types';
+import {ALL_FIELD_TYPES} from '@kepler.gl/constants';
+import {console as globalConsole} from 'global/window';
+import {range} from 'd3-array';
+import {isHexWkb, notNullorUndefined} from './data';
+
+export const ACCEPTED_ANALYZER_TYPES = [
+ AnalyzerDATA_TYPES.DATE,
+ AnalyzerDATA_TYPES.TIME,
+ AnalyzerDATA_TYPES.DATETIME,
+ AnalyzerDATA_TYPES.NUMBER,
+ AnalyzerDATA_TYPES.INT,
+ AnalyzerDATA_TYPES.FLOAT,
+ AnalyzerDATA_TYPES.BOOLEAN,
+ AnalyzerDATA_TYPES.STRING,
+ AnalyzerDATA_TYPES.GEOMETRY,
+ AnalyzerDATA_TYPES.GEOMETRY_FROM_STRING,
+ AnalyzerDATA_TYPES.PAIR_GEOMETRY_FROM_STRING,
+ AnalyzerDATA_TYPES.ZIPCODE,
+ AnalyzerDATA_TYPES.ARRAY,
+ AnalyzerDATA_TYPES.OBJECT
+];
+
+const IGNORE_DATA_TYPES = Object.keys(AnalyzerDATA_TYPES).filter(
+ type => !ACCEPTED_ANALYZER_TYPES.includes(type)
+);
+
+/**
+ * Getting sample data for analyzing field type.
+ */
+export function getSampleForTypeAnalyze({
+ fields,
+ rows,
+ sampleCount = 50
+}: {
+ fields: string[];
+ rows: unknown[][] | RowData;
+ sampleCount?: number;
+}): RowData {
+ const total = Math.min(sampleCount, rows.length);
+ // const fieldOrder = fields.map(f => f.name);
+ const sample = range(0, total, 1).map(() => ({}));
+
+ if (rows.length < 1) {
+ return [];
+ }
+ const isRowObject = !Array.isArray(rows[0]);
+
+ // collect sample data for each field
+ fields.forEach((field, fieldIdx) => {
+ // row counter
+ let i = 0;
+ // sample counter
+ let j = 0;
+
+ while (j < total) {
+ if (i >= rows.length) {
+ // if depleted data pool
+ sample[j][field] = null;
+ j++;
+ } else if (notNullorUndefined(rows[i][isRowObject ? field : fieldIdx])) {
+ const value = rows[i][isRowObject ? field : fieldIdx];
+ sample[j][field] = typeof value === 'string' ? value.trim() : value;
+ j++;
+ i++;
+ } else {
+ i++;
+ }
+ }
+ });
+
+ return sample;
+}
+
+/**
+ * Convert type-analyzer output to kepler.gl field types
+ *
+ * @param aType
+ * @returns corresponding type in `ALL_FIELD_TYPES`
+ */
+/* eslint-disable complexity */
+export function analyzerTypeToFieldType(aType: string): string {
+ const {
+ DATE,
+ TIME,
+ DATETIME,
+ NUMBER,
+ INT,
+ FLOAT,
+ BOOLEAN,
+ STRING,
+ GEOMETRY,
+ GEOMETRY_FROM_STRING,
+ PAIR_GEOMETRY_FROM_STRING,
+ ZIPCODE,
+ ARRAY,
+ OBJECT
+ } = AnalyzerDATA_TYPES;
+
+ // TODO: un recognized types
+ // CURRENCY PERCENT NONE
+ switch (aType) {
+ case DATE:
+ return ALL_FIELD_TYPES.date;
+ case TIME:
+ case DATETIME:
+ return ALL_FIELD_TYPES.timestamp;
+ case FLOAT:
+ return ALL_FIELD_TYPES.real;
+ case INT:
+ return ALL_FIELD_TYPES.integer;
+ case BOOLEAN:
+ return ALL_FIELD_TYPES.boolean;
+ case GEOMETRY:
+ case GEOMETRY_FROM_STRING:
+ case PAIR_GEOMETRY_FROM_STRING:
+ return ALL_FIELD_TYPES.geojson;
+ case ARRAY:
+ return ALL_FIELD_TYPES.array;
+ case OBJECT:
+ return ALL_FIELD_TYPES.object;
+ case NUMBER:
+ case STRING:
+ case ZIPCODE:
+ return ALL_FIELD_TYPES.string;
+ default:
+ globalConsole.warn(`Unsupported analyzer type: ${aType}`);
+ return ALL_FIELD_TYPES.string;
+ }
+}
+
+/**
+ * Analyze field types from data in `string` format, e.g. uploaded csv.
+ * Assign `type`, `fieldIdx` and `format` (timestamp only) to each field
+ *
+ * @param data array of row object
+ * @param fieldOrder array of field names as string
+ * @returns formatted fields
+ * @public
+ * @example
+ *
+ * import {getFieldsFromData} from 'kepler.gl/common-utils';
+ * const data = [{
+ * time: '2016-09-17 00:09:55',
+ * value: '4',
+ * surge: '1.2',
+ * isTrip: 'true',
+ * zeroOnes: '0'
+ * }, {
+ * time: '2016-09-17 00:30:08',
+ * value: '3',
+ * surge: null,
+ * isTrip: 'false',
+ * zeroOnes: '1'
+ * }, {
+ * time: null,
+ * value: '2',
+ * surge: '1.3',
+ * isTrip: null,
+ * zeroOnes: '1'
+ * }];
+ *
+ * const fieldOrder = ['time', 'value', 'surge', 'isTrip', 'zeroOnes'];
+ * const fields = getFieldsFromData(data, fieldOrder);
+ * // fields = [
+ * // {name: 'time', format: 'YYYY-M-D H:m:s', fieldIdx: 1, type: 'timestamp'},
+ * // {name: 'value', format: '', fieldIdx: 4, type: 'integer'},
+ * // {name: 'surge', format: '', fieldIdx: 5, type: 'real'},
+ * // {name: 'isTrip', format: '', fieldIdx: 6, type: 'boolean'},
+ * // {name: 'zeroOnes', format: '', fieldIdx: 7, type: 'integer'}];
+ *
+ */
+export function getFieldsFromData(data: RowData, fieldOrder: string[]): Field[] {
+ // add a check for epoch timestamp
+ const metadata = Analyzer.computeColMeta(
+ data,
+ [
+ {regex: /.*geojson|all_points/g, dataType: 'GEOMETRY'},
+ {regex: /.*census/g, dataType: 'STRING'}
+ ],
+ {ignoredDataTypes: IGNORE_DATA_TYPES}
+ );
+
+ const {fieldByIndex} = renameDuplicateFields(fieldOrder);
+
+ const result = fieldOrder.map((field, index) => {
+ const name = fieldByIndex[index];
+
+ const fieldMeta = metadata.find(m => m.key === field);
+
+ // fieldMeta could be undefined if the field has no data and Analyzer.computeColMeta
+ // will ignore the field. In this case, we will simply assign the field type to STRING
+ // since dropping the column in the RowData could be expensive
+ let type = fieldMeta?.type || 'STRING';
+ const format = fieldMeta?.format || '';
+
+ // check if string is hex wkb
+ if (type === AnalyzerDATA_TYPES.STRING) {
+ type = data.some(d => isHexWkb(d[name])) ? AnalyzerDATA_TYPES.GEOMETRY : type;
+ }
+
+ return {
+ name,
+ id: name,
+ displayName: name,
+ format,
+ fieldIdx: index,
+ type: analyzerTypeToFieldType(type),
+ analyzerType: type,
+ valueAccessor: dc => d => {
+ return dc.valueAt(d.index, index);
+ }
+ };
+ });
+
+ return result;
+}
+
+/**
+ * pass in an array of field names, rename duplicated one
+ * and return a map from old field index to new name
+ *
+ * @param fieldOrder
+ * @returns new field name by index
+ */
+export function renameDuplicateFields(fieldOrder: string[]): {
+ allNames: string[];
+ fieldByIndex: string[];
+} {
+ return fieldOrder.reduce<{allNames: string[]; fieldByIndex: string[]}>(
+ (accu, field, i) => {
+ const {allNames} = accu;
+ let fieldName = field;
+
+ // add a counter to duplicated names
+ if (allNames.includes(field)) {
+ let counter = 0;
+ while (allNames.includes(`${field}-${counter}`)) {
+ counter++;
+ }
+ fieldName = `${field}-${counter}`;
+ }
+
+ accu.fieldByIndex[i] = fieldName;
+ accu.allNames.push(fieldName);
+
+ return accu;
+ },
+ {allNames: [], fieldByIndex: []}
+ );
+}
diff --git a/src/common-utils/src/data.ts b/src/common-utils/src/data.ts
new file mode 100644
index 0000000000..18bf7ba48a
--- /dev/null
+++ b/src/common-utils/src/data.ts
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT
+// Copyright contributors to the kepler.gl project
+
+export function notNullorUndefined>(d: T | null | undefined): d is T {
+ return d !== undefined && d !== null;
+}
+
+/**
+ * Check if string is a valid Well-known binary (WKB) in HEX format
+ * https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
+ *
+ * @param str input string
+ * @returns true if string is a valid WKB in HEX format
+ */
+export function isHexWkb(str: string | null): boolean {
+ if (!str) return false;
+ // check if the length of the string is even and is at least 10 characters long
+ if (str.length < 10 || str.length % 2 !== 0) {
+ return false;
+ }
+ // check if first two characters are 00 or 01
+ if (!str.startsWith('00') && !str.startsWith('01')) {
+ return false;
+ }
+ // check if the rest of the string is a valid hex
+ return /^[0-9a-fA-F]+$/.test(str.slice(2));
+}
+
+/**
+ * Converts non-arrays to arrays. Leaves arrays alone. Converts
+ * undefined values to empty arrays ([] instead of [undefined]).
+ * Otherwise, just returns [item] for non-array items.
+ *
+ * @param {*} item
+ * @returns {array} boom! much array. very indexed. so useful.
+ */
+export function toArray(item: T | T[]): T[] {
+ if (Array.isArray(item)) {
+ return item;
+ }
+
+ if (typeof item === 'undefined' || item === null) {
+ return [];
+ }
+
+ return [item];
+}
diff --git a/src/common-utils/src/index.ts b/src/common-utils/src/index.ts
new file mode 100644
index 0000000000..fd626ebbbd
--- /dev/null
+++ b/src/common-utils/src/index.ts
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: MIT
+// Copyright contributors to the kepler.gl project
+
+export * from './data';
+export * from './data-type';
+export * from './string';
diff --git a/src/common-utils/src/string.ts b/src/common-utils/src/string.ts
new file mode 100644
index 0000000000..3b6fc93559
--- /dev/null
+++ b/src/common-utils/src/string.ts
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: MIT
+// Copyright contributors to the kepler.gl project
+
+/**
+ * Generate a hash string based on number of character
+ * @param {number} count
+ * @returns {string} hash string
+ */
+export function generateHashId(count = 6): string {
+ return Math.random().toString(36).substr(count);
+}
diff --git a/src/common-utils/tsconfig.production.json b/src/common-utils/tsconfig.production.json
new file mode 100644
index 0000000000..f8ee4aa488
--- /dev/null
+++ b/src/common-utils/tsconfig.production.json
@@ -0,0 +1,28 @@
+{
+ "compilerOptions": {
+ "target": "es2020",
+ "allowJs": false,
+ "checkJs": false,
+ "jsx": "react",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "noImplicitAny": false,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "outDir": "dist",
+ "sourceMap": true,
+ "strictNullChecks": true,
+ "suppressImplicitAnyIndexErrors": false,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "baseUrl": "./src"
+ },
+ "include": ["src"]
+}
diff --git a/src/components/package.json b/src/components/package.json
index d49b469b4c..04c0158672 100644
--- a/src/components/package.json
+++ b/src/components/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/components",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -37,19 +37,20 @@
"@dnd-kit/sortable": "^7.0.2",
"@dnd-kit/utilities": "^3.2.1",
"@floating-ui/react": "0.25.1",
- "@kepler.gl/actions": "3.0.0",
- "@kepler.gl/cloud-providers": "3.0.0",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/effects": "3.0.0",
- "@kepler.gl/layers": "3.0.0",
- "@kepler.gl/localization": "3.0.0",
- "@kepler.gl/processors": "3.0.0",
- "@kepler.gl/reducers": "3.0.0",
- "@kepler.gl/schemas": "3.0.0",
- "@kepler.gl/styles": "3.0.0",
- "@kepler.gl/table": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/actions": "3.1.0-alpha.0",
+ "@kepler.gl/cloud-providers": "3.1.0-alpha.0",
+ "@kepler.gl/common-utils": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/effects": "3.1.0-alpha.0",
+ "@kepler.gl/layers": "3.1.0-alpha.0",
+ "@kepler.gl/localization": "3.1.0-alpha.0",
+ "@kepler.gl/processors": "3.1.0-alpha.0",
+ "@kepler.gl/reducers": "3.1.0-alpha.0",
+ "@kepler.gl/schemas": "3.1.0-alpha.0",
+ "@kepler.gl/styles": "3.1.0-alpha.0",
+ "@kepler.gl/table": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@mapbox/mapbox-sdk": "^0.15.3",
"@nebula.gl/edit-modes": "1.0.2-alpha.1",
"@tippyjs/react": "^4.2.0",
diff --git a/src/components/src/common/field-selector.tsx b/src/components/src/common/field-selector.tsx
index df058ca616..e317a51d73 100644
--- a/src/components/src/common/field-selector.tsx
+++ b/src/components/src/common/field-selector.tsx
@@ -7,7 +7,7 @@ import styled from 'styled-components';
import {createSelector} from 'reselect';
import {Field, TooltipField} from '@kepler.gl/types';
-import {notNullorUndefined, toArray} from '@kepler.gl/utils';
+import {notNullorUndefined, toArray} from '@kepler.gl/common-utils';
import ItemSelector from './item-selector/item-selector';
import {classList} from './item-selector/dropdown-list';
diff --git a/src/components/src/common/field-token.tsx b/src/components/src/common/field-token.tsx
index 49567f05e4..e66657eaf6 100644
--- a/src/components/src/common/field-token.tsx
+++ b/src/components/src/common/field-token.tsx
@@ -8,30 +8,27 @@ import {FIELD_TYPE_DISPLAY, FIELD_COLORS} from '@kepler.gl/constants';
export type FieldTokenProps = {
type: string;
};
+const FieldTag = styled.div`
+ background-color: rgba(${props => props.color}, 0.2);
+ border-radius: 2px;
+ border: 1px solid rgb(${props => props.color});
+ color: rgb(${props => props.color});
+ display: inline-block;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 0 5px;
+ text-align: center;
+ width: ${props => props.theme.fieldTokenWidth}px;
+ line-height: ${props => props.theme.fieldTokenHeight}px;
+`;
function FieldTokenFactory(
fieldTypeDisplay: ReturnType,
fieldColors: ReturnType
): React.FC {
- const FieldTag = styled.div`
- background-color: rgba(${props => props.color}, 0.2);
- border-radius: 2px;
- border: 1px solid rgb(${props => props.color});
- color: rgb(${props => props.color});
- display: inline-block;
- font-size: 10px;
- font-weight: 400;
- padding: 0 5px;
- text-align: center;
- width: ${props => props.theme.fieldTokenWidth}px;
- line-height: ${props => props.theme.fieldTokenHeight}px;
- `;
-
const FieldToken = ({type}: FieldTokenProps) => (
-
- {fieldTypeDisplay[type].label}
+
+ {fieldTypeDisplay[type]?.label}
);
return FieldToken;
diff --git a/src/components/src/common/item-selector/dropdown-select.tsx b/src/components/src/common/item-selector/dropdown-select.tsx
index 9b61abdb71..c537830a70 100644
--- a/src/components/src/common/item-selector/dropdown-select.tsx
+++ b/src/components/src/common/item-selector/dropdown-select.tsx
@@ -1,14 +1,14 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
-import React from 'react';
+import React, {ComponentType} from 'react';
import styled from 'styled-components';
-import {notNullorUndefined} from '@kepler.gl/utils';
-import {ComponentType} from 'react';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
+import {FormattedMessage} from '@kepler.gl/localization';
+
import {ArrowDown, Delete} from '../icons';
import {ListItem} from './dropdown-list';
-import {FormattedMessage} from '@kepler.gl/localization';
export type ListItemProps = {
value: Option;
@@ -100,7 +100,6 @@ function DropdownSelect ({
displayOption,
disabled,
onClick,
- error,
inputTheme,
size,
value,
diff --git a/src/components/src/common/item-selector/item-selector.tsx b/src/components/src/common/item-selector/item-selector.tsx
index e95856be32..99cfe058b4 100644
--- a/src/components/src/common/item-selector/item-selector.tsx
+++ b/src/components/src/common/item-selector/item-selector.tsx
@@ -11,7 +11,8 @@ import ChickletedInput from './chickleted-input';
import Typeahead from './typeahead';
import DropdownList, {ListItem} from './dropdown-list';
import Portaled from '../../common/portaled';
-import {toArray, observeDimensions, unobserveDimensions} from '@kepler.gl/utils';
+import {observeDimensions, unobserveDimensions} from '@kepler.gl/utils';
+import {toArray} from '@kepler.gl/common-utils';
import {injectIntl, IntlShape} from 'react-intl';
import {ListItemProps} from './dropdown-select';
import DropdownSelect from './dropdown-select';
diff --git a/src/components/src/common/map-layer-selector.tsx b/src/components/src/common/map-layer-selector.tsx
index e92a6d9b46..6473ff0b96 100644
--- a/src/components/src/common/map-layer-selector.tsx
+++ b/src/components/src/common/map-layer-selector.tsx
@@ -4,7 +4,7 @@
import React from 'react';
import styled from 'styled-components';
import Checkbox from './checkbox';
-import {generateHashId} from '@kepler.gl/utils';
+import {generateHashId} from '@kepler.gl/common-utils';
const MapLayerSelect = styled.div`
padding: 12px;
diff --git a/src/components/src/container.tsx b/src/components/src/container.tsx
index b5bcba03c3..f93af11465 100644
--- a/src/components/src/container.tsx
+++ b/src/components/src/container.tsx
@@ -1,16 +1,15 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
-import React, {Component, ComponentType, Dispatch} from 'react';
-import {connect, ConnectedProps} from 'react-redux';
-import memoize from 'lodash.memoize';
+import React, {useRef, ComponentType, Dispatch, useEffect, useMemo} from 'react';
+import {connect, ConnectedProps, useDispatch} from 'react-redux';
+
import {console as Console} from 'global/window';
import {injector, provideRecipesToInjector, flattenDeps} from './injector';
import KeplerGlFactory from './kepler-gl';
-
import {registerEntry, deleteEntry, renameEntry, forwardTo} from '@kepler.gl/actions';
-import {notNullorUndefined} from '@kepler.gl/utils';
import {KeplerGlState} from '@kepler.gl/reducers';
+import {getApplicationConfig} from '@kepler.gl/utils';
export const ERROR_MSG = {
noState:
@@ -69,26 +68,32 @@ export function ContainerFactory(
* @public
*/
- class Container extends Component {
- // default id and address if not provided
- static defaultProps = {
- id: 'map',
- getState: state => state.keplerGl,
- mint: true
- };
-
- componentDidMount() {
- const {
- id,
- mint,
- mapboxApiAccessToken,
- mapboxApiUrl,
- mapStylesReplaceDefault,
- initialUiState
- } = this.props;
+ function usePreviousId(value) {
+ const ref = useRef();
+ useEffect(() => {
+ ref.current = value;
+ });
+ return ref.current;
+ }
+ const Container: React.FC = props => {
+ const {
+ // default id and address if not provided
+ id = 'map',
+ getState = state => state.keplerGl,
+ mint = true,
+ mapboxApiAccessToken,
+ mapboxApiUrl,
+ mapStylesReplaceDefault,
+ initialUiState,
+ state
+ } = props;
+ const prevId = usePreviousId(id);
+ const dispatch = useDispatch();
+
+ useEffect(() => {
// add a new entry to reducer
- this.props.dispatch(
+ dispatch(
registerEntry({
id,
mint,
@@ -98,56 +103,53 @@ export function ContainerFactory(
initialUiState
})
);
- }
- componentDidUpdate(prevProps) {
- // check if id has changed, if true, copy state over
- if (
- notNullorUndefined(prevProps.id) &&
- notNullorUndefined(this.props.id) &&
- prevProps.id !== this.props.id
- ) {
- this.props.dispatch(renameEntry(prevProps.id, this.props.id));
+ // initialize plugins
+ if (getApplicationConfig().plugins.length) {
+ getApplicationConfig().plugins.forEach(async plugin => {
+ await plugin.init();
+ });
}
- }
-
- componentWillUnmount() {
- if (this.props.mint !== false) {
- // delete entry in reducer
- this.props.dispatch(deleteEntry(this.props.id));
- }
- }
- getSelector = memoize((id, getState) => state => {
- if (!getState(state)) {
- // log error
- Console.error(ERROR_MSG.noState);
+ // cleanup
+ return () => {
+ if (mint !== false) {
+ // delete entry in reducer
+ dispatch(deleteEntry(id));
+ }
+ };
+ }, [id]);
- return null;
- }
- return getState(state)[id];
- });
- getDispatch = memoize((id, dispatch) => forwardTo(id, dispatch));
-
- render() {
- const {id, getState, dispatch, state} = this.props;
- const selector = this.getSelector(id, getState);
-
- if (!selector || !selector(state)) {
- // instance state hasn't been mounted yet
- return
;
+ useEffect(() => {
+ // check if id has changed, if true, copy state over
+ if (prevId && id && prevId !== id) {
+ dispatch(renameEntry(prevId, id));
}
-
- return (
-
- );
+ }, [dispatch, prevId, id]);
+
+ const stateSelector = useMemo(
+ () => keplerState => {
+ if (!getState(keplerState)) {
+ // log error
+ Console.error(ERROR_MSG.noState);
+
+ return null;
+ }
+ return getState(keplerState)[id];
+ },
+ [id, getState]
+ );
+ const forwardDispatch = useMemo(() => forwardTo(id, dispatch), [id, dispatch]);
+
+ // const selector = getSelector(id, getState);
+
+ if (!stateSelector || !stateSelector(state)) {
+ // instance state hasn't been mounted yet
+ return
;
}
- }
+
+ return ;
+ };
return connector(Container);
}
diff --git a/src/components/src/index.ts b/src/components/src/index.ts
index 3c347295f4..2245370a61 100644
--- a/src/components/src/index.ts
+++ b/src/components/src/index.ts
@@ -27,6 +27,7 @@ import {
default as LayerColumnModeConfigFactory,
ColumnModeConfigFactory
} from './side-panel/layer-panel/layer-column-mode-config';
+import DataTableFactory from './common/data-table';
// Components
export {
@@ -250,8 +251,8 @@ export {
LegendRowFactory,
ResetColorLabelFactory
} from './common/color-legend';
-export {default as DataTableFactory} from './common/data-table';
export {default as CanvasHack} from './common/data-table/canvas';
+export {renderedSize} from './common/data-table/cell-size';
export {
default as DataTableConfigFactory,
NumberFormatConfig
@@ -428,6 +429,7 @@ export {
ChannelByValueSelectorFactory,
ColorSelectorFactory,
ColumnModeConfigFactory,
+ DataTableFactory,
FieldListItemFactoryFactory,
InfoHelperFactory,
LayerColorRangeSelectorFactory,
@@ -462,6 +464,7 @@ export const ColorSelector = appInjector.get(ColorSelectorFactory);
export const LayerColorSelector = appInjector.get(LayerColorSelectorFactory);
export const LayerColorRangeSelector = appInjector.get(LayerColorRangeSelectorFactory);
export const ArcLayerColorSelector = appInjector.get(ArcLayerColorSelectorFactory);
+export const DataTable = appInjector.get(DataTableFactory);
// hooks
export {CloudListProvider, useCloudListProvider} from './hooks/use-cloud-list-provider';
diff --git a/src/components/src/kepler-gl.tsx b/src/components/src/kepler-gl.tsx
index e4f97b5474..4e729f98f9 100644
--- a/src/components/src/kepler-gl.tsx
+++ b/src/components/src/kepler-gl.tsx
@@ -20,6 +20,8 @@ import {
VisStateActions
} from '@kepler.gl/actions';
+import {generateHashId} from '@kepler.gl/common-utils';
+
type KeplerGlActions = {
visStateActions: typeof VisStateActions;
mapStateActions: typeof MapStateActions;
@@ -52,7 +54,6 @@ import {CloudListProvider} from './hooks/use-cloud-list-provider';
import {
filterObjectByPredicate,
- generateHashId,
validateToken,
mergeMessages,
observeDimensions,
diff --git a/src/components/src/layer-animation-controller.tsx b/src/components/src/layer-animation-controller.tsx
index 57c37def01..5a3ad5ddba 100644
--- a/src/components/src/layer-animation-controller.tsx
+++ b/src/components/src/layer-animation-controller.tsx
@@ -4,7 +4,8 @@
import React, {useCallback} from 'react';
import {ANIMATION_WINDOW} from '@kepler.gl/constants';
import {AnimationConfig, Timeline} from '@kepler.gl/types';
-import {snapToMarks, getTimelineFromAnimationConfig, toArray} from '@kepler.gl/utils';
+import {snapToMarks, getTimelineFromAnimationConfig} from '@kepler.gl/utils';
+import {toArray} from '@kepler.gl/common-utils';
import AnimationControllerFactory from './common/animation-control/animation-controller';
interface LayerAnimationControllerProps {
diff --git a/src/components/src/map-container.tsx b/src/components/src/map-container.tsx
index c7011d65fc..82e452cec4 100644
--- a/src/components/src/map-container.tsx
+++ b/src/components/src/map-container.tsx
@@ -4,7 +4,7 @@
// libraries
import React, {Component, createRef, useMemo} from 'react';
import styled, {withTheme} from 'styled-components';
-import {Map, MapboxMap, MapRef} from 'react-map-gl';
+import {Map, MapRef} from 'react-map-gl';
import {PickInfo} from '@deck.gl/core/lib/deck';
import DeckGL from '@deck.gl/react';
import {createSelector, Selector} from 'reselect';
@@ -364,7 +364,7 @@ export default function MapContainerFactory(
}
_deck: any = null;
- _map: MapboxMap | null = null;
+ _map: GetMapRef | null = null;
_ref = createRef();
_deckGLErrorsElapsed: {[id: string]: number} = {};
diff --git a/src/components/src/map/layer-hover-info.tsx b/src/components/src/map/layer-hover-info.tsx
index bedd23bc15..6b15a6a92f 100644
--- a/src/components/src/map/layer-hover-info.tsx
+++ b/src/components/src/map/layer-hover-info.tsx
@@ -7,7 +7,7 @@ import {TooltipField} from '@kepler.gl/types';
import {CenterFlexbox} from '../common/styled-components';
import {Layers} from '../common/icons';
import PropTypes from 'prop-types';
-import {notNullorUndefined} from '@kepler.gl/utils';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import {Layer} from '@kepler.gl/layers';
import {
AggregationLayerHoverData,
diff --git a/src/components/src/map/map-popover.tsx b/src/components/src/map/map-popover.tsx
index a698a6872e..420b4f1458 100644
--- a/src/components/src/map/map-popover.tsx
+++ b/src/components/src/map/map-popover.tsx
@@ -9,7 +9,8 @@ import {injectIntl, IntlShape} from 'react-intl';
import {FormattedMessage} from '@kepler.gl/localization';
import {RootContext} from '../context';
import {parseGeoJsonRawFeature} from '@kepler.gl/layers';
-import {idToPolygonGeo, generateHashId} from '@kepler.gl/utils';
+import {idToPolygonGeo} from '@kepler.gl/utils';
+import {generateHashId} from '@kepler.gl/common-utils';
import {LAYER_TYPES} from '@kepler.gl/constants';
import {LayerHoverProp} from '@kepler.gl/reducers';
import {Feature, FeatureSelectionContext} from '@kepler.gl/types';
diff --git a/src/components/src/side-panel/layer-panel/layer-column-config.tsx b/src/components/src/side-panel/layer-panel/layer-column-config.tsx
index 156097ce53..c992f53641 100644
--- a/src/components/src/side-panel/layer-panel/layer-column-config.tsx
+++ b/src/components/src/side-panel/layer-panel/layer-column-config.tsx
@@ -11,7 +11,7 @@ import {
ColumnLabels,
EnhancedFieldPair
} from '@kepler.gl/types';
-import {toArray} from '@kepler.gl/utils';
+import {toArray} from '@kepler.gl/common-utils';
import ColumnSelectorFactory from './column-selector';
import {MinimalField} from '../../common/field-selector';
diff --git a/src/constants/package.json b/src/constants/package.json
index 2dbe3b4b15..f9d3f9311a 100644
--- a/src/constants/package.json
+++ b/src/constants/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/constants",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,7 +30,7 @@
"umd"
],
"dependencies": {
- "@kepler.gl/types": "3.0.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
"@types/d3-scale": "^3.2.2",
"@types/keymirror": "^0.1.1",
"colorbrewer": "^1.5.0",
diff --git a/src/deckgl-arrow-layers/package.json b/src/deckgl-arrow-layers/package.json
index dd58464440..4d98cabbd8 100644
--- a/src/deckgl-arrow-layers/package.json
+++ b/src/deckgl-arrow-layers/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/deckgl-arrow-layers",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "Deck.gl layers with GeoArrow and GeoParquet support",
"license": "MIT",
"main": "dist/index.js",
diff --git a/src/deckgl-layers/package.json b/src/deckgl-layers/package.json
index 268ebc190d..7735bca55b 100644
--- a/src/deckgl-layers/package.json
+++ b/src/deckgl-layers/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/deckgl-layers",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -35,9 +35,9 @@
"@deck.gl/core": "^8.9.27",
"@deck.gl/geo-layers": "^8.9.27",
"@deck.gl/layers": "^8.9.27",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@luma.gl/constants": "^8.5.20",
"@luma.gl/core": "^8.5.20",
"@mapbox/geo-viewport": "^0.4.1",
diff --git a/src/effects/package.json b/src/effects/package.json
index 337a3bba96..000bca5cd8 100644
--- a/src/effects/package.json
+++ b/src/effects/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/effects",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl viaual effects",
"license": "MIT",
"main": "dist/index.js",
@@ -31,9 +31,9 @@
],
"dependencies": {
"@deck.gl/core": "^8.9.27",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@luma.gl/core": "^8.5.20",
"@luma.gl/shadertools": "^8.5.20",
"suncalc": "^1.9.0"
diff --git a/src/effects/src/effect.ts b/src/effects/src/effect.ts
index dc35a57b2f..3958b92e17 100644
--- a/src/effects/src/effect.ts
+++ b/src/effects/src/effect.ts
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
-import {generateHashId, validateEffectParameters} from '@kepler.gl/utils';
+import {validateEffectParameters} from '@kepler.gl/utils';
+import {generateHashId} from '@kepler.gl/common-utils';
import {
Effect as EffectInterface,
EffectProps,
diff --git a/src/layers/package.json b/src/layers/package.json
index 9d521b99d3..85b06054c2 100644
--- a/src/layers/package.json
+++ b/src/layers/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/layers",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -36,13 +36,14 @@
"@deck.gl/geo-layers": "^8.9.27",
"@deck.gl/layers": "^8.9.27",
"@deck.gl/mesh-layers": "^8.9.27",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/deckgl-arrow-layers": "3.0.0",
- "@kepler.gl/deckgl-layers": "3.0.0",
- "@kepler.gl/localization": "3.0.0",
- "@kepler.gl/table": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/common-utils": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/deckgl-arrow-layers": "3.1.0-alpha.0",
+ "@kepler.gl/deckgl-layers": "3.1.0-alpha.0",
+ "@kepler.gl/localization": "3.1.0-alpha.0",
+ "@kepler.gl/table": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@loaders.gl/arrow": "^4.3.2",
"@loaders.gl/core": "^4.3.2",
"@loaders.gl/gis": "^4.3.2",
diff --git a/src/layers/src/base-layer.ts b/src/layers/src/base-layer.ts
index 35bd3fdf7c..91439d4e24 100644
--- a/src/layers/src/base-layer.ts
+++ b/src/layers/src/base-layer.ts
@@ -37,18 +37,15 @@ import {
import {
DataContainerInterface,
- generateHashId,
getColorGroupByName,
getLatLngBounds,
getSampleContainerData,
hasColorMap,
hexToRgb,
isPlainObject,
- toArray,
- notNullorUndefined,
reverseColorRange
} from '@kepler.gl/utils';
-
+import {generateHashId, toArray, notNullorUndefined} from '@kepler.gl/common-utils';
import {Datasets, GpuFilter, KeplerTable} from '@kepler.gl/table';
import {
ColorUI,
diff --git a/src/layers/src/editor-layer/editor-layer.ts b/src/layers/src/editor-layer/editor-layer.ts
index d9279c3ee9..bd8c109f58 100644
--- a/src/layers/src/editor-layer/editor-layer.ts
+++ b/src/layers/src/editor-layer/editor-layer.ts
@@ -13,7 +13,7 @@ import {PathStyleExtension} from '@deck.gl/extensions';
import {EDITOR_LAYER_ID, EDITOR_MODES, EDITOR_LAYER_PICKING_RADIUS} from '@kepler.gl/constants';
import {Viewport, Editor, Feature, FeatureSelectionContext} from '@kepler.gl/types';
-import {generateHashId} from '@kepler.gl/utils';
+import {generateHashId} from '@kepler.gl/common-utils';
import {EDIT_TYPES} from './constants';
import {LINE_STYLE, FEATURE_STYLE, EDIT_HANDLE_STYLE} from './feature-styles';
diff --git a/src/layers/src/geojson-layer/geojson-layer.ts b/src/layers/src/geojson-layer/geojson-layer.ts
index b38ee500f2..c7e6bbbb17 100644
--- a/src/layers/src/geojson-layer/geojson-layer.ts
+++ b/src/layers/src/geojson-layer/geojson-layer.ts
@@ -49,7 +49,7 @@ import {
VisConfigBoolean,
Merge,
RGBColor,
- Field,
+ ProtoDatasetField,
LayerColumn
} from '@kepler.gl/types';
import {KeplerTable} from '@kepler.gl/table';
@@ -206,7 +206,7 @@ const getTableModeFieldValue = (field, data) => {
const geoFieldAccessor =
({geojson}: GeoJsonLayerColumnsConfig) =>
- (dc: DataContainerInterface): Field | null =>
+ (dc: DataContainerInterface): ProtoDatasetField | null =>
dc.getField ? dc.getField(geojson.fieldIdx) : null;
// access feature properties from geojson sub layer
@@ -377,6 +377,7 @@ export default class GeoJsonLayer extends Layer {
.filter(
f =>
(f.type === 'geojson' || f.type === 'geoarrow') &&
+ f.analyzerType &&
SUPPORTED_ANALYZER_TYPES[f.analyzerType]
)
.map(f => f.name);
@@ -403,7 +404,7 @@ export default class GeoJsonLayer extends Layer {
const defaultLayerConfig = super.getDefaultLayerConfig(props ?? {});
return {
...defaultLayerConfig,
-
+
columnMode: props?.columnMode ?? DEFAULT_COLUMN_MODE,
// add height visual channel
heightField: null,
diff --git a/src/layers/src/layer-text-label.ts b/src/layers/src/layer-text-label.ts
index 35760e88ea..d90607734a 100644
--- a/src/layers/src/layer-text-label.ts
+++ b/src/layers/src/layer-text-label.ts
@@ -3,7 +3,8 @@
import * as arrow from 'apache-arrow';
import {getDistanceScales} from 'viewport-mercator-project';
-import {notNullorUndefined, DataContainerInterface, ArrowDataContainer} from '@kepler.gl/utils';
+import {DataContainerInterface, ArrowDataContainer} from '@kepler.gl/utils';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import uniq from 'lodash.uniq';
export const defaultPadding = 20;
diff --git a/src/layers/src/layer-utils.ts b/src/layers/src/layer-utils.ts
index a962904f7c..2f3dbe71be 100644
--- a/src/layers/src/layer-utils.ts
+++ b/src/layers/src/layer-utils.ts
@@ -5,7 +5,13 @@ import * as arrow from 'apache-arrow';
import {Feature, BBox} from 'geojson';
import {getGeoMetadata} from '@loaders.gl/gis';
-import {Field, FieldPair, SupportedColumnMode, LayerColumn} from '@kepler.gl/types';
+import {
+ Field,
+ ProtoDatasetField,
+ FieldPair,
+ SupportedColumnMode,
+ LayerColumn
+} from '@kepler.gl/types';
import {DataContainerInterface, ArrowDataContainer} from '@kepler.gl/utils';
import {
getBinaryGeometriesFromArrow,
@@ -150,7 +156,7 @@ export function getGeojsonLayerMetaFromArrow({
}: {
dataContainer: DataContainerInterface;
geoColumn: arrow.Vector;
- geoField: Field;
+ geoField: ProtoDatasetField;
chunkIndex?: number;
}): GeojsonLayerMetaProps {
const encoding = geoField?.metadata?.get('ARROW:extension:name');
diff --git a/src/layers/src/trip-layer/trip-utils.ts b/src/layers/src/trip-layer/trip-utils.ts
index 201eaedbce..d76432baa4 100644
--- a/src/layers/src/trip-layer/trip-utils.ts
+++ b/src/layers/src/trip-layer/trip-utils.ts
@@ -6,12 +6,8 @@ import {Analyzer, DATA_TYPES} from 'type-analyzer';
import {Field} from '@kepler.gl/types';
import {parseGeoJsonRawFeature, getGeojsonFeatureTypes} from '../geojson-layer/geojson-utils';
-import {
- DataContainerInterface,
- getSampleContainerData,
- notNullorUndefined,
- timeToUnixMilli
-} from '@kepler.gl/utils';
+import {DataContainerInterface, getSampleContainerData, timeToUnixMilli} from '@kepler.gl/utils';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import {Feature} from '@turf/helpers';
import {GeoJsonProperties, Geometry} from 'geojson';
diff --git a/src/localization/package.json b/src/localization/package.json
index cfa860ad2e..ba77d83628 100644
--- a/src/localization/package.json
+++ b/src/localization/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/localization",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
diff --git a/src/processors/package.json b/src/processors/package.json
index 742e3d4f0e..ab5b7a1cb4 100644
--- a/src/processors/package.json
+++ b/src/processors/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/processors",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -31,10 +31,12 @@
],
"dependencies": {
"@danmarshall/deckgl-typings": "4.9.22",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/schemas": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/common-utils": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/schemas": "3.1.0-alpha.0",
+ "@kepler.gl/table": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@loaders.gl/arrow": "^4.3.2",
"@loaders.gl/core": "^4.3.2",
"@loaders.gl/csv": "^4.3.2",
diff --git a/src/processors/src/data-processor.ts b/src/processors/src/data-processor.ts
index 80e5fbee8f..6e5e34971a 100644
--- a/src/processors/src/data-processor.ts
+++ b/src/processors/src/data-processor.ts
@@ -11,14 +11,15 @@ import {ProcessorResult, Field} from '@kepler.gl/types';
import {
arrowDataTypeToAnalyzerDataType,
arrowDataTypeToFieldType,
- notNullorUndefined,
hasOwnProperty,
- isPlainObject,
- analyzerTypeToFieldType,
+ isPlainObject
+} from '@kepler.gl/utils';
+import {notNullorUndefined, toArray} from '@kepler.gl/common-utils';
+import {
getSampleForTypeAnalyze,
getFieldsFromData,
- toArray
-} from '@kepler.gl/utils';
+ analyzerTypeToFieldType
+} from '@kepler.gl/common-utils';
import {KeplerGlSchema, ParsedDataset, SavedMap, LoadedMap} from '@kepler.gl/schemas';
import {Feature} from '@nebula.gl/edit-modes';
@@ -247,7 +248,7 @@ export function processRowObject(rawData: unknown[]): ProcessorResult {
const keys = Object.keys(rawData[0]); // [lat, lng, value]
const rows = rawData.map(d => keys.map(key => d[key])); // [[31.27, 127.56, 3]]
- // row object an still contain values like `Null` or `N/A`
+ // row object can still contain values like `Null` or `N/A`
cleanUpFalsyCsvValue(rows);
return processCsvData(rows, keys);
@@ -387,38 +388,39 @@ export function processArrowTable(arrowTable: ArrowTable): ProcessorResult | nul
return processArrowBatches(arrowTable.data.batches);
}
-/**
- * Parse arrow batches returned from parseInBatches()
- *
- * @param arrowTable the arrow table to parse
- * @returns dataset containing `fields` and `rows` or null
- */
-export function processArrowBatches(arrowBatches: arrow.RecordBatch[]): ProcessorResult | null {
- if (arrowBatches.length === 0) {
- return null;
- }
- const arrowTable = new arrow.Table(arrowBatches);
- const fields: Field[] = [];
-
- // parse fields
- arrowTable.schema.fields.forEach((field: arrow.Field, index: number) => {
- const isGeometryColumn = field.metadata.get('ARROW:extension:name')?.startsWith('geoarrow');
- fields.push({
+export function arrowSchemaToFields(schema: arrow.Schema): Field[] {
+ return schema.fields.map((field: arrow.Field, index: number) => {
+ const isGeoArrowColumn = field.metadata.get('ARROW:extension:name')?.startsWith('geoarrow');
+ return {
+ ...field,
name: field.name,
id: field.name,
displayName: field.name,
format: '',
fieldIdx: index,
- type: isGeometryColumn ? ALL_FIELD_TYPES.geoarrow : arrowDataTypeToFieldType(field.type),
- analyzerType: isGeometryColumn
+ type: isGeoArrowColumn ? ALL_FIELD_TYPES.geoarrow : arrowDataTypeToFieldType(field.type),
+ analyzerType: isGeoArrowColumn
? AnalyzerDATA_TYPES.GEOMETRY
: arrowDataTypeToAnalyzerDataType(field.type),
valueAccessor: (dc: any) => d => {
return dc.valueAt(d.index, index);
},
metadata: field.metadata
- });
+ };
});
+}
+/**
+ * Parse arrow batches returned from parseInBatches()
+ *
+ * @param arrowTable the arrow table to parse
+ * @returns dataset containing `fields` and `rows` or null
+ */
+export function processArrowBatches(arrowBatches: arrow.RecordBatch[]): ProcessorResult | null {
+ if (arrowBatches.length === 0) {
+ return null;
+ }
+ const arrowTable = new arrow.Table(arrowBatches);
+ const fields = arrowSchemaToFields(arrowTable.schema);
const cols = [...Array(arrowTable.numCols).keys()].map(i => arrowTable.getChildAt(i));
diff --git a/src/processors/src/file-handler.ts b/src/processors/src/file-handler.ts
index ac3a75cf8a..d137f4b309 100644
--- a/src/processors/src/file-handler.ts
+++ b/src/processors/src/file-handler.ts
@@ -8,10 +8,16 @@ import {CSVLoader} from '@loaders.gl/csv';
import {GeoArrowLoader} from '@loaders.gl/arrow';
import {ParquetWasmLoader} from '@loaders.gl/parquet';
import {Loader} from '@loaders.gl/loader-utils';
-import {generateHashId, isPlainObject, generateHashIdFromString} from '@kepler.gl/utils';
+import {
+ isPlainObject,
+ generateHashIdFromString,
+ getApplicationConfig,
+ getError
+} from '@kepler.gl/utils';
+import {generateHashId} from '@kepler.gl/common-utils';
import {DATASET_FORMATS} from '@kepler.gl/constants';
-import {LoadedMap, ProcessorResult} from '@kepler.gl/types';
-import {Feature, AddDataToMapPayload} from '@kepler.gl/types';
+import {AddDataToMapPayload, Feature, LoadedMap, ProcessorResult} from '@kepler.gl/types';
+import {KeplerTable} from '@kepler.gl/table';
import {FeatureCollection} from '@turf/helpers';
import {
@@ -200,21 +206,29 @@ export async function readFileInBatches({
return readBatch(progressIterator, file.name);
}
-export function processFileData({
+export async function processFileData({
content,
fileCache
}: {
content: ProcessFileDataContent;
fileCache: FileCacheItem[];
}): Promise {
- return new Promise((resolve, reject) => {
- const {fileName, data} = content;
- let format: string | undefined;
- let processor: ((data: any) => ProcessorResult | LoadedMap | null) | undefined;
-
- // generate unique id with length of 4 using fileName string
- const id = generateHashIdFromString(fileName);
-
+ const {fileName, data} = content;
+ let format: string | undefined;
+ let processor: ((data: any) => ProcessorResult | LoadedMap | null) | undefined;
+ console.log('Processing file', fileName);
+ // generate unique id with length of 4 using fileName string
+ const id = generateHashIdFromString(fileName);
+ // decide on which table class to use based on application config
+ const table = getApplicationConfig().table ?? KeplerTable;
+
+ if (typeof table.getFileProcessor === 'function') {
+ // use custom processors from table class
+ const processorResult = table.getFileProcessor(data);
+ format = processorResult.format;
+ processor = processorResult.processor;
+ } else {
+ // use default processors
if (isArrowData(data)) {
format = DATASET_FORMATS.arrow;
processor = processArrowBatches;
@@ -222,31 +236,37 @@ export function processFileData({
format = DATASET_FORMATS.keplergl;
processor = processKeplerglJSON;
} else if (isRowObject(data)) {
+ // csv file goes here
format = DATASET_FORMATS.row;
processor = processRowObject;
} else if (isGeoJson(data)) {
format = DATASET_FORMATS.geojson;
processor = processGeojson;
}
-
- if (format && processor) {
- const result = processor(data);
-
- resolve([
- ...fileCache,
- {
- data: result,
- info: {
- id,
- label: content.fileName,
- format
- }
- }
- ]);
+ }
+ if (format && processor) {
+ // eslint-disable-next-line no-useless-catch
+ let result;
+ try {
+ result = await processor(data);
+ } catch (error) {
+ throw new Error(`Can not process uploaded file, ${getError(error as Error)}`);
}
- reject('Unknown File Format');
- });
+ return [
+ ...fileCache,
+ {
+ data: result,
+ info: {
+ id,
+ label: content.fileName,
+ format
+ }
+ }
+ ];
+ } else {
+ throw new Error('Can not process uploaded file, unknown file format');
+ }
}
export function filesToDataPayload(fileCache: FileCacheItem[]): AddDataToMapPayload[] {
diff --git a/src/reducers/package.json b/src/reducers/package.json
index 4bdc4c66af..fc5050b8a2 100644
--- a/src/reducers/package.json
+++ b/src/reducers/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/reducers",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,20 +30,21 @@
"umd"
],
"dependencies": {
- "@kepler.gl/actions": "3.0.0",
- "@kepler.gl/cloud-providers": "3.0.0",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/deckgl-arrow-layers": "3.0.0",
- "@kepler.gl/deckgl-layers": "3.0.0",
- "@kepler.gl/effects": "3.0.0",
- "@kepler.gl/layers": "3.0.0",
- "@kepler.gl/localization": "3.0.0",
- "@kepler.gl/processors": "3.0.0",
- "@kepler.gl/schemas": "3.0.0",
- "@kepler.gl/table": "3.0.0",
- "@kepler.gl/tasks": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/actions": "3.1.0-alpha.0",
+ "@kepler.gl/cloud-providers": "3.1.0-alpha.0",
+ "@kepler.gl/common-utils": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/deckgl-arrow-layers": "3.1.0-alpha.0",
+ "@kepler.gl/deckgl-layers": "3.1.0-alpha.0",
+ "@kepler.gl/effects": "3.1.0-alpha.0",
+ "@kepler.gl/layers": "3.1.0-alpha.0",
+ "@kepler.gl/localization": "3.1.0-alpha.0",
+ "@kepler.gl/processors": "3.1.0-alpha.0",
+ "@kepler.gl/schemas": "3.1.0-alpha.0",
+ "@kepler.gl/table": "3.1.0-alpha.0",
+ "@kepler.gl/tasks": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@loaders.gl/loader-utils": "^4.3.2",
"@turf/bbox": "^6.0.1",
"@types/lodash.clonedeep": "^4.5.7",
diff --git a/src/reducers/src/combined-updaters.ts b/src/reducers/src/combined-updaters.ts
index 7ce54f1498..0be3b1d0d7 100644
--- a/src/reducers/src/combined-updaters.ts
+++ b/src/reducers/src/combined-updaters.ts
@@ -143,7 +143,7 @@ export const addDataToMapUpdater = (
...payload.options
};
- // check if progresive loading dataset by bataches, and update visState directly
+ // check if progressive loading dataset by batches, and update visState directly
const isProgressiveLoading =
Array.isArray(datasets) &&
datasets[0]?.info.format === 'arrow' &&
@@ -189,6 +189,8 @@ export const addDataToMapUpdater = (
),
if_(Boolean(info), pick_('visState')(apply_(setMapInfoUpdater, {info}))),
+ // Note that fit bounds here won't be called in case datasets are created in Tasks.
+ // A separate Task to update bounds is created once the datasets are ready.
with_(({visState}) =>
pick_('mapState')(
apply_(
diff --git a/src/reducers/src/interaction-utils.ts b/src/reducers/src/interaction-utils.ts
index d390842998..4c304bd2ad 100644
--- a/src/reducers/src/interaction-utils.ts
+++ b/src/reducers/src/interaction-utils.ts
@@ -11,14 +11,8 @@ import {
} from '@kepler.gl/constants';
import {Field, TooltipField, CompareType} from '@kepler.gl/types';
-import {
- DataRow,
- parseFieldValue,
- getFormatter,
- isNumber,
- defaultFormatter,
- notNullorUndefined
-} from '@kepler.gl/utils';
+import {DataRow, parseFieldValue, getFormatter, isNumber, defaultFormatter} from '@kepler.gl/utils';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
/**
* Minus sign used in tooltip formatting.
diff --git a/src/reducers/src/map-style-updaters.ts b/src/reducers/src/map-style-updaters.ts
index 3850e3e097..0f488a3a9e 100644
--- a/src/reducers/src/map-style-updaters.ts
+++ b/src/reducers/src/map-style-updaters.ts
@@ -13,11 +13,11 @@ import {
editTopMapStyle,
editBottomMapStyle,
getStyleImageIcon,
- generateHashId,
isPlainObject,
hexToRgb,
colorMaybeToRGB
} from '@kepler.gl/utils';
+import {generateHashId} from '@kepler.gl/common-utils';
import {
DEFAULT_MAP_STYLES,
DEFAULT_LAYER_GROUPS,
diff --git a/src/reducers/src/merger-handler.ts b/src/reducers/src/merger-handler.ts
index 848242518c..8d46c187cb 100644
--- a/src/reducers/src/merger-handler.ts
+++ b/src/reducers/src/merger-handler.ts
@@ -2,7 +2,8 @@
// Copyright contributors to the kepler.gl project
import {getGlobalTaskQueue} from 'react-palm/tasks';
-import {isObject, toArray} from '@kepler.gl/utils';
+import {isObject} from '@kepler.gl/utils';
+import {toArray} from '@kepler.gl/common-utils';
import {ValueOf} from '@kepler.gl/types';
import {VisState, Merger, PostMergerPayload} from '@kepler.gl/schemas';
@@ -67,7 +68,7 @@ export function mergeStateFromMergers(
// check if asyncTask was created (time consuming tasks)
if (newTasks.length && merger.waitToFinish) {
- // skip rest, the async merger will call applyMergerupdater() to continue
+ // skip rest, the async merger will call applyMergerUpdater() to continue
return {mergedState, allMerged: false};
}
}
diff --git a/src/reducers/src/provider-state-updaters.ts b/src/reducers/src/provider-state-updaters.ts
index a48e5257a7..19a3c6a667 100644
--- a/src/reducers/src/provider-state-updaters.ts
+++ b/src/reducers/src/provider-state-updaters.ts
@@ -3,7 +3,8 @@
import {withTask} from 'react-palm/tasks';
import Console from 'global/console';
-import {generateHashId, getError, isPlainObject, toArray} from '@kepler.gl/utils';
+import {getError, isPlainObject} from '@kepler.gl/utils';
+import {generateHashId, toArray} from '@kepler.gl/common-utils';
import {
EXPORT_FILE_TO_CLOUD_TASK,
ACTION_TASK,
diff --git a/src/reducers/src/vis-state-updaters.ts b/src/reducers/src/vis-state-updaters.ts
index 9793f66f31..6298109a61 100644
--- a/src/reducers/src/vis-state-updaters.ts
+++ b/src/reducers/src/vis-state-updaters.ts
@@ -11,16 +11,24 @@ import isEqual from 'lodash.isequal';
import pick from 'lodash.pick';
import uniq from 'lodash.uniq';
import xor from 'lodash.xor';
-import {disableStackCapturing, withTask} from 'react-palm/tasks';
+import Task, {disableStackCapturing, withTask} from 'react-palm/tasks';
// Tasks
-import {DELAY_TASK, LOAD_FILE_TASK, PROCESS_FILE_DATA, UNWRAP_TASK} from '@kepler.gl/tasks';
+import {
+ DELAY_TASK,
+ ACTION_TASK,
+ LOAD_FILE_TASK,
+ PROCESS_FILE_DATA,
+ UNWRAP_TASK
+} from '@kepler.gl/tasks';
// Actions
import {
ActionTypes,
+ CreateNewDatasetSuccessPayload,
MapStateActions,
ReceiveMapConfigPayload,
VisStateActions,
applyLayerConfig,
+ createNewDatasetSuccess,
layerConfigChange,
layerTypeChange,
layerVisConfigChange,
@@ -30,7 +38,8 @@ import {
loadFilesSuccess,
loadNextFile,
nextFileBatch,
- processFileContent
+ processFileContent,
+ fitBounds as fitMapBounds
} from '@kepler.gl/actions';
// Utils
@@ -45,7 +54,6 @@ import {
adjustValueToFilterDomain,
featureToFilterValue,
filterDatasetCPU,
- generateHashId,
generatePolygonFilter,
getDefaultFilter,
getFilterIdInFeature,
@@ -57,13 +65,12 @@ import {
parseFieldValue,
removeLayerFromSplitMaps,
set,
- toArray,
mergeFilterDomainStep,
updateFilterPlot,
removeFilterPlot,
isLayerAnimatable
} from '@kepler.gl/utils';
-
+import {generateHashId, toArray} from '@kepler.gl/common-utils';
// Mergers
import {
ANIMATION_WINDOW,
@@ -137,6 +144,9 @@ import {
TIME_INTERVALS_ORDERED
} from '@kepler.gl/utils';
import {createEffect} from '@kepler.gl/effects';
+import {PayloadAction} from '@reduxjs/toolkit';
+
+import {findMapBounds} from './data-utils';
// react-palm
// disable capture exception for react-palm call to withTask
@@ -2123,7 +2133,7 @@ export const updateVisDataUpdater = (
const {config, options} = action;
// apply config if passed from action
- // TODO: we don't handle asyn mergers here yet
+ // TODO: we don't handle async mergers here yet
const previousState = config
? receiveMapConfigUpdater(state, {
payload: {config, options}
@@ -2132,19 +2142,37 @@ export const updateVisDataUpdater = (
const datasets = toArray(action.datasets);
- const newDataEntries = datasets.reduce(
- // @ts-expect-error Type '{}' is missing the following properties from type 'ProtoDataset': data, info
- (accu, {info = {}, ...rest} = {}) => ({
- ...accu,
- ...(createNewDataEntry({info, ...rest}, state.datasets) || {})
- }),
- {}
+ const allCreateDatasetsTasks = datasets.map(
+ ({info = {}, ...rest}) => createNewDataEntry({info, ...rest}, state.datasets) || {}
);
+ // call all Tasks
+ const tasks = Task.allSettled(allCreateDatasetsTasks).map(results =>
+ createNewDatasetSuccess({results, addToMapOptions: options})
+ );
+
+ return withTask(previousState, tasks);
+};
+export const createNewDatasetSuccessUpdater = (
+ state: VisState,
+ action: PayloadAction
+): VisState => {
+ // console.log('createNewDatasetSuccessUpdater', action.payload);
+ const {results, addToMapOptions} = action.payload;
+ const newDataEntries = results.reduce((accu, result) => {
+ if (result.status === 'fulfilled') {
+ const dataset = result.value;
+ return {...accu, [dataset.id]: dataset};
+ } else {
+ // handle create dataset error
+ console.error(result.reason);
+ return accu;
+ }
+ }, {} as Datasets);
// save new dataset entry to state
const mergedState = {
- ...previousState,
- datasets: mergeDatasetsByOrder(previousState, newDataEntries)
+ ...state,
+ datasets: mergeDatasetsByOrder(state, newDataEntries)
};
// merge state with config to be merged
@@ -2154,7 +2182,7 @@ export const updateVisDataUpdater = (
const newDataIds = Object.keys(newDataEntries);
const postMergerPayload = {
newDataIds,
- options,
+ options: addToMapOptions,
layerMergers
};
@@ -2259,12 +2287,26 @@ function postMergeUpdater(mergedState: VisState, postMergerPayload: PostMergerPa
updatedState = updateAnimationDomain(updatedState);
// try to process layerMergers after dataset+datasetMergers
- return layerMergers && layerMergers.length > 0
- ? applyMergersUpdater(updatedState, {
- mergers: layerMergers,
- postMergerPayload: {...postMergerPayload, layerMergers: []}
- })
- : updatedState;
+ updatedState =
+ layerMergers && layerMergers.length > 0
+ ? applyMergersUpdater(updatedState, {
+ mergers: layerMergers,
+ postMergerPayload: {...postMergerPayload, layerMergers: []}
+ })
+ : updatedState;
+
+ // center the map once the dataset is created
+ if (newLayers.length && (options || {}).centerMap) {
+ const bounds = findMapBounds(newLayers);
+ if (bounds) {
+ const fitBoundsTask = ACTION_TASK().map(() => {
+ return fitMapBounds(bounds);
+ });
+ updatedState = withTask(updatedState, fitBoundsTask);
+ }
+ }
+
+ return updatedState;
}
/**
diff --git a/src/reducers/src/vis-state.ts b/src/reducers/src/vis-state.ts
index e0e31dfd8a..f6de096dd1 100644
--- a/src/reducers/src/vis-state.ts
+++ b/src/reducers/src/vis-state.ts
@@ -153,7 +153,9 @@ const actionHandler = {
[ActionTypes.REMOVE_EFFECT]: visStateUpdaters.removeEffectUpdater,
- [ActionTypes.UPDATE_EFFECT]: visStateUpdaters.updateEffectUpdater
+ [ActionTypes.UPDATE_EFFECT]: visStateUpdaters.updateEffectUpdater,
+
+ [ActionTypes.CREATE_NEW_DATASET_SUCCESS]: visStateUpdaters.createNewDatasetSuccessUpdater
};
// construct vis-state reducer
diff --git a/src/schemas/package.json b/src/schemas/package.json
index fa091f17da..a2244cc4c8 100644
--- a/src/schemas/package.json
+++ b/src/schemas/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/schemas",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl schemas used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,12 +30,13 @@
"umd"
],
"dependencies": {
- "@kepler.gl/ai-assistant": "3.0.0",
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/layers": "3.0.0",
- "@kepler.gl/table": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/ai-assistant": "3.1.0-alpha.0",
+ "@kepler.gl/common-utils": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/layers": "3.1.0-alpha.0",
+ "@kepler.gl/table": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@loaders.gl/loader-utils": "^4.3.2",
"@types/keymirror": "^0.1.1",
"@types/lodash.clonedeep": "^4.5.7",
diff --git a/src/schemas/src/dataset-schema.ts b/src/schemas/src/dataset-schema.ts
index b1725b5e82..ecd0446e60 100644
--- a/src/schemas/src/dataset-schema.ts
+++ b/src/schemas/src/dataset-schema.ts
@@ -8,7 +8,7 @@ import {ProtoDataset, RGBColor} from '@kepler.gl/types';
import {KeplerTable} from '@kepler.gl/table';
import {VERSIONS} from './versions';
import Schema from './schema';
-import {getFieldsFromData, getSampleForTypeAnalyze} from '@kepler.gl/utils';
+import {getFieldsFromData, getSampleForTypeAnalyze} from '@kepler.gl/common-utils';
export type SavedField = {
name: string;
diff --git a/src/schemas/src/vis-state-schema.ts b/src/schemas/src/vis-state-schema.ts
index 302459a396..e2e36c4c08 100644
--- a/src/schemas/src/vis-state-schema.ts
+++ b/src/schemas/src/vis-state-schema.ts
@@ -4,7 +4,8 @@
import pick from 'lodash.pick';
import {VERSIONS} from './versions';
import {LAYER_VIS_CONFIGS, FILTER_VIEW_TYPES} from '@kepler.gl/constants';
-import {isFilterValidToSave, notNullorUndefined, findById} from '@kepler.gl/utils';
+import {isFilterValidToSave, findById} from '@kepler.gl/utils';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import Schema from './schema';
import cloneDeep from 'lodash.clonedeep';
import {
diff --git a/src/styles/package.json b/src/styles/package.json
index 8422086c65..a4ffdd8454 100644
--- a/src/styles/package.json
+++ b/src/styles/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/styles",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,7 +30,7 @@
"umd"
],
"dependencies": {
- "@kepler.gl/constants": "3.0.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
"@types/styled-components": "^5.1.25",
"styled-components": "^4.1.3"
},
diff --git a/src/table/package.json b/src/table/package.json
index 2885c09c2f..ebfdd60f39 100644
--- a/src/table/package.json
+++ b/src/table/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/table",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,16 +30,18 @@
"umd"
],
"dependencies": {
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/layers": "3.0.0",
- "@kepler.gl/types": "3.0.0",
- "@kepler.gl/utils": "3.0.0",
+ "@kepler.gl/common-utils": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/layers": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
+ "@kepler.gl/utils": "3.1.0-alpha.0",
"@types/d3-array": "^2.8.0",
"@types/lodash.uniq": "^4.5.7",
"d3-array": "^2.8.0",
"global": "^4.3.0",
"lodash.uniq": "^4.0.1",
- "moment": "^2.10.6"
+ "moment": "^2.10.6",
+ "react-palm": "^3.3.8"
},
"nyc": {
"sourceMap": false,
diff --git a/src/table/src/dataset-utils.ts b/src/table/src/dataset-utils.ts
index 62f845a57e..6108eb3812 100644
--- a/src/table/src/dataset-utils.ts
+++ b/src/table/src/dataset-utils.ts
@@ -4,8 +4,14 @@
import uniq from 'lodash.uniq';
import KeplerTable, {Datasets} from './kepler-table';
import {ProtoDataset, RGBColor} from '@kepler.gl/types';
+import Task from 'react-palm/tasks';
-import {hexToRgb, validateInputData, datasetColorMaker} from '@kepler.gl/utils';
+import {
+ hexToRgb,
+ validateInputData,
+ datasetColorMaker,
+ getApplicationConfig
+} from '@kepler.gl/utils';
// apply a color for each dataset
// to use as label colors
@@ -56,17 +62,31 @@ export function createNewDataEntry(
// get keplerTable from datasets
const keplerTable = datasets[info.id];
// update the data in keplerTable
- keplerTable.update(validatedData);
- return {
- [keplerTable.id]: keplerTable
- };
+ return UPDATE_TABLE_TASK({table: keplerTable, data: validatedData});
}
info = info || {};
const color = info.color || getNewDatasetColor(datasets);
- const keplerTable = new KeplerTable({info, data: validatedData, color, ...opts});
- return {
- [keplerTable.id]: keplerTable
- };
+ return CREATE_TABLE_TASK({
+ info,
+ color,
+ opts,
+ data: validatedData
+ });
}
+
+async function updateTable({table, data}) {
+ const updated = await table.update(data); // Assuming `table` has an `update` method
+ return updated;
+}
+
+async function createTable({info, color, opts, data}) {
+ const TableClass = getApplicationConfig().table ?? KeplerTable;
+ const table = new TableClass({info, color, ...opts});
+ await table.importData({data});
+
+ return table;
+}
+const UPDATE_TABLE_TASK = Task.fromPromise(updateTable, 'UPDATE_TABLE_TASK');
+const CREATE_TABLE_TASK = Task.fromPromise(createTable, 'CREATE_TABLE_TASK');
diff --git a/src/table/src/gpu-filter-utils.ts b/src/table/src/gpu-filter-utils.ts
index 8e4c0e2b0b..15d58bec55 100644
--- a/src/table/src/gpu-filter-utils.ts
+++ b/src/table/src/gpu-filter-utils.ts
@@ -4,8 +4,9 @@
import moment from 'moment';
import {MAX_GPU_FILTERS, FILTER_TYPES} from '@kepler.gl/constants';
import {Field, Filter} from '@kepler.gl/types';
+import {set, DataContainerInterface} from '@kepler.gl/utils';
+import {toArray, notNullorUndefined} from '@kepler.gl/common-utils';
-import {set, toArray, notNullorUndefined, DataContainerInterface} from '@kepler.gl/utils';
import {GpuFilter} from './kepler-table';
/**
diff --git a/src/table/src/kepler-table.ts b/src/table/src/kepler-table.ts
index 2cc19fea21..425000b9eb 100644
--- a/src/table/src/kepler-table.ts
+++ b/src/table/src/kepler-table.ts
@@ -30,7 +30,6 @@ import {getGpuFilterProps, getDatasetFieldIndexForFilter} from './gpu-filter-uti
import {Layer} from '@kepler.gl/layers';
import {
- generateHashId,
getSortingFunction,
timeToUnixMilli,
createDataContainer,
@@ -48,9 +47,9 @@ import {
getOrdinalDomain,
getQuantileDomain,
DataContainerInterface,
- notNullorUndefined,
FilterChanged
} from '@kepler.gl/utils';
+import {generateHashId, notNullorUndefined} from '@kepler.gl/common-utils';
export type GpuFilter = {
filterRange: number[][];
@@ -112,7 +111,7 @@ export function maybeToDate(
return dc.valueAt(d.index, fieldIdx);
}
-class KeplerTable {
+class KeplerTable {
readonly id: string;
type?: string;
@@ -120,15 +119,15 @@ class KeplerTable {
color: RGBColor;
// fields and data
- fields: Field[];
+ fields: F[] = [];
dataContainer: DataContainerInterface;
- allIndexes: number[];
- filteredIndex: number[];
+ allIndexes: number[] = [];
+ filteredIndex: number[] = [];
filteredIdxCPU?: number[];
- filteredIndexForDomain: number[];
- fieldPairs: FieldPair[];
+ filteredIndexForDomain: number[] = [];
+ fieldPairs: FieldPair[] = [];
gpuFilter: GpuFilter;
filterRecord?: FilterRecord;
filterRecordCPU?: FilterRecord;
@@ -150,14 +149,12 @@ class KeplerTable {
constructor({
info,
- data,
color,
metadata,
supportedFilterTypes = null,
disableDataOperation = false
}: {
info?: ProtoDataset['info'];
- data: ProtoDataset['data'];
color: RGBColor;
metadata?: ProtoDataset['metadata'];
supportedFilterTypes?: ProtoDataset['supportedFilterTypes'];
@@ -169,32 +166,13 @@ class KeplerTable {
// return this;
// }
- const dataContainerData = data.cols ? data.cols : data.rows;
- const inputDataFormat = data.cols ? DataForm.COLS_ARRAY : DataForm.ROWS_ARRAY;
-
- const dataContainer = createDataContainer(dataContainerData, {
- // @ts-expect-error ProtoDataset field missing property fieldIdx, valueAccessor
- fields: data.fields,
- inputDataFormat
- });
-
const datasetInfo = {
id: generateHashId(4),
label: 'new dataset',
type: '',
...info
};
- const dataId = datasetInfo.id;
- // @ts-expect-error
- const fields: Field[] = data.fields.map((f, i) => ({
- ...f,
- fieldIdx: i,
- id: f.name,
- displayName: f.displayName || f.name,
- valueAccessor: getFieldValueAccessor(f, i, dataContainer)
- }));
- const allIndexes = dataContainer.getPlainIndex();
const defaultMetadata = {
id: datasetInfo.id,
// @ts-ignore
@@ -211,15 +189,41 @@ class KeplerTable {
...metadata
};
+ this.supportedFilterTypes = supportedFilterTypes;
+ this.disableDataOperation = disableDataOperation;
+
+ this.dataContainer = createDataContainer([]);
+ this.gpuFilter = getGpuFilterProps([], this.id, [], undefined);
+ }
+
+ importData({data}: {data: ProtoDataset['data']}) {
+ const dataContainerData = data.cols ? data.cols : data.rows;
+ const inputDataFormat = data.cols ? DataForm.COLS_ARRAY : DataForm.ROWS_ARRAY;
+
+ const dataContainer = createDataContainer(dataContainerData, {
+ fields: data.fields,
+ inputDataFormat
+ });
+
+ const fields: Field[] = data.fields.map((f, i) => ({
+ ...f,
+ fieldIdx: i,
+ id: f.name,
+ displayName: f.displayName || f.name,
+ analyzerType: f.analyzerType || ALL_FIELD_TYPES.string,
+ format: f.format || '',
+ valueAccessor: getFieldValueAccessor(f, i, dataContainer)
+ }));
+
+ const allIndexes = dataContainer.getPlainIndex();
this.dataContainer = dataContainer;
this.allIndexes = allIndexes;
this.filteredIndex = allIndexes;
this.filteredIndexForDomain = allIndexes;
this.fieldPairs = findPointFieldPairs(fields);
+ // @ts-expect-error Make sure that fields satisfies F extends Field
this.fields = fields;
- this.gpuFilter = getGpuFilterProps([], dataId, fields, undefined);
- this.supportedFilterTypes = supportedFilterTypes;
- this.disableDataOperation = disableDataOperation;
+ this.gpuFilter = getGpuFilterProps([], this.id, fields, undefined);
}
/**
@@ -242,7 +246,7 @@ class KeplerTable {
* Get field
* @param columnName
*/
- getColumnField(columnName: string): Field | undefined {
+ getColumnField(columnName: string): F | undefined {
const field = this.fields.find(fd => fd[FID_KEY] === columnName);
this._assetField(columnName, field);
return field;
@@ -281,7 +285,7 @@ class KeplerTable {
* @param fieldIdx
* @param newField
*/
- updateColumnField(fieldIdx: number, newField: Field): void {
+ updateColumnField(fieldIdx: number, newField: F): void {
this.fields = Object.assign([...this.fields], {[fieldIdx]: newField});
}
@@ -297,7 +301,7 @@ class KeplerTable {
* Save filterProps to field and retrieve it
* @param columnName
*/
- getColumnFilterProps(columnName: string): Field['filterProps'] | null | undefined {
+ getColumnFilterProps(columnName: string): F['filterProps'] | null | undefined {
const fieldIdx = this.getColumnFieldIdx(columnName);
if (fieldIdx < 0) {
return null;
@@ -329,7 +333,7 @@ class KeplerTable {
* @param layers
* @param opt
*/
- filterTable(filters: Filter[], layers: Layer[], opt?: FilterDatasetOpt): KeplerTable {
+ filterTable(filters: Filter[], layers: Layer[], opt?: FilterDatasetOpt): KeplerTable {
const {dataContainer, id: dataId, filterRecord: oldFilterRecord, fields} = this;
// if there is no filters
@@ -385,7 +389,7 @@ class KeplerTable {
* @param filters
* @param layers
*/
- filterTableCPU(filters: Filter[], layers: Layer[]): KeplerTable {
+ filterTableCPU(filters: Filter[], layers: Layer[]): KeplerTable {
const opt = {
cpuOnly: true,
ignoreDomain: true
@@ -423,7 +427,7 @@ class KeplerTable {
* Calculate field domain based on field type and data
* for Filter
*/
- getColumnFilterDomain(field: Field): FieldDomain {
+ getColumnFilterDomain(field: F): FieldDomain {
const {dataContainer} = this;
const {valueAccessor} = field;
@@ -454,10 +458,7 @@ class KeplerTable {
/**
* Get the domain of this column based on scale type
*/
- getColumnLayerDomain(
- field: Field,
- scaleType: string
- ): number[] | string[] | [number, number] | null {
+ getColumnLayerDomain(field: F, scaleType: string): number[] | string[] | [number, number] | null {
const {dataContainer, filteredIndexForDomain} = this;
if (!SCALE_TYPES[scaleType]) {
@@ -516,7 +517,7 @@ class KeplerTable {
}
export type Datasets = {
- [key: string]: KeplerTable;
+ [key: string]: KeplerTable;
};
// HELPER FUNCTIONS (MAINLY EXPORTED FOR TEST...)
@@ -601,10 +602,10 @@ export function findPointFieldPairs(fields: Field[]): FieldPair[] {
* @type
*/
export function sortDatasetByColumn(
- dataset: KeplerTable,
+ dataset: KeplerTable,
column: string,
mode?: string
-): KeplerTable {
+): KeplerTable {
const {allIndexes, fields, dataContainer} = dataset;
const fieldIndex = fields.findIndex(f => f.name === column);
if (fieldIndex < 0) {
@@ -640,7 +641,7 @@ export function sortDatasetByColumn(
return dataset;
}
-export function pinTableColumns(dataset: KeplerTable, column: string): KeplerTable {
+export function pinTableColumns(dataset: KeplerTable, column: string): KeplerTable {
const field = dataset.getColumnField(column);
if (!field) {
return dataset;
@@ -658,7 +659,7 @@ export function pinTableColumns(dataset: KeplerTable, column: string): KeplerTab
return copyTableAndUpdate(dataset, {pinnedColumns});
}
-export function copyTable(original: KeplerTable): KeplerTable {
+export function copyTable(original: KeplerTable): KeplerTable {
return Object.assign(Object.create(Object.getPrototypeOf(original)), original);
}
@@ -667,9 +668,9 @@ export function copyTable(original: KeplerTable): KeplerTable {
* @returns
*/
export function copyTableAndUpdate(
- original: KeplerTable,
- options: Partial = {}
-): KeplerTable {
+ original: KeplerTable,
+ options: Partial> = {}
+): KeplerTable {
return Object.entries(options).reduce((acc, entry) => {
acc[entry[0]] = entry[1];
return acc;
diff --git a/src/tasks/package.json b/src/tasks/package.json
index cf72cb8cd2..5ed5b3e0d8 100644
--- a/src/tasks/package.json
+++ b/src/tasks/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/tasks",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,7 +30,7 @@
"umd"
],
"dependencies": {
- "@kepler.gl/processors": "3.0.0",
+ "@kepler.gl/processors": "3.1.0-alpha.0",
"react-palm": "^3.3.8"
},
"nyc": {
diff --git a/src/types/actions.d.ts b/src/types/actions.d.ts
index add827c2aa..5d734dfd4b 100644
--- a/src/types/actions.d.ts
+++ b/src/types/actions.d.ts
@@ -31,6 +31,15 @@ export type ExportFileToCloudPayload = {
/**
* Input dataset parsed to addDataToMap
*/
+export type ProtoDatasetField = {
+ name: string;
+ type: string;
+ format?: string;
+ displayName?: string;
+ analyzerType?: string;
+ id?: string;
+ metadata?: Record;
+};
export type ProtoDataset = {
info: {
id?: string;
@@ -41,14 +50,7 @@ export type ProtoDataset = {
hidden?: boolean;
};
data: {
- fields: {
- name: string;
- type?: string;
- format?: string;
- displayName?: string;
- analyzerType?: string;
- id?: string;
- }[];
+ fields: ProtoDatasetField[];
rows: any[][];
cols?: any[];
};
diff --git a/src/types/layers.d.ts b/src/types/layers.d.ts
index 266bf33578..15da495ce8 100644
--- a/src/types/layers.d.ts
+++ b/src/types/layers.d.ts
@@ -98,16 +98,16 @@ export type LayerWeightConfig = {
};
export type Field = {
- analyzerType: string;
- id?: string;
name: string;
displayName: string;
- format: string;
type: string;
fieldIdx: number;
valueAccessor(v: {index: number}): any;
+ analyzerType?: string;
+ id?: string;
+ format: string;
filterProps?: FilterProps;
- metadata?: any;
+ metadata?: Record;
displayFormat?: string;
};
diff --git a/src/types/package.json b/src/types/package.json
index 8df15a4504..8d905306cf 100644
--- a/src/types/package.json
+++ b/src/types/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/types",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl types used by kepler.gl components, actions and reducers",
"license": "MIT",
"types": "index.d.ts",
diff --git a/src/utils/package.json b/src/utils/package.json
index 50259d0462..0c50feac0c 100644
--- a/src/utils/package.json
+++ b/src/utils/package.json
@@ -1,7 +1,7 @@
{
"name": "@kepler.gl/utils",
"author": "Shan He ",
- "version": "3.0.0",
+ "version": "3.1.0-alpha.0",
"description": "kepler.gl constants used by kepler.gl components, actions and reducers",
"license": "MIT",
"main": "dist/index.js",
@@ -30,8 +30,9 @@
"umd"
],
"dependencies": {
- "@kepler.gl/constants": "3.0.0",
- "@kepler.gl/types": "3.0.0",
+ "@kepler.gl/common-utils": "3.1.0-alpha.0",
+ "@kepler.gl/constants": "3.1.0-alpha.0",
+ "@kepler.gl/types": "3.1.0-alpha.0",
"@luma.gl/constants": "^8.5.20",
"@luma.gl/core": "^8.5.20",
"@mapbox/geo-viewport": "^0.4.1",
diff --git a/src/utils/src/application-config.ts b/src/utils/src/application-config.ts
index 359152a510..f4640af573 100644
--- a/src/utils/src/application-config.ts
+++ b/src/utils/src/application-config.ts
@@ -23,6 +23,10 @@ export type KeplerApplicationConfig = {
mapLibCssClass?: string;
mapLibName?: string;
mapLibUrl?: string;
+ plugins?: any[];
+ // KeplerTable alternative
+ // TODO improve typing by exporting KeplerTable interface to @kepler.gl/types
+ table?: any;
};
const DEFAULT_APPLICATION_CONFIG: Required> = {
@@ -37,7 +41,11 @@ const DEFAULT_APPLICATION_CONFIG: Required
getMap: (mapRef: MapRef): mapboxgl.Map => mapRef?.getMap(),
mapLibCssClass: 'maplibregl',
mapLibName: 'MapLibre',
- mapLibUrl: 'https://www.maplibre.org/'
+ mapLibUrl: 'https://www.maplibre.org/',
+ plugins: [],
+ // The default table class is KeplerTable.
+ // TODO include KeplerTable here when the circular dependency with @kepler.gl/table and @kepler.gl/utils are resolved.
+ table: null
};
const applicationConfig: Required> =
diff --git a/src/utils/src/arrow-data-container.ts b/src/utils/src/arrow-data-container.ts
index cabefa4691..d31034748e 100644
--- a/src/utils/src/arrow-data-container.ts
+++ b/src/utils/src/arrow-data-container.ts
@@ -4,7 +4,7 @@
import * as arrow from 'apache-arrow';
import {console as globalConsole} from 'global/window';
import {DATA_TYPES as AnalyzerDATA_TYPES} from 'type-analyzer';
-import {Field} from '@kepler.gl/types';
+import {ProtoDatasetField} from '@kepler.gl/types';
import {ALL_FIELD_TYPES} from '@kepler.gl/constants';
import {DataRow, SharedRowOptions} from './data-row';
@@ -12,7 +12,7 @@ import {DataContainerInterface, RangeOptions} from './data-container-interface';
type ArrowDataContainerInput = {
cols: arrow.Vector[];
- fields?: Field[];
+ fields?: ProtoDatasetField[];
};
/**
@@ -44,7 +44,7 @@ export class ArrowDataContainer implements DataContainerInterface {
_cols: arrow.Vector[];
_numColumns: number;
_numRows: number;
- _fields: Field[];
+ _fields: ProtoDatasetField[];
_numChunks: number;
// cache column data to make valueAt() faster
// _colData: any[][];
@@ -144,7 +144,7 @@ export class ArrowDataContainer implements DataContainerInterface {
return this._cols[columnIndex];
}
- getField(columnIndex: number): Field {
+ getField(columnIndex: number): ProtoDatasetField {
return this._fields[columnIndex];
}
diff --git a/src/utils/src/data-container-interface.ts b/src/utils/src/data-container-interface.ts
index 350a2f2e4f..37e669d1de 100644
--- a/src/utils/src/data-container-interface.ts
+++ b/src/utils/src/data-container-interface.ts
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
-import {Field} from '@kepler.gl/types';
+import {ProtoDatasetField} from '@kepler.gl/types';
import {DataRow, SharedRowOptions} from './data-row';
/**
@@ -82,7 +82,7 @@ export interface DataContainerInterface {
* @param columnIndex Column index.
* @returns The field object at the specified index.
*/
- getField?(columnIndex: number): Field;
+ getField?(columnIndex: number): ProtoDatasetField;
/**
* Returns the underlying data object.
diff --git a/src/utils/src/data-container-utils.ts b/src/utils/src/data-container-utils.ts
index 05a5fccea0..46f01af1b0 100644
--- a/src/utils/src/data-container-utils.ts
+++ b/src/utils/src/data-container-utils.ts
@@ -6,11 +6,11 @@ import {RowDataContainer} from './row-data-container';
import {IndexedDataContainer} from './indexed-data-container';
import {DataContainerInterface} from './data-container-interface';
-import {Field} from '@kepler.gl/types';
+import {ProtoDatasetField} from '@kepler.gl/types';
export type DataContainerOptions = {
inputDataFormat?: string; // one of DataForm
- fields?: Field[];
+ fields?: ProtoDatasetField[];
};
export const DataForm = {
diff --git a/src/utils/src/data-scale-utils.ts b/src/utils/src/data-scale-utils.ts
index eb4ef80ad7..78dfb0a668 100644
--- a/src/utils/src/data-scale-utils.ts
+++ b/src/utils/src/data-scale-utils.ts
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import {ALL_FIELD_TYPES, ColorMap, ColorRange, SCALE_FUNC, SCALE_TYPES} from '@kepler.gl/constants';
import {Layer, VisualChannel, VisualChannelDomain} from '@kepler.gl/layers';
import {HexColor, MapState} from '@kepler.gl/types';
@@ -8,7 +9,7 @@ import {bisectLeft, quantileSorted as d3Quantile, extent} from 'd3-array';
import moment from 'moment';
import {isRgbColor, rgbToHex} from './color-utils';
import {DataContainerInterface} from './data-container-interface';
-import {formatNumber, notNullorUndefined, reverseFormatNumber, unique} from './data-utils';
+import {formatNumber, reverseFormatNumber, unique} from './data-utils';
import {getTimeWidgetHintFormatter} from './filter-utils';
import {isPlainObject} from './utils';
diff --git a/src/utils/src/data-utils.ts b/src/utils/src/data-utils.ts
index c5fb67e4f5..f34364233f 100644
--- a/src/utils/src/data-utils.ts
+++ b/src/utils/src/data-utils.ts
@@ -12,6 +12,7 @@ import {
TOOLTIP_KEY,
TooltipFormat
} from '@kepler.gl/constants';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import {Field, Millisecond} from '@kepler.gl/types';
import {snapToMarks} from './plot';
@@ -86,13 +87,6 @@ export function timeToUnixMilli(value: string | number | Date, format: string):
return null;
}
-/**
- * whether null or undefined
- */
-export function notNullorUndefined>(d: T | null | undefined): d is T {
- return d !== undefined && d !== null;
-}
-
/**
* Whether d is a number, this filtered out NaN as well
*/
@@ -452,7 +446,3 @@ export function datetimeFormatter(
: // return empty string instead of 'Invalid date' if ts is undefined/null
format => ts => ts ? moment.utc(ts).format(format) : '';
}
-
-export function notNullOrUndefined(d: any): boolean {
- return d !== undefined && d !== null;
-}
diff --git a/src/utils/src/dataset-utils.ts b/src/utils/src/dataset-utils.ts
index 620e284548..ba7417defd 100644
--- a/src/utils/src/dataset-utils.ts
+++ b/src/utils/src/dataset-utils.ts
@@ -1,20 +1,19 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
-import {console as globalConsole} from 'global/window';
import {
ALL_FIELD_TYPES,
FIELD_OPTS,
TOOLTIP_FORMATS,
TOOLTIP_FORMAT_TYPES
} from '@kepler.gl/constants';
-import {Analyzer, DATA_TYPES as AnalyzerDATA_TYPES} from 'type-analyzer';
+import {getSampleForTypeAnalyze, getFieldsFromData} from '@kepler.gl/common-utils';
+import {Analyzer} from 'type-analyzer';
import assert from 'assert';
import {
ProcessorResult,
RGBColor,
- RowData,
Field,
FieldPair,
TimeLabelFormat,
@@ -22,11 +21,11 @@ import {
ProtoDataset
} from '@kepler.gl/types';
import {TooltipFormat} from '@kepler.gl/constants';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import {isPlainObject} from './utils';
-import {notNullorUndefined, getFormatter} from './data-utils';
+import {getFormatter} from './data-utils';
import {getFormatValue} from './format';
-import {range} from 'd3-array';
import {hexToRgb} from './color-utils';
// apply a color for each dataset
@@ -226,27 +225,6 @@ export function findDefaultColorField({
return null;
}
-export const ACCEPTED_ANALYZER_TYPES = [
- AnalyzerDATA_TYPES.DATE,
- AnalyzerDATA_TYPES.TIME,
- AnalyzerDATA_TYPES.DATETIME,
- AnalyzerDATA_TYPES.NUMBER,
- AnalyzerDATA_TYPES.INT,
- AnalyzerDATA_TYPES.FLOAT,
- AnalyzerDATA_TYPES.BOOLEAN,
- AnalyzerDATA_TYPES.STRING,
- AnalyzerDATA_TYPES.GEOMETRY,
- AnalyzerDATA_TYPES.GEOMETRY_FROM_STRING,
- AnalyzerDATA_TYPES.PAIR_GEOMETRY_FROM_STRING,
- AnalyzerDATA_TYPES.ZIPCODE,
- AnalyzerDATA_TYPES.ARRAY,
- AnalyzerDATA_TYPES.OBJECT
-];
-
-const IGNORE_DATA_TYPES = Object.keys(AnalyzerDATA_TYPES).filter(
- type => !ACCEPTED_ANALYZER_TYPES.includes(type)
-);
-
/**
* Validate input data, adding missing field types, rename duplicate columns
*/
@@ -268,7 +246,7 @@ export function validateInputData(data: ProtoDataset['data']): ProcessorResult {
const allValid = fields.every((f, i) => {
if (!isPlainObject(f)) {
assert(`fields needs to be an array of object, but find ${typeof f}`);
- fields[i] = {name: `column_${i}`};
+ fields[i] = {name: `column_${i}`, type: ALL_FIELD_TYPES.string};
}
if (!f.name) {
@@ -330,246 +308,6 @@ function findNonEmptyRowsAtField(rows: unknown[][], fieldIdx: number, total: num
}
return sample;
}
-/**
- * Getting sample data for analyzing field type.
- */
-export function getSampleForTypeAnalyze({
- fields,
- rows,
- sampleCount = 50
-}: {
- fields: string[];
- rows: unknown[][];
- sampleCount?: number;
-}): RowData {
- const total = Math.min(sampleCount, rows.length);
- // const fieldOrder = fields.map(f => f.name);
- const sample = range(0, total, 1).map(() => ({}));
-
- // collect sample data for each field
- fields.forEach((field, fieldIdx) => {
- // data counter
- let i = 0;
- // sample counter
- let j = 0;
-
- while (j < total) {
- if (i >= rows.length) {
- // if depleted data pool
- sample[j][field] = null;
- j++;
- } else if (notNullorUndefined(rows[i][fieldIdx])) {
- const value = rows[i][fieldIdx];
- sample[j][field] = typeof value === 'string' ? value.trim() : value;
- j++;
- i++;
- } else {
- i++;
- }
- }
- });
-
- return sample;
-}
-
-/**
- * Check if string is a valid Well-known binary (WKB) in HEX format
- * https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
- *
- * @param str input string
- * @returns true if string is a valid WKB in HEX format
- */
-export function isHexWkb(str: string | null): boolean {
- if (!str) return false;
- // check if the length of the string is even and is at least 10 characters long
- if (str.length < 10 || str.length % 2 !== 0) {
- return false;
- }
- // check if first two characters are 00 or 01
- if (!str.startsWith('00') && !str.startsWith('01')) {
- return false;
- }
- // check if the rest of the string is a valid hex
- return /^[0-9a-fA-F]+$/.test(str.slice(2));
-}
-
-/**
- * Analyze field types from data in `string` format, e.g. uploaded csv.
- * Assign `type`, `fieldIdx` and `format` (timestamp only) to each field
- *
- * @param data array of row object
- * @param fieldOrder array of field names as string
- * @returns formatted fields
- * @public
- * @example
- *
- * import {getFieldsFromData} from 'kepler.gl/processors';
- * const data = [{
- * time: '2016-09-17 00:09:55',
- * value: '4',
- * surge: '1.2',
- * isTrip: 'true',
- * zeroOnes: '0'
- * }, {
- * time: '2016-09-17 00:30:08',
- * value: '3',
- * surge: null,
- * isTrip: 'false',
- * zeroOnes: '1'
- * }, {
- * time: null,
- * value: '2',
- * surge: '1.3',
- * isTrip: null,
- * zeroOnes: '1'
- * }];
- *
- * const fieldOrder = ['time', 'value', 'surge', 'isTrip', 'zeroOnes'];
- * const fields = getFieldsFromData(data, fieldOrder);
- * // fields = [
- * // {name: 'time', format: 'YYYY-M-D H:m:s', fieldIdx: 1, type: 'timestamp'},
- * // {name: 'value', format: '', fieldIdx: 4, type: 'integer'},
- * // {name: 'surge', format: '', fieldIdx: 5, type: 'real'},
- * // {name: 'isTrip', format: '', fieldIdx: 6, type: 'boolean'},
- * // {name: 'zeroOnes', format: '', fieldIdx: 7, type: 'integer'}];
- *
- */
-export function getFieldsFromData(data: RowData, fieldOrder: string[]): Field[] {
- // add a check for epoch timestamp
- const metadata = Analyzer.computeColMeta(
- data,
- [
- {regex: /.*geojson|all_points/g, dataType: 'GEOMETRY'},
- {regex: /.*census/g, dataType: 'STRING'}
- ],
- {ignoredDataTypes: IGNORE_DATA_TYPES}
- );
-
- const {fieldByIndex} = renameDuplicateFields(fieldOrder);
-
- const result = fieldOrder.map((field, index) => {
- const name = fieldByIndex[index];
-
- const fieldMeta = metadata.find(m => m.key === field);
-
- // fieldMeta could be undefined if the field has no data and Analyzer.computeColMeta
- // will ignore the field. In this case, we will simply assign the field type to STRING
- // since dropping the column in the RowData could be expensive
- let type = fieldMeta?.type || 'STRING';
- const format = fieldMeta?.format || '';
-
- // check if string is hex wkb
- if (type === AnalyzerDATA_TYPES.STRING) {
- type = data.some(d => isHexWkb(d[name])) ? AnalyzerDATA_TYPES.GEOMETRY : type;
- }
-
- return {
- name,
- id: name,
- displayName: name,
- format,
- fieldIdx: index,
- type: analyzerTypeToFieldType(type),
- analyzerType: type,
- valueAccessor: dc => d => {
- return dc.valueAt(d.index, index);
- }
- };
- });
-
- return result;
-}
-
-/**
- * pass in an array of field names, rename duplicated one
- * and return a map from old field index to new name
- *
- * @param fieldOrder
- * @returns new field name by index
- */
-export function renameDuplicateFields(fieldOrder: string[]): {
- allNames: string[];
- fieldByIndex: string[];
-} {
- return fieldOrder.reduce<{allNames: string[]; fieldByIndex: string[]}>(
- (accu, field, i) => {
- const {allNames} = accu;
- let fieldName = field;
-
- // add a counter to duplicated names
- if (allNames.includes(field)) {
- let counter = 0;
- while (allNames.includes(`${field}-${counter}`)) {
- counter++;
- }
- fieldName = `${field}-${counter}`;
- }
-
- accu.fieldByIndex[i] = fieldName;
- accu.allNames.push(fieldName);
-
- return accu;
- },
- {allNames: [], fieldByIndex: []}
- );
-}
-
-/**
- * Convert type-analyzer output to kepler.gl field types
- *
- * @param aType
- * @returns corresponding type in `ALL_FIELD_TYPES`
- */
-/* eslint-disable complexity */
-export function analyzerTypeToFieldType(aType: string): string {
- const {
- DATE,
- TIME,
- DATETIME,
- NUMBER,
- INT,
- FLOAT,
- BOOLEAN,
- STRING,
- GEOMETRY,
- GEOMETRY_FROM_STRING,
- PAIR_GEOMETRY_FROM_STRING,
- ZIPCODE,
- ARRAY,
- OBJECT
- } = AnalyzerDATA_TYPES;
-
- // TODO: un recognized types
- // CURRENCY PERCENT NONE
- switch (aType) {
- case DATE:
- return ALL_FIELD_TYPES.date;
- case TIME:
- case DATETIME:
- return ALL_FIELD_TYPES.timestamp;
- case FLOAT:
- return ALL_FIELD_TYPES.real;
- case INT:
- return ALL_FIELD_TYPES.integer;
- case BOOLEAN:
- return ALL_FIELD_TYPES.boolean;
- case GEOMETRY:
- case GEOMETRY_FROM_STRING:
- case PAIR_GEOMETRY_FROM_STRING:
- return ALL_FIELD_TYPES.geojson;
- case ARRAY:
- return ALL_FIELD_TYPES.array;
- case OBJECT:
- return ALL_FIELD_TYPES.object;
- case NUMBER:
- case STRING:
- case ZIPCODE:
- return ALL_FIELD_TYPES.string;
- default:
- globalConsole.warn(`Unsupported analyzer type: ${aType}`);
- return ALL_FIELD_TYPES.string;
- }
-}
const TIME_DISPLAY = '2020-05-11 14:00';
diff --git a/src/utils/src/export-utils.ts b/src/utils/src/export-utils.ts
index cc0acd86ce..453c5cd114 100644
--- a/src/utils/src/export-utils.ts
+++ b/src/utils/src/export-utils.ts
@@ -13,8 +13,9 @@ import {
OneXResolutionOption,
ExportImage
} from '@kepler.gl/constants';
+import {generateHashId} from '@kepler.gl/common-utils';
import domtoimage from './dom-to-image';
-import {generateHashId, set} from './utils';
+import {set} from './utils';
import {exportMapToHTML} from './export-map-html';
import {getApplicationConfig} from './application-config';
diff --git a/src/utils/src/filter-utils.ts b/src/utils/src/filter-utils.ts
index 6690bb8b36..d33a648b95 100644
--- a/src/utils/src/filter-utils.ts
+++ b/src/utils/src/filter-utils.ts
@@ -41,9 +41,10 @@ import {
AnimationConfig
} from '@kepler.gl/types';
+import {generateHashId, toArray, notNullorUndefined} from '@kepler.gl/common-utils';
import {DataContainerInterface} from './data-container-interface';
-import {generateHashId, set, toArray} from './utils';
-import {notNullorUndefined, timeToUnixMilli, unique} from './data-utils';
+import {set} from './utils';
+import {timeToUnixMilli, unique} from './data-utils';
import {getCentroid} from './h3-utils';
import {updateTimeFilterPlotType, updateRangeFilterPlotType} from './plot';
import {KeplerTableModel} from './types';
diff --git a/src/utils/src/h3-utils.ts b/src/utils/src/h3-utils.ts
index 64f00647a2..7346f365dd 100644
--- a/src/utils/src/h3-utils.ts
+++ b/src/utils/src/h3-utils.ts
@@ -3,7 +3,7 @@
import {h3GetResolution, H3Index, h3IsValid, h3ToGeo, h3ToGeoBoundary} from 'h3-js';
import {ALL_FIELD_TYPES} from '@kepler.gl/constants';
-import {notNullorUndefined} from './data-utils';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
export {h3GetResolution, h3IsValid};
diff --git a/src/utils/src/index.ts b/src/utils/src/index.ts
index d01fef6507..6bc80717a8 100644
--- a/src/utils/src/index.ts
+++ b/src/utils/src/index.ts
@@ -50,15 +50,10 @@ export {
} from './time';
export {
- ACCEPTED_ANALYZER_TYPES,
- analyzerTypeToFieldType,
datasetColorMaker,
findDefaultColorField,
getFieldFormatLabels,
- getFieldsFromData,
getFormatLabels,
- getSampleForTypeAnalyze,
- renameDuplicateFields,
validateInputData
} from './dataset-utils';
export {exportMapToHTML} from './export-map-html';
@@ -147,5 +142,5 @@ export {getCentroid, getHexFields, h3IsValid, idToPolygonGeo} from './h3-utils';
export type {Centroid} from './h3-utils';
// Application config
-export {getApplicationConfig, initApplicationConfig} from '../../utils/src/application-config';
-export type {KeplerApplicationConfig, MapLibInstance} from '../../utils/src/application-config';
+export {getApplicationConfig, initApplicationConfig} from './application-config';
+export type {KeplerApplicationConfig, MapLibInstance} from './application-config';
diff --git a/src/utils/src/notifications-utils.ts b/src/utils/src/notifications-utils.ts
index 3d0343eb28..319d232238 100644
--- a/src/utils/src/notifications-utils.ts
+++ b/src/utils/src/notifications-utils.ts
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
-import {generateHashId} from './utils';
+import {generateHashId} from '@kepler.gl/common-utils';
import {
DEFAULT_NOTIFICATION_MESSAGE,
diff --git a/src/utils/src/plot.ts b/src/utils/src/plot.ts
index d60b2618db..c962335a55 100644
--- a/src/utils/src/plot.ts
+++ b/src/utils/src/plot.ts
@@ -17,6 +17,7 @@ import {
ValueOf,
LineDatum
} from '@kepler.gl/types';
+import {notNullorUndefined} from '@kepler.gl/common-utils';
import {
ANIMATION_WINDOW,
BINS,
@@ -28,7 +29,7 @@ import {
} from '@kepler.gl/constants';
import {VisState} from '@kepler.gl/schemas';
-import {notNullOrUndefined, roundValToStep} from './data-utils';
+import {roundValToStep} from './data-utils';
import {aggregate, AGGREGATION_NAME} from './aggregation';
import {capitalizeFirstLetter} from './strings';
import {getDefaultTimeFormat} from './format';
@@ -413,11 +414,11 @@ export function splitSeries(series) {
let temp: any[] = [];
for (let i = 0; i < series.length; i++) {
const d = series[i];
- if (!notNullOrUndefined(d.y) && temp.length) {
+ if (!notNullorUndefined(d.y) && temp.length) {
// ends temp
lines.push(temp);
temp = [];
- } else if (notNullOrUndefined(d.y)) {
+ } else if (notNullorUndefined(d.y)) {
temp.push(d);
}
@@ -426,7 +427,7 @@ export function splitSeries(series) {
}
}
- const markers = lines.length > 1 ? series.filter(d => notNullOrUndefined(d.y)) : [];
+ const markers = lines.length > 1 ? series.filter(d => notNullorUndefined(d.y)) : [];
return {lines, markers};
}
diff --git a/src/utils/src/row-data-container.ts b/src/utils/src/row-data-container.ts
index 4284ea0068..50222a3172 100644
--- a/src/utils/src/row-data-container.ts
+++ b/src/utils/src/row-data-container.ts
@@ -2,12 +2,12 @@
// Copyright contributors to the kepler.gl project
import {DataRow, SharedRowOptions} from './data-row';
-import {Field} from '@kepler.gl/types';
+import {ProtoDatasetField} from '@kepler.gl/types';
import {DataContainerInterface, RangeOptions} from './data-container-interface';
type RowDataContainerInput = {
rows: any[][];
- fields?: Field[];
+ fields?: ProtoDatasetField[];
};
/**
diff --git a/src/utils/src/time.ts b/src/utils/src/time.ts
index 4bbbde87be..5543861212 100644
--- a/src/utils/src/time.ts
+++ b/src/utils/src/time.ts
@@ -13,9 +13,9 @@ import {
INTERVAL,
TickInterval
} from '@kepler.gl/constants';
+import {toArray} from '@kepler.gl/common-utils';
import {AnimationConfig, Timeline, TimeRangeFilter} from '@kepler.gl/types';
-import {toArray} from './utils';
import {getFrequency} from './aggregation';
export const TileTimeInterval = {
diff --git a/src/utils/src/utils.ts b/src/utils/src/utils.ts
index fdc1d90bb1..174ce34b0e 100644
--- a/src/utils/src/utils.ts
+++ b/src/utils/src/utils.ts
@@ -4,15 +4,6 @@
import window from 'global/window';
import {capitalizeFirstLetter} from './strings';
-/**
- * Generate a hash string based on number of character
- * @param {number} count
- * @returns {string} hash string
- */
-export function generateHashId(count = 6): string {
- return Math.random().toString(36).substr(count);
-}
-
/**
* Generate a hash string based on string
* @param str
@@ -68,26 +59,6 @@ export const camelize = (str: string): string => {
});
};
-/**
- * Converts non-arrays to arrays. Leaves arrays alone. Converts
- * undefined values to empty arrays ([] instead of [undefined]).
- * Otherwise, just returns [item] for non-array items.
- *
- * @param {*} item
- * @returns {array} boom! much array. very indexed. so useful.
- */
-export function toArray(item: T | T[]): T[] {
- if (Array.isArray(item)) {
- return item;
- }
-
- if (typeof item === 'undefined' || item === null) {
- return [];
- }
-
- return [item];
-}
-
/**
* immutably insert value to an Array or Object
* @param {Array|Object} obj
diff --git a/test/browser/components/container-test.js b/test/browser/components/container-test.js
index 3fe784d8a6..720c209498 100644
--- a/test/browser/components/container-test.js
+++ b/test/browser/components/container-test.js
@@ -244,13 +244,15 @@ test('Components -> Container -> Mount then rename', t => {
// mount with mint: false
t.doesNotThrow(() => {
wrapper = mount(
- s.smoothie}
- id={testId.id}
- mapboxApiAccessToken="hello.world"
- dispatch={dispatch}
- store={store}
- />
+
+ s.smoothie}
+ id={testId.id}
+ mapboxApiAccessToken="hello.world"
+ dispatch={dispatch}
+ store={store}
+ />
+
);
}, 'Should not throw error when mount');
@@ -283,14 +285,24 @@ test('Components -> Container -> Mount then rename', t => {
};
t.deepEqual(nextState, expectedState, 'should register milkshake to root reducer');
- wrapper.setProps({id: 'milkshake-2'});
- // actions = store.getActions();
+ wrapper.setProps({
+ children: (
+ s.smoothie}
+ id={'milkshake-2'}
+ mapboxApiAccessToken="hello.world"
+ dispatch={dispatch}
+ store={store}
+ />
+ )
+ });
+
const expectedActions1 = {
type: '@@kepler.gl/RENAME_ENTRY',
payload: {oldId: 'milkshake', newId: 'milkshake-2'}
};
- t.deepEqual(store.getActions().pop(), expectedActions1, 'should rename entry');
+ t.deepEqual(store.getActions().pop(), expectedActions1, 'should rename entry ');
const nextState1 = appReducer(nextState, expectedActions1);
const expectedState1 = {
diff --git a/test/browser/components/injector-test.js b/test/browser/components/injector-test.js
index 7cbf4dc9c8..0873e9c4da 100644
--- a/test/browser/components/injector-test.js
+++ b/test/browser/components/injector-test.js
@@ -235,7 +235,7 @@ test('Components -> injector -> withState.lens', t => {
});
test('Components -> injector -> withState.mapStateToProps', t => {
- const CustomHeader = () => smoothie
;
+ const CustomHeader = () => smoothie
;
const myCustomHeaderFactory = () =>
withState([], state => ({ids: Object.keys(state)}))(CustomHeader);
diff --git a/test/browser/components/side-panel/channel-by-value-selctor-test.js b/test/browser/components/side-panel/channel-by-value-selctor-test.js
index c3472ce12d..b7797dcfb3 100644
--- a/test/browser/components/side-panel/channel-by-value-selctor-test.js
+++ b/test/browser/components/side-panel/channel-by-value-selctor-test.js
@@ -200,7 +200,7 @@ test('Components -> ChannelByValueSelector -> ColorScaleSelector -> disabled', t
t.end();
});
-test.only('Components -> ChannelByValueSelector -> ColorScaleSelector -> ColorBreakDisplay', t => {
+test('Components -> ChannelByValueSelector -> ColorScaleSelector -> ColorBreakDisplay', t => {
const InitialState = cloneDeep(StateWFilesFiltersLayerColor);
const {layers, datasets} = InitialState.visState;
const pointLayer = layers[0];
diff --git a/test/browser/components/side-panel/layer-list.spec.js b/test/browser/components/side-panel/layer-list.spec.js
index b06fe30da7..aaf310c297 100644
--- a/test/browser/components/side-panel/layer-list.spec.js
+++ b/test/browser/components/side-panel/layer-list.spec.js
@@ -20,19 +20,11 @@ import {keplerGlReducerCore as keplerGlReducer} from '@kepler.gl/reducers';
import {renderWithTheme} from '../../../helpers/component-jest-utils';
import testLayerData from '../../../fixtures/test-layer-data';
import {dataId as csvDataId} from '../../../fixtures/test-csv-data';
+import {applyActions} from '../../../helpers/mock-state';
// TODO: need to be deleted and imported from raw-states
const InitialState = keplerGlReducer(undefined, keplerGlInit({}));
-function applyActions(reducer, initialState, actions) {
- const actionQ = Array.isArray(actions) ? actions : [actions];
-
- return actionQ.reduce(
- (updatedState, {action, payload}) => reducer(updatedState, action(...payload)),
- initialState
- );
-}
-
function mockStateWithMultipleH3Layers() {
const initialState = cloneDeep(InitialState);
const prepareState = applyActions(keplerGlReducer, initialState, [
diff --git a/test/browser/layer-tests/geojson-layer-specs.js b/test/browser/layer-tests/geojson-layer-specs.js
index 771fdb95eb..80f9e01fd6 100644
--- a/test/browser/layer-tests/geojson-layer-specs.js
+++ b/test/browser/layer-tests/geojson-layer-specs.js
@@ -3,7 +3,7 @@
import test from 'tape';
import {defaultElevation, defaultLineWidth, defaultRadius, KeplerGlLayers} from '@kepler.gl/layers';
-import {copyTableAndUpdate, createNewDataEntry} from '@kepler.gl/table';
+import {copyTableAndUpdate} from '@kepler.gl/table';
const {GeojsonLayer} = KeplerGlLayers;
@@ -18,6 +18,7 @@ import {
geoFilterDomain0,
geojsonFilterDomain0
} from 'test/helpers/layer-utils';
+import {createNewDataEntryMock} from 'test/helpers/table-utils';
import {
updatedGeoJsonLayer,
geoJsonWithStyle,
@@ -48,7 +49,7 @@ test('#GeojsonLayer -> constructor', t => {
t.end();
});
-test('#GeojsonLayer -> formatLayerData', t => {
+test('#GeojsonLayer -> formatLayerData', async t => {
const filteredIndex = [0, 2, 4];
const TEST_CASES = [
@@ -400,7 +401,7 @@ test('#GeojsonLayer -> formatLayerData', t => {
color: [5, 5, 5]
}
},
- datasets: createNewDataEntry({
+ datasets: await createNewDataEntryMock({
info: {id: dataId},
data: processGeojson(geoJsonWithStyle)
}),
diff --git a/test/browser/layer-tests/point-layer-specs.js b/test/browser/layer-tests/point-layer-specs.js
index 58598f88d7..ab23683f8e 100644
--- a/test/browser/layer-tests/point-layer-specs.js
+++ b/test/browser/layer-tests/point-layer-specs.js
@@ -19,7 +19,8 @@ import {processGeojson} from '@kepler.gl/processors';
import {geoJsonWithStyle, geojsonData} from 'test/fixtures/geojson';
import testArcData, {pointFromNeighbor} from 'test/fixtures/test-arc-data';
import {StateWArcNeighbors} from 'test/helpers/mock-state';
-import {copyTableAndUpdate, createNewDataEntry} from '@kepler.gl/table';
+import {createNewDataEntryMock} from 'test/helpers/table-utils';
+import {copyTableAndUpdate} from '@kepler.gl/table';
import {KeplerGlLayers} from '@kepler.gl/layers';
import {INITIAL_MAP_STATE} from '@kepler.gl/reducers';
import {DEFAULT_TEXT_LABEL, PROJECTED_PIXEL_SIZE_MULTIPLIER} from '@kepler.gl/constants';
@@ -732,7 +733,7 @@ test('#PointLayer -> updateLayer', t => {
t.end();
});
-test('#PointLayer -> formatLayerData -> Geojson column mode', t => {
+test('#PointLayer -> formatLayerData -> Geojson column mode', async t => {
// create a mockup GeoJson dataset with Point and MultiPoint geometry
const geoJsonWithMultiPoint = cloneDeep(geoJsonWithStyle);
geoJsonWithMultiPoint.features.push({
@@ -809,7 +810,7 @@ test('#PointLayer -> formatLayerData -> Geojson column mode', t => {
}
}
},
- datasets: createNewDataEntry({
+ datasets: await createNewDataEntryMock({
info: {id: dataId},
data: geojsonPointDataset
}),
@@ -873,7 +874,7 @@ test('#PointLayer -> formatLayerData -> Geojson column mode', t => {
}
}
},
- datasets: createNewDataEntry({
+ datasets: await createNewDataEntryMock({
info: {id: dataId},
data: geojsonPolygonDataset
}),
@@ -918,7 +919,7 @@ test('#PointLayer -> formatLayerData -> Geojson column mode', t => {
}
}
},
- datasets: createNewDataEntry({
+ datasets: await createNewDataEntryMock({
info: {id: dataId},
data: geojsonMultiPolygonDataset
}),
@@ -988,7 +989,7 @@ test('#PointLayer -> formatLayerData -> Geojson column mode', t => {
}
}
},
- datasets: createNewDataEntry({
+ datasets: await createNewDataEntryMock({
info: {id: dataId},
data: geojsonGeometryCollectionDataset
}),
@@ -1062,7 +1063,7 @@ test('#PointLayer -> formatLayerData -> Geojson column mode', t => {
}
}
},
- datasets: createNewDataEntry({
+ datasets: await createNewDataEntryMock({
info: {id: dataId},
data: geojsonPointWithNullDataset
}),
diff --git a/test/fixtures/synced-filter-with-trip-layer.js b/test/fixtures/synced-filter-with-trip-layer.js
index 730ba55ecb..9db9ded364 100644
--- a/test/fixtures/synced-filter-with-trip-layer.js
+++ b/test/fixtures/synced-filter-with-trip-layer.js
@@ -5,7 +5,7 @@ import {processKeplerglJSON} from '@kepler.gl/processors';
import CloneDeep from 'lodash.clonedeep';
import {keplerGlReducerCore as coreReducer} from '@kepler.gl/reducers';
import {addDataToMap} from '@kepler.gl/actions';
-import {InitialState} from '../helpers/mock-state';
+import {InitialState, applyActions} from '../helpers/mock-state';
export const syncedFilterWithTripLayerMap = {
datasets: [
@@ -391,7 +391,13 @@ export const syncedFilterWithTripLayerMap = {
export const mockStateWithSyncedFilterAndTripLayer = () => {
const initialState = CloneDeep(InitialState);
const result = processKeplerglJSON(syncedFilterWithTripLayerMap);
- const newState = coreReducer(initialState, addDataToMap(result));
+
+ const newState = applyActions(coreReducer, initialState, [
+ {
+ action: addDataToMap,
+ payload: [result]
+ }
+ ]);
return newState;
};
diff --git a/test/helpers/comparison-utils.js b/test/helpers/comparison-utils.js
index c66d8b0969..8ab7e18c54 100644
--- a/test/helpers/comparison-utils.js
+++ b/test/helpers/comparison-utils.js
@@ -2,7 +2,7 @@
// Copyright contributors to the kepler.gl project
import {FILTER_TYPES} from '@kepler.gl/constants';
-import {toArray} from '@kepler.gl/utils';
+import {toArray} from '@kepler.gl/common-utils';
import {KeplerTable} from '@kepler.gl/table';
export function cmpObjectKeys(t, expectedObj, actualObj, name) {
diff --git a/test/helpers/layer-utils.js b/test/helpers/layer-utils.js
index 6e26f2249c..737481deff 100644
--- a/test/helpers/layer-utils.js
+++ b/test/helpers/layer-utils.js
@@ -291,24 +291,27 @@ export function testUpdateLayer(t, {layerConfig, shouldUpdate}) {
value: [3, 8.33]
};
- const stateWithLayer = keplerGlReducerCore(
- initialState,
- addDataToMap({
- datasets: {
- info: {id: dataId},
- data: processCsvData(testLayerData)
- },
+ const addDataToMapPayload = {
+ datasets: {
+ info: {id: dataId},
+ data: processCsvData(testLayerData)
+ },
+ config: {
+ version: 'v1',
config: {
- version: 'v1',
- config: {
- visState: {
- layers: [layerConfig],
- filters: [filter0, filter1]
- }
+ visState: {
+ layers: [layerConfig],
+ filters: [filter0, filter1]
}
}
- })
- );
+ }
+ };
+ const stateWithLayer = applyActions(keplerGlReducerCore, initialState, [
+ {
+ action: addDataToMap,
+ payload: [addDataToMapPayload]
+ }
+ ]);
const layer = stateWithLayer.visState.layers[0];
t.ok(layer, 'should create layer');
diff --git a/test/helpers/mock-state.js b/test/helpers/mock-state.js
index 04773661f4..c3121b7549 100644
--- a/test/helpers/mock-state.js
+++ b/test/helpers/mock-state.js
@@ -3,7 +3,7 @@
import test from 'tape-catch';
import cloneDeep from 'lodash.clonedeep';
-import {drainTasksForTesting} from 'react-palm/tasks';
+import {drainTasksForTesting, succeedTaskWithValues} from 'react-palm/tasks';
import {
getInitialInputStyle,
@@ -29,6 +29,7 @@ import {
UIStateActions,
ProviderActions
} from '@kepler.gl/actions';
+import {KeplerTable} from '@kepler.gl/table';
// fixtures
import {
@@ -80,18 +81,69 @@ export const geojsonInfo = {
params: {file: null}
};
+/**
+ * Applies actions one by one using the reducer.
+ * After each action drain Tasks and automarically resolve tasks
+ * of type CREATE_TABLE_TASK in order to create datasets.
+ * @param {Reducer} reducer A reducer to use.
+ * @param {State} initialState Initial state.
+ * @param {Action | Action[]}actions An array of actions.
+ * @returns
+ */
export function applyActions(reducer, initialState, actions) {
const actionQ = Array.isArray(actions) ? actions : [actions];
- return actionQ.reduce(
- (updatedState, {action, payload}) => reducer(updatedState, action(...payload)),
- initialState
- );
+ // remove any existing tasks before actions
+ drainTasksForTesting();
+
+ let updatedState = actionQ.reduce((updatedState, {action, payload}) => {
+ let newState = reducer(updatedState, action(...payload));
+ const tasks = drainTasksForTesting();
+ newState = applyCreateTableTasks(tasks, reducer, newState);
+ return newState;
+ }, initialState);
+
+ return updatedState;
}
// TODO: need to be deleted and imported from raw-states
export const InitialState = keplerGlReducer(undefined, {});
+/**
+ * Mock instant sync result of createNewDataEntry.
+ */
+const mockCreateNewDataEntry = ({info, color, opts, data}) => {
+ const table = new KeplerTable({info, color, ...opts});
+ table.importData({data});
+ return table;
+};
+
+/**
+ * Execute tasks and mock CREATE_TABLE_TASK with success.
+ * @param {Task[]} tasks
+ * @param {Reducer} reducer
+ * @param {VisState} initialState
+ * @returns
+ */
+export const applyCreateTableTasks = (tasks, reducer, initialState) => {
+ return tasks.reduce((updatedState, task) => {
+ if (!task.label.includes('CREATE_TABLE_TASK')) return updatedState;
+ const tables = task.payload.map(payload => mockCreateNewDataEntry(payload));
+ return reducer(updatedState, succeedTaskWithValues(task, tables));
+ }, initialState);
+};
+
+/**
+ * Execute existing tasts and mock CREATE_TABLE_TASK with success.
+ * @param {VisStateReducer} reducer
+ * @param {VisState} initialState
+ * @returns
+ */
+export function applyExistingDatasetTasks(reducer, initialState) {
+ const tasks = drainTasksForTesting();
+ return applyCreateTableTasks(tasks, reducer, initialState);
+}
+
/**
* Mock app state with uploaded geojson and csv file
* @returns {Immutable} appState
@@ -114,8 +166,7 @@ export function mockStateWithFileUpload() {
payload: [[{info: geojsonInfo, data: {fields: geojsonFields, rows: geojsonRows}}]]
}
]);
- // cleanup tasks created during loadMapStyles
- drainTasksForTesting();
+
// replace layer id and color with controlled value for testing
updatedState.visState.layers.forEach((l, i) => {
const oldLayerId = l.id;
@@ -205,9 +256,6 @@ function mockStateWithLayerCustomColorBreaksLegends() {
}
]);
- // cleanup tasks created during loadMapStyles
- drainTasksForTesting();
-
test(t => {
t.equal(updatedState.visState.layers.length, 1, 'should load 1 layer');
t.deepEqual(
@@ -580,19 +628,22 @@ export function mockStateWithMultipleH3Layers() {
function mockStateWithTripData() {
const initialState = cloneDeep(InitialState);
- return keplerGlReducer(
- initialState,
- addDataToMap({
- datasets: {
- info: {
- label: 'Sample Trips',
- id: tripDataId
- },
- data: {fields: tripFields, rows: tripRows}
+ const addDataPayload = {
+ datasets: {
+ info: {
+ label: 'Sample Trips',
+ id: tripDataId
},
- config: tripConfig
- })
- );
+ data: {fields: tripFields, rows: tripRows}
+ },
+ config: tripConfig
+ };
+ return applyActions(keplerGlReducer, initialState, [
+ {
+ action: addDataToMap,
+ payload: [addDataPayload]
+ }
+ ]);
}
export function mockStateWithLayerDimensions(state) {
diff --git a/test/helpers/table-utils.js b/test/helpers/table-utils.js
new file mode 100644
index 0000000000..3c97a17d46
--- /dev/null
+++ b/test/helpers/table-utils.js
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MIT
+// Copyright contributors to the kepler.gl project
+
+import {createNewDataEntry} from '@kepler.gl/table';
+
+/**
+ * A test function to execute the task from createNewDataEntry with await syntax.
+ * @param {ProtoDataset} props
+ * @returns {Datasets}
+ */
+export const createNewDataEntryMock = async props => {
+ const newDataEntry = createNewDataEntry(props);
+ let table = null;
+ await newDataEntry.run(
+ async (effectorPrime, success, error) => {
+ const res = effectorPrime(success, error);
+ await res;
+ },
+ value => {
+ table = value;
+ }
+ );
+ return {
+ [props.info.id]: table
+ };
+};
diff --git a/test/node/reducers/composer-state-test.js b/test/node/reducers/composer-state-test.js
index a0437f8d23..cab648aac1 100644
--- a/test/node/reducers/composer-state-test.js
+++ b/test/node/reducers/composer-state-test.js
@@ -8,10 +8,13 @@ import keplerGlReducer, {
addDataToMapUpdater,
replaceDataInMapUpdater,
fitBoundsUpdater,
- INITIAL_UI_STATE
+ INITIAL_UI_STATE,
+ visStateReducer,
+ mapStateReducer
} from '@kepler.gl/reducers';
import {processCsvData} from '@kepler.gl/processors';
import {registerEntry} from '@kepler.gl/actions';
+import {drainTasksForTesting, succeedTaskWithValues} from 'react-palm/tasks';
import testCsvData, {sampleConfig, dataWithNulls} from 'test/fixtures/test-csv-data';
import testHexIdData, {
@@ -21,6 +24,8 @@ import testHexIdData, {
expectedMergedDataset
} from 'test/fixtures/test-hex-id-data';
import {cmpLayers, cmpFilters, cmpDataset, cmpInteraction} from 'test/helpers/comparison-utils';
+import {applyExistingDatasetTasks} from 'test/helpers/mock-state';
+
const mockRawData = {
fields: [
{
@@ -81,19 +86,21 @@ test('#composerStateReducer - addDataToMapUpdater: mapStyle', t => {
}
});
+ drainTasksForTesting();
+
t.equal(newState.mapStyle.styleType, 'light', 'Map style is set correctly');
t.end();
});
-test('#composerStateReducer - addDataToMapUpdater: mapState should be centered', t => {
+test('#composerStateReducer - addDataToMapUpdater: mapState should be centered (after dataset tasts are completed)', t => {
// init kepler.gl root and instance
const state = keplerGlReducer({}, registerEntry({id: 'test'})).test;
const mapStateProperties = {
latitude: 33.88608913680742,
longitude: -84.43459130456425
};
- const newState = addDataToMapUpdater(state, {
+ let newState = addDataToMapUpdater(state, {
payload: {
datasets: {
data: mockRawData,
@@ -110,6 +117,15 @@ test('#composerStateReducer - addDataToMapUpdater: mapState should be centered',
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ newState.visState = applyExistingDatasetTasks(visStateReducer, newState.visState);
+
+ // layers should generate a fit bounds task
+ const tasks = drainTasksForTesting();
+ t.equal(tasks.length, 1, 'One fit bounds task should be present');
+
+ newState.mapState = mapStateReducer(newState.mapState, succeedTaskWithValues(tasks[0], {}));
+
t.equal(newState.mapState.latitude, 29.23, 'centerMap: true should override mapState config');
t.equal(newState.mapState.longitude, 60.71, 'centerMap: true should override mapState config');
@@ -131,6 +147,8 @@ test('#composerStateReducer - addDataToMapUpdater: uiState', t => {
}
});
+ drainTasksForTesting();
+
const expectedUIState = {
...INITIAL_UI_STATE,
initialState: {},
@@ -153,7 +171,7 @@ test('#composerStateReducer - addDataToMapUpdater: keepExistingConfig', t => {
const state = keplerGlReducer({}, registerEntry({id: 'test'})).test;
// old state contain splitMaps
- const oldState = addDataToMapUpdater(state, {
+ let oldState = addDataToMapUpdater(state, {
payload: {
datasets: {
data,
@@ -165,6 +183,9 @@ test('#composerStateReducer - addDataToMapUpdater: keepExistingConfig', t => {
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ oldState = {...oldState, visState: applyExistingDatasetTasks(visStateReducer, oldState.visState)};
+
const {
layers: oldLayers,
filters: oldFilters,
@@ -177,7 +198,7 @@ test('#composerStateReducer - addDataToMapUpdater: keepExistingConfig', t => {
const hexDataId = hexIdDataConfig.dataId;
// keepExistingConfig is not defined, default to false
- const nextState1 = addDataToMapUpdater(oldState, {
+ let nextState1 = addDataToMapUpdater(oldState, {
payload: {
datasets: {
data: hexData,
@@ -189,6 +210,12 @@ test('#composerStateReducer - addDataToMapUpdater: keepExistingConfig', t => {
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ nextState1 = {
+ ...nextState1,
+ visState: applyExistingDatasetTasks(visStateReducer, nextState1.visState)
+ };
+
t.deepEqual(nextState1.visState.layerOrder, ['avlgol'], 'Should contain nextState1 layer order');
cmpDataset(t, expectedMergedDataset, nextState1.visState.datasets[hexDataId]);
@@ -199,7 +226,7 @@ test('#composerStateReducer - addDataToMapUpdater: keepExistingConfig', t => {
cmpFilters(t, mergedFilters, nextState1.visState.filters);
// add data and config keep existing data and config
- const nextState2 = addDataToMapUpdater(oldState, {
+ let nextState2 = addDataToMapUpdater(oldState, {
payload: {
datasets: {
data: hexData,
@@ -214,6 +241,12 @@ test('#composerStateReducer - addDataToMapUpdater: keepExistingConfig', t => {
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ nextState2 = {
+ ...nextState2,
+ visState: applyExistingDatasetTasks(visStateReducer, nextState2.visState)
+ };
+
const actualVisState = nextState2.visState;
const newLayers = [...oldLayers, mergedH3Layer];
@@ -378,20 +411,37 @@ test('#composerStateReducer - replaceDataInMapUpdater', t => {
const state = keplerGlReducer({}, registerEntry({id: 'test'})).test;
// old state contain splitMaps
- const oldState = addDataToMapUpdater(state, {
+ let oldState = addDataToMapUpdater(state, {
payload: {
datasets,
config: sampleConfig.config
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ oldState = {...oldState, visState: applyExistingDatasetTasks(visStateReducer, oldState.visState)};
+
const oldSavedConfig = state.visState.schema.getConfigToSave(oldState).config;
- const nextState = replaceDataInMapUpdater(oldState, {
+ let nextState = replaceDataInMapUpdater(oldState, {
payload: {
datasetToReplaceId: sampleConfig.dataId,
datasetToUse
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ nextState = {
+ ...nextState,
+ visState: applyExistingDatasetTasks(visStateReducer, nextState.visState)
+ };
+
+ // layers should generate a fit bounds task
+ const tasks = drainTasksForTesting();
+ t.equal(tasks.length, 1, 'A fit bounds Task should be present');
+ nextState = {
+ ...nextState,
+ mapState: mapStateReducer(nextState.mapState, succeedTaskWithValues(tasks[0], {}))
+ };
+
const nextSavedConfig = nextState.visState.schema.getConfigToSave(nextState).config;
const expectedLayers = oldSavedConfig.visState.layers.map(l => ({
@@ -492,21 +542,28 @@ test('#composerStateReducer - replaceDataInMapUpdater: same dataId', t => {
const state = keplerGlReducer({}, registerEntry({id: 'test'})).test;
// old state contain splitMaps
- const oldState = addDataToMapUpdater(state, {
+ let oldState = addDataToMapUpdater(state, {
payload: {
datasets,
config: sampleConfig.config
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ oldState = {...oldState, visState: applyExistingDatasetTasks(visStateReducer, oldState.visState)};
const oldSavedConfig = state.visState.schema.getConfigToSave(oldState).config;
- const nextState = replaceDataInMapUpdater(oldState, {
+ let nextState = replaceDataInMapUpdater(oldState, {
payload: {
datasetToReplaceId: sampleConfig.dataId,
datasetToUse
}
});
+ // create datasets from existing tasks, trigger auto create layers
+ nextState = {
+ ...nextState,
+ visState: applyExistingDatasetTasks(visStateReducer, nextState.visState)
+ };
// dataset should be replaced
t.ok(nextState.visState.datasets[sampleConfig.dataId], ' dataset should be replaced');
diff --git a/test/node/reducers/root-test.js b/test/node/reducers/root-test.js
index 1e70a5e541..5a96151d5e 100644
--- a/test/node/reducers/root-test.js
+++ b/test/node/reducers/root-test.js
@@ -14,6 +14,7 @@ import {
ActionTypes
} from '@kepler.gl/actions';
import {createAction, handleActions} from 'redux-actions';
+import {applyActions} from 'test/helpers/mock-state';
test('keplerGlReducer.initialState', t => {
const test1Reducer = keplerGlReducer.initialState({
@@ -318,17 +319,20 @@ test('keplerGlReducer.plugin override', t => {
let nextState = testReducer(undefined, registerEntry({id: 'test3'}));
- nextState = testReducer(
- nextState,
- addDataToMap({
- datasets: {
- data: mockRawData,
- info: {
- id: 'foo'
- }
+ const addDataToMapPayload = {
+ datasets: {
+ data: mockRawData,
+ info: {
+ id: 'foo'
}
- })
- );
+ }
+ };
+ nextState = applyActions(testReducer, nextState, [
+ {
+ action: addDataToMap,
+ payload: [addDataToMapPayload]
+ }
+ ]);
t.equal(nextState.test3.visState.layers.length, 4, 'Should have 4 layer');
diff --git a/test/node/reducers/vis-state-merger-test.js b/test/node/reducers/vis-state-merger-test.js
index 30ef16a336..8862e48ec6 100644
--- a/test/node/reducers/vis-state-merger-test.js
+++ b/test/node/reducers/vis-state-merger-test.js
@@ -81,7 +81,8 @@ import {
StateWSplitMaps,
testCsvDataId,
testGeoJsonDataId,
- StateWFiles
+ StateWFiles,
+ applyActions
} from 'test/helpers/mock-state';
import {
@@ -131,7 +132,9 @@ test('VisStateMerger.v0 -> mergeFilters -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed filters
cmpFilters(t, mergedFiltersV0, stateWData.filters);
@@ -164,7 +167,9 @@ test('VisStateMerger.v1 -> mergeFilters -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed filters
cmpFilters(t, expectedMergedFilterV1, stateWData.filters);
@@ -198,7 +203,9 @@ test('VisStateMerger.v0 -> mergeFilters -> toWorkingState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed filters
cmpFilters(t, [...oldFilters, ...mergedFiltersV0], stateWData.filters);
@@ -235,7 +242,9 @@ test('VisStateMerger.v1 -> mergeFilters -> toWorkingState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed filters
cmpFilters(t, [...oldFilters, ...mergedFiltersV1], stateWData.filters);
@@ -330,7 +339,9 @@ test('VisStateMerger.current -> mergeLayers -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(appStateToSave.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed layers
const genericLayersByOrder = stateToSave.visState.layerOrder.map(id =>
@@ -364,7 +375,10 @@ test('visStateMerger -> mergeLayer -> incremental load', t => {
// load dataset2
const parsedData2 = SchemaManager.parseSavedData([dataset2]);
- const stateWithData2 = coreReducer(stateWithConfig, addDataToMap({datasets: parsedData2}));
+ const stateWithData2 = applyActions(coreReducer, stateWithConfig, [
+ {action: addDataToMap, payload: [{datasets: parsedData2}]}
+ ]);
+
t.deepEqual(
stateWithData2.visState.preserveLayerOrder,
['hexagon-2', 'point-0', 'geojson-1'],
@@ -390,7 +404,10 @@ test('visStateMerger -> mergeLayer -> incremental load', t => {
// load dataset1
const parsedData1 = SchemaManager.parseSavedData([dataset1]);
- const stateWithData1 = coreReducer(stateWithData2, addDataToMap({datasets: parsedData1}));
+ const stateWithData1 = applyActions(coreReducer, stateWithData2, [
+ {action: addDataToMap, payload: [{datasets: parsedData1}]}
+ ]);
+
t.deepEqual(
stateWithData1.visState.preserveLayerOrder,
['hexagon-2', 'point-0', 'geojson-1'],
@@ -445,7 +462,9 @@ test('VisStateMerger.v1 -> mergeLayers -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(savedStateV1.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed layers
cmpLayers(t, mergedLayersV1, stateWData.layers, {id: true, color: true});
@@ -478,7 +497,9 @@ test('VisStateMerger.v1.label -> mergeLayers -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(savedStateV1Label.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed layers
cmpLayers(t, mergedLayersV1Label, stateWData.layers, {id: true});
@@ -527,7 +548,9 @@ test('VisStateMerger.v1.split -> mergeLayers -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test split Maps
t.deepEqual(stateWData.splitMaps, expectedConfig, 'should merge splitMaps');
@@ -578,7 +601,9 @@ test('VisStateMerger.v0 -> mergeLayers -> toWorkingState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed layers
cmpLayers(t, [...oldLayers, ...mergedLayersV0], stateWData.layers);
@@ -633,7 +658,9 @@ test('VisStateMerger.v1 -> mergeLayers -> toWorkingState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed filters
cmpLayers(t, [...oldLayers, ...mergedLayersV1], stateWData.layers);
@@ -717,7 +744,9 @@ test('VisStateMerger.v0 -> mergeInteractions -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed interactions
t.deepEqual(stateWData.interactionConfig, mergedInteractionsV0, 'should merge interactionConfig');
@@ -814,7 +843,9 @@ test('VisStateMerger.v0 -> mergeInteractions -> toWorkingState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
const expectedInteractions = {
...defaultInteractionConfig,
@@ -986,7 +1017,9 @@ test('VisStateMerger.v1 -> mergeInteractions -> toEmptyState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
// test parsed interactions
t.deepEqual(stateWData.interactionConfig, MergedInteractionV1, 'should merge interactionConfig');
@@ -1119,7 +1152,9 @@ test('VisStateMerger.v1 -> mergeInteractions -> toWorkingState', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
const expectedInteractions = {
...defaultInteractionConfig,
@@ -1259,7 +1294,9 @@ test('VisStateMerger.v1 -> mergeInteractions -> coordinate', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// load data into reducer
- const stateWData = visStateReducer(mergedState, updateVisData(parsedData));
+ const stateWData = applyActions(visStateReducer, mergedState, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
const expectedInteractions = {
...defaultInteractionConfig,
@@ -1403,7 +1440,9 @@ test('VisStateMerger - mergeSplitMaps -> split to split', t => {
const parsedData = SchemaManager.parseSavedData(savedConfig.datasets);
// 3. load data into reducer
- const mergedState3 = visStateReducer(mergedState2, updateVisData(parsedData));
+ const mergedState3 = applyActions(visStateReducer, mergedState2, [
+ {action: updateVisData, payload: [parsedData]}
+ ]);
t.deepEqual(mergedState3.splitMaps, expectedToMergeAll, 'Should merge all splitMaps');
t.deepEqual(mergedState3.splitMapsToBeMerged, [], 'Should empty splitMapsToBeMerged');
@@ -1490,7 +1529,9 @@ test('VisStateMerger - mergeTripGeojson', t => {
// processKeplerglJSON
const result = processKeplerglJSON(savedStateV1TripGeoJson);
- const updatedCore = coreReducer(initialState, addDataToMap(result));
+ const updatedCore = applyActions(coreReducer, initialState, [
+ {action: addDataToMap, payload: [result]}
+ ]);
const mergedVieState = updatedCore.visState;
@@ -1566,10 +1607,9 @@ test('VisStateMerger.v1 -> mergeFilters -> multiFilters', t => {
const oldState = cloneDeep(InitialState);
const oldVisState = oldState.visState;
- const mergedState = visStateReducer(
- oldVisState,
- updateVisData(stateParsed.datasets, {}, stateParsed.config)
- );
+ const mergedState = applyActions(visStateReducer, oldVisState, [
+ {action: updateVisData, payload: [stateParsed.datasets, {}, stateParsed.config]}
+ ]);
// check datasets is filtered
// and field has filterProps
@@ -1725,7 +1765,9 @@ test('VisStateMerger.v1 -> mergeFilters -> syncedFilters', t => {
t.equal(datasets.length, 2, 'should save 2 datasets');
// load config to initial state
- const stateWithConfig = coreReducer(InitialState, addDataToMap({config}));
+ const stateWithConfig = applyActions(coreReducer, InitialState, [
+ {action: addDataToMap, payload: [{config}]}
+ ]);
t.equal(stateWithConfig.visState.filters.length, 0, 'should not load filter without data');
t.equal(
@@ -1737,12 +1779,17 @@ test('VisStateMerger.v1 -> mergeFilters -> syncedFilters', t => {
const parsedDatasets = SchemaManager.parseSavedData(datasets);
// load data 1
- const stateWithData1 = coreReducer(stateWithConfig, addDataToMap({datasets: parsedDatasets[0]}));
+ const stateWithData1 = applyActions(coreReducer, stateWithConfig, [
+ {action: addDataToMap, payload: [{datasets: parsedDatasets[0]}]}
+ ]);
+
t.equal(Object.keys(stateWithData1.visState.datasets).length, 1, 'should load 1 dataset');
t.equal(stateWithData1.visState.filters.length, 0, 'should not load filter without all datasets');
// load data 2
- const stateWithData2 = coreReducer(stateWithData1, addDataToMap({datasets: parsedDatasets[1]}));
+ const stateWithData2 = applyActions(coreReducer, stateWithData1, [
+ {action: addDataToMap, payload: [{datasets: parsedDatasets[1]}]}
+ ]);
t.equal(Object.keys(stateWithData2.visState.datasets).length, 2, 'should load 2 datasets');
t.equal(
stateWithData2.visState.filters.length,
@@ -1991,10 +2038,9 @@ test('VisStateMerger -> load time filter/trip layer synced map', t => {
const initialState = cloneDeep(InitialState);
const initialVisState = initialState.visState;
- const visState = visStateReducer(
- initialVisState,
- updateVisData(stateParsed.datasets, {}, stateParsed.config)
- );
+ const visState = applyActions(visStateReducer, initialVisState, [
+ {action: updateVisData, payload: [stateParsed.datasets, {}, stateParsed.config]}
+ ]);
const newFilter = visState.filters[0];
@@ -2131,7 +2177,7 @@ const mockReducer = keplerGlReducer
});
// eslint-disable-next-line max-statements
-test('VisStateMerger -> asyne mergers', t => {
+test('VisStateMerger -> asynс mergers', t => {
// adding mock process to state
const stateToSave = cloneDeep(StateWMultiFilters);
const appStateToSave = SchemaManager.save(stateToSave);
@@ -2148,15 +2194,13 @@ test('VisStateMerger -> asyne mergers', t => {
const initialState = mockReducer(undefined, registerEntry({id: 'test'}));
// apply config with process to merge
- const nextState = mockReducer(
- initialState,
- // add csv data first
- updateVisData(
- stateParsed.datasets.find(d => d.info.id === testCsvDataId),
- {},
- configWithProcess
- )
- );
+ const nextState = applyActions(mockReducer, initialState, [
+ {
+ // add csv data first
+ action: updateVisData,
+ payload: [stateParsed.datasets.find(d => d.info.id === testCsvDataId), {}, configWithProcess]
+ }
+ ]);
t.deepEqual(
nextState.test.visState.isMergingDatasets,
@@ -2177,11 +2221,13 @@ test('VisStateMerger -> asyne mergers', t => {
t.equal(tasks[0].type, 'MOCK_MERGE_TASK', 'should create merger task');
// add another dataset will async merger is in process
- const nextState1 = mockReducer(
- nextState,
- // add geojson data
- updateVisData(stateParsed.datasets.find(d => d.info.id === testGeoJsonDataId))
- );
+ const nextState1 = applyActions(mockReducer, nextState, [
+ {
+ // add geojson data
+ action: updateVisData,
+ payload: [stateParsed.datasets.find(d => d.info.id === testGeoJsonDataId)]
+ }
+ ]);
t.ok(nextState1.test.visState.datasets[testGeoJsonDataId], 'should add geojson data');
diff --git a/test/node/reducers/vis-state-test.js b/test/node/reducers/vis-state-test.js
index ea7d743656..7309d7b56f 100644
--- a/test/node/reducers/vis-state-test.js
+++ b/test/node/reducers/vis-state-test.js
@@ -27,7 +27,7 @@ import {
import {processCsvData, processGeojson} from '@kepler.gl/processors';
import {Layer, KeplerGlLayers, COLUMN_MODE_TABLE} from '@kepler.gl/layers';
-import {createNewDataEntry, maybeToDate} from '@kepler.gl/table';
+import {maybeToDate} from '@kepler.gl/table';
import {
createDataContainer,
applyFilterFieldName,
@@ -107,6 +107,7 @@ import {
testCsvDataSlice2Id
} from '../../fixtures/test-csv-data';
import {mockStateWithSyncedFilterAndTripLayer} from '../../fixtures/synced-filter-with-trip-layer';
+import {createNewDataEntryMock} from 'test/helpers/table-utils';
const mockData = {
fields: [
@@ -361,11 +362,11 @@ test('#visStateReducer -> LAYER_TYPE_CHANGE.0', t => {
t.end();
});
-test('#visStateReducer -> LAYER_TYPE_CHANGE.1', t => {
+test('#visStateReducer -> LAYER_TYPE_CHANGE.1', async t => {
const layer = new Layer({id: 'more_layer'});
const oldState = {
...INITIAL_VIS_STATE,
- datasets: createNewDataEntry({
+ datasets: await createNewDataEntryMock({
info: {id: 'puppy', label: 'puppy'},
data: {
rows: mockData.data,
@@ -432,14 +433,14 @@ test('#visStateReducer -> LAYER_TYPE_CHANGE.1', t => {
t.end();
});
-test('#visStateReducer -> LAYER_TYPE_CHANGE.2', t => {
+test('#visStateReducer -> LAYER_TYPE_CHANGE.2', async t => {
const pointLayer = new PointLayer({id: 'a', dataId: 'smoothie'});
const mockColorRange = {
name: 'abc',
isReversed: true,
colors: ['a', 'b', 'c']
};
- const datasets = createNewDataEntry({
+ const datasets = await createNewDataEntryMock({
info: {id: 'smoothie'},
data: {
rows: testAllData,
@@ -543,7 +544,7 @@ test('#visStateReducer -> LAYER_TYPE_CHANGE.2', t => {
t.end();
});
-test('#visStateReducer -> LAYER_TYPE_CHANGE.3 -> animationConfig', t => {
+test('#visStateReducer -> LAYER_TYPE_CHANGE.3 -> animationConfig', async t => {
const layer = new GeojsonLayer({
label: 'taro and blue',
dataId: 'taro',
@@ -553,7 +554,7 @@ test('#visStateReducer -> LAYER_TYPE_CHANGE.3 -> animationConfig', t => {
id: 'taro'
});
- const dataset = createNewDataEntry({
+ const dataset = await createNewDataEntryMock({
info: {id: 'taro'},
data: processGeojson(tripGeojson)
});
@@ -698,10 +699,12 @@ test('#visStateReducer -> LAYER_CONFIG_CHANGE -> isVisible -> splitMaps', t => {
test('#visStateReducer -> LAYER_CONFIG_CHANGE -> columnMode', t => {
const initialState = InitialState.visState;
// const initialState = cloneDeep(state || InitialState);
- const updatedState = reducer(
- initialState,
- VisStateActions.updateVisData({info: tripCsvDataInfo, data: processCsvData(tripCsvData)})
- );
+ const updatedState = applyActions(reducer, initialState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [{info: tripCsvDataInfo, data: processCsvData(tripCsvData)}]
+ }
+ ]);
const pointLayer = updatedState.layers[0];
// change layer type to trip
@@ -824,16 +827,20 @@ test('visStateReducer -> layerDataIdChangeUpdater', t => {
test('visStateReducer -> layerDataIdChangeUpdater -> geojson', t => {
const initialState = CloneDeep(StateWFilesFiltersLayerColor).visState;
- const nextState = reducer(
- initialState,
+ const nextState = applyActions(reducer, initialState, [
// add another geojson
- VisStateActions.updateVisData([
- {
- info: {id: 'geojson2', label: 'Some Geojson'},
- data: {fields: geojsonFields, rows: geojsonRows.slice(0, 3)}
- }
- ])
- );
+ {
+ action: VisStateActions.updateVisData,
+ payload: [
+ [
+ {
+ info: {id: 'geojson2', label: 'Some Geojson'},
+ data: {fields: geojsonFields, rows: geojsonRows.slice(0, 3)}
+ }
+ ]
+ ]
+ }
+ ]);
// find geojson layer
const index = nextState.layers.findIndex(l => l.type === 'geojson');
@@ -874,10 +881,12 @@ test('visStateReducer -> layerDataIdChangeUpdater -> validation', t => {
...row.slice(fieldIdx + 1, row.length)
]);
// add another dataset
- const nextState = reducer(
- initialState,
- VisStateActions.updateVisData([{info: newDataInfo, data: {fields, rows}}])
- );
+ const nextState = applyActions(reducer, initialState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [[{info: newDataInfo, data: {fields, rows}}]]
+ }
+ ]);
const nextState1 = reducer(
nextState,
@@ -1361,16 +1370,20 @@ test('#visStateReducer -> UPDATE_VIS_DATA.1 -> No data', t => {
test('#visStateReducer -> UPDATE_VIS_DATA.2 -> to empty state', t => {
const oldState = INITIAL_VIS_STATE;
- const newState = reducer(
- oldState,
- VisStateActions.updateVisData([
- {
- data: mockRawData,
- info: {id: 'smoothie', label: 'exciting dataset'},
- metadata: {album: 'taro_and_blue'}
- }
- ])
- );
+ const newState = applyActions(reducer, oldState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [
+ [
+ {
+ data: mockRawData,
+ info: {id: 'smoothie', label: 'exciting dataset'},
+ metadata: {album: 'taro_and_blue'}
+ }
+ ]
+ ]
+ }
+ ]);
const expectedDatasets = {
smoothie: {
@@ -1547,15 +1560,19 @@ test('#visStateReducer -> UPDATE_VIS_DATA.3 -> merge w/ existing state', t => {
smoothie: []
};
- const newState = reducer(
- oldState,
- VisStateActions.updateVisData([
- {
- data: mockRawData,
- info: {id: 'smoothie', label: 'smoothie and milkshake'}
- }
- ])
- );
+ const newState = applyActions(reducer, oldState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [
+ [
+ {
+ data: mockRawData,
+ info: {id: 'smoothie', label: 'smoothie and milkshake'}
+ }
+ ]
+ ]
+ }
+ ]);
Object.keys(expectedDatasets).forEach(key =>
cmpDataset(t, expectedDatasets[key], newState.datasets[key])
@@ -1607,7 +1624,12 @@ test('#visStateReducer -> UPDATE_VIS_DATA.4.Geojson -> geojson data', t => {
const [layer1Color, layer1StrokeColor] = getNextColorMakerValue(2);
// receive data
- const initialState = reducer(initialVisState, VisStateActions.updateVisData(payload));
+ const initialState = applyActions(reducer, initialVisState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [payload]
+ }
+ ]);
const expectedDatasets = {
metadata: {
@@ -1706,7 +1728,12 @@ test('#visStateReducer -> UPDATE_VIS_DATA.4.Geojson -> with config', t => {
];
// receive data
- const initialState = reducer(initialVisState, VisStateActions.updateVisData(payload));
+ const initialState = applyActions(reducer, initialVisState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [payload]
+ }
+ ]);
t.equal(initialState.layers.length, 1, 'should create 1 layer');
@@ -1740,7 +1767,12 @@ test('#visStateReducer -> UPDATE_VIS_DATA.4.Geojson -> with config', t => {
}
};
- const testState = reducer(initialState, VisStateActions.updateVisData(datasets, {}, config));
+ const testState = applyActions(reducer, initialState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [datasets, {}, config]
+ }
+ ]);
t.deepEqual(
Object.keys(testState.datasets),
@@ -1804,15 +1836,19 @@ test('#visStateReducer -> UPDATE_VIS_DATA -> mergeFilters', t => {
value: mockFilter.value
};
- const newState = reducer(
- oldState,
- VisStateActions.updateVisData([
- {
- data: mockRawData,
- info: {id: 'smoothie', label: 'smoothie and milkshake'}
- }
- ])
- );
+ const newState = applyActions(reducer, oldState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [
+ [
+ {
+ data: mockRawData,
+ info: {id: 'smoothie', label: 'smoothie and milkshake'}
+ }
+ ]
+ ]
+ }
+ ]);
const dc = createDataContainer(mockRawData.rows, {fields: mockRawData.fields});
const allIndexes = dc.getPlainIndex();
@@ -1951,15 +1987,19 @@ test('#visStateReducer -> UPDATE_VIS_DATA.SPLIT_MAPS', t => {
layerOrder: [layers[2].id, layers[1].id, layers[0].id, layers[3].id]
};
- const newState = reducer(
- oldState,
- VisStateActions.updateVisData([
- {
- data: mockRawData,
- info: {id: 'smoothie', label: 'smoothie and milkshake'}
- }
- ])
- );
+ const newState = applyActions(reducer, oldState, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [
+ [
+ {
+ data: mockRawData,
+ info: {id: 'smoothie', label: 'smoothie and milkshake'}
+ }
+ ]
+ ]
+ }
+ ]);
// first visible layer should be point
const id1 = newState.layers[4].id;
@@ -2018,7 +2058,12 @@ test('#visStateReducer -> setFilter.dynamicDomain & cpu', t => {
];
// receive data
- const initialState = reducer(INITIAL_VIS_STATE, VisStateActions.updateVisData(payload));
+ const initialState = applyActions(reducer, INITIAL_VIS_STATE, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [payload]
+ }
+ ]);
const expectedLayer1 = new PointLayer({
isVisible: true,
@@ -2650,7 +2695,12 @@ function testSetFilterDynamicDomainGPU(t, setFilter) {
];
// receive data
- const initialState = reducer(INITIAL_VIS_STATE, VisStateActions.updateVisData(payload));
+ const initialState = applyActions(reducer, INITIAL_VIS_STATE, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [payload]
+ }
+ ]);
// add filter
const stateWithFilter = reducer(initialState, VisStateActions.addFilter('milkshake'));
@@ -2827,7 +2877,7 @@ test('#visStateReducer -> UPDATE_FILTER_ANIMATION_SPEED', t => {
t.end();
});
-test('#visStateReducer -> setFilter.fixedDomain & DynamicDomain & gpu & cpu', t => {
+test('#visStateReducer -> setFilter.fixedDomain & DynamicDomain & gpu & cpu', async t => {
// get test data
const {fields, rows} = processCsvData(testData);
const payload = [
@@ -2840,13 +2890,15 @@ test('#visStateReducer -> setFilter.fixedDomain & DynamicDomain & gpu & cpu', t
}
];
- const datasetSmoothie = createNewDataEntry({
- info: {id: 'smoothie', label: 'queen smoothie'},
- data: {
- rows: testAllData,
- fields: testFields
- }
- }).smoothie;
+ const datasetSmoothie = (
+ await createNewDataEntryMock({
+ info: {id: 'smoothie', label: 'queen smoothie'},
+ data: {
+ rows: testAllData,
+ fields: testFields
+ }
+ })
+ ).smoothie;
// add fixedDomain & gpu filter
const stateWidthTsFilter = applyActions(reducer, INITIAL_VIS_STATE, [
@@ -3178,7 +3230,12 @@ test('#visStateReducer -> SET_FILTER_PLOT.yAxis', t => {
];
// receive data
- const initialState = reducer(INITIAL_VIS_STATE, VisStateActions.updateVisData(payload));
+ const initialState = applyActions(reducer, INITIAL_VIS_STATE, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [payload]
+ }
+ ]);
// add filter
const stateWithFilter = reducer(initialState, VisStateActions.addFilter('smoothie'));
@@ -4834,7 +4891,12 @@ test('#visStateReducer -> POLYGON: Create polygon filter', t => {
};
// visStateUpdateVisDataUpdater - creates 4 layers
- let newReducer = reducer(state, VisStateActions.updateVisData(datasets, options, {}));
+ let newReducer = applyActions(reducer, state, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [datasets, options, {}]
+ }
+ ]);
// add new polygon feature
newReducer = reducer(newReducer, VisStateActions.setFeatures([mockPolygonFeature]));
@@ -4901,7 +4963,12 @@ test('#visStateReducer -> POLYGON: Create polygon filter', t => {
t.equal(newReducer.layerData[1].data.length, 0, 'Layer Point 2 show show 0 points');
// Adding a new dataset - creates extra 4 layers
- newReducer = reducer(newReducer, VisStateActions.updateVisData(datasets, options, {}));
+ newReducer = applyActions(reducer, newReducer, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [datasets, options, {}]
+ }
+ ]);
t.equal(newReducer.layerData[4].data.length, 4, 'Layer Point 5 should full data');
@@ -5038,7 +5105,12 @@ test('#visStateReducer -> POLYGON: Toggle filter feature', t => {
};
// visStateUpdateVisDataUpdater - creates 4 layers
- let newReducer = reducer(state, VisStateActions.updateVisData(datasets, options, {}));
+ let newReducer = applyActions(reducer, state, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [datasets, options, {}]
+ }
+ ]);
newReducer = reducer(newReducer, VisStateActions.addLayer());
@@ -5208,7 +5280,12 @@ test('#visStateReducer -> POLYGON: delete polygon filter', t => {
};
// visStateUpdateVisDataUpdater - creates 4 layers
- let newReducer = reducer(state, VisStateActions.updateVisData(datasets, options, {}));
+ let newReducer = applyActions(reducer, state, [
+ {
+ action: VisStateActions.updateVisData,
+ payload: [datasets, options, {}]
+ }
+ ]);
newReducer = reducer(newReducer, VisStateActions.addLayer());
@@ -5598,9 +5675,10 @@ test('#visStateReducer -> LOAD_FILES', async t => {
}
const nextState = reducer(initialState, VisStateActions.loadFiles(mockFiles));
- const [task1, ...more] = drainTasksForTesting();
- t.equal(more.length, 0, 'should ceate 1 task');
+ const tasks = drainTasksForTesting();
+ t.equal(tasks.length, 2, 'should ceate 2 tasks');
+ const task1 = tasks[1];
const expectedTask1 = {
type: 'LOAD_FILE_TASK',
diff --git a/test/node/utils/data-processor-test.js b/test/node/utils/data-processor-test.js
index e59cb368be..2715851e89 100644
--- a/test/node/utils/data-processor-test.js
+++ b/test/node/utils/data-processor-test.js
@@ -32,14 +32,14 @@ import {
processRowObject
} from '@kepler.gl/processors';
+import {validateInputData, createDataContainer} from '@kepler.gl/utils';
+
import {
ACCEPTED_ANALYZER_TYPES,
analyzerTypeToFieldType,
- getSampleForTypeAnalyze,
- validateInputData,
getFieldsFromData,
- createDataContainer
-} from '@kepler.gl/utils';
+ getSampleForTypeAnalyze
+} from '@kepler.gl/common-utils';
import {formatCsv} from '@kepler.gl/reducers';
diff --git a/test/node/utils/index.js b/test/node/utils/index.js
index 2a857792ad..5ee5b38a3c 100644
--- a/test/node/utils/index.js
+++ b/test/node/utils/index.js
@@ -4,6 +4,7 @@
import './data-utils-test';
import './data-processor-test';
import './kepler-table-test';
+import './kepler-table-utils-test';
import './data-container-test';
import './filter-utils-test';
import './gpu-filter-utils-test';
diff --git a/test/node/utils/kepler-table-test.js b/test/node/utils/kepler-table-test.js
index 833d7b0fe8..10fba3e369 100644
--- a/test/node/utils/kepler-table-test.js
+++ b/test/node/utils/kepler-table-test.js
@@ -6,12 +6,13 @@ import moment from 'moment';
import testData, {numericRangesCsv, testFields} from 'test/fixtures/test-csv-data';
import {preciseRound, getFilterFunction} from '@kepler.gl/utils';
-import {createNewDataEntry, findPointFieldPairs} from '@kepler.gl/table';
-
+import {findPointFieldPairs} from '@kepler.gl/table';
import {processCsvData} from '@kepler.gl/processors';
-import {cmpFields} from '../../helpers/comparison-utils';
import {FILTER_TYPES} from '@kepler.gl/constants';
+import {cmpFields} from '../../helpers/comparison-utils';
+import {createNewDataEntryMock} from '../../helpers/table-utils';
+
function testGetTimeFieldDomain(table, t) {
const test_cases = [
{
@@ -215,15 +216,16 @@ function testGetFilterFunction({fields, dataContainer}, t) {
);
}
-test('KeplerTable -> getColumnFilterDomain -> time', t => {
+test('KeplerTable -> getColumnFilterDomain -> time', async t => {
const expectedFields = testFields;
const data = processCsvData(testData);
- const newDataEntry = createNewDataEntry({
- info: {id: 'test'},
- data
- });
- const dataset = newDataEntry.test;
+ const dataset = (
+ await createNewDataEntryMock({
+ info: {id: 'test'},
+ data
+ })
+ ).test;
cmpFields(t, expectedFields, dataset.fields, dataset.id);
testGetTimeFieldDomain(dataset, t);
testGetFilterFunction(dataset, t);
@@ -233,11 +235,12 @@ test('KeplerTable -> getColumnFilterDomain -> time', t => {
test('KeplerTable -> getColumnFilterDomain -> numeric', async t => {
const data = processCsvData(numericRangesCsv);
- const newDataEntry = createNewDataEntry({
- info: {id: 'test'},
- data
- });
- const dataset = newDataEntry.test;
+ const dataset = (
+ await createNewDataEntryMock({
+ info: {id: 'test'},
+ data
+ })
+ ).test;
testGetNumericFieldStep(dataset, t);
diff --git a/test/node/utils/kepler-table-utils-test.js b/test/node/utils/kepler-table-utils-test.js
new file mode 100644
index 0000000000..3d934f61b5
--- /dev/null
+++ b/test/node/utils/kepler-table-utils-test.js
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MIT
+// Copyright contributors to the kepler.gl project
+
+import test from 'tape';
+
+import {createNewDataEntry} from '@kepler.gl/table';
+
+test('Dataset Utils -> createNewDataEntry', t => {
+ const task = createNewDataEntry({
+ info: {id: 'test', color: [0, 92, 255]},
+ data: {
+ rows: [[10], [20]],
+ fields: []
+ }
+ });
+
+ t.equal(task.label, 'CREATE_TABLE_TASK', 'should create CREATE_TABLE_TASK task');
+ t.equal(task.type, 'CREATE_TABLE_TASK', 'should create CREATE_TABLE_TASK task');
+ t.deepEqual(
+ task.payload,
+ {
+ info: {id: 'test', color: [0, 92, 255]},
+ color: [0, 92, 255],
+ opts: {},
+ data: {rows: [[10], [20]], fields: [], cols: undefined}
+ },
+ 'should create correct CREATE_TABLE_TASK task payload'
+ );
+
+ t.end();
+});
diff --git a/test/node/utils/layer-utils-test.js b/test/node/utils/layer-utils-test.js
index 740b785ef3..61e2cb012a 100644
--- a/test/node/utils/layer-utils-test.js
+++ b/test/node/utils/layer-utils-test.js
@@ -14,9 +14,10 @@ const {PointLayer, ArcLayer, GeojsonLayer, LineLayer} = KeplerGlLayers;
import {wktCsv} from 'test/fixtures/test-csv-data';
import {cmpLayers} from 'test/helpers/comparison-utils';
import {getNextColorMakerValue} from 'test/helpers/layer-utils';
+import {createNewDataEntryMock} from 'test/helpers/table-utils';
import tripGeojson, {timeStampDomain, tripBounds} from 'test/fixtures/trip-geojson';
import {geoJsonWithStyle} from 'test/fixtures/geojson';
-import {KeplerTable, findPointFieldPairs, createNewDataEntry} from '@kepler.gl/table';
+import {KeplerTable, findPointFieldPairs} from '@kepler.gl/table';
import {createDataContainer} from '@kepler.gl/utils';
test('layerUtils -> findDefaultLayer.1', t => {
@@ -282,7 +283,9 @@ test('layerUtils -> findDefaultLayer.2', t => {
info: {
id: dataId,
label: 'sf_zip_geo'
- },
+ }
+ });
+ dataset.importData({
data: {
rows: [
[
@@ -531,7 +534,9 @@ test('layerUtils -> findDefaultLayer:GeojsonLayer', t => {
const dataset = new KeplerTable({
info: {
label: 'sf_zip_geo'
- },
+ }
+ });
+ dataset.importData({
data: {
rows: [
[
@@ -811,7 +816,7 @@ test('layerUtils -> findDefaultLayer: TripLayer', t => {
t.end();
});
-test('layerUtils -> findDefaultLayer: TripLayer.1 -> no ts', t => {
+test('layerUtils -> findDefaultLayer: TripLayer.1 -> no ts', async t => {
// change 3rd coordinate to string
const modified = tripGeojson.features.map(f => ({
...f,
@@ -826,7 +831,7 @@ test('layerUtils -> findDefaultLayer: TripLayer.1 -> no ts', t => {
features: modified
};
- const dataset = createNewDataEntry({
+ const dataset = await createNewDataEntryMock({
info: {id: 'taro'},
data: processGeojson(noTripGeojson)
});
@@ -839,7 +844,7 @@ test('layerUtils -> findDefaultLayer: TripLayer.1 -> no ts', t => {
t.end();
});
-test('layerUtils -> findDefaultLayer: TripLayer.1 -> ts as string', t => {
+test('layerUtils -> findDefaultLayer: TripLayer.1 -> ts as string', async t => {
const tripData = {
type: 'FeatureCollection',
features: [
@@ -858,7 +863,7 @@ test('layerUtils -> findDefaultLayer: TripLayer.1 -> ts as string', t => {
]
};
- const dataset = createNewDataEntry({
+ const dataset = await createNewDataEntryMock({
info: {id: 'taro'},
data: processGeojson(tripData)
});
diff --git a/test/node/utils/util-test.js b/test/node/utils/util-test.js
index a90bb00af8..0bc7d450f8 100644
--- a/test/node/utils/util-test.js
+++ b/test/node/utils/util-test.js
@@ -8,9 +8,9 @@ import {
camelize,
capitalizeFirstLetter,
getError,
- set,
- toArray
+ set
} from '@kepler.gl/utils';
+import {toArray} from '@kepler.gl/common-utils';
import test from 'tape';
test('Utils -> set', t => {
diff --git a/yarn.lock b/yarn.lock
index 3ce66ec1ed..f6627c194f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2991,16 +2991,16 @@ __metadata:
languageName: node
linkType: hard
-"@kepler.gl/actions@npm:3.0.0, @kepler.gl/actions@workspace:src/actions":
+"@kepler.gl/actions@npm:3.1.0-alpha.0, @kepler.gl/actions@workspace:src/actions":
version: 0.0.0-use.local
resolution: "@kepler.gl/actions@workspace:src/actions"
dependencies:
"@deck.gl/core": "npm:^8.9.27"
- "@kepler.gl/cloud-providers": "npm:3.0.0"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/layers": "npm:3.0.0"
- "@kepler.gl/processors": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
+ "@kepler.gl/cloud-providers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/processors": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
"@reduxjs/toolkit": "npm:^1.7.2"
"@types/lodash.curry": "npm:^4.1.7"
"@types/react-redux": "npm:^7.1.23"
@@ -3013,30 +3013,42 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/ai-assistant@npm:3.0.0, @kepler.gl/ai-assistant@workspace:src/ai-assistant":
+"@kepler.gl/ai-assistant@npm:3.1.0-alpha.0, @kepler.gl/ai-assistant@workspace:src/ai-assistant":
version: 0.0.0-use.local
resolution: "@kepler.gl/ai-assistant@workspace:src/ai-assistant"
dependencies:
- "@kepler.gl/components": "npm:3.0.0"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/layers": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/components": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
global: "npm:^4.3.0"
react-ai-assist: "npm:0.0.14"
languageName: unknown
linkType: soft
-"@kepler.gl/cloud-providers@npm:3.0.0, @kepler.gl/cloud-providers@workspace:src/cloud-providers":
+"@kepler.gl/cloud-providers@npm:3.1.0-alpha.0, @kepler.gl/cloud-providers@workspace:src/cloud-providers":
version: 0.0.0-use.local
resolution: "@kepler.gl/cloud-providers@workspace:src/cloud-providers"
dependencies:
- "@kepler.gl/types": "npm:3.0.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
react: "npm:^18.2.0"
languageName: unknown
linkType: soft
-"@kepler.gl/components@npm:3.0.0, @kepler.gl/components@workspace:src/components":
+"@kepler.gl/common-utils@npm:3.1.0-alpha.0, @kepler.gl/common-utils@workspace:src/common-utils":
+ version: 0.0.0-use.local
+ resolution: "@kepler.gl/common-utils@workspace:src/common-utils"
+ dependencies:
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ d3-array: "npm:^2.8.0"
+ global: "npm:^4.3.0"
+ type-analyzer: "npm:0.4.0"
+ languageName: unknown
+ linkType: soft
+
+"@kepler.gl/components@npm:3.1.0-alpha.0, @kepler.gl/components@workspace:src/components":
version: 0.0.0-use.local
resolution: "@kepler.gl/components@workspace:src/components"
dependencies:
@@ -3047,19 +3059,20 @@ __metadata:
"@dnd-kit/sortable": "npm:^7.0.2"
"@dnd-kit/utilities": "npm:^3.2.1"
"@floating-ui/react": "npm:0.25.1"
- "@kepler.gl/actions": "npm:3.0.0"
- "@kepler.gl/cloud-providers": "npm:3.0.0"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/effects": "npm:3.0.0"
- "@kepler.gl/layers": "npm:3.0.0"
- "@kepler.gl/localization": "npm:3.0.0"
- "@kepler.gl/processors": "npm:3.0.0"
- "@kepler.gl/reducers": "npm:3.0.0"
- "@kepler.gl/schemas": "npm:3.0.0"
- "@kepler.gl/styles": "npm:3.0.0"
- "@kepler.gl/table": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/actions": "npm:3.1.0-alpha.0"
+ "@kepler.gl/cloud-providers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/common-utils": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/effects": "npm:3.1.0-alpha.0"
+ "@kepler.gl/layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/localization": "npm:3.1.0-alpha.0"
+ "@kepler.gl/processors": "npm:3.1.0-alpha.0"
+ "@kepler.gl/reducers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/schemas": "npm:3.1.0-alpha.0"
+ "@kepler.gl/styles": "npm:3.1.0-alpha.0"
+ "@kepler.gl/table": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@mapbox/mapbox-sdk": "npm:^0.15.3"
"@nebula.gl/edit-modes": "npm:1.0.2-alpha.1"
"@tippyjs/react": "npm:^4.2.0"
@@ -3137,11 +3150,11 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/constants@npm:3.0.0, @kepler.gl/constants@workspace:src/constants":
+"@kepler.gl/constants@npm:3.1.0-alpha.0, @kepler.gl/constants@workspace:src/constants":
version: 0.0.0-use.local
resolution: "@kepler.gl/constants@workspace:src/constants"
dependencies:
- "@kepler.gl/types": "npm:3.0.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
"@types/d3-scale": "npm:^3.2.2"
"@types/keymirror": "npm:^0.1.1"
colorbrewer: "npm:^1.5.0"
@@ -3151,7 +3164,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/deckgl-arrow-layers@npm:3.0.0, @kepler.gl/deckgl-arrow-layers@workspace:src/deckgl-arrow-layers":
+"@kepler.gl/deckgl-arrow-layers@npm:3.1.0-alpha.0, @kepler.gl/deckgl-arrow-layers@workspace:src/deckgl-arrow-layers":
version: 0.0.0-use.local
resolution: "@kepler.gl/deckgl-arrow-layers@workspace:src/deckgl-arrow-layers"
dependencies:
@@ -3169,7 +3182,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/deckgl-layers@npm:3.0.0, @kepler.gl/deckgl-layers@workspace:src/deckgl-layers":
+"@kepler.gl/deckgl-layers@npm:3.1.0-alpha.0, @kepler.gl/deckgl-layers@workspace:src/deckgl-layers":
version: 0.0.0-use.local
resolution: "@kepler.gl/deckgl-layers@workspace:src/deckgl-layers"
dependencies:
@@ -3178,9 +3191,9 @@ __metadata:
"@deck.gl/core": "npm:^8.9.27"
"@deck.gl/geo-layers": "npm:^8.9.27"
"@deck.gl/layers": "npm:^8.9.27"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@luma.gl/constants": "npm:^8.5.20"
"@luma.gl/core": "npm:^8.5.20"
"@mapbox/geo-viewport": "npm:^0.4.1"
@@ -3198,21 +3211,21 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/effects@npm:3.0.0, @kepler.gl/effects@workspace:src/effects":
+"@kepler.gl/effects@npm:3.1.0-alpha.0, @kepler.gl/effects@workspace:src/effects":
version: 0.0.0-use.local
resolution: "@kepler.gl/effects@workspace:src/effects"
dependencies:
"@deck.gl/core": "npm:^8.9.27"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@luma.gl/core": "npm:^8.5.20"
"@luma.gl/shadertools": "npm:^8.5.20"
suncalc: "npm:^1.9.0"
languageName: unknown
linkType: soft
-"@kepler.gl/layers@npm:3.0.0, @kepler.gl/layers@workspace:src/layers":
+"@kepler.gl/layers@npm:3.1.0-alpha.0, @kepler.gl/layers@workspace:src/layers":
version: 0.0.0-use.local
resolution: "@kepler.gl/layers@workspace:src/layers"
dependencies:
@@ -3222,13 +3235,14 @@ __metadata:
"@deck.gl/geo-layers": "npm:^8.9.27"
"@deck.gl/layers": "npm:^8.9.27"
"@deck.gl/mesh-layers": "npm:^8.9.27"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/deckgl-arrow-layers": "npm:3.0.0"
- "@kepler.gl/deckgl-layers": "npm:3.0.0"
- "@kepler.gl/localization": "npm:3.0.0"
- "@kepler.gl/table": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/common-utils": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/deckgl-arrow-layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/deckgl-layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/localization": "npm:3.1.0-alpha.0"
+ "@kepler.gl/table": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@loaders.gl/arrow": "npm:^4.3.2"
"@loaders.gl/core": "npm:^4.3.2"
"@loaders.gl/gis": "npm:^4.3.2"
@@ -3265,7 +3279,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/localization@npm:3.0.0, @kepler.gl/localization@workspace:src/localization":
+"@kepler.gl/localization@npm:3.1.0-alpha.0, @kepler.gl/localization@workspace:src/localization":
version: 0.0.0-use.local
resolution: "@kepler.gl/localization@workspace:src/localization"
dependencies:
@@ -3275,15 +3289,17 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/processors@npm:3.0.0, @kepler.gl/processors@workspace:src/processors":
+"@kepler.gl/processors@npm:3.1.0-alpha.0, @kepler.gl/processors@workspace:src/processors":
version: 0.0.0-use.local
resolution: "@kepler.gl/processors@workspace:src/processors"
dependencies:
"@danmarshall/deckgl-typings": "npm:4.9.22"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/schemas": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/common-utils": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/schemas": "npm:3.1.0-alpha.0"
+ "@kepler.gl/table": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@loaders.gl/arrow": "npm:^4.3.2"
"@loaders.gl/core": "npm:^4.3.2"
"@loaders.gl/csv": "npm:^4.3.2"
@@ -3298,24 +3314,25 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/reducers@npm:3.0.0, @kepler.gl/reducers@workspace:src/reducers":
+"@kepler.gl/reducers@npm:3.1.0-alpha.0, @kepler.gl/reducers@workspace:src/reducers":
version: 0.0.0-use.local
resolution: "@kepler.gl/reducers@workspace:src/reducers"
dependencies:
- "@kepler.gl/actions": "npm:3.0.0"
- "@kepler.gl/cloud-providers": "npm:3.0.0"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/deckgl-arrow-layers": "npm:3.0.0"
- "@kepler.gl/deckgl-layers": "npm:3.0.0"
- "@kepler.gl/effects": "npm:3.0.0"
- "@kepler.gl/layers": "npm:3.0.0"
- "@kepler.gl/localization": "npm:3.0.0"
- "@kepler.gl/processors": "npm:3.0.0"
- "@kepler.gl/schemas": "npm:3.0.0"
- "@kepler.gl/table": "npm:3.0.0"
- "@kepler.gl/tasks": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/actions": "npm:3.1.0-alpha.0"
+ "@kepler.gl/cloud-providers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/common-utils": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/deckgl-arrow-layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/deckgl-layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/effects": "npm:3.1.0-alpha.0"
+ "@kepler.gl/layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/localization": "npm:3.1.0-alpha.0"
+ "@kepler.gl/processors": "npm:3.1.0-alpha.0"
+ "@kepler.gl/schemas": "npm:3.1.0-alpha.0"
+ "@kepler.gl/table": "npm:3.1.0-alpha.0"
+ "@kepler.gl/tasks": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@loaders.gl/loader-utils": "npm:^4.3.2"
"@turf/bbox": "npm:^6.0.1"
"@types/lodash.clonedeep": "npm:^4.5.7"
@@ -3343,16 +3360,17 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/schemas@npm:3.0.0, @kepler.gl/schemas@workspace:src/schemas":
+"@kepler.gl/schemas@npm:3.1.0-alpha.0, @kepler.gl/schemas@workspace:src/schemas":
version: 0.0.0-use.local
resolution: "@kepler.gl/schemas@workspace:src/schemas"
dependencies:
- "@kepler.gl/ai-assistant": "npm:3.0.0"
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/layers": "npm:3.0.0"
- "@kepler.gl/table": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/ai-assistant": "npm:3.1.0-alpha.0"
+ "@kepler.gl/common-utils": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/table": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@loaders.gl/loader-utils": "npm:^4.3.2"
"@types/keymirror": "npm:^0.1.1"
"@types/lodash.clonedeep": "npm:^4.5.7"
@@ -3364,54 +3382,57 @@ __metadata:
languageName: unknown
linkType: soft
-"@kepler.gl/styles@npm:3.0.0, @kepler.gl/styles@workspace:src/styles":
+"@kepler.gl/styles@npm:3.1.0-alpha.0, @kepler.gl/styles@workspace:src/styles":
version: 0.0.0-use.local
resolution: "@kepler.gl/styles@workspace:src/styles"
dependencies:
- "@kepler.gl/constants": "npm:3.0.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
"@types/styled-components": "npm:^5.1.25"
styled-components: "npm:^4.1.3"
languageName: unknown
linkType: soft
-"@kepler.gl/table@npm:3.0.0, @kepler.gl/table@workspace:src/table":
+"@kepler.gl/table@npm:3.1.0-alpha.0, @kepler.gl/table@workspace:src/table":
version: 0.0.0-use.local
resolution: "@kepler.gl/table@workspace:src/table"
dependencies:
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/layers": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
- "@kepler.gl/utils": "npm:3.0.0"
+ "@kepler.gl/common-utils": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/layers": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
+ "@kepler.gl/utils": "npm:3.1.0-alpha.0"
"@types/d3-array": "npm:^2.8.0"
"@types/lodash.uniq": "npm:^4.5.7"
d3-array: "npm:^2.8.0"
global: "npm:^4.3.0"
lodash.uniq: "npm:^4.0.1"
moment: "npm:^2.10.6"
+ react-palm: "npm:^3.3.8"
languageName: unknown
linkType: soft
-"@kepler.gl/tasks@npm:3.0.0, @kepler.gl/tasks@workspace:src/tasks":
+"@kepler.gl/tasks@npm:3.1.0-alpha.0, @kepler.gl/tasks@workspace:src/tasks":
version: 0.0.0-use.local
resolution: "@kepler.gl/tasks@workspace:src/tasks"
dependencies:
- "@kepler.gl/processors": "npm:3.0.0"
+ "@kepler.gl/processors": "npm:3.1.0-alpha.0"
react-palm: "npm:^3.3.8"
languageName: unknown
linkType: soft
-"@kepler.gl/types@npm:3.0.0, @kepler.gl/types@workspace:src/types":
+"@kepler.gl/types@npm:3.1.0-alpha.0, @kepler.gl/types@workspace:src/types":
version: 0.0.0-use.local
resolution: "@kepler.gl/types@workspace:src/types"
languageName: unknown
linkType: soft
-"@kepler.gl/utils@npm:3.0.0, @kepler.gl/utils@workspace:src/utils":
+"@kepler.gl/utils@npm:3.1.0-alpha.0, @kepler.gl/utils@workspace:src/utils":
version: 0.0.0-use.local
resolution: "@kepler.gl/utils@workspace:src/utils"
dependencies:
- "@kepler.gl/constants": "npm:3.0.0"
- "@kepler.gl/types": "npm:3.0.0"
+ "@kepler.gl/common-utils": "npm:3.1.0-alpha.0"
+ "@kepler.gl/constants": "npm:3.1.0-alpha.0"
+ "@kepler.gl/types": "npm:3.1.0-alpha.0"
"@luma.gl/constants": "npm:^8.5.20"
"@luma.gl/core": "npm:^8.5.20"
"@mapbox/geo-viewport": "npm:^0.4.1"
@@ -19973,7 +19994,7 @@ __metadata:
"@deck.gl/test-utils": "npm:^8.9.27"
"@hubble.gl/core": "npm:1.2.0-alpha.6"
"@hubble.gl/react": "npm:1.2.0-alpha.6"
- "@kepler.gl/components": "npm:3.0.0"
+ "@kepler.gl/components": "npm:3.1.0-alpha.0"
"@loaders.gl/polyfills": "npm:^4.3.2"
"@luma.gl/test-utils": "npm:^8.5.20"
"@nebula.gl/layers": "npm:1.0.2-alpha.1"