Skip to content

Commit

Permalink
[Bug] do not display geocoder dataset in side panel
Browse files Browse the repository at this point in the history
Signed-off-by: hodoje <nikolakaraklic@gmail.com>
  • Loading branch information
hodoje committed Dec 13, 2021
1 parent a20db97 commit 22ea7a9
Show file tree
Hide file tree
Showing 9 changed files with 294 additions and 40 deletions.
18 changes: 11 additions & 7 deletions src/components/geocoder-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ function isValid(key) {
return /pk\..*\..*/.test(key);
}

export function getUpdateVisDataPayload(lat, lon, text) {
return [
[generateGeocoderDataset(lat, lon, text)],
{
keepExistingConfig: true
},
PARSED_CONFIG
];
}

export default function GeocoderPanelFactory() {
class GeocoderPanel extends Component {
static propTypes = {
Expand All @@ -122,13 +132,7 @@ export default function GeocoderPanelFactory() {
bbox
} = geoItem;
this.removeGeocoderDataset();
this.props.updateVisData(
[generateGeocoderDataset(lat, lon, text)],
{
keepExistingConfig: true
},
PARSED_CONFIG
);
this.props.updateVisData(...getUpdateVisDataPayload(lat, lon, text));
const bounds = bbox || [
lon - GEOCODER_GEO_OFFSET,
lat - GEOCODER_GEO_OFFSET,
Expand Down
59 changes: 35 additions & 24 deletions src/components/kepler-gl.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ import {
KEPLER_GL_NAME,
KEPLER_GL_VERSION,
THEME,
DEFAULT_MAPBOX_API_URL
DEFAULT_MAPBOX_API_URL,
GEOCODER_DATASET_NAME
} from 'constants/default-settings';
import {MISSING_MAPBOX_TOKEN} from 'constants/user-feedbacks';

Expand All @@ -52,7 +53,7 @@ import PlotContainerFactory from './plot-container';
import NotificationPanelFactory from './notification-panel';
import GeoCoderPanelFactory from './geocoder-panel';

import {generateHashId} from 'utils/utils';
import {filterObjectByPredicate, generateHashId} from 'utils/utils';
import {validateToken} from 'utils/mapbox-utils';
import {mergeMessages} from 'utils/locale-utils';

Expand Down Expand Up @@ -138,30 +139,40 @@ export const mapFieldsSelector = props => ({
locale: props.uiState.locale
});

export const sidePanelSelector = (props, availableProviders) => ({
appName: props.appName,
version: props.version,
appWebsite: props.appWebsite,
mapStyle: props.mapStyle,
onSaveMap: props.onSaveMap,
uiState: props.uiState,
mapStyleActions: props.mapStyleActions,
visStateActions: props.visStateActions,
uiStateActions: props.uiStateActions,
export function getVisibleDatasets(datasets) {
// We don't want Geocoder dataset to be present in SidePanel dataset list
return filterObjectByPredicate(datasets, (key, value) => key !== GEOCODER_DATASET_NAME);
}

datasets: props.visState.datasets,
filters: props.visState.filters,
layers: props.visState.layers,
layerOrder: props.visState.layerOrder,
layerClasses: props.visState.layerClasses,
interactionConfig: props.visState.interactionConfig,
mapInfo: props.visState.mapInfo,
layerBlending: props.visState.layerBlending,
export const sidePanelSelector = (props, availableProviders) => {
// visibleDatasets
const filteredDatasets = getVisibleDatasets(props.visState.datasets);

width: props.sidePanelWidth,
availableProviders,
mapSaved: props.providerState.mapSaved
});
return {
appName: props.appName,
version: props.version,
appWebsite: props.appWebsite,
mapStyle: props.mapStyle,
onSaveMap: props.onSaveMap,
uiState: props.uiState,
mapStyleActions: props.mapStyleActions,
visStateActions: props.visStateActions,
uiStateActions: props.uiStateActions,

datasets: filteredDatasets,
filters: props.visState.filters,
layers: props.visState.layers,
layerOrder: props.visState.layerOrder,
layerClasses: props.visState.layerClasses,
interactionConfig: props.visState.interactionConfig,
mapInfo: props.visState.mapInfo,
layerBlending: props.visState.layerBlending,

width: props.sidePanelWidth,
availableProviders,
mapSaved: props.providerState.mapSaved
};
};

export const plotContainerSelector = props => ({
width: props.width,
Expand Down
19 changes: 11 additions & 8 deletions src/components/side-panel/interaction-panel/tooltip-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import Switch from 'components/common/switch';
import ItemSelector from 'components/common/item-selector/item-selector';
import {COMPARE_TYPES} from 'constants/tooltip';
import FieldSelectorFactory from '../../common/field-selector';
import {GEOCODER_DATASET_NAME} from 'constants/default-settings';

const TooltipConfigWrapper = styled.div`
.item-selector > div > div {
Expand Down Expand Up @@ -131,14 +132,16 @@ function TooltipConfigFactory(DatasetTag, FieldSelector) {
const TooltipConfig = ({config, datasets, onChange, intl}) => {
return (
<TooltipConfigWrapper>
{Object.keys(config.fieldsToShow).map(dataId => (
<DatasetTooltipConfig
key={dataId}
config={config}
onChange={onChange}
dataset={datasets[dataId]}
/>
))}
{Object.keys(config.fieldsToShow).map(dataId =>
dataId === GEOCODER_DATASET_NAME ? null : (
<DatasetTooltipConfig
key={dataId}
config={config}
onChange={onChange}
dataset={datasets[dataId]}
/>
)
)}
<CompareSwitchWrapper>
<FormattedMessage id="compare.modeLabel" />
<Switch
Expand Down
14 changes: 14 additions & 0 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,17 @@ export function arrayInsert(arr, index, val) {
export function isTest() {
return process?.env?.NODE_ENV === 'test';
}

/**
* Filters an object by an arbitrary predicate
* Returns a new object containing all elements that match the predicate
* @param {Object} obj Object to be filtered
* @param {Function} predicate Predicate by which the object will be filtered
* @returns {Object}
*/
export function filterObjectByPredicate(obj, predicate) {
return Object.entries(obj).reduce(
(acc, entry) => (predicate(entry[0], entry[1]) ? {...acc, [entry[0]]: entry[1]} : acc),
{}
);
}
99 changes: 99 additions & 0 deletions test/browser/components/kepler-gl-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import React from 'react';
import test from 'tape';
import {mount} from 'enzyme';
import sinon from 'sinon';
import {drainTasksForTesting, succeedTaskWithValues} from 'react-palm/tasks';
import configureStore from 'redux-mock-store';
import {Provider} from 'react-redux';
Expand All @@ -40,6 +41,9 @@ import {
import NotificationPanelFactory from 'components/notification-panel';
import {ActionTypes} from 'actions';
import {DEFAULT_MAP_STYLES, EXPORT_IMAGE_ID} from 'constants';
import {GEOCODER_DATASET_NAME} from 'constants/default-settings';
// mock state
import {StateWithGeocoderDataset} from 'test/helpers/mock-state';

const KeplerGl = appInjector.get(KeplerGlFactory);
const SidePanel = appInjector.get(SidePanelFactory);
Expand Down Expand Up @@ -474,3 +478,98 @@ test('Components -> KeplerGl -> Mount -> Load custom map style task', t => {

t.end();
});

// Test data has only the 'geocoder_dataset' dataset
// This function will return its name if it finds the dataset
// in other case it will return null
function findGeocoderDatasetName(wrapper) {
const datasetTitleContainer = wrapper.find('.dataset-name');
let result;
try {
result = datasetTitleContainer.text();
} catch (e) {
result = null;
}
return result;
}

test('Components -> KeplerGl -> SidePanel -> Geocoder dataset display', t => {
drainTasksForTesting();

const toggleSidePanel = sinon.spy();

// Create custom SidePanel that will accept toggleSidePanel as a spy
function CustomSidePanelFactory(...deps) {
const OriginalSidePanel = SidePanelFactory(...deps);
const CustomSidePanel = props => {
const customUIStateActions = {
...props.uiStateActions,
toggleSidePanel
};
return <OriginalSidePanel {...props} uiStateActions={customUIStateActions} />;
};
return CustomSidePanel;
}
CustomSidePanelFactory.deps = SidePanelFactory.deps;

const CustomKeplerGl = appInjector
.provide(SidePanelFactory, CustomSidePanelFactory)
.get(KeplerGlFactory);

// Create initial state based on mocked state with geocoder dataset and use that for mocking the store
const store = mockStore({
keplerGl: {
map: StateWithGeocoderDataset
}
});

let wrapper;

t.doesNotThrow(() => {
wrapper = mount(
<Provider store={store}>
<CustomKeplerGl
id="map"
mapboxApiAccessToken="smoothie-the-cat"
selector={state => state.keplerGl.map}
dispatch={store.dispatch}
/>
</Provider>
);
}, 'Should not throw error when mount KeplerGl');

// Check if we have 4 sidepanel tabs
t.equal(wrapper.find('.side-panel__tab').length, 4, 'should render 4 panel tabs');

// click layer tab
const layerTab = wrapper.find('.side-panel__tab').at(0);
layerTab.simulate('click');
t.ok(toggleSidePanel.calledWith('layer'), 'should call toggleSidePanel with layer');
t.notEqual(
findGeocoderDatasetName(wrapper),
GEOCODER_DATASET_NAME,
`should not be equal to ${GEOCODER_DATASET_NAME}`
);

// click filters tab
const filterTab = wrapper.find('.side-panel__tab').at(1);
filterTab.simulate('click');
t.ok(toggleSidePanel.calledWith('filter'), 'should call toggleSidePanel with filter');
t.notEqual(
findGeocoderDatasetName(wrapper),
GEOCODER_DATASET_NAME,
`should not be equal to ${GEOCODER_DATASET_NAME}`
);

// click interaction tab
const interactionTab = wrapper.find('.side-panel__tab').at(2);
interactionTab.simulate('click');
t.ok(toggleSidePanel.calledWith('interaction'), 'should call toggleSidePanel with interaction');
t.notEqual(
findGeocoderDatasetName(wrapper),
GEOCODER_DATASET_NAME,
`should not be equal to ${GEOCODER_DATASET_NAME}`
);

t.end();
});
28 changes: 27 additions & 1 deletion test/browser/components/tooltip-config-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import DropdownList from 'components/common/item-selector/dropdown-list';
import Typeahead from 'components/common/item-selector/typeahead';

import {Hash, Delete} from 'components/common/icons';
import {StateWFiles} from 'test/helpers/mock-state';
import {StateWFiles, StateWithGeocoderDataset} from 'test/helpers/mock-state';
import {appInjector} from 'components/container';

const TooltipConfig = appInjector.get(TooltipConfigFactory);
Expand Down Expand Up @@ -252,3 +252,29 @@ test('TooltipConfig - render -> tooltip format', t => {
t.deepEqual(onChange.args[0], [expectedArgs0], 'should call onchange to set format');
t.end();
});

test('TooltipConfig -> render -> do not display Geocoder dataset fields', t => {
// Contains only a single dataset which is the geocoder_dataset
const datasets = StateWithGeocoderDataset.visState.datasets;
const tooltipConfig = StateWithGeocoderDataset.visState.interactionConfig.tooltip.config;

const FieldSelector = appInjector.get(FieldSelectorFactory);
const onChange = sinon.spy();
let wrapper;

t.doesNotThrow(() => {
wrapper = mountWithTheme(
<IntlWrapper>
<TooltipConfig onChange={onChange} config={tooltipConfig} datasets={datasets} />
</IntlWrapper>
);
}, 'Should render');

// Since only the geocoder_dataset is present, nothing should be rendered except the TooltipConfig
t.equal(wrapper.find(TooltipConfig).length, 1, 'Should render 1 TooltipConfig');
t.equal(wrapper.find(DatasetTag).length, 0, 'Should render 1 DatasetTag');
t.equal(wrapper.find(FieldSelector).length, 0, 'Should render 1 FieldSelector');
t.equal(wrapper.find(ChickletedInput).length, 0, 'Should render 1 ChickletedInput');

t.end();
});
48 changes: 48 additions & 0 deletions test/helpers/mock-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import tripGeojson, {tripDataInfo} from 'test/fixtures/trip-geojson';
import {processCsvData, processGeojson} from 'processors/data-processor';
import {COMPARE_TYPES} from 'constants/tooltip';
import {MOCK_MAP_STYLE} from './mock-map-styles';
import {getUpdateVisDataPayload} from 'components/geocoder-panel';

const geojsonFields = cloneDeep(fields);
const geojsonRows = cloneDeep(rows);
Expand Down Expand Up @@ -457,6 +458,52 @@ function mockStateWithTooltipFormat() {
return prepareState;
}

function mockStateWithGeocoderDataset() {
const initialState = cloneDeep(InitialState);

const oldInteractionConfig = initialState.visState.interactionConfig.tooltip;
const newInteractionConfig = {
...oldInteractionConfig,
config: {
...oldInteractionConfig.config,
fieldsToShow: {
...oldInteractionConfig.config.fieldsToShow,
geocoder_dataset: [
{
name: 'lt',
format: null
},
{
name: 'ln',
format: null
},
{
name: 'icon',
format: null
},
{
name: 'text',
format: null
}
]
},
compareMode: false,
compareType: COMPARE_TYPES.ABSOLUTE
}
};
const geocoderDataset = getUpdateVisDataPayload(48.85658, 2.35183, 'Paris');

const prepareState = applyActions(keplerGlReducer, initialState, [
{
action: VisStateActions.updateVisData,
payload: geocoderDataset
},
{action: VisStateActions.interactionConfigChange, payload: [newInteractionConfig]}
]);

return prepareState;
}

// saved hexagon layer
export const expectedSavedLayer0 = {
id: 'hexagon-2',
Expand Down Expand Up @@ -747,6 +794,7 @@ export const StateWTrips = mockStateWithTripData();
export const StateWTripGeojson = mockStateWithTripGeojson();
export const StateWTooltipFormat = mockStateWithTooltipFormat();
export const StateWH3Layer = mockStateWithH3Layer();
export const StateWithGeocoderDataset = mockStateWithGeocoderDataset();

export const expectedSavedTripLayer = {
id: 'trip-0',
Expand Down
1 change: 1 addition & 0 deletions test/node/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ import './color-util-test';
import './util-test';
import './export-utils-test';
import './s2-utils-test';
import './kepler-gl-utils-test';

0 comments on commit 22ea7a9

Please sign in to comment.