Skip to content

Commit ccb9cf8

Browse files
Ihor DykhtaIhor Dykhta
authored andcommitted
upgrade demo-app example
Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local>
1 parent b0cd696 commit ccb9cf8

10 files changed

Lines changed: 3063 additions & 2240 deletions

File tree

examples/demo-app/esbuild.config.mjs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ import process from 'node:process';
99
import fs from 'node:fs';
1010
import {spawn} from 'node:child_process';
1111
import {join} from 'node:path';
12+
import {dirname} from 'node:path';
13+
import {fileURLToPath} from 'node:url';
1214
import KeplerPackage from '../../package.json' assert {type: 'json'};
1315

16+
const __dirname = dirname(fileURLToPath(import.meta.url));
17+
1418
const args = process.argv;
1519

1620
const BASE_NODE_MODULES_DIR = './node_modules';
@@ -125,10 +129,48 @@ const config = {
125129
replace({
126130
__PACKAGE_VERSION__: KeplerPackage.version,
127131
include: /constants\/src\/default-settings\.ts/
128-
})
132+
}),
133+
// styled-components: @hubble.gl/react nests its own copy.
134+
// react-palm: several @kepler.gl/* packages nest their own copy.
135+
// Both are singletons that break when loaded more than once.
136+
{
137+
name: 'dedupe-singletons',
138+
setup(build) {
139+
build.onResolve({filter: /^(styled-components|react-palm(\/|$)|react$|react-dom$)/}, async args => {
140+
if (args.pluginData?.deduped) return;
141+
const result = await build.resolve(args.path, {
142+
resolveDir: __dirname,
143+
kind: args.kind,
144+
pluginData: {deduped: true}
145+
});
146+
return result;
147+
});
148+
}
149+
}
129150
]
130151
};
131152

153+
// Force @luma.gl/* and @deck.gl/* to the root monorepo node_modules.
154+
// The demo-app may install newer patch versions, but kepler.gl was built
155+
// and tested against the root versions (luma.gl 9.3.2 / deck.gl 9.3.1).
156+
// NOT added to config.plugins directly — it is injected conditionally so
157+
// that --env.deck / --env.deck_src modes (which alias deck.gl to a local
158+
// source tree) are not overridden.
159+
const dedupeWebglPlugin = {
160+
name: 'dedupe-webgl',
161+
setup(build) {
162+
build.onResolve({filter: /^(@luma\.gl\/|@deck\.gl\/)/}, async args => {
163+
if (args.pluginData?.deduped) return;
164+
const result = await build.resolve(args.path, {
165+
resolveDir: NODE_MODULES_DIR,
166+
kind: args.kind,
167+
pluginData: {deduped: true}
168+
});
169+
return result;
170+
});
171+
}
172+
};
173+
132174
function addAliases(externals, args) {
133175
const resolveAlias = getThirdPartyLibraryAliases(true);
134176

@@ -280,6 +322,7 @@ function openURL(url) {
280322
// Optionally generate a bundle analysis
281323
plugins: [
282324
...config.plugins,
325+
dedupeWebglPlugin,
283326
{
284327
name: 'bundle-analyzer',
285328
setup(build) {
@@ -308,10 +351,17 @@ function openURL(url) {
308351
? localAliases
309352
: getThirdPartyLibraryAliases(false);
310353
const nodeModulesDir = isLocal ? NODE_MODULES_DIR : BASE_NODE_MODULES_DIR;
354+
// Skip dedupe-webgl when a local deck.gl source override is active so that
355+
// --env.deck / --env.deck_src aliases are not overridden by the plugin.
356+
const useDeckOverride = args.includes('--env.deck') || args.includes('--env.deck_src');
311357

312358
await esbuild
313359
.context({
314360
...config,
361+
plugins: [
362+
...config.plugins,
363+
...(useDeckOverride ? [] : [dedupeWebglPlugin])
364+
],
315365
minify: false,
316366
sourcemap: true,
317367
alias: {

examples/demo-app/package.json

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@
1414
"@auth0/auth0-spa-js": "^2.1.2",
1515
"@carto/toolkit": "0.0.1-rc.18",
1616
"@emotion/is-prop-valid": "^1.2.1",
17-
"@kepler.gl/actions": "^3.2.0",
18-
"@kepler.gl/ai-assistant": "^3.2.0",
19-
"@kepler.gl/cloud-providers": "^3.2.0",
20-
"@kepler.gl/components": "^3.2.0",
21-
"@kepler.gl/constants": "^3.2.0",
22-
"@kepler.gl/duckdb": "^3.2.0",
23-
"@kepler.gl/processors": "^3.2.0",
24-
"@kepler.gl/reducers": "^3.2.0",
25-
"@kepler.gl/schemas": "^3.2.0",
26-
"@kepler.gl/styles": "^3.2.0",
27-
"@kepler.gl/utils": "^3.2.0",
17+
"@kepler.gl/actions": "^3.3.0-alpha.6",
18+
"@kepler.gl/ai-assistant": "^3.3.0-alpha.6",
19+
"@kepler.gl/cloud-providers": "^3.3.0-alpha.6",
20+
"@kepler.gl/components": "^3.3.0-alpha.6",
21+
"@kepler.gl/constants": "^3.3.0-alpha.6",
22+
"@kepler.gl/duckdb": "^3.3.0-alpha.6",
23+
"@kepler.gl/processors": "^3.3.0-alpha.6",
24+
"@kepler.gl/reducers": "^3.3.0-alpha.6",
25+
"@kepler.gl/schemas": "^3.3.0-alpha.6",
26+
"@kepler.gl/styles": "^3.3.0-alpha.6",
27+
"@kepler.gl/utils": "^3.3.0-alpha.6",
2828
"@loaders.gl/arrow": "^4.3.2",
2929
"@loaders.gl/core": "^4.3.2",
3030
"@loaders.gl/csv": "^4.3.2",
@@ -39,7 +39,6 @@
3939
"d3-format": "^2.0.0",
4040
"dropbox": "^4.0.12",
4141
"esbuild": "^0.28.1",
42-
"global": "^4.3.0",
4342
"keymirror": "^0.1.1",
4443
"markdown-to-jsx": "^7.7.6",
4544
"prop-types": "^15.6.0",
@@ -49,19 +48,10 @@
4948
"react-redux": "^9.1.0",
5049
"react-resizable-panels": "^2.1.7",
5150
"react-router-dom": "^6.28.0",
52-
"react-virtualized": "^9.21.0",
5351
"redux": "^5.0.0",
54-
"redux-actions": "^2.2.1",
5552
"redux-logger": "^3.0.6",
5653
"redux-thunk": "^1.0.0",
57-
"styled-components": "6.4.3",
58-
"usehooks-ts": "^3.1.0"
59-
},
60-
"resolutions": {
61-
"@luma.gl/core": "8.5.21",
62-
"@luma.gl/webgl": "8.5.21",
63-
"@deck.gl/core": "8.9.27",
64-
"@deck.gl/extensions": "8.9.27"
54+
"styled-components": "6.4.3"
6555
},
6656
"engines": {
6757
"node": ">=20"

examples/demo-app/src/actions.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright contributors to the kepler.gl project
33

4-
import {fetch} from 'global';
5-
64
import {loadFiles, toggleModal} from '@kepler.gl/actions';
75
import {parseUri} from '@kepler.gl/common-utils';
86
import {load} from '@loaders.gl/core';

examples/demo-app/src/app.tsx

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
// Copyright contributors to the kepler.gl project
33

44
import React, {useCallback, useEffect, useRef, useState} from 'react';
5-
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
65
import styled, {ThemeProvider, StyleSheetManager} from 'styled-components';
7-
import Window from 'global/window';
8-
import {connect, useDispatch} from 'react-redux';
6+
import {useDispatch} from 'react-redux';
97
import cloneDeep from 'lodash/cloneDeep';
108
import isEqual from 'lodash/isEqual';
119
import {useSelector} from 'react-redux';
@@ -173,6 +171,23 @@ const App = props => {
173171

174172
const prevQueryRef = useRef<number>(null);
175173

174+
const startScreenCapture = useSelector(
175+
(state: any) => state.demo.aiAssistant.screenshotToAsk.startScreenCapture
176+
);
177+
178+
const mapContainerRef = useRef<HTMLDivElement>(null);
179+
const [mapDimensions, setMapDimensions] = useState({width: 0, height: 0});
180+
181+
useEffect(() => {
182+
if (!mapContainerRef.current) return;
183+
const observer = new ResizeObserver(entries => {
184+
const {width, height} = entries[0].contentRect;
185+
setMapDimensions({width, height});
186+
});
187+
observer.observe(mapContainerRef.current);
188+
return () => observer.disconnect();
189+
}, []);
190+
176191
// Handle OAuth callback on /auth route
177192
useEffect(() => {
178193
if (location.pathname === '/auth' && window.opener) {
@@ -273,7 +288,7 @@ const App = props => {
273288

274289
const _disableBanner = useCallback(() => {
275290
hideBanner();
276-
Window.localStorage.setItem(BannerKey, 'true');
291+
window.localStorage.setItem(BannerKey, 'true');
277292
}, [hideBanner]);
278293

279294
const _loadRowData = useCallback(() => {
@@ -575,7 +590,7 @@ const App = props => {
575590
features: sampleGeojsonPoints.features.slice(0, 5)
576591
});
577592
_loadGeojsonData();
578-
Window.setTimeout(() => {
593+
window.setTimeout(() => {
579594
dispatch(
580595
replaceDataInMap({
581596
datasetToReplaceId: 'bart-stops-geo',
@@ -874,7 +889,7 @@ const App = props => {
874889
// }}
875890
>
876891
<ScreenshotWrapper
877-
startScreenCapture={props.demo.aiAssistant.screenshotToAsk.startScreenCapture}
892+
startScreenCapture={startScreenCapture}
878893
setScreenCaptured={_setScreenCaptured}
879894
setStartScreenCapture={_setStartScreenCapture}
880895
className="h-screen"
@@ -887,23 +902,21 @@ const App = props => {
887902
<Panel defaultSize={isAiAssistantPanelOpen ? 70 : 100}>
888903
<PanelGroup direction="vertical">
889904
<Panel defaultSize={isSqlPanelOpen ? 60 : 100}>
890-
<AutoSizer>
891-
{({height, width}) => (
892-
<KeplerGl
893-
mapboxApiAccessToken={CLOUD_PROVIDERS_CONFIGURATION.MAPBOX_TOKEN}
894-
id="map"
895-
getState={keplerGlGetState}
896-
width={width}
897-
height={height}
898-
cloudProviders={CLOUD_PROVIDERS}
899-
localeMessages={messages}
900-
onExportToCloudSuccess={onExportFileSuccess}
901-
onLoadCloudMapSuccess={onLoadCloudMapSuccess}
902-
featureFlags={DEFAULT_FEATURE_FLAGS}
903-
onViewStateChange={onViewStateChange}
904-
/>
905-
)}
906-
</AutoSizer>
905+
<div ref={mapContainerRef} style={{width: '100%', height: '100%'}}>
906+
<KeplerGl
907+
mapboxApiAccessToken={CLOUD_PROVIDERS_CONFIGURATION.MAPBOX_TOKEN}
908+
id="map"
909+
getState={keplerGlGetState}
910+
width={mapDimensions.width}
911+
height={mapDimensions.height}
912+
cloudProviders={CLOUD_PROVIDERS}
913+
localeMessages={messages}
914+
onExportToCloudSuccess={onExportFileSuccess}
915+
onLoadCloudMapSuccess={onLoadCloudMapSuccess}
916+
featureFlags={DEFAULT_FEATURE_FLAGS}
917+
onViewStateChange={onViewStateChange}
918+
/>
919+
</div>
907920
</Panel>
908921

909922
{isSqlPanelOpen && (
@@ -933,7 +946,4 @@ const App = props => {
933946
);
934947
};
935948

936-
const mapStateToProps = state => state;
937-
const dispatchToProps = dispatch => ({dispatch});
938-
939-
export default connect(mapStateToProps, dispatchToProps)(App);
949+
export default App;

examples/demo-app/src/cloud-providers/carto/carto-provider.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Copyright contributors to the kepler.gl project
33

44
import {OAuthApp} from '@carto/toolkit';
5-
import Console from 'global/console';
65
import CartoIcon from './carto-icon';
76
import {Provider} from '@kepler.gl/cloud-providers';
87
import {createDataContainer} from '@kepler.gl/utils';

examples/demo-app/src/cloud-providers/dropbox/dropbox-provider.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
// DROPBOX
55
import {Dropbox} from 'dropbox';
6-
import Window from 'global/window';
76
import DropboxIcon from './dropbox-icon';
87
import {MAP_URI} from '../../constants/default-settings';
98
import {KEPLER_FORMAT, Provider} from '@kepler.gl/cloud-providers';

examples/demo-app/src/main.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import React from 'react';
55
import ReactDOM from 'react-dom/client';
6-
import document from 'global/document';
76
import {Provider} from 'react-redux';
87
import {BrowserRouter, Routes, Route} from 'react-router-dom';
98
import store from './store';

examples/demo-app/src/reducers/index.js

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Copyright contributors to the kepler.gl project
33

44
import {combineReducers} from 'redux';
5-
import {handleActions} from 'redux-actions';
65
import Task, {withTask} from 'react-palm/tasks';
76

87
import {aiAssistantReducer} from '@kepler.gl/ai-assistant';
@@ -97,23 +96,18 @@ const initialAppState = {
9796
};
9897

9998
// App reducer
100-
export const appReducer = handleActions(
101-
{
102-
[INIT]: state => ({
103-
...state,
104-
loaded: true
105-
}),
106-
[LOAD_MAP_SAMPLE_FILE]: (state, action) => ({
107-
...state,
108-
sampleMaps: action.samples
109-
}),
110-
[SET_SAMPLE_LOADING_STATUS]: (state, action) => ({
111-
...state,
112-
isMapLoading: action.isMapLoading
113-
})
114-
},
115-
initialAppState
116-
);
99+
export const appReducer = (state = initialAppState, action) => {
100+
switch (action.type) {
101+
case INIT:
102+
return {...state, loaded: true};
103+
case LOAD_MAP_SAMPLE_FILE:
104+
return {...state, sampleMaps: action.samples};
105+
case SET_SAMPLE_LOADING_STATUS:
106+
return {...state, isMapLoading: action.isMapLoading};
107+
default:
108+
return state;
109+
}
110+
};
117111

118112
const {DEFAULT_EXPORT_MAP} = uiStateUpdaters;
119113

examples/demo-app/src/store.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ import thunk from 'redux-thunk';
88
import {enhanceReduxMiddleware} from '@kepler.gl/reducers';
99
import {getApplicationConfig} from '@kepler.gl/utils';
1010

11-
// eslint-disable-next-line no-unused-vars
12-
import Window from 'global/window';
13-
1411
import demoReducer from './reducers/index';
1512

1613
const reducers = combineReducers({
@@ -50,7 +47,7 @@ if (NODE_ENV === 'local') {
5047

5148
const logger = createLogger({
5249
collapsed: () => true,
53-
predicate: (_getState, action) => Window.__KEPLER_LOG_FULL__ || !suppressed.has(action.type)
50+
predicate: (_getState, action) => window.__KEPLER_LOG_FULL__ || !suppressed.has(action.type)
5451
});
5552
middlewares.push(logger);
5653
}
@@ -66,10 +63,10 @@ let composeEnhancers = compose;
6663
* comment out code below to enable Redux Devtools
6764
*/
6865

69-
if (Window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
66+
if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
7067
const level = getApplicationConfig().reduxLogLevel ?? 1;
7168
const suppressed = SUPPRESSED_BY_LEVEL[level] ?? LEVEL1_ACTIONS;
72-
composeEnhancers = Window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
69+
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
7370
actionsBlacklist: [...suppressed]
7471
});
7572
}

0 commit comments

Comments
 (0)