feat: visibility toggle in plugin legend; persist layer visibility and basemap opacity on save [PR6] [DHIS2-18242]#3650
Conversation
|
🚀 Deployed on https://pr-3650.maps.netlify.dhis2.org |
BRaimbault
left a comment
There was a problem hiding this comment.
Ready for review
c6e1d66 to
92a3e8f
Compare
|
HendrikThePendric
left a comment
There was a problem hiding this comment.
Changes look good to me. One thing I noticed is that you had to effectively make the same change to each layer class implementation. At first this seemed like a potential code smell to me, the base class should call this.setLayerVisibility(). But when I started to compare various layer classes I noticed that these all do different things and possibly the sequence of these things matters as well. So for this PR, I'd say what you did there is fine.
Perhaps in the future it would be worth looking into extracting some common steps into methods of the base Layer and then calling these helpers in the extending classes. But that would be completely out-of-scope for this PR.



Parent
Implements
Overview
Sixth PR in the series. Adds a visibility toggle (eye icon) to each layer row in the plugin legend panel, letting users show/hide individual layers without leaving the plugin view. Separately, makes layer visibility and basemap opacity persistent: both are now saved when a map is saved and fully restored when it is reopened, including under the new v43+
basemaps[]API format.Changes
Layer visibility toggle in plugin legend DHIS2-20287
An eye icon button is added to each layer row in the plugin legend panel. Clicking it toggles the layer's visibility without affecting the saved state. The toggle is managed via a
visibilityOverridesmap inMap.jsx, keyed by layer ID, that overlays the savedisVisiblevalue. Overrides are reset whenmapViewschanges (new map loaded). ThelayersWithVisibilitycomputed array (visibilityOverrides[id] ?? layer.isVisible ?? true) is passed both toMapView(so layers are actually hidden/shown) and toLegend(so the eye icon reflects the current state). The button callse.stopPropagation()to avoid collapsing the legend panel.Files:
src/components/plugin/Map.jsx,src/components/plugin/Legend.jsx,src/components/plugin/LegendLayer.jsx,src/components/plugin/styles/Legend.cssPersist layer visibility and basemap opacity DHIS2-19078
Save path (
favorites.js):cleanLayerConfignow writeshidden: layer.isVisible === falseinto each mapView before the property pick ('hidden'added tovalidLayerProperties). The oldgetBasemapStringis replaced bygetBasemapPayload, which encodesid,opacity, andhiddenfor the basemap. On DHIS2 v43+, it returns abasemaps: [{ id, opacity, hidden }]array (VERSION-TOGGLE DHIS2-20417); on older servers it returns a JSON-encodedbasemapstring. Both paths use=== falsechecks so layers/basemaps without an explicitisVisibledefault to visible.FileMenu.jsxnow passesserverVersiontocleanMapConfigto activate the toggle.Load path (
getMigratedMapConfig.js):extractBasemapnow handles the v43+basemaps[]array and the new JSON-encodedbasemapstring, recoveringopacityandisVisiblefrom both. Defaults (id ?? defaultBasemapId,opacity ?? 1,isVisible ?? true) are applied at a single return statement rather than per-branch.upgradeMapViewsnow runs unconditionally (not only for legacy maps) soisVisible: view.hidden !== trueis set on every mapView regardless of format.'basemaps'is added togetBaseFieldsso the API fetch includes the field for v43+ maps.Layer components and loaders: All 8 loaders no longer hardcode
isVisible: true, allowing the value set bygetMigratedMapConfigto flow through to the Redux store. All 8 layer components callthis.setLayerVisibility()immediately aftermap.addLayer()so the layer's initial on-map visibility matches Redux state.reducers/map.jsdefaultsisVisible ?? truefor newly-added layers.External layer opacity:
createExternalBasemapLayerandcreateExternalOverlayLayerno longer hardcodeopacity: 1; opacity is instead provided by the layer component's default parameter (opacity = 1), consistent with all other layer types.Files:
src/util/favorites.js,src/util/getMigratedMapConfig.js,src/util/helpers.js,src/util/external.js,src/reducers/map.js,src/components/app/FileMenu.jsx, all 8 layer components, all 8 loadersTests update
src/components/plugin/__tests__/LegendLayer.spec.jsx(new) — eye-open/off button rendering; default visibility; no button without handler; click callstoggleLayerVisibility(id); click stops propagationsrc/util/__tests__/favorites.spec.js—hidden: true/falseoutput fromisVisible; hidden basemap in legacy JSON; non-default opacity in legacy JSON; v43+basemaps[]format with and without hidden basemapsrc/util/__tests__/getMigratedMapConfig.spec.js—hidden: true/falsemapView →isVisible; JSON basemap string → opacity/isVisible round-trip; v43+basemaps[]→ opacity/isVisible round-tripManual testing
Netlify: https://pr-3650.maps.netlify.dhis2.org/ + Instance: https://dev.im.dhis2.org/maps-app-42-3
Test maps
Quality checklist