diff --git a/package.json b/package.json index a261eedecd..0b3b3bf210 100644 --- a/package.json +++ b/package.json @@ -317,6 +317,7 @@ "@deck.gl/mesh-layers": "^8.4.16", "@deck.gl/react": "^8.4.16", "@deck.gl/test-utils": "^8.4.16", + "d3-array": "^2.8.0", "d3-scale": "^3.2.3", "dot-prop": "6.0.0", "kind-of": "6.0.3", diff --git a/src/actions/vis-state-actions.ts b/src/actions/vis-state-actions.ts index c9f43541e4..4e2f221779 100644 --- a/src/actions/vis-state-actions.ts +++ b/src/actions/vis-state-actions.ts @@ -572,7 +572,7 @@ export type AddDataToMapUpdaterOptions = { export type UpdateVisDataUpdaterAction = { datasets: AddDataToMapPayload['datasets']; options: AddDataToMapPayload['options']; - config: AddDataToMapPayload['config']; + config?: AddDataToMapPayload['config']; } & AddDataToMapPayload; // * @param dataset.info -info of a dataset // * @param dataset.info.id - id of this dataset. If config is defined, `id` should matches the `dataId` in config. @@ -598,7 +598,7 @@ export type UpdateVisDataUpdaterAction = { export function updateVisData( datasets: AddDataToMapPayload['datasets'], options: AddDataToMapPayload['options'], - config: AddDataToMapPayload['config'] + config?: AddDataToMapPayload['config'] ): Merge { return { type: ActionTypes.UPDATE_VIS_DATA, diff --git a/src/components/filters/filter-panels/new-filter-panel.tsx b/src/components/filters/filter-panels/new-filter-panel.tsx index 7f44a0c9c2..0822df538d 100644 --- a/src/components/filters/filter-panels/new-filter-panel.tsx +++ b/src/components/filters/filter-panels/new-filter-panel.tsx @@ -23,7 +23,7 @@ import {StyledFilterContent} from 'components/common/styled-components'; import FilterPanelHeaderFactory from 'components/side-panel/filter-panel/filter-panel-header'; import SourceDataSelectorFactory from 'components/side-panel/common/source-data-selector'; import FieldSelectorFactory from '../../common/field-selector'; -import {FilterBase} from 'reducers'; +import {FilterBase, LineChart} from 'reducers'; import {FilterPanelComponent} from './types'; import KeplerTable, {Field} from 'utils/table-utils/kepler-table'; @@ -47,7 +47,7 @@ function NewFilterPanelFactory( SourceDataSelector: ReturnType, FieldSelector: ReturnType ) { - const NewFilterPanel: FilterPanelComponent = React.memo( + const NewFilterPanel: FilterPanelComponent> = React.memo( ({idx, filter, datasets, allAvailableFields, setFilter, removeFilter}) => { const onFieldSelector = useCallback(field => setFilter(idx, 'name', field.name), [ idx, diff --git a/src/reducers/combined-updaters.ts b/src/reducers/combined-updaters.ts index d43d975a8e..2327b153a1 100644 --- a/src/reducers/combined-updaters.ts +++ b/src/reducers/combined-updaters.ts @@ -164,14 +164,19 @@ export const addDataToMapUpdater = ( return compose_([ pick_('visState')( - apply_(visStateUpdateVisDataUpdater, { + apply_(visStateUpdateVisDataUpdater, { datasets, options, config: parsedConfig }) ), - if_(Boolean(info), pick_('visState')(apply_(setMapInfoUpdater, {info}))), + if_( + Boolean(info), + pick_('visState')( + apply_(setMapInfoUpdater, {info}) + ) + ), with_(({visState}) => pick_('mapState')( diff --git a/src/reducers/vis-state-merger.ts b/src/reducers/vis-state-merger.ts index e0cb60f074..617d67744b 100644 --- a/src/reducers/vis-state-merger.ts +++ b/src/reducers/vis-state-merger.ts @@ -37,7 +37,7 @@ import {TooltipInfo} from './vis-state-updaters'; import {SavedInteractionConfig} from 'schemas'; export type Merger = { - merge: (state: VisState, config: any, fromConfig?: boolean) => VisState; + merge: (state: S, config: any, fromConfig?: boolean) => S; prop: string; toMergeProp?: string; }; @@ -48,11 +48,11 @@ export type VisStateMergers = Merger[]; * save it for later * */ -export function mergeFilters( - state: VisState, +export function mergeFilters( + state: S, filtersToMerge: NonNullable['filters'], fromConfig?: boolean -): VisState { +): S { if (!Array.isArray(filtersToMerge) || !filtersToMerge.length) { return state; } @@ -115,11 +115,11 @@ export function serializeLayer(newLayer): ParsedLayer { * save it for later * */ -export function mergeLayers( - state: VisState, +export function mergeLayers( + state: S, layersToMerge: NonNullable['layers'] = [], fromConfig?: boolean -): VisState { +): S { const preserveLayerOrder = fromConfig ? layersToMerge.map(l => l.id) : state.preserveLayerOrder; if (!Array.isArray(layersToMerge) || !layersToMerge.length) { @@ -145,7 +145,6 @@ export function mergeLayers( ...state, layers: newLayers, layerOrder: newLayerOrder, - // @ts-expect-error preserveLayerOrder, layerToBeMerged: [...state.layerToBeMerged, ...unmerged] }; @@ -202,11 +201,11 @@ export function insertLayerAtRightOrder( * Merge interactions with saved config * */ -export function mergeInteractions( - state: VisState, +export function mergeInteractions( + state: S, interactionToBeMerged: Partial | undefined, fromConfig?: boolean -): VisState { +): S { const merged: Partial = {}; const unmerged: Partial = {}; @@ -263,7 +262,6 @@ export function mergeInteractions( return { ...state, - // @ts-expect-error interactionConfig: { ...state.interactionConfig, ...merged @@ -279,11 +277,11 @@ export function mergeInteractions( * 2. if current map is NOT split, but splitMaps contain maps * : add to splitMaps, and add current layers to splitMaps */ -export function mergeSplitMaps( - state: VisState, +export function mergeSplitMaps( + state: S, splitMaps: NonNullable['splitMaps'] = [], fromConfig?: boolean -): VisState { +): S { const merged = [...state.splitMaps]; const unmerged = []; splitMaps.forEach((sm, i) => { @@ -353,11 +351,11 @@ export function mergeInteractionTooltipConfig( * Merge layerBlending with saved * */ -export function mergeLayerBlending( - state: VisState, +export function mergeLayerBlending( + state: S, layerBlending: NonNullable['layerBlending'], fromConfig?: boolean -): VisState { +): S { if (layerBlending && LAYER_BLENDINGS[layerBlending]) { return { ...state, @@ -371,11 +369,11 @@ export function mergeLayerBlending( /** * Merge animation config */ -export function mergeAnimationConfig( - state: VisState, +export function mergeAnimationConfig( + state: S, animation: NonNullable['animationConfig'], fromConfig?: boolean -): VisState { +): S { if (animation && animation.currentTime) { return { ...state, diff --git a/src/reducers/vis-state-updaters.ts b/src/reducers/vis-state-updaters.ts index 2579ef949b..a277f326f6 100644 --- a/src/reducers/vis-state-updaters.ts +++ b/src/reducers/vis-state-updaters.ts @@ -149,7 +149,7 @@ export type LineChart = { xDomain: [number, number]; }; -export type FilterBase = { +export type FilterBase = { dataId: string[]; id: string; @@ -173,7 +173,7 @@ export type FilterBase = { // plot yAxis: Field | null; plotType: string; - lineChart?: LineChart; + lineChart?: L; // gpu filter gpu: boolean; gpuChannel?: number[]; @@ -183,7 +183,7 @@ export type FilterBase = { layerId?: string[]; }; -export type RangeFilter = FilterBase & +export type RangeFilter = FilterBase & RangeFieldDomain & { type: 'range'; fieldType: 'real' | 'integer'; @@ -192,20 +192,20 @@ export type RangeFilter = FilterBase & typeOptions: ['range']; }; -export type SelectFilter = FilterBase & +export type SelectFilter = FilterBase & SelectFieldDomain & { type: 'select'; fieldType: 'boolean'; value: boolean; }; -export type MultiSelectFilter = FilterBase & +export type MultiSelectFilter = FilterBase & MultiSelectFieldDomain & { type: 'range'; fieldType: 'string' | 'date'; value: string[]; }; -export type TimeRangeFilter = FilterBase & +export type TimeRangeFilter = FilterBase & TimeRangeFieldDomain & { type: 'timeRange'; fieldType: 'timestamp'; @@ -218,7 +218,7 @@ export type TimeRangeFilter = FilterBase & animationWindow: string; }; -export type PolygonFilter = FilterBase & { +export type PolygonFilter = FilterBase & { layerId: string[]; type: 'polygon'; fixedDomain: true; @@ -226,7 +226,7 @@ export type PolygonFilter = FilterBase & { }; export type Filter = - | FilterBase + | FilterBase | RangeFilter | TimeRangeFilter | SelectFilter @@ -503,10 +503,10 @@ export const INITIAL_VIS_STATE: VisState = { * Update state with updated layer and layerData * */ -export function updateStateWithLayerAndData( - state: VisState, +export function updateStateWithLayerAndData( + state: S, {layerData, layer, idx}: {layerData?: any; layer: Layer; idx: number} -): VisState { +): S { return { ...state, layers: state.layers.map((lyr, i) => (i === idx ? layer : lyr)), @@ -516,7 +516,7 @@ export function updateStateWithLayerAndData( }; } -export function updateStateOnLayerVisibilityChange(state: VisState, layer: Layer): VisState { +export function updateStateOnLayerVisibilityChange(state: S, layer: Layer): S { let newState = state; if (state.splitMaps.length) { newState = { @@ -539,10 +539,10 @@ export function updateStateOnLayerVisibilityChange(state: VisState, layer: Layer * @memberof visStateUpdaters * @returns nextState */ -export function layerConfigChangeUpdater( - state: VisState, +export function layerConfigChangeUpdater( + state: S, action: VisStateActions.LayerConfigChangeUpdaterAction -): VisState { +): S { const {oldLayer} = action; const idx = state.layers.findIndex(l => l.id === oldLayer.id); const props = Object.keys(action.newConfig); @@ -629,10 +629,10 @@ function updateTextLabelPropAndValue(idx, prop, value, textLabel) { * @memberof visStateUpdaters * @returns nextState */ -export function layerTextLabelChangeUpdater( - state: VisState, +export function layerTextLabelChangeUpdater( + state: S, action: VisStateActions.LayerTextLabelChangeUpdaterAction -): VisState { +): S { const {oldLayer, idx, prop, value} = action; const {textLabel} = oldLayer.config; @@ -666,15 +666,15 @@ function validateExistingLayerWithData(dataset, layerClasses, layer) { * @memberof visStateUpdaters * @returns nextState */ -export function layerDataIdChangeUpdater( - state: VisState, +export function layerDataIdChangeUpdater( + state: S, action: { oldLayer: Layer; newConfig: { dataId: string; }; } -): VisState { +): S { const {oldLayer, newConfig} = action; const {dataId} = newConfig; @@ -755,10 +755,10 @@ function setInitialLayerConfig(layer, datasets, layerClasses) { * @memberof visStateUpdaters * @public */ -export function layerTypeChangeUpdater( - state: VisState, +export function layerTypeChangeUpdater( + state: S, action: VisStateActions.LayerTypeChangeUpdaterAction -): VisState { +): S { const {oldLayer, newType} = action; if (!oldLayer) { return state; @@ -820,10 +820,10 @@ export function layerTypeChangeUpdater( * @returns {Object} nextState * @public */ -export function layerVisualChannelChangeUpdater( - state: VisState, +export function layerVisualChannelChangeUpdater( + state: S, action: VisStateActions.LayerVisualChannelConfigChangeUpdaterAction -): VisState { +): S { const {oldLayer, newConfig, channel} = action; if (!oldLayer.config.dataId) { return state; @@ -846,10 +846,10 @@ export function layerVisualChannelChangeUpdater( * @memberof visStateUpdaters * @public */ -export function layerVisConfigChangeUpdater( - state: VisState, +export function layerVisConfigChangeUpdater( + state: S, action: VisStateActions.LayerVisConfigChangeUpdaterAction -): VisState { +): S { const {oldLayer} = action; const idx = state.layers.findIndex(l => l.id === oldLayer.id); const props = Object.keys(action.newVisConfig); @@ -874,10 +874,10 @@ export function layerVisConfigChangeUpdater( * @memberof visStateUpdaters * @public */ -export function setFilterAnimationTimeUpdater( - state: VisState, +export function setFilterAnimationTimeUpdater( + state: S, action: VisStateActions.SetFilterAnimationTimeUpdaterAction -): VisState { +): S { return setFilterUpdater(state, action); } @@ -886,10 +886,10 @@ export function setFilterAnimationTimeUpdater( * @memberof visStateUpdaters * @public */ -export function setFilterAnimationWindowUpdater( - state: VisState, +export function setFilterAnimationWindowUpdater( + state: S, {id, animationWindow}: VisStateActions.SetFilterAnimationWindowUpdaterAction -): VisState { +): S { return { ...state, filters: state.filters.map(f => @@ -907,10 +907,10 @@ export function setFilterAnimationWindowUpdater( * @memberof visStateUpdaters * @public */ -export function setFilterUpdater( - state: VisState, +export function setFilterUpdater( + state: S, action: VisStateActions.SetFilterUpdaterAction -): VisState { +): S { const {idx, prop, value, valueIndex = 0} = action; const oldFilter = state.filters[idx]; @@ -1043,10 +1043,10 @@ export function setFilterUpdater( * @memberof visStateUpdaters * @public */ -export const setFilterPlotUpdater = ( - state: VisState, +export const setFilterPlotUpdater = ( + state: S, {idx, newProp, valueIndex = 0}: VisStateActions.SetFilterPlotUpdaterAction -): VisState => { +): S => { let newFilter = {...state.filters[idx], ...newProp}; const prop = Object.keys(newProp)[0]; if (prop === 'yAxis') { @@ -1072,10 +1072,10 @@ export const setFilterPlotUpdater = ( * @memberof visStateUpdaters * @public */ -export const addFilterUpdater = ( - state: VisState, +export const addFilterUpdater = ( + state: S, action: VisStateActions.AddFilterUpdaterAction -): VisState => +): S => !action.dataId ? state : { @@ -1087,10 +1087,10 @@ export const addFilterUpdater = ( * Set layer color palette ui state * @memberof visStateUpdaters */ -export const layerColorUIChangeUpdater = ( - state: VisState, +export const layerColorUIChangeUpdater = ( + state: S, {oldLayer, prop, newConfig}: VisStateActions.LayerColorUIChangeUpdaterAction -): VisState => { +): S => { const oldVixConfig = oldLayer.config.visConfig[prop]; const newLayer = oldLayer.updateLayerColorUI(prop, newConfig); const newVisConfig = newLayer.config.visConfig[prop]; @@ -1113,10 +1113,10 @@ export const layerColorUIChangeUpdater = ( * @memberof visStateUpdaters * @public */ -export const toggleFilterAnimationUpdater = ( - state: VisState, +export const toggleFilterAnimationUpdater = ( + state: S, action: VisStateActions.ToggleFilterAnimationUpdaterAction -): VisState => ({ +): S => ({ ...state, filters: state.filters.map((f, i) => (i === action.idx ? {...f, isAnimating: !f.isAnimating} : f)) }); @@ -1125,10 +1125,10 @@ export const toggleFilterAnimationUpdater = ( * @memberof visStateUpdaters * @public */ -export const toggleLayerAnimationUpdater = ( - state: VisState, +export const toggleLayerAnimationUpdater = ( + state: S, action: VisStateActions.ToggleLayerAnimationUpdaterAction -): VisState => ({ +): S => ({ ...state, animationConfig: { ...state.animationConfig, @@ -1141,10 +1141,10 @@ export const toggleLayerAnimationUpdater = ( * @memberof visStateUpdaters * @public */ -export const toggleLayerAnimationControlUpdater = ( - state: VisState, +export const toggleLayerAnimationControlUpdater = ( + state: S, action: VisStateActions.ToggleLayerAnimationControlUpdaterAction -): VisState => ({ +): S => ({ ...state, animationConfig: { ...state.animationConfig, @@ -1157,10 +1157,10 @@ export const toggleLayerAnimationControlUpdater = ( * @memberof visStateUpdaters * @public */ -export const updateFilterAnimationSpeedUpdater = ( - state: VisState, +export const updateFilterAnimationSpeedUpdater = ( + state: S, action: VisStateActions.UpdateFilterAnimationSpeedUpdaterAction -): VisState => ({ +): S => ({ ...state, filters: state.filters.map((f, i) => (i === action.idx ? {...f, speed: action.speed} : f)) }); @@ -1171,10 +1171,10 @@ export const updateFilterAnimationSpeedUpdater = ( * @public * */ -export const setLayerAnimationTimeUpdater = ( - state: VisState, +export const setLayerAnimationTimeUpdater = ( + state: S, {value}: VisStateActions.SetLayerAnimationTimeUpdaterAction -): VisState => ({ +): S => ({ ...state, animationConfig: { ...state.animationConfig, @@ -1188,10 +1188,10 @@ export const setLayerAnimationTimeUpdater = ( * @public * */ -export const updateLayerAnimationSpeedUpdater = ( - state: VisState, +export const updateLayerAnimationSpeedUpdater = ( + state: S, {speed}: VisStateActions.UpdateLayerAnimationSpeedUpdaterAction -): VisState => { +): S => { return { ...state, animationConfig: { @@ -1206,10 +1206,10 @@ export const updateLayerAnimationSpeedUpdater = ( * @memberof visStateUpdaters * @public */ -export const enlargeFilterUpdater = ( - state: VisState, +export const enlargeFilterUpdater = ( + state: S, action: VisStateActions.EnlargeFilterUpdaterAction -): VisState => { +): S => { return { ...state, filters: state.filters.map((f, i) => @@ -1227,10 +1227,10 @@ export const enlargeFilterUpdater = ( * Toggles filter feature visibility * @memberof visStateUpdaters */ -export const toggleFilterFeatureUpdater = ( - state: VisState, +export const toggleFilterFeatureUpdater = ( + state: S, action: VisStateActions.ToggleFilterFeatureUpdaterAction -): VisState => { +): S => { const filter = state.filters[action.idx]; const isVisible = get(filter, ['value', 'properties', 'isVisible']); const newFilter = { @@ -1251,10 +1251,10 @@ export const toggleFilterFeatureUpdater = ( * @memberof visStateUpdaters * @public */ -export const removeFilterUpdater = ( - state: VisState, +export const removeFilterUpdater = ( + state: S, action: VisStateActions.RemoveFilterUpdaterAction -): VisState => { +): S => { const {idx} = action; const {dataId, id} = state.filters[idx]; @@ -1284,10 +1284,10 @@ export const removeFilterUpdater = ( * @memberof visStateUpdaters * @public */ -export const addLayerUpdater = ( - state: VisState, +export const addLayerUpdater = ( + state: S, action: VisStateActions.AddLayerUpdaterAction -): VisState => { +): S => { let newLayer; let newLayerData; if (action.config) { @@ -1327,10 +1327,10 @@ export const addLayerUpdater = ( * @memberof visStateUpdaters * @public */ -export const removeLayerUpdater = ( - state: VisState, +export const removeLayerUpdater = ( + state: S, {idx}: VisStateActions.RemoveLayerUpdaterAction -): VisState => { +): S => { const {layers, layerData, clicked, hoverInfo} = state; const layerToRemove = state.layers[idx]; const newMaps = removeLayerFromSplitMaps(state.splitMaps, layerToRemove); @@ -1354,10 +1354,10 @@ export const removeLayerUpdater = ( * @memberof visStateUpdaters * @public */ -export const duplicateLayerUpdater = ( - state: VisState, +export const duplicateLayerUpdater = ( + state: S, {idx}: VisStateActions.DuplicateLayerUpdaterAction -): VisState => { +): S => { const {layers} = state; const original = state.layers[idx]; const originalLayerOrderIdx = state.layerOrder.findIndex(i => i === idx); @@ -1407,10 +1407,10 @@ export const duplicateLayerUpdater = ( * @memberof visStateUpdaters * @public */ -export const reorderLayerUpdater = ( - state: VisState, +export const reorderLayerUpdater = ( + state: S, {order}: VisStateActions.ReorderLayerUpdaterAction -): VisState => ({ +): S => ({ ...state, layerOrder: order }); @@ -1420,10 +1420,10 @@ export const reorderLayerUpdater = ( * @memberof visStateUpdaters * @public */ -export const removeDatasetUpdater = ( - state: VisState, +export const removeDatasetUpdater = ( + state: S, action: VisStateActions.RemoveDatasetUpdaterAction -): VisState => { +): S => { // extract dataset key const {dataId: datasetKey} = action; const {datasets} = state; @@ -1484,10 +1484,10 @@ export const removeDatasetUpdater = ( * @memberof visStateUpdaters * @public */ -export const updateLayerBlendingUpdater = ( - state: VisState, +export const updateLayerBlendingUpdater = ( + state: S, action: VisStateActions.UpdateLayerBlendingUpdaterAction -): VisState => ({ +): S => ({ ...state, layerBlending: action.mode }); @@ -1497,10 +1497,10 @@ export const updateLayerBlendingUpdater = ( * @memberof visStateUpdaters * @public */ -export const showDatasetTableUpdater = ( - state: VisState, +export const showDatasetTableUpdater = ( + state: S, action: VisStateActions.ShowDatasetTableUpdaterAction -): VisState => { +): S => { return { ...state, editingDataset: action.dataId @@ -1539,26 +1539,27 @@ export const updateTableColorUpdater = ( * @memberof visStateUpdaters * @public */ -export const resetMapConfigUpdater = (state: VisState): VisState => ({ - ...INITIAL_VIS_STATE, - ...state.initialState, - initialState: state.initialState -}); +export const resetMapConfigUpdater = (state: S): S => + ({ + ...INITIAL_VIS_STATE, + ...state.initialState, + initialState: state.initialState + } as S); /** * Propagate `visState` reducer with a new configuration. Current config will be override. * @memberof visStateUpdaters * @public */ -export const receiveMapConfigUpdater = ( - state: VisState, +export const receiveMapConfigUpdater = ( + state: S, { payload: {config = {version: ''}, options = {}} }: { type?: typeof ActionTypes.RECEIVE_MAP_CONFIG; payload: ReceiveMapConfigPayload; } -): VisState => { +): S => { if (!config.visState) { return state; } @@ -1581,10 +1582,10 @@ export const receiveMapConfigUpdater = ( * @memberof visStateUpdaters * @public */ -export const layerHoverUpdater = ( - state: VisState, +export const layerHoverUpdater = ( + state: S, action: VisStateActions.OnLayerHoverUpdaterAction -): VisState => ({ +): S => ({ ...state, hoverInfo: { // deck.gl info is mutable @@ -1599,10 +1600,10 @@ export const layerHoverUpdater = ( * @memberof visStateUpdaters * @public */ -export function interactionConfigChangeUpdater( - state: VisState, +export function interactionConfigChangeUpdater( + state: S, action: VisStateActions.InteractionConfigChangeUpdaterAction -): VisState { +): S { const {config} = action; const interactionConfig = { @@ -1644,10 +1645,10 @@ export function interactionConfigChangeUpdater( * @memberof visStateUpdaters * @public */ -export const layerClickUpdater = ( - state: VisState, +export const layerClickUpdater = ( + state: S, action: VisStateActions.OnLayerClickUpdaterAction -): VisState => ({ +): S => ({ ...state, mousePos: state.interactionConfig.coordinate.enabled ? { @@ -1663,10 +1664,10 @@ export const layerClickUpdater = ( * @memberof visStateUpdaters * @public */ -export const mapClickUpdater = ( - state: VisState, +export const mapClickUpdater = ( + state: S, action: VisStateActions.OnMapClickUpdaterAction -): VisState => { +): S => { return { ...state, clicked: null @@ -1678,10 +1679,10 @@ export const mapClickUpdater = ( * @memberof visStateUpdaters * @public */ -export const mouseMoveUpdater = ( - state: VisState, +export const mouseMoveUpdater = ( + state: S, {evt}: VisStateActions.OnMouseMoveUpdaterAction -): VisState => { +): S => { if (Object.values(state.interactionConfig).some(config => config.enabled)) { return { ...state, @@ -1700,10 +1701,10 @@ export const mouseMoveUpdater = ( * @memberof visStateUpdaters * @public */ -export const toggleSplitMapUpdater = ( - state: VisState, +export const toggleSplitMapUpdater = ( + state: S, action: MapStateActions.ToggleSplitMapUpdaterAction -): VisState => +): S => state.splitMaps && state.splitMaps.length === 0 ? { ...state, @@ -1718,10 +1719,10 @@ export const toggleSplitMapUpdater = ( * @memberof visStateUpdaters * @public */ -export const toggleLayerForMapUpdater = ( - state: VisState, +export const toggleLayerForMapUpdater = ( + state: S, {mapIndex, layerId}: VisStateActions.ToggleLayerForMapUpdaterAction -): VisState => { +): S => { const {splitMaps} = state; return { @@ -1748,10 +1749,10 @@ export const toggleLayerForMapUpdater = ( */ /* eslint-disable max-statements */ // eslint-disable-next-line complexity -export const updateVisDataUpdater = ( - state: VisState, +export const updateVisDataUpdater = ( + state: S, action: VisStateActions.UpdateVisDataUpdaterAction -): VisState => { +): S => { // datasets can be a single data entries or an array of multiple data entries const {config, options} = action; const datasets = toArray(action.datasets); @@ -1839,10 +1840,10 @@ export const updateVisDataUpdater = ( * @memberof visStateUpdaters * @public */ -export function renameDatasetUpdater( - state: VisState, +export function renameDatasetUpdater( + state: S, action: VisStateActions.RenameDatasetUpdaterAction -): VisState { +): S { const {dataId, label} = action; const {datasets} = state; const existing = datasets[dataId]; @@ -1871,10 +1872,10 @@ export function renameDatasetUpdater( * @param {Object} action action * @returns {Object} nextState */ -export function closeSpecificMapAtIndex( - state: VisState, +export function closeSpecificMapAtIndex( + state: S, action: MapStateActions.ToggleSplitMapUpdaterAction -): VisState { +): S { // retrieve layers meta data from the remaining map that we need to keep const indexToRetrieve = 1 - action.payload; const mapLayers = state.splitMaps[indexToRetrieve].layers; @@ -1903,10 +1904,10 @@ export function closeSpecificMapAtIndex( * @memberof visStateUpdaters * @public */ -export const loadFilesUpdater = ( - state: VisState, +export const loadFilesUpdater = ( + state: S, action: VisStateActions.LoadFilesUpdaterAction -): VisState => { +): S => { const {files, onFinish = loadFilesSuccess} = action; if (!files.length) { return state; @@ -1933,10 +1934,10 @@ export const loadFilesUpdater = ( * @memberof visStateUpdaters * @public */ -export function loadFileStepSuccessUpdater( - state: VisState, +export function loadFileStepSuccessUpdater( + state: S, action: VisStateActions.LoadFileStepSuccessAction -): VisState { +): S { if (!state.fileLoading) { return state; } @@ -1963,7 +1964,7 @@ export function loadFileStepSuccessUpdater( * @memberof visStateUpdaters * @public */ -export function loadNextFileUpdater(state: VisState): VisState { +export function loadNextFileUpdater(state: S): S { if (!state.fileLoading) { return state; } @@ -2015,10 +2016,10 @@ export function makeLoadFileTask(file, fileCache, loaders: LoaderObject[] = [], * @memberof visStateUpdaters * @public */ -export function processFileContentUpdater( - state: VisState, +export function processFileContentUpdater( + state: S, action: VisStateActions.ProcessFileContentUpdaterAction -): VisState { +): S { const {content, fileCache} = action.payload; const stateWithProgress = updateFileLoadingProgressUpdater(state, { @@ -2052,12 +2053,12 @@ export function parseProgress(prevProgress = {}, progress) { * @memberof visStateUpdaters * @public */ -export const nextFileBatchUpdater = ( - state: VisState, +export const nextFileBatchUpdater = ( + state: S, { payload: {gen, fileName, progress, accumulated, onFinish} }: VisStateActions.NextFileBatchUpdaterAction -): VisState => { +): S => { const stateWithProgress = updateFileLoadingProgressUpdater(state, { fileName, progress: parseProgress(state.fileLoadingProgress[fileName], progress) @@ -2086,10 +2087,10 @@ export const nextFileBatchUpdater = ( * @memberof visStateUpdaters * @public */ -export const loadFilesErrUpdater = ( - state: VisState, +export const loadFilesErrUpdater = ( + state: S, {error, fileName}: VisStateActions.LoadFilesErrUpdaterAction -): VisState => { +): S => { // update ui with error message Console.warn(error); if (!state.fileLoading) { @@ -2114,10 +2115,10 @@ export const loadFilesErrUpdater = ( * @memberof visStateUpdaters * @public */ -export const applyCPUFilterUpdater = ( - state: VisState, +export const applyCPUFilterUpdater = ( + state: S, {dataId}: VisStateActions.ApplyCPUFilterUpdaterAction -): VisState => { +): S => { // apply cpuFilter const dataIds = toArray(dataId); @@ -2129,10 +2130,10 @@ export const applyCPUFilterUpdater = ( * @memberof visStateUpdaters * @public */ -export const setMapInfoUpdater = ( - state: VisState, +export const setMapInfoUpdater = ( + state: S, action: VisStateActions.SetMapInfoUpdaterAction -): VisState => ({ +): S => ({ ...state, mapInfo: { ...state.mapInfo, @@ -2142,10 +2143,10 @@ export const setMapInfoUpdater = ( /** * Helper function to update All layer domain and layer data of state */ -export function addDefaultLayers( - state: VisState, +export function addDefaultLayers( + state: S, datasets: Datasets -): {state: VisState; newLayers: Layer[]} { +): {state: S; newLayers: Layer[]} { const empty: Layer[] = []; const defaultLayers = Object.values(datasets).reduce((accu, dataset) => { const foundLayers = findDefaultLayer(dataset, state.layerClasses); @@ -2205,11 +2206,11 @@ export function updateFileLoadingProgressUpdater(state, {fileName, progress}) { /** * Helper function to update layer domains for an array of datasets */ -export function updateAllLayerDomainData( - state: VisState, +export function updateAllLayerDomainData( + state: S, dataId: string | string[], updatedFilter?: Filter -): VisState { +): S { const dataIds = typeof dataId === 'string' ? [dataId] : dataId; const newLayers: Layer[] = []; const newLayerData: any[] = []; @@ -2241,14 +2242,14 @@ export function updateAllLayerDomainData( return newState; } -export function updateAnimationDomain(state: VisState): VisState { +export function updateAnimationDomain(state: S): S { // merge all animatable layer domain and update global config const animatableLayers = state.layers.filter( l => l.config.isVisible && l.config.animation && l.config.animation.enabled && - // @ts-expect-error + // @ts-expect-error trip-layer-only Array.isArray(l.animationDomain) ); @@ -2265,9 +2266,9 @@ export function updateAnimationDomain(state: VisState): VisState { const mergedDomain: [number, number] = animatableLayers.reduce( (accu, layer) => [ - // @ts-expect-error + // @ts-expect-error trip-layer-only Math.min(accu[0], layer.animationDomain[0]), - // @ts-expect-error + // @ts-expect-error trip-layer-only Math.max(accu[1], layer.animationDomain[1]) ], [Number(Infinity), -Infinity] @@ -2291,10 +2292,10 @@ export function updateAnimationDomain(state: VisState): VisState { * Update the status of the editor * @memberof visStateUpdaters */ -export const setEditorModeUpdater = ( - state: VisState, +export const setEditorModeUpdater = ( + state: S, {mode}: VisStateActions.SetEditorModeUpdaterAction -): VisState => ({ +): S => ({ ...state, editor: { ...state.editor, @@ -2308,10 +2309,10 @@ export const setEditorModeUpdater = ( * Update editor features * @memberof visStateUpdaters */ -export function setFeaturesUpdater( - state: VisState, +export function setFeaturesUpdater( + state: S, {features = []}: VisStateActions.SetFeaturesUpdaterAction -): VisState { +): S { const lastFeature = features.length && features[features.length - 1]; const newState = { @@ -2340,6 +2341,7 @@ export function setFeaturesUpdater( if (filterId && feature) { const featureValue = featureToFilterValue(feature, filterId); const filterIdx = state.filters.findIndex(fil => fil.id === filterId); + // @ts-ignore return setFilterUpdater(newState, { idx: filterIdx, prop: 'value', @@ -2354,10 +2356,10 @@ export function setFeaturesUpdater( * Set the current selected feature * @memberof uiStateUpdaters */ -export const setSelectedFeatureUpdater = ( - state: VisState, +export const setSelectedFeatureUpdater = ( + state: S, {feature}: VisStateActions.SetSelectedFeatureUpdaterAction -): VisState => ({ +): S => ({ ...state, editor: { ...state.editor, @@ -2369,10 +2371,10 @@ export const setSelectedFeatureUpdater = ( * Delete existing feature from filters * @memberof visStateUpdaters */ -export function deleteFeatureUpdater( - state: VisState, +export function deleteFeatureUpdater( + state: S, {feature}: VisStateActions.DeleteFeatureUpdaterAction -): VisState { +): S { if (!feature) { return state; } @@ -2408,10 +2410,10 @@ export function deleteFeatureUpdater( * Toggle feature as layer filter * @memberof visStateUpdaters */ -export function setPolygonFilterLayerUpdater( - state: VisState, +export function setPolygonFilterLayerUpdater( + state: S, payload: VisStateActions.SetPolygonFilterLayerUpdaterAction -): VisState { +): S { const {layer, feature} = payload; const filterId = getFilterIdInFeature(feature); @@ -2480,10 +2482,10 @@ export function setPolygonFilterLayerUpdater( * @memberof visStateUpdaters * @public */ -export function sortTableColumnUpdater( - state: VisState, +export function sortTableColumnUpdater( + state: S, {dataId, column, mode}: VisStateActions.SortTableColumnUpdaterAction -): VisState { +): S { const dataset = state.datasets[dataId]; if (!dataset) { return state; @@ -2505,10 +2507,10 @@ export function sortTableColumnUpdater( * @memberof visStateUpdaters * @public */ -export function pinTableColumnUpdater( - state: VisState, +export function pinTableColumnUpdater( + state: S, {dataId, column}: VisStateActions.PinTableColumnUpdaterAction -): VisState { +): S { const dataset = state.datasets[dataId]; if (!dataset) { return state; @@ -2523,10 +2525,10 @@ export function pinTableColumnUpdater( * @memberof visStateUpdaters * @public */ -export function copyTableColumnUpdater( - state: VisState, +export function copyTableColumnUpdater( + state: S, {dataId, column}: VisStateActions.CopyTableColumnUpdaterAction -): VisState { +): S { const dataset = state.datasets[dataId]; if (!dataset) { return state; @@ -2548,10 +2550,10 @@ export function copyTableColumnUpdater( /** * Update editor */ -export function toggleEditorVisibilityUpdater( - state: VisState, +export function toggleEditorVisibilityUpdater( + state: S, action: VisStateActions.ToggleEditorVisibilityUpdaterAction -): VisState { +): S { return { ...state, editor: { @@ -2561,10 +2563,10 @@ export function toggleEditorVisibilityUpdater( }; } -export function setFilterAnimationTimeConfigUpdater( - state: VisState, +export function setFilterAnimationTimeConfigUpdater( + state: S, {idx, config}: VisStateActions.SetFilterAnimationTimeConfigAction -): VisState { +): S { const oldFilter = state.filters[idx]; if (!oldFilter) { Console.error(`filters.${idx} is undefined`); @@ -2600,10 +2602,10 @@ function checkTimeConfigArgs(config) { /** * Update editor */ -export function setLayerAnimationTimeConfigUpdater( - state: VisState, +export function setLayerAnimationTimeConfigUpdater( + state: S, {config}: VisStateActions.SetLayerAnimationTimeConfigAction -): VisState { +): S { if (!config) { return state; } diff --git a/src/utils/filter-utils.ts b/src/utils/filter-utils.ts index 3708d97b4e..af8f9c8521 100644 --- a/src/utils/filter-utils.ts +++ b/src/utils/filter-utils.ts @@ -157,7 +157,7 @@ export const LAYER_FILTERS = [FILTER_TYPES.polygon]; /** * Generates a filter with a dataset id as dataId */ -export function getDefaultFilter(dataId: string | null | string[]): FilterBase { +export function getDefaultFilter(dataId: string | null | string[]): FilterBase { return { ...DEFAULT_FILTER_STRUCTURE, // store it as dataId and it could be one or many @@ -492,7 +492,7 @@ export function getFilterFunction( } } -export function updateFilterDataId(dataId: string): FilterBase { +export function updateFilterDataId(dataId: string): FilterBase { return getDefaultFilter(dataId); } @@ -1090,13 +1090,13 @@ export function filterDatasetCPU(state: VisState, dataId: string): VisState { /** * Validate parsed filters with datasets and add filterProps to field */ -export function validateFiltersUpdateDatasets( - state: VisState, +export function validateFiltersUpdateDatasets( + state: S, filtersToValidate: ParsedFilter[] = [] ): { validated: Filter[]; failed: Filter[]; - updatedDatasets: Datasets; + updatedDatasets: S['datasets']; } { // TODO Better Typings here const validated: any[] = []; diff --git a/src/utils/index.ts b/src/utils/index.ts index 42e2eba038..62a001ab0e 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -56,6 +56,8 @@ export {getHexFields, containValidTime} from '@kepler.gl/layers'; export { default as KeplerTable, findPointFieldPairs, + getFieldValueAccessor, + copyTable, copyTableAndUpdate } from './table-utils/kepler-table'; export {createDataContainer, createIndexedDataContainer} from './table-utils/data-container-utils'; diff --git a/src/utils/table-utils/kepler-table.ts b/src/utils/table-utils/kepler-table.ts index 62917f1572..b45f34f8d5 100644 --- a/src/utils/table-utils/kepler-table.ts +++ b/src/utils/table-utils/kepler-table.ts @@ -175,15 +175,7 @@ class KeplerTable { fieldIdx: i, id: f.name, displayName: f.displayName || f.name, - // @ts-expect-error - valueAccessor: maybeToDate.bind( - null, - // is time - f.type === ALL_FIELD_TYPES.timestamp, - i, - f.format, - dataContainer - ) + valueAccessor: getFieldValueAccessor(f, i, dataContainer) })); const allIndexes = dataContainer.getPlainIndex(); @@ -596,7 +588,7 @@ export function pinTableColumns(dataset: KeplerTable, column: string): KeplerTab // @ts-ignore return copyTableAndUpdate(dataset, {pinnedColumns}); } -export function copyTable(original: T): T { +export function copyTable(original: T): T { return Object.assign(Object.create(Object.getPrototypeOf(original)), original); } @@ -604,11 +596,30 @@ export function copyTable(original: T): T { * @type * @returns */ -export function copyTableAndUpdate(original: T, options: Partial = {}): T { +export function copyTableAndUpdate( + original: T, + options: Partial = {} +): T { return Object.entries(options).reduce((acc, entry) => { acc[entry[0]] = entry[1]; return acc; }, copyTable(original)); } +export function getFieldValueAccessor< + F extends { + type?: Field['type']; + format?: Field['format']; + } +>(f: F, i: number, dc: DataContainerInterface) { + return maybeToDate.bind( + null, + // is time + f.type === ALL_FIELD_TYPES.timestamp, + i, + f.format || '', + dc + ); +} + export default KeplerTable; diff --git a/test/helpers/comparison-utils.js b/test/helpers/comparison-utils.js index cbb518a285..9b11c86b47 100644 --- a/test/helpers/comparison-utils.js +++ b/test/helpers/comparison-utils.js @@ -43,7 +43,7 @@ export function cmpFilters(t, expectedFilter, actualFilter, opt = {}, idx = '', `${name} should have same number of filters` ); expectedFilter.forEach((f, i) => { - cmpFilters(t, expectedFilter[i], actualFilter[i], opt, i, name); + cmpFilters(t, expectedFilter[i], actualFilter[i], opt, String(i), name); }); } else { cmpObjectKeys( @@ -163,7 +163,7 @@ export function cmpSavedLayers(t, expectedLayer, actualLayer, opt = {}, idx = '' if (Array.isArray(expectedLayer) && Array.isArray(actualLayer)) { t.equal(actualLayer.length, expectedLayer.length, 'should have same number of layers'); expectedLayer.forEach((_, i) => { - cmpSavedLayers(t, expectedLayer[i], actualLayer[i], opt, i); + cmpSavedLayers(t, expectedLayer[i], actualLayer[i], opt, String(i)); }); } else { cmpObjectKeys(t, expectedLayer, actualLayer, `idx:${idx} | layer.${actualLayer.type}`); @@ -332,7 +332,7 @@ export function cmpInteraction(t, expectedInt, actualInt) { }); } -export function cmpParsedAppConfigs(t, expectedConfig, actualConfig, {name} = {}) { +export function cmpParsedAppConfigs(t, expectedConfig, actualConfig, {name = ''} = {}) { t.deepEqual(actualConfig, expectedConfig, `${name} should be expected`); Object.keys(actualConfig).forEach(key => { diff --git a/yarn.lock b/yarn.lock index fc98cdfebd..109b871c29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5197,12 +5197,7 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= -d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" - integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== - -d3-array@^2.3.0, d3-array@^2.8.0: +d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0, d3-array@^2.3.0, d3-array@^2.8.0: version "2.12.1" resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==