Skip to content

Commit

Permalink
Merge branch 'master' into igr/ups-text-labels-fix-2
Browse files Browse the repository at this point in the history
  • Loading branch information
igorDykhta authored Oct 3, 2023
2 parents 5d8e859 + 9d99f0b commit d5c6baa
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 36 deletions.
2 changes: 1 addition & 1 deletion examples/custom-map-style/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Custom Map Style

![map layers](https://cdn.unfolded.ai/statics/keplergl/documentation/f-map-styles-8.jpg "custom map style")
![map layers](https://studio-public-data.foursquare.com/statics/keplergl/documentation/f-map-styles-8.jpg "custom map style")

Demo how to use kepler.gl with other basemap services other than Mapbox.

Expand Down
6 changes: 5 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ const config = {
// node_modules and pnp folders by default so that they are not transpiled
// Some libraries (even if transitive) are transitioning to ESM and need additional transpilation. Relevant issues:
// - tiny-sdf: https://github.com/visgl/deck.gl/issues/7735
transformIgnorePatterns: ["/node_modules/(?!(@mapbox/tiny-sdf)/)", "\\.pnp\\.[^\\\/]+$"]
// TODO For some reason transformIgnorePatterns are ignored in combination with TS, using moduleNameMapper instead.
// transformIgnorePatterns: ["/node_modules/(?!(@mapbox/tiny-sdf)/)", "\\.pnp\\.[^\\\/]+$"]
moduleNameMapper: {
'@mapbox/tiny-sdf': `<rootDir>/node_modules/@mapbox/tiny-sdf/index.cjs`
}
};

module.exports = config;
4 changes: 2 additions & 2 deletions src/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"@types/react-modal": "^3.13.1",
"@types/react-onclickoutside": "^6.7.4",
"@types/react-redux": "^7.1.23",
"@types/react-virtualized": "^9.21.20",
"@types/react-virtualized": "^9.21.23",
"@types/react-vis": "1.11.7",
"@types/styled-components": "^5.1.25",
"classnames": "^2.2.1",
Expand Down Expand Up @@ -115,7 +115,7 @@
"react-redux": "^8.0.5",
"react-sortable-hoc": "^1.8.3",
"react-tooltip": "^4.2.17",
"react-virtualized": "^9.21.1",
"react-virtualized": "^9.22.4",
"react-vis": "1.11.7",
"redux": "^4.2.1",
"reselect": "^4.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/src/common/color-legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export const LegendRow = ({label = '', displayLabel, color, idx}) => (
<g transform={`translate(0, ${idx * (ROW_H + GAP)})`}>
<rect width={RECT_W} height={ROW_H} style={{fill: color}} />
<text x={RECT_W + 8} y={ROW_H - 1}>
{displayLabel ? label.toString() : ''}
{displayLabel ? label?.toString() ?? 'N/A' : ''}
</text>
</g>
);
5 changes: 3 additions & 2 deletions src/components/src/common/data-table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export const Container = styled.div<ContainerProps>`
flex-direction: row;
flex-grow: 1;
overflow: hidden;
border-top: none;
.scroll-in-ui-thread.pinned-columns--header {
overflow: hidden;
Expand Down Expand Up @@ -219,7 +218,7 @@ interface GetRowCellProps {
/*
* This is an accessor method used to generalize getting a cell from a data row
*/
const getRowCell = (
const defaultGetRowCell = (
{dataContainer, columns, column, colMeta, rowIndex, sortOrder}: GetRowCellProps,
formatter
) => {
Expand Down Expand Up @@ -408,6 +407,7 @@ export interface DataTableProps {
sortOrder?: number[] | null;
showStats?: boolean;
hasCustomScrollBarStyle?: boolean;
getRowCell?: (renderDataCellProps: GetRowCellProps, formatter: any) => string | number;
}

interface DataTableState {
Expand Down Expand Up @@ -505,6 +505,7 @@ function DataTableFactory(HeaderCell: ReturnType<typeof HeaderCellFactory>) {
scaleCellsToWidth = debounce(this.doScaleCellsToWidth, 300);

renderDataCell = (columns, isPinned, props: DataTableProps) => {
const getRowCell = this.props.getRowCell ?? defaultGetRowCell;
return cellInfo => {
const {columnIndex, key, style, rowIndex} = cellInfo;
const {dataContainer, colMeta} = props;
Expand Down
1 change: 1 addition & 0 deletions src/components/src/common/dataset-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const DatasetName = styled.div.attrs({
font-weight: 500;
font-size: 12px;
color: ${props => props.theme.titleColorLT};
white-space: nowrap;
`;

interface DatasetLabelType {
Expand Down
2 changes: 1 addition & 1 deletion src/components/src/map/layer-hover-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const Row: React.FC<RowProps> = ({name, value, deltaValue, url}) => {
const asImg = /<img>/.test(name);
return (
<tr className="layer-hover-info__row" key={name}>
<td className="row__name">{name}</td>
<td className="row__name">{asImg ? name.replace('<img>', '') : name}</td>
<td className="row__value">
{asImg ? (
<img src={value} />
Expand Down
39 changes: 25 additions & 14 deletions src/components/src/modals/data-table-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,15 @@ const StyledModal = styled.div`

const DatasetCatalog = styled.div`
display: flex;
padding: ${dgSettings.verticalPadding} ${dgSettings.sidePadding} 0;
padding: ${dgSettings.verticalPadding} ${dgSettings.sidePadding} 0 0;
.overflow-horizontal {
display: flex;
overflow-x: auto;
overflow-y: hidden;
flex-direction: row;
${props => props.theme.modalScrollBar}
}
`;

interface DatasetModalTabProps {
Expand All @@ -66,9 +74,8 @@ export const DatasetModalTab = styled.div<DatasetModalTabProps>`
margin: 0 3px;
padding: 0 5px;
:first-child {
margin-left: 0;
padding-left: 0;
:hover {
border-bottom: 3px solid black;
}
`;

Expand All @@ -81,6 +88,7 @@ const StyledConfigureButton = styled.div`
svg {
stroke: black;
}
cursor: pointer;
`;

interface DatasetTabsUnmemoizedProps {
Expand All @@ -95,16 +103,18 @@ const DatasetTabsUnmemoized: React.FC<DatasetTabsUnmemoizedProps> = ({
showDatasetTable
}) => (
<DatasetCatalog className="dataset-modal-catalog">
{Object.values(datasets).map(dataset => (
<DatasetModalTab
className="dataset-modal-tab"
active={dataset === activeDataset}
key={dataset.id}
onClick={() => showDatasetTable(dataset.id)}
>
<DatasetLabel dataset={dataset} />
</DatasetModalTab>
))}
<div className="overflow-horizontal">
{Object.values(datasets).map(dataset => (
<DatasetModalTab
className="dataset-modal-tab"
active={dataset === activeDataset}
key={dataset.id}
onClick={() => showDatasetTable(dataset.id)}
>
<DatasetLabel dataset={dataset} />
</DatasetModalTab>
))}
</div>
</DatasetCatalog>
);

Expand All @@ -120,6 +130,7 @@ const TableContainer = styled.div`
flex-grow: 1;
min-height: 100%;
max-height: 100%;
max-width: 100%;
`;

interface DataTableModalProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ const TopRow = styled.div`
justify-content: space-between;
`;

/**
* only provide suggested field pairs if there is a match,
* otherwise the user can select a suggested field pair that will create invalid columns and a hard crash
*/
function getFieldPairsSuggestionsForColumn(
enhancedFieldPairs,
columnPairs: ColumnPairs | null | undefined,
columnKey: string
) {
const matchingFieldPairs = enhancedFieldPairs?.filter(({pair}) =>
pair.hasOwnProperty(columnPairs?.[columnKey]?.fieldPairKey)
);
return matchingFieldPairs.length > 0 ? matchingFieldPairs : null;
}

LayerColumnConfigFactory.deps = [ColumnSelectorFactory];

function LayerColumnConfigFactory(ColumnSelector: ReturnType<typeof ColumnSelectorFactory>) {
Expand Down Expand Up @@ -103,7 +118,7 @@ function LayerColumnConfigFactory(ColumnSelector: ReturnType<typeof ColumnSelect
label={(columnLabels && columnLabels[key]) || key}
key={key}
allFields={fields}
fieldPairs={enhancedFieldPairs}
fieldPairs={getFieldPairsSuggestionsForColumn(enhancedFieldPairs, columnPairs, key)}
onSelect={val => onUpdateColumn(key, val)}
/>
))}
Expand Down
2 changes: 1 addition & 1 deletion src/constants/src/default-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {TOOLTIP_FORMAT_TYPES} from './tooltip';
import {RGBAColor} from '@kepler.gl/types';

export const ACTION_PREFIX = '@@kepler.gl/';
export const KEPLER_UNFOLDED_BUCKET = 'https://cdn.unfolded.ai/statics/keplergl';
export const KEPLER_UNFOLDED_BUCKET = 'https://studio-public-data.foursquare.com/statics/keplergl';
export const BASEMAP_ICON_PREFIX = `${KEPLER_UNFOLDED_BUCKET}/geodude`;
export const DEFAULT_MAPBOX_API_URL = 'https://api.mapbox.com';
export const TRANSITION_DURATION = 0;
Expand Down
6 changes: 6 additions & 0 deletions src/layers/src/base-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,12 @@ class Layer {
}

const {pair: partnerKey, fieldPairKey} = this.columnPairs?.[key];

if (!pair[fieldPairKey]) {
// do not allow `key: undefined` to creep into the `updatedColumn` object
return this.config.columns;
}

const {fieldPairKey: partnerFieldPairKey} = this.columnPairs?.[partnerKey];

return {
Expand Down
6 changes: 4 additions & 2 deletions src/reducers/src/vis-state-updaters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,9 +406,11 @@ export function applyLayerConfigUpdater(
return nextState;
}

const serializedOldLayer = serializeLayer(oldLayer, state.schema);
// serializeLayer() might return null if the old layer is not valid,
// we should still apply the changes in that case
const serializedOldLayer = serializeLayer(oldLayer, state.schema) ?? {config: {}};
const serializedNewLayer = serializeLayer(newLayer, state.schema);
if (!serializedNewLayer || !serializedOldLayer) {
if (!serializedNewLayer) {
return state;
}
if (!isEqual(serializedOldLayer, serializedNewLayer)) {
Expand Down
10 changes: 9 additions & 1 deletion src/utils/src/export-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,15 @@ export function downloadFile(fileBlob: Blob, fileName: string) {
link.setAttribute('download', fileName);

document.body.appendChild(link);
link.click();
// in some cases where maps are embedded, e.g. need to
// create and dispatch an event so that the browser downloads
// the file instead of navigating to the url
const evt = new MouseEvent('click', {
view: window,
bubbles: false,
cancelable: true
});
link.dispatchEvent(evt);
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
Expand Down
2 changes: 1 addition & 1 deletion test/helpers/component-jest-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import {Provider} from 'react-redux';
import configureStore from 'redux-mock-store';
import {ThemeProvider} from 'styled-components';
import {IntlProvider} from 'react-intl';
import {messages} from 'localization';

import {render} from '@testing-library/react';
import {theme} from '@kepler.gl/styles';
import {messages} from '@kepler.gl/localization';
import {keplerGlReducerCore as coreReducer} from '@kepler.gl/reducers';
import {keplerGlInit} from '@kepler.gl/actions';

Expand Down
44 changes: 44 additions & 0 deletions test/node/utils/kepler-table-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,50 @@ test('KeplerTable -> findPointFieldPairs', t => {
suffix: ['latitude', 'longitude']
}
]
},
{
fields: ['point_lat', 'point_lng', 'alt'],
expected: [
{
defaultName: 'point',
pair: {
// no matching "alt" altitude found for this pair
lat: {
fieldIdx: 0,
value: 'point_lat'
},
lng: {
fieldIdx: 1,
value: 'point_lng'
}
},
suffix: ['lat', 'lng']
}
]
},
{
fields: ['point_lat', 'point_lng', 'point_alt'],
expected: [
{
defaultName: 'point',
pair: {
// a matching "point_alt" altitude was found for this pair
lat: {
fieldIdx: 0,
value: 'point_lat'
},
lng: {
fieldIdx: 1,
value: 'point_lng'
},
alt: {
fieldIdx: 2,
value: 'point_alt'
}
},
suffix: ['lat', 'lng']
}
]
}
];

Expand Down
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3789,10 +3789,10 @@
dependencies:
"@types/react" "*"

"@types/react-virtualized@^9.21.20":
version "9.21.20"
resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.20.tgz#756c78b5512a2a1804fdaf749a5f5cff3d805e5b"
integrity sha512-i8nZf1LpuX5rG4DZLaPGayIQwjxsZwmst5VdNhEznDTENel9p3A735AdRRp2iueFOyOuWBmaEaDxg8AD3GHilA==
"@types/react-virtualized@^9.21.23":
version "9.21.23"
resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.23.tgz#62c4b20b796351eca8e2f816c263b39b69ed97d0"
integrity sha512-8GX+P+nUl+c1qlyb3z0lQExQfoHPscBliZiBEUQ90PzMHY76XvkMawmKMyhvAUlCemhlEnvZdvWsyQAK5E/Jeg==
dependencies:
"@types/prop-types" "*"
"@types/react" "*"
Expand Down Expand Up @@ -14346,10 +14346,10 @@ react-tooltip@^4.2.17:
prop-types "^15.7.2"
uuid "^7.0.3"

react-virtualized@^9.21.1:
version "9.22.3"
resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.3.tgz#f430f16beb0a42db420dbd4d340403c0de334421"
integrity sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==
react-virtualized@^9.22.4:
version "9.22.5"
resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.5.tgz#bfb96fed519de378b50d8c0064b92994b3b91620"
integrity sha512-YqQMRzlVANBv1L/7r63OHa2b0ZsAaDp1UhVNEdUaXI8A5u6hTpA5NYtUueLH2rFuY/27mTGIBl7ZhqFKzw18YQ==
dependencies:
"@babel/runtime" "^7.7.2"
clsx "^1.0.4"
Expand Down

0 comments on commit d5c6baa

Please sign in to comment.