Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
f7d0e20
fix:yarn upgrade arg tweak
JoshuaVulcan Oct 17, 2025
365d1a2
hotfix:symbol icon size conventions
JoshuaVulcan Oct 17, 2025
386a049
hotfix:legacy fill color support
JoshuaVulcan Oct 17, 2025
763ed03
fix:polygon transparency when no fill is defined. saner line width de…
JoshuaVulcan Oct 20, 2025
f088e74
removing icon-size expression
JoshuaVulcan Oct 20, 2025
c0d9d8f
fix:restoring default images
JoshuaVulcan Oct 20, 2025
b1cee9e
tweak:more reliable layer ordering
JoshuaVulcan Oct 20, 2025
ffb1d14
test:fix broken test after new import chain
JoshuaVulcan Oct 20, 2025
916929f
fix:stabler 'before' layer for spatial features layer.
JoshuaVulcan Oct 20, 2025
32ca36f
fix:broken tests from layer name change
JoshuaVulcan Oct 20, 2025
93cf6ff
bugfix:forwarding feature dimensions along to styleimagemissing addma…
JoshuaVulcan Oct 21, 2025
c99c8fb
feat:upgraded service workers w/tile service caching
JoshuaVulcan Oct 22, 2025
85de02e
nit:better comment context
JoshuaVulcan Oct 22, 2025
73bc42a
chore:dead code pruning
JoshuaVulcan Oct 22, 2025
d2ba7e7
chore:comment cleanup
JoshuaVulcan Oct 22, 2025
cebf356
path tweak
JoshuaVulcan Oct 22, 2025
a1a1d73
debug:temp logging to check out in-env issues with profile switching
JoshuaVulcan Oct 22, 2025
628e791
bugfix:layer order issues
JoshuaVulcan Oct 22, 2025
5b0ce4b
nit:removing console.log
JoshuaVulcan Oct 22, 2025
b4abbf3
Update src/sw-custom.js
JoshuaVulcan Oct 22, 2025
abdd18a
Merge branch 'ERA-12142' of github.com:PADAS/das-web-react into ERA-1…
JoshuaVulcan Oct 22, 2025
dc2f27e
nit:PR feedback
JoshuaVulcan Oct 22, 2025
97381ff
fix:better conditional handling and 304/etag support
JoshuaVulcan Oct 22, 2025
77a2775
Update src/sw-custom.js
JoshuaVulcan Oct 22, 2025
70501af
Merge branch 'ERA-12142' of github.com:PADAS/das-web-react into ERA-1…
JoshuaVulcan Oct 22, 2025
bed376a
tweak:remove type check so we can stale-while-revalidate cache all OK…
JoshuaVulcan Oct 22, 2025
499372b
debug:logging for test env
JoshuaVulcan Oct 22, 2025
9db0370
chore:removing old debug logs
JoshuaVulcan Oct 22, 2025
208a4c8
fix:cache strategy key being stripped of auth in certain conditions
JoshuaVulcan Oct 22, 2025
5f40a44
fix:precache error handling to prevent full failure on version change…
JoshuaVulcan Oct 22, 2025
f8c16cd
debug:logging
JoshuaVulcan Oct 22, 2025
2dd84a1
debug:logging
JoshuaVulcan Oct 22, 2025
690fbde
debug:auth header forwarding
JoshuaVulcan Oct 23, 2025
d05983f
hotfix:fix spatial features layer appearing when no subjects accessib…
JoshuaVulcan Oct 23, 2025
c160f1a
duh. undoing custom implementation of StaleWhileRevalidate 🤡
JoshuaVulcan Oct 23, 2025
f690675
nit:comment placement
JoshuaVulcan Oct 23, 2025
4291e38
merging up release branch
JoshuaVulcan Oct 23, 2025
bc89212
pr feedback: code style, consistency, formatting, linting
JoshuaVulcan Oct 23, 2025
2f651c7
legacy typo fix
JoshuaVulcan Oct 23, 2025
09ecdb3
pr feedback: code organization nit
JoshuaVulcan Oct 23, 2025
a4a359b
sw-custom tweak
JoshuaVulcan Oct 23, 2025
76b899f
tweak:higher precache filesize tolerance
JoshuaVulcan Oct 23, 2025
d7b30a3
tweak:higher precache filesize tolerance
JoshuaVulcan Oct 23, 2025
e02e067
maxEntries cache config
JoshuaVulcan Oct 24, 2025
d8e0fc5
nit:comment removal
JoshuaVulcan Oct 24, 2025
243c84e
nit:PR feedback, cleaning up blank lines
JoshuaVulcan Oct 24, 2025
bf9b323
nit:PR feedback, cleaning up blank lines
JoshuaVulcan Oct 24, 2025
743c936
nit:PR feedback, clearer comment
JoshuaVulcan Oct 24, 2025
e848a67
nit:PR feedback for more concise fn
JoshuaVulcan Oct 24, 2025
852c0fc
nit:PR feedback for more concise fn
JoshuaVulcan Oct 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/develop-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
run: ci-helpers/makeversion.py

- name: Install dependencies
run: yarn --ignore-scripts
run: yarn install
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why are we doing this change? Note that yarn install and just yarn is the same, but I wonder if there's a reason behind removing --ignore-scripts flag.


- name: Run tests
run: yarn test-ci
Expand Down
2 changes: 1 addition & 1 deletion react-app-config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ module.exports = function (webpackEnv) {
// Bump up the default maximum size (2mb) that's precached,
// to make lazy-loading failure scenarios less likely.
// See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024,
}),
// TypeScript type checking
useTypeScript &&
Expand Down
20 changes: 20 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,26 @@ export const App = () => {
finishDrag(e);
}, [disallowDragAndDrop, finishDrag]);


// set user scope for service worker caching
useEffect(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I know I already made you move this, sorry 😅 But I just thought it would be nice to clean a bit our App component by hiding some of these implementations behind a hook. Not urgent, not a blocker. But if you like the idea, it would be awesome to put this in a useSetServiceWorkerScope or something. That way we would simplify this component but also it would make logic incredibly easy to test! (Even for a Cursor agent jeje)

if (navigator?.serviceWorker?.controller) {
if (user?.id) {
const scopeHash = selectedUserProfile?.id ?? user.id;
navigator.serviceWorker.controller.postMessage({
type: 'SET_SCOPE',
scope: { hash: scopeHash }
});
} else {
// Clear scope when user logs out
navigator.serviceWorker.controller.postMessage({
type: 'SET_SCOPE',
scope: { hash: null }
});
}
}
}, [user, selectedUserProfile]);

useEffect(() => {
/* use these catch blocks to provide error toasts if/as desired */
dispatch(fetchEventTypes());
Expand Down
22 changes: 20 additions & 2 deletions src/Map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -589,9 +589,27 @@ const Map = ({ children, onMapLoad, socket }) => {
// querying from the root /static/ dir of the host means this is one of our static assets, let's get it
// if the map says it's missing.
if (id.includes('/static/')) {
const src = id.replace(/(\.svg|\.png|\.jpg).*$/, '$1');
const dimensions = {};
const match = id.match(/^(.*?)(?:-([^-.]+)-([^-.]+))?$/);

let src = id;
if (match) {
const [, path, width, height] = match;
src = path;

if (width && width !== 'x') {
dimensions.width = Number(width);
}
if (height && height !== 'x') {
dimensions.height = Number(height);
}
}

// Sanitize the src path to remove internal icon ID suffixes
src = src.replace(/(\.svg|\.png|\.jpg).*$/, '$1');

try {
const img = await addMapImage({ src, id });
await addMapImage({ src, id, ...dimensions });
} catch (error) {
console.warn('Error adding map image:', { event, error });
}
Expand Down
30 changes: 23 additions & 7 deletions src/SpatialFeaturesLayer/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React, { memo, useContext, useMemo, useCallback, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { MapContext } from '../App';
import { addMapImage } from '../utils/map';
import { API_URL, DEFAULT_SYMBOL_LAYOUT, DEFAULT_SYMBOL_PAINT } from '../constants';

import MarkerImage from '../common/images/icons/mapbox-blue-marker-icon.png';
import RangerStationsImage from '../common/images/icons/ranger-stations.png';

const SPATIAL_FEATURES_SOURCE = 'spatial-features-source';

const VECTOR_TILE_URL = `${API_URL}spatialfeatures/tiles/{z}/{x}/{y}.pbf`;
Expand All @@ -14,6 +18,8 @@ export const LINES_LAYER_ID = 'spatial-features-lines';
export const POLYGONS_LAYER_ID = 'spatial-features-polygons';
// const POLYGONS_LABELS_LAYER_ID = 'spatial-features-polygon-labels';

const BEFORE_LAYER_ID = 'feature-separation-layer';

const DEFAULT_LINE_PAINT_COLOR = [
'case',
['has', 'stroke'], ['get', 'stroke'],
Expand All @@ -26,10 +32,11 @@ const DEFAULT_LINE_PAINT_COLOR = [
const DEFAULT_POLYGON_FILL_COLOR = [
'case',
['has', 'fill'], ['get', 'fill'],
['has', 'color'], ['get', 'color'],
['has', 'fill-color'], ['get', 'fill-color'],
['has', 'fill_color'], ['get', 'fill_color'],
['has', 'color'], ['get', 'color'],
['has', 'stroke'], ['get', 'stroke'],
'#ff6600'
'rgba(255, 102, 0, 0)'
];


Expand Down Expand Up @@ -114,7 +121,7 @@ const SpatialFeaturesLayer = ({ onFeatureClick }) => {
...DEFAULT_SYMBOL_PAINT
},
filter: symbolLayerFilter
});
}, BEFORE_LAYER_ID);
}

if (!map.getLayer(LINES_LAYER_ID)) {
Expand All @@ -131,7 +138,7 @@ const SpatialFeaturesLayer = ({ onFeatureClick }) => {
['has', 'width'], ['get', 'width'],
['has', 'line_width'], ['get', 'line_width'],
['has', 'stroke_width'], ['get', 'stroke_width'],
3
1,
],
'line-opacity': [
'case',
Expand All @@ -143,7 +150,7 @@ const SpatialFeaturesLayer = ({ onFeatureClick }) => {
]
},
filter: lineLayerFilter
});
}, BEFORE_LAYER_ID);
}

if (!map.getLayer(POLYGONS_LAYER_ID)) {
Expand All @@ -166,11 +173,11 @@ const SpatialFeaturesLayer = ({ onFeatureClick }) => {
['has', 'stroke'], ['get', 'stroke'],
['has', 'outline_color'], ['get', 'outline_color'],
['has', 'border_color'], ['get', 'border_color'],
'#ff6600'
'rgba(255, 102, 0, 0.25)'
]
},
filter: polygonLayerFilter
});
}, BEFORE_LAYER_ID);
}

/* // Add separate label layers for each geometry type
Expand Down Expand Up @@ -361,6 +368,15 @@ const SpatialFeaturesLayer = ({ onFeatureClick }) => {
}
}, [map, polygonLayerFilter]);

useEffect(() => {
if (!map?.hasImage?.('marker-icon')) {
addMapImage({ src: MarkerImage, id: 'marker-icon' });
}
if (!map?.hasImage?.('ranger-stations')) {
addMapImage({ src: RangerStationsImage, id: 'ranger-stations' });
}
}, [map]);

return null;
};

Expand Down
11 changes: 7 additions & 4 deletions src/SpatialFeaturesLayer/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ jest.mock('../App', () => {
// Mock these to prevent dependency chain issues
jest.mock('../utils/analyzers', () => ({}));
jest.mock('../ducks/analyzers', () => ({}));
jest.mock('../utils/map', () => ({
addMapImage: jest.fn()
}));

jest.mock('../constants', () => ({
API_URL: 'http://test-api.com/',
Expand All @@ -39,7 +42,7 @@ jest.mock('../constants', () => ({
ANALYZER_POLYS_CRITICAL_SOURCE: 'analyzer-polygon-critical-source',
ANALYZER_POLYS_WARNING_SOURCE: 'analyzer-polygon-warning-source',
CLUSTERS_SOURCE_ID: 'clusters-source'
}
},
}));

jest.mock('react-redux', () => ({
Expand Down Expand Up @@ -102,7 +105,7 @@ describe('SpatialFeaturesLayer', () => {
['==', ['geometry-type'], 'Point'],
['!', ['in', ['get', 'id'], ['literal', ['hidden-feature-1', 'hidden-feature-2']]]]
])
}));
}), 'feature-separation-layer');

// Verify line layer was added
expect(mockMap.addLayer).toHaveBeenCalledWith(expect.objectContaining({
Expand All @@ -115,7 +118,7 @@ describe('SpatialFeaturesLayer', () => {
['==', ['geometry-type'], 'LineString'],
['!', ['in', ['get', 'id'], ['literal', ['hidden-feature-1', 'hidden-feature-2']]]]
])
}));
}), 'feature-separation-layer');

// Verify polygon layer was added
expect(mockMap.addLayer).toHaveBeenCalledWith(expect.objectContaining({
Expand All @@ -128,7 +131,7 @@ describe('SpatialFeaturesLayer', () => {
['==', ['geometry-type'], 'Polygon'],
['!', ['in', ['get', 'id'], ['literal', ['hidden-feature-1', 'hidden-feature-2']]]]
])
}));
}), 'feature-separation-layer');

// Verify click handlers were added
expect(mockMap.on).toHaveBeenCalledWith('click', SYMBOLS_LAYER_ID, expect.any(Function));
Expand Down
14 changes: 6 additions & 8 deletions src/ducks/subjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,21 @@ export const clearSubjectData = () => ({
});

export const fetchSubjectGroups = () => dispatch => axios.get(SUBJECT_GROUPS_API_URL)
.then(response => dispatch(fetchSubjectGroupsSuccess(response)));
.then(response => dispatch(fetchSubjectGroupsSuccess(response)))
.catch(_error => dispatch(fetchSubjectGroupsError())); // Fallback to empty array on error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The method fetchSubjectGroupsError is a bit deceiving. Makes you feel there's a special handling for errors but all we do is call the "success" action creator with an empty array. We can modernize and keep the intention clearer like this:

export const fetchSubjectGroups = () => async (dispatch) => {
  let subjectGroups;
  try {
    subjectGroups = await axios.get(SUBJECT_GROUPS_API_URL);
  } catch (_error) {
    subjectGroups = [];
  }

  dispatch(fetchSubjectGroupsSuccess(subjectGroups));
};


const fetchMapSubjectsSuccess = response => ({
type: FETCH_MAP_SUBJECTS_SUCCESS,
payload: response.data,
});
/*
const fetchMapSubjectsError = error => ({
type: FETCH_MAP_SUBJECTS_ERROR,
payload: error,
});
*/

const fetchSubjectGroupsSuccess = response => ({
type: FETCH_SUBJECT_GROUPS_SUCCESS,
payload: response.data.data,
payload: response?.data?.data ?? [],
});

const fetchSubjectGroupsError = _error => fetchSubjectGroupsSuccess([]);

const INITIAL_MAP_SUBJECT_STATE = {
bbox: null,
subjects: [],
Expand Down
2 changes: 1 addition & 1 deletion src/sw-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const buildSW = () => {
globDirectory: path.join(process.cwd(), 'build'),
globPatterns: ['**/*.{js,html,css,png,svg}'],
globIgnores: ['**/*service-worker*.js', '**/*precache-manifest*.js'],
maximumFileSizeToCacheInBytes: 50 * 1024 * 102,
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // 10 MB
})
.then(({ count, size, warnings }) => {
warnings.forEach(console.warn);
Expand Down
Loading