@defra/interactive-map 0.0.30-alpha → 0.0.32-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/README.md +2 -2
  2. package/assets/images/bright-ofm-thumb.jpg +0 -0
  3. package/assets/images/dark-ofm-thumb.jpg +0 -0
  4. package/assets/images/road-ofm-thumb.jpg +0 -0
  5. package/assets/templates/add-polygons.njk +143 -0
  6. package/assets/templates/add-symbols.njk +119 -0
  7. package/assets/templates/{map.njk → basic-map.njk} +9 -17
  8. package/assets/templates/button-map.njk +56 -0
  9. package/assets/templates/draw-tools.njk +161 -0
  10. package/assets/templates/marker-panel.njk +91 -0
  11. package/assets/templates/place-marker.njk +104 -0
  12. package/assets/templates/search-control.njk +98 -0
  13. package/assets/templates/select-feature.njk +101 -0
  14. package/assets/templates/style-switcher.njk +87 -0
  15. package/assets/templates/toggle-marker-label.njk +74 -0
  16. package/dist/css/index.css +1 -1
  17. package/dist/esm/im-core.js +1 -1
  18. package/dist/esm/im-shell.js +1 -1
  19. package/dist/umd/im-core.js +1 -1
  20. package/dist/umd/index.js +1 -1
  21. package/docs/api/context.md +4 -4
  22. package/docs/api.md +166 -37
  23. package/docs/assets/css/docusaurus.scss +36 -4
  24. package/docs/assets/images/add-polygons.jpg +0 -0
  25. package/docs/assets/images/add-symbols.jpg +0 -0
  26. package/docs/assets/images/basic-map.jpg +0 -0
  27. package/docs/assets/images/button-first.jpg +0 -0
  28. package/docs/assets/images/deuteranopia-ozs-map-thumb.jpg +0 -0
  29. package/docs/assets/images/draw.jpg +0 -0
  30. package/docs/assets/images/marker-panel.jpg +0 -0
  31. package/docs/assets/images/night-ozs-map-thumb.jpg +0 -0
  32. package/docs/assets/images/outdoor-ozs-map-thumb.jpg +0 -0
  33. package/docs/assets/images/place-marker.jpg +0 -0
  34. package/docs/assets/images/screenshot.jpg +0 -0
  35. package/docs/assets/images/search.jpg +0 -0
  36. package/docs/assets/images/select-feature.jpg +0 -0
  37. package/docs/assets/images/style-switcher.jpg +0 -0
  38. package/docs/assets/images/toggle-marker-label.jpg +0 -0
  39. package/docs/assets/images/tritanopia-ozs-map-thumb.jpg +0 -0
  40. package/docs/examples/add-marker-with-panel.mdx +3 -3
  41. package/docs/examples/add-polygons.mdx +225 -0
  42. package/docs/examples/add-symbols.mdx +177 -0
  43. package/docs/examples/basic-map.mdx +2 -2
  44. package/docs/examples/draw-tools.mdx +271 -0
  45. package/docs/examples/index.mdx +95 -11
  46. package/docs/examples/place-marker.mdx +151 -0
  47. package/docs/examples/search-control.mdx +71 -0
  48. package/docs/examples/select-feature.mdx +146 -0
  49. package/docs/examples/style-switcher.mdx +135 -0
  50. package/docs/examples/toggle-marker-label.mdx +3 -3
  51. package/docs/plugins/datasets.md +157 -122
  52. package/docs/plugins/interact.md +1 -4
  53. package/docusaurus.config.cjs +9 -2
  54. package/govuk-prototype-kit.config.json +52 -2
  55. package/package.json +1 -1
  56. package/plugins/beta/datasets/dist/css/index.css +5 -2
  57. package/plugins/beta/datasets/dist/esm/im-datasets-ml-adapter.js +1 -0
  58. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  59. package/plugins/beta/datasets/dist/esm/index.js +1 -1
  60. package/plugins/beta/datasets/dist/umd/im-datasets-ml-adapter.js +2 -0
  61. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +2 -0
  62. package/plugins/beta/datasets/dist/umd/index.js +2 -0
  63. package/plugins/beta/datasets/src/adapters/loadLayerAdapter.js +33 -0
  64. package/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +44 -120
  65. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +145 -245
  66. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +516 -0
  67. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.js +209 -0
  68. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +483 -0
  69. package/plugins/beta/datasets/src/api/addDataset.js +2 -5
  70. package/plugins/beta/datasets/src/api/addDataset.test.js +16 -0
  71. package/plugins/beta/datasets/src/api/getOpacity.js +14 -14
  72. package/plugins/beta/datasets/src/api/getOpacity.test.js +72 -0
  73. package/plugins/beta/datasets/src/api/getStyle.js +8 -9
  74. package/plugins/beta/datasets/src/api/getStyle.test.js +42 -0
  75. package/plugins/beta/datasets/src/api/removeDataset.js +7 -7
  76. package/plugins/beta/datasets/src/api/removeDataset.test.js +45 -0
  77. package/plugins/beta/datasets/src/api/setData.js +9 -3
  78. package/plugins/beta/datasets/src/api/setData.test.js +62 -0
  79. package/plugins/beta/datasets/src/api/setDatasetVisibility.js +5 -30
  80. package/plugins/beta/datasets/src/api/setDatasetVisibility.test.js +31 -0
  81. package/plugins/beta/datasets/src/api/setFeatureVisibility.js +9 -18
  82. package/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +74 -0
  83. package/plugins/beta/datasets/src/api/setGlobals.js +20 -0
  84. package/plugins/beta/datasets/src/api/setGlobals.test.js +63 -0
  85. package/plugins/beta/datasets/src/api/setOpacity.js +8 -27
  86. package/plugins/beta/datasets/src/api/setOpacity.test.js +31 -0
  87. package/plugins/beta/datasets/src/api/setStyle.js +5 -21
  88. package/plugins/beta/datasets/src/api/setStyle.test.js +53 -0
  89. package/plugins/beta/datasets/src/components/Key/Key.jsx +51 -0
  90. package/plugins/beta/datasets/src/components/Key/KeyGroupItem.jsx +18 -0
  91. package/plugins/beta/datasets/src/components/Key/KeyItem.jsx +20 -0
  92. package/plugins/beta/datasets/src/components/Key/KeySvg.jsx +22 -0
  93. package/plugins/beta/datasets/src/components/Key/KeySvg.test.jsx +87 -0
  94. package/plugins/beta/datasets/src/components/Key/KeySvgLine.jsx +19 -0
  95. package/plugins/beta/datasets/src/components/Key/KeySvgLine.test.jsx +71 -0
  96. package/plugins/beta/datasets/src/components/{KeySvgPattern.jsx → Key/KeySvgPattern.jsx} +3 -4
  97. package/plugins/beta/datasets/src/components/Key/KeySvgPattern.test.jsx +55 -0
  98. package/plugins/beta/datasets/src/components/Key/KeySvgRect.jsx +22 -0
  99. package/plugins/beta/datasets/src/components/Key/KeySvgRect.test.jsx +85 -0
  100. package/plugins/beta/datasets/src/components/{KeySvgSymbol.jsx → Key/KeySvgSymbol.jsx} +5 -5
  101. package/plugins/beta/datasets/src/components/Key/KeySvgSymbol.test.jsx +80 -0
  102. package/plugins/beta/datasets/src/components/Key/svgProperties.test.js +61 -0
  103. package/plugins/beta/datasets/src/{panels → components/LayersMenu}/Layers.module.scss +15 -11
  104. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenu.jsx +33 -0
  105. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuCheckbox.jsx +31 -0
  106. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuGroupWrapper.jsx +19 -0
  107. package/plugins/beta/datasets/src/datasets.scss +2 -2
  108. package/plugins/beta/datasets/src/fetch/createDynamicSource.js +8 -8
  109. package/plugins/beta/datasets/src/{DatasetsInit.jsx → initialise/DatasetsInit.jsx} +19 -21
  110. package/plugins/beta/datasets/src/{defaults.js → initialise/defaults.js} +17 -2
  111. package/plugins/beta/datasets/src/initialise/defaults.test.js +127 -0
  112. package/plugins/beta/datasets/src/{datasets.js → initialise/initialiseDatasets.js} +30 -26
  113. package/plugins/beta/datasets/src/initialise/initialiseDatasets.test.js +273 -0
  114. package/plugins/beta/datasets/src/manifest.js +8 -6
  115. package/plugins/beta/datasets/src/reducers/__data__/demoDatasets.js +253 -0
  116. package/plugins/beta/datasets/src/reducers/datasetsToMenu.js +83 -0
  117. package/plugins/beta/datasets/src/reducers/datasetsToMenu.test.js +84 -0
  118. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +41 -0
  119. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js +117 -0
  120. package/plugins/beta/datasets/src/reducers/pluginState.js +206 -0
  121. package/plugins/beta/datasets/src/reducers/pluginState.test.js +386 -0
  122. package/plugins/beta/datasets/src/registry/__mocks__/datasetRegistry.js +29 -0
  123. package/plugins/beta/datasets/src/registry/createDataset.js +5 -0
  124. package/plugins/beta/datasets/src/registry/dataset.js +176 -0
  125. package/plugins/beta/datasets/src/registry/dataset.test.js +497 -0
  126. package/plugins/beta/datasets/src/registry/datasetDefinitionCache.js +35 -0
  127. package/plugins/beta/datasets/src/registry/datasetRegistry.js +116 -0
  128. package/plugins/beta/datasets/src/registry/datasetRegistry.test.js +335 -0
  129. package/plugins/beta/datasets/src/registry/dynamicGeoJson.js +17 -0
  130. package/plugins/beta/datasets/src/registry/globalDataset.js +36 -0
  131. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  132. package/plugins/beta/draw-es/src/api/addFeature.js +12 -3
  133. package/plugins/beta/draw-es/src/events.js +8 -3
  134. package/plugins/beta/draw-es/src/events.test.js +2 -0
  135. package/plugins/beta/draw-es/src/graphic.js +26 -2
  136. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  137. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  138. package/plugins/beta/draw-ml/src/DrawInit.jsx +8 -0
  139. package/plugins/beta/draw-ml/src/api/newLine.js +1 -0
  140. package/plugins/beta/draw-ml/src/api/newPolygon.js +1 -0
  141. package/plugins/beta/draw-ml/src/events.js +13 -1
  142. package/plugins/beta/draw-ml/src/index.js +1 -1
  143. package/plugins/beta/draw-ml/src/manifest.js +3 -0
  144. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +21 -12
  145. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +4 -0
  146. package/plugins/beta/draw-ol/dist/esm/EditMode.js +1 -1
  147. package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
  148. package/plugins/beta/draw-ol/src/edit/keyboardHandler.js +4 -2
  149. package/plugins/beta/map-styles/src/mapStyles.scss +41 -41
  150. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  151. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  152. package/plugins/interact/dist/umd/index.js +1 -1
  153. package/plugins/interact/src/InteractInit.jsx +3 -5
  154. package/plugins/interact/src/InteractInit.test.js +1 -3
  155. package/plugins/interact/src/events.js +2 -29
  156. package/plugins/interact/src/events.test.js +4 -102
  157. package/plugins/interact/src/hooks/useAttachEvents.js +3 -4
  158. package/plugins/interact/src/hooks/useAttachEvents.test.js +1 -3
  159. package/plugins/interact/src/hooks/useCrossHairVisibility.js +4 -10
  160. package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +5 -10
  161. package/plugins/interact/src/hooks/useHighlightSync.js +1 -10
  162. package/plugins/interact/src/hooks/useHighlightSync.test.js +2 -21
  163. package/plugins/interact/src/hooks/useInteractionHandlers.js +15 -12
  164. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +28 -29
  165. package/plugins/interact/src/manifest.js +0 -35
  166. package/plugins/interact/src/manifest.test.js +3 -43
  167. package/plugins/interact/src/reducer.js +4 -22
  168. package/plugins/interact/src/reducer.test.js +11 -39
  169. package/plugins/search/dist/css/index.css +5 -2
  170. package/plugins/search/src/components/Form/Form.module.scss +5 -2
  171. package/plugins/search/src/search.scss +4 -4
  172. package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
  173. package/providers/beta/esri/src/esriProvider.js +4 -0
  174. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  175. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  176. package/providers/beta/openlayers/src/openlayersProvider.js +4 -0
  177. package/providers/beta/openlayers/src/openlayersProvider.test.js +5 -0
  178. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  179. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  180. package/providers/maplibre/src/maplibreProvider.js +6 -4
  181. package/providers/maplibre/src/maplibreProvider.test.js +5 -0
  182. package/providers/maplibre/src/utils/highlightFeatures.js +74 -25
  183. package/providers/maplibre/src/utils/highlightFeatures.test.js +132 -0
  184. package/providers/maplibre/src/utils/patternImages.js +2 -4
  185. package/providers/maplibre/src/utils/symbolImages.js +1 -4
  186. package/rollup.esm.mjs +2 -8
  187. package/src/App/components/CrossHair/CrossHair.module.scss +8 -8
  188. package/src/App/components/MapButton/MapButton.jsx +16 -1
  189. package/src/App/components/MapButton/MapButton.module.scss +12 -1
  190. package/src/App/components/MapButton/MapButton.test.jsx +40 -1
  191. package/src/App/hooks/useContinueEnabledEvaluator.js +31 -0
  192. package/src/App/hooks/useContinueEnabledEvaluator.test.js +118 -0
  193. package/src/App/hooks/useEvaluateProp.js +15 -15
  194. package/src/App/hooks/useEvaluateProp.test.js +80 -76
  195. package/src/App/hooks/useLayoutMeasurements.js +11 -5
  196. package/src/App/hooks/useResizeObserver.js +15 -2
  197. package/src/App/hooks/useResizeObserver.test.js +1 -0
  198. package/src/App/renderer/PluginInits.jsx +2 -0
  199. package/src/App/renderer/mapButtons.js +21 -1
  200. package/src/App/renderer/mapButtons.test.js +46 -1
  201. package/src/App/store/appReducer.js +1 -1
  202. package/src/App/store/appReducer.test.js +37 -0
  203. package/src/InteractiveMap/InteractiveMap.js +14 -4
  204. package/src/InteractiveMap/InteractiveMap.test.js +11 -3
  205. package/src/InteractiveMap/behaviourController.js +3 -1
  206. package/src/InteractiveMap/behaviourController.test.js +6 -3
  207. package/src/InteractiveMap/domStateManager.js +2 -0
  208. package/src/config/appConfig.js +25 -0
  209. package/src/config/appConfig.test.js +50 -0
  210. package/src/config/defaults.js +1 -0
  211. package/src/config/events.js +21 -3
  212. package/src/scss/settings/_dimensions.scss +1 -0
  213. package/src/services/patternRegistry.js +8 -4
  214. package/src/types.js +7 -0
  215. package/src/utils/patternUtils.js +1 -2
  216. package/src/utils/patternUtils.test.js +9 -0
  217. package/webpack.dev.mjs +10 -0
  218. package/webpack.umd.mjs +1 -1
  219. package/docs/assets/images/screens-blue.jpg +0 -0
  220. package/docs/assets/images/screens-white.jpg +0 -0
  221. package/plugins/beta/datasets/dist/adapters/maplibre/esm/im-datasets-ml-adapter.js +0 -1
  222. package/plugins/beta/datasets/dist/adapters/maplibre/esm/index.js +0 -1
  223. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-maplibre-adapter.js +0 -2
  224. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-plugin.js +0 -2
  225. package/plugins/beta/datasets/dist/umd/maplibre/index.js +0 -2
  226. package/plugins/beta/datasets/src/adapters/maplibre/index.js +0 -18
  227. package/plugins/beta/datasets/src/adapters/maplibre/layerIds.js +0 -75
  228. package/plugins/beta/datasets/src/adapters/maplibre/patternImages.js +0 -27
  229. package/plugins/beta/datasets/src/adapters/maplibre/symbolImages.js +0 -31
  230. package/plugins/beta/datasets/src/components/KeySvg.jsx +0 -24
  231. package/plugins/beta/datasets/src/components/KeySvgLine.jsx +0 -19
  232. package/plugins/beta/datasets/src/components/KeySvgRect.jsx +0 -22
  233. package/plugins/beta/datasets/src/index.maplibre.umd.js +0 -23
  234. package/plugins/beta/datasets/src/panels/Key.jsx +0 -62
  235. package/plugins/beta/datasets/src/panels/Layers.jsx +0 -141
  236. package/plugins/beta/datasets/src/reducer.js +0 -219
  237. package/plugins/beta/datasets/src/reducers/keyReducer.js +0 -34
  238. package/plugins/beta/datasets/src/utils/filters.js +0 -34
  239. package/plugins/beta/datasets/src/utils/mergeSublayer.js +0 -86
  240. package/plugins/beta/draw-ml/dist/css/index.css +0 -21
  241. /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-maplibre-adapter.js.LICENSE.txt → im-datasets-ml-adapter.js.LICENSE.txt} +0 -0
  242. /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-plugin.js.LICENSE.txt → im-datasets-plugin.js.LICENSE.txt} +0 -0
  243. /package/plugins/beta/datasets/dist/umd/{maplibre/index.js.LICENSE.txt → index.js.LICENSE.txt} +0 -0
  244. /package/plugins/beta/datasets/src/components/{EmptyKey.jsx → Key/EmptyKey.jsx} +0 -0
  245. /package/plugins/beta/datasets/src/components/{EmptyKey.test.jsx → Key/EmptyKey.test.jsx} +0 -0
  246. /package/plugins/beta/datasets/src/{panels → components/Key}/Key.module.scss +0 -0
  247. /package/plugins/beta/datasets/src/components/{svgProperties.js → Key/svgProperties.js} +0 -0
@@ -0,0 +1,84 @@
1
+ import {
2
+ datasets, expectedDatasetsMenuConfig,
3
+ datasetsWithGroups, expectedDatasetsMenuConfigWithGroups
4
+ } from './__data__/demoDatasets.js'
5
+
6
+ import { datasetsToMenu } from './datasetsToMenu'
7
+
8
+ describe('datasetsToMenu', () => {
9
+ describe('Missing or empty datasets', () => {
10
+ it('handles empty datasets', async () => {
11
+ expect(datasetsToMenu({ datasets: [] }))
12
+ .toEqual([])
13
+ })
14
+
15
+ it('handles missing datasets', async () => {
16
+ expect(datasetsToMenu({}))
17
+ .toEqual([])
18
+ })
19
+ })
20
+
21
+ describe('Datasets without groups', () => {
22
+ it('transforms datasets to menu config', async () => {
23
+ expect(datasetsToMenu({ datasets }))
24
+ .toEqual(expectedDatasetsMenuConfig)
25
+ })
26
+ })
27
+
28
+ describe('Datasets with groups', () => {
29
+ it('transforms datasets with groups to menu config', async () => {
30
+ const datasetsWithGroupsMenuConfig = datasetsToMenu({ datasets: datasetsWithGroups })
31
+ expect(datasetsWithGroupsMenuConfig)
32
+ .toEqual(expectedDatasetsMenuConfigWithGroups)
33
+ })
34
+ })
35
+
36
+ describe('showInMenu inheritance for sublayers', () => {
37
+ const sublayerDataset = (datasetShowInMenu, sublayerShowInMenu) => ({
38
+ id: 'test',
39
+ label: 'Test',
40
+ showInMenu: datasetShowInMenu,
41
+ sublayers: [
42
+ { id: 'a', label: 'A', ...(sublayerShowInMenu !== undefined && { showInMenu: sublayerShowInMenu }) },
43
+ { id: 'b', label: 'B', ...(sublayerShowInMenu !== undefined && { showInMenu: sublayerShowInMenu }) }
44
+ ]
45
+ })
46
+
47
+ it('sublayers inherit showInMenu: true from the dataset when not explicitly set', () => {
48
+ const result = datasetsToMenu({ datasets: [sublayerDataset(true, undefined)] })
49
+ expect(result[0].items).toHaveLength(2)
50
+ })
51
+
52
+ it('sublayer can opt out with showInMenu: false when dataset has showInMenu: true', () => {
53
+ const dataset = {
54
+ id: 'test',
55
+ label: 'Test',
56
+ showInMenu: true,
57
+ sublayers: [
58
+ { id: 'a', label: 'A', showInMenu: false },
59
+ { id: 'b', label: 'B' }
60
+ ]
61
+ }
62
+ const result = datasetsToMenu({ datasets: [dataset] })
63
+ expect(result[0].items).toEqual([{ id: 'test-b', label: 'B' }])
64
+ })
65
+
66
+ it('sublayers with showInMenu: true appear when dataset does not have showInMenu set', () => {
67
+ const dataset = {
68
+ id: 'test',
69
+ label: 'Test',
70
+ sublayers: [
71
+ { id: 'a', label: 'A', showInMenu: true },
72
+ { id: 'b', label: 'B' }
73
+ ]
74
+ }
75
+ const result = datasetsToMenu({ datasets: [dataset] })
76
+ expect(result[0].items).toEqual([{ id: 'test-a', label: 'A' }])
77
+ })
78
+
79
+ it('does not add a menu entry when dataset has showInMenu: true but all sublayers opt out', () => {
80
+ const result = datasetsToMenu({ datasets: [sublayerDataset(true, false)] })
81
+ expect(result).toHaveLength(0)
82
+ })
83
+ })
84
+ })
@@ -0,0 +1,41 @@
1
+ import { applyDatasetDefaultsWithoutFlattening } from '../initialise/defaults.js'
2
+
3
+ const flattenSublayer = (parentId, sublayer) => {
4
+ const id = `${parentId}-${sublayer.id}`
5
+ const sublayerId = sublayer.id
6
+ if (sublayer.visibility !== 'hidden') {
7
+ sublayer.visibility = 'visible'
8
+ }
9
+ return { ...sublayer, id, parentId, sublayerId }
10
+ }
11
+
12
+ const reduceDatasets = (acc, dataset) => {
13
+ const { id } = dataset
14
+ const processed = applyDatasetDefaultsWithoutFlattening(dataset)
15
+ // For sublayers, don't let defaults override the absence of showInKey/showInMenu —
16
+ // the Dataset class inherits these from the parent when not explicitly set by the user
17
+ if (dataset.parentId) {
18
+ if (!('showInKey' in dataset)) { delete processed.showInKey }
19
+ if (!('showInMenu' in dataset)) { delete processed.showInMenu }
20
+ }
21
+ acc[id] = processed
22
+ const { orderedDatasets } = acc
23
+ orderedDatasets.push(id)
24
+ const flattenedSublayers = dataset.sublayers?.map((sublayer) => flattenSublayer(id, sublayer))
25
+ if (flattenedSublayers?.length) {
26
+ const sublayerIds = flattenedSublayers?.map(sublayer => sublayer.id)
27
+ const sublayers = flattenedSublayers?.reduce(reduceDatasets, { orderedDatasets })
28
+ acc[id].sublayerIds = sublayerIds
29
+ delete acc[id].sublayers
30
+ return { ...acc, ...sublayers, orderedDatasets }
31
+ }
32
+ return { ...acc, orderedDatasets }
33
+ }
34
+
35
+ export const mappedDatasetsReducer = (state) => {
36
+ const datasets = state.datasets || []
37
+ const mappedDatasets = datasets.reduce(reduceDatasets, { orderedDatasets: [] })
38
+ const { orderedDatasets } = mappedDatasets
39
+ delete mappedDatasets.orderedDatasets
40
+ return { ...state, mappedDatasets, orderedDatasets }
41
+ }
@@ -0,0 +1,117 @@
1
+ import { mappedDatasetsReducer } from './mappedDatasetsReducer'
2
+ import { datasetDefaults } from '../initialise/defaults.js'
3
+
4
+ describe('mappedDatasetsReducer', () => {
5
+ it('handles empty datasets', () => {
6
+ const result = mappedDatasetsReducer({ datasets: [] })
7
+ expect(result.mappedDatasets).toEqual({})
8
+ expect(result.orderedDatasets).toEqual([])
9
+ })
10
+
11
+ it('handles missing datasets', () => {
12
+ const result = mappedDatasetsReducer({})
13
+ expect(result.mappedDatasets).toEqual({})
14
+ expect(result.orderedDatasets).toEqual([])
15
+ })
16
+
17
+ it('maps a single dataset with no sublayers', () => {
18
+ const state = {
19
+ datasets: [{ id: 'roads', label: 'Roads', minZoom: 10 }]
20
+ }
21
+ const result = mappedDatasetsReducer(state)
22
+ expect(result.mappedDatasets).toEqual({
23
+ roads: { ...datasetDefaults, id: 'roads', label: 'Roads', minZoom: 10 }
24
+ })
25
+ expect(result.orderedDatasets).toEqual(['roads'])
26
+ })
27
+
28
+ it('maps multiple datasets preserving order', () => {
29
+ const state = {
30
+ datasets: [
31
+ { id: 'alpha', label: 'Alpha' },
32
+ { id: 'beta', label: 'Beta' },
33
+ { id: 'gamma', label: 'Gamma' }
34
+ ]
35
+ }
36
+ const result = mappedDatasetsReducer(state)
37
+ expect(result.orderedDatasets).toEqual(['alpha', 'beta', 'gamma'])
38
+ expect(Object.keys(result.mappedDatasets)).toEqual(['alpha', 'beta', 'gamma'])
39
+ })
40
+
41
+ it('preserves other state properties', () => {
42
+ const state = {
43
+ datasets: [],
44
+ someOtherProp: 'value',
45
+ nested: { foo: 'bar' }
46
+ }
47
+ const result = mappedDatasetsReducer(state)
48
+ expect(result.someOtherProp).toBe('value')
49
+ expect(result.nested).toEqual({ foo: 'bar' })
50
+ })
51
+
52
+ describe('with sublayers', () => {
53
+ const state = {
54
+ datasets: [{
55
+ id: 'land-covers',
56
+ label: 'Land covers',
57
+ sublayers: [
58
+ { id: 'grassland', label: 'Grassland' },
59
+ { id: 'woodland', label: 'Woodland', visibility: 'hidden' }
60
+ ]
61
+ }]
62
+ }
63
+
64
+ it('removes the sublayers property from the parent dataset', () => {
65
+ const result = mappedDatasetsReducer(state)
66
+ expect(result.mappedDatasets['land-covers'].sublayers).toBeUndefined()
67
+ })
68
+
69
+ it('adds sublayerIds to the parent dataset', () => {
70
+ const result = mappedDatasetsReducer(state)
71
+ expect(result.mappedDatasets['land-covers'].sublayerIds).toEqual([
72
+ 'land-covers-grassland',
73
+ 'land-covers-woodland'
74
+ ])
75
+ })
76
+
77
+ it('adds flattened sublayers to mappedDatasets', () => {
78
+ const result = mappedDatasetsReducer(state)
79
+ expect(result.mappedDatasets['land-covers-grassland']).toBeDefined()
80
+ expect(result.mappedDatasets['land-covers-woodland']).toBeDefined()
81
+ })
82
+
83
+ it('sets compound id on flattened sublayer', () => {
84
+ const result = mappedDatasetsReducer(state)
85
+ expect(result.mappedDatasets['land-covers-grassland'].id).toBe('land-covers-grassland')
86
+ })
87
+
88
+ it('sets parentId on flattened sublayer', () => {
89
+ const result = mappedDatasetsReducer(state)
90
+ expect(result.mappedDatasets['land-covers-grassland'].parentId).toBe('land-covers')
91
+ })
92
+
93
+ it('sets sublayerId to the original sublayer id', () => {
94
+ const result = mappedDatasetsReducer(state)
95
+ expect(result.mappedDatasets['land-covers-grassland'].sublayerId).toBe('grassland')
96
+ })
97
+
98
+ it('sets visibility to visible for sublayers without explicit visibility', () => {
99
+ const result = mappedDatasetsReducer(state)
100
+ expect(result.mappedDatasets['land-covers-grassland'].visibility).toBe('visible')
101
+ })
102
+
103
+ it('preserves hidden visibility on sublayers', () => {
104
+ const result = mappedDatasetsReducer(state)
105
+ expect(result.mappedDatasets['land-covers-woodland'].visibility).toBe('hidden')
106
+ })
107
+
108
+ it('includes sublayers in orderedDatasets after their parent', () => {
109
+ const result = mappedDatasetsReducer(state)
110
+ expect(result.orderedDatasets).toEqual([
111
+ 'land-covers',
112
+ 'land-covers-grassland',
113
+ 'land-covers-woodland'
114
+ ])
115
+ })
116
+ })
117
+ })
@@ -0,0 +1,206 @@
1
+ import { datasetsToMenu, addDatasetToMenu, removeDatasetsFromMenu } from './datasetsToMenu.js'
2
+ import { mappedDatasetsReducer } from './mappedDatasetsReducer.js'
3
+ import { logger } from '../../../../../src/services/logger.js'
4
+
5
+ const initialState = {
6
+ globals: {
7
+ visible: true,
8
+ opacity: 1,
9
+ opacityMode: 'dataset'
10
+ // 'dataset': registryDataset opacity is used instead if set;
11
+ // 'global': registryDataset opacity is ignored
12
+ // 'multiply': registryDataset opacity is multiplied by parent opacity and global opacity
13
+ },
14
+ key: {
15
+ items: [],
16
+ hasGroups: false
17
+ },
18
+ actionsArray: []
19
+ }
20
+
21
+ const validateDatasetExists = (state, datasetId, prefix, suffix = 'not found') => {
22
+ if (!state.mappedDatasets[datasetId]) {
23
+ logger.error(`${prefix}: Dataset with id '${datasetId}' ${suffix}`)
24
+ return false
25
+ }
26
+ return true
27
+ }
28
+
29
+ let actionId = 0
30
+ const addAction = (method, parameters, state) => {
31
+ actionId = state.actionsArray.length ? actionId + 1 : 0
32
+ return { ...state, actionsArray: [...state.actionsArray, { method, parameters, actionId }] }
33
+ }
34
+
35
+ const setGlobalState = (state, payload) => {
36
+ // For now we only have opacityMode, but if we add more global state
37
+ // properties we may not require applyGlobalOpacity to be triggered here.
38
+ return addAction('applyGlobalOpacity', [], {
39
+ ...state,
40
+ globals: { ...state.globals, ...payload }
41
+ })
42
+ }
43
+
44
+ const setDatasets = (state, payload) => {
45
+ const { datasets, mappedDatasets, orderedDatasets } = payload
46
+ const menu = payload.menu || datasetsToMenu({ datasets })
47
+ return {
48
+ ...state,
49
+ mappedDatasets,
50
+ orderedDatasets,
51
+ menu
52
+ }
53
+ }
54
+
55
+ const addDataset = (state, payload) => {
56
+ const { dataset, mapStyle } = payload
57
+ if (state.mappedDatasets[dataset.id]) {
58
+ logger.error(`addDataset: Dataset with id '${dataset.id}' already exists`)
59
+ return state
60
+ }
61
+ const { mappedDatasets: newDatasets, orderedDatasets: newOrderedDatasets } = mappedDatasetsReducer({ datasets: [dataset] })
62
+ const menu = addDatasetToMenu(state, dataset)
63
+
64
+ return addAction('addDataset', [dataset.id, mapStyle], {
65
+ ...state,
66
+ mappedDatasets: { ...state.mappedDatasets, ...newDatasets },
67
+ orderedDatasets: [...state.orderedDatasets, ...newOrderedDatasets],
68
+ menu
69
+ })
70
+ }
71
+
72
+ const removeDataset = (state, payload) => {
73
+ const { id } = payload
74
+ if (!validateDatasetExists(state, id, 'removeDataset')) {
75
+ return state
76
+ }
77
+ const mappedDatasets = { ...state.mappedDatasets }
78
+ const datasetsToRemove = [id, ...(mappedDatasets[id]?.sublayerIds || [])]
79
+ datasetsToRemove.forEach((datasetId) => delete mappedDatasets[datasetId])
80
+ // Remove from orderedDatasets
81
+ const orderedDatasets = state.orderedDatasets.filter(datasetId => !datasetsToRemove.includes(datasetId))
82
+ // Remove from menu, and remove any menu groups that are left with no items
83
+ return {
84
+ ...state,
85
+ mappedDatasets,
86
+ orderedDatasets,
87
+ menu: removeDatasetsFromMenu(state.menu, datasetsToRemove)
88
+ }
89
+ }
90
+
91
+ const setDatasetVisibility = (state, payload) => {
92
+ const { datasetId, visible } = payload
93
+ if (!validateDatasetExists(state, datasetId, 'setDatasetVisibility')) {
94
+ return state
95
+ }
96
+
97
+ return addAction('applyDatasetVisibility', [datasetId, visible], {
98
+ ...state,
99
+ mappedDatasets: { ...state.mappedDatasets, [datasetId]: { ...state.mappedDatasets[datasetId], visible } }
100
+ })
101
+ }
102
+
103
+ const setGlobalVisibility = (state, payload) => {
104
+ const { visible } = payload
105
+
106
+ return addAction('applyGlobalVisibility', [visible], {
107
+ ...state,
108
+ globals: { ...state.globals, visible }
109
+ })
110
+ }
111
+
112
+ const hideFeatures = (state, payload) => {
113
+ const { datasetId, featureIds } = payload
114
+ if (!validateDatasetExists(state, datasetId, 'setFeatureVisibility - hideFeatures')) {
115
+ return state
116
+ }
117
+ const mappedDataset = { ...state.mappedDatasets[datasetId] }
118
+ const existingIds = mappedDataset.hiddenFeatures || []
119
+ const newIds = Array.from(new Set([...existingIds, ...featureIds]))
120
+ mappedDataset.hiddenFeatures = newIds
121
+
122
+ return addAction('applyFeatureFilter', [datasetId], {
123
+ ...state,
124
+ mappedDatasets: { ...state.mappedDatasets, [datasetId]: mappedDataset }
125
+ })
126
+ }
127
+
128
+ const showFeatures = (state, payload) => {
129
+ const { datasetId, featureIds } = payload
130
+ if (!validateDatasetExists(state, datasetId, 'setFeatureVisibility - showFeatures')) {
131
+ return state
132
+ }
133
+ const mappedDataset = { ...state.mappedDatasets[datasetId] }
134
+ const existingIds = mappedDataset.hiddenFeatures || []
135
+ const newIds = existingIds.filter(id => !featureIds.includes(id))
136
+ mappedDataset.hiddenFeatures = newIds.length ? newIds : [-1] // If no features are hidden, set to -1 to force a filter update
137
+
138
+ return addAction('applyFeatureFilter', [datasetId], {
139
+ ...state,
140
+ mappedDatasets: { ...state.mappedDatasets, [datasetId]: mappedDataset }
141
+ })
142
+ }
143
+
144
+ const removeAdapterActions = (state, completedActions) => {
145
+ if (!completedActions?.length) { return state }
146
+ return {
147
+ ...state,
148
+ actionsArray: state.actionsArray.filter((current) => !completedActions.includes(current))
149
+ }
150
+ }
151
+
152
+ const setDatasetStyle = (state, payload) => {
153
+ const { datasetId, styleChanges, mapStyle } = payload
154
+ if (!validateDatasetExists(state, datasetId, 'setDatasetStyle')) {
155
+ return state
156
+ }
157
+ const style = { ...state.mappedDatasets[datasetId].style, ...styleChanges }
158
+ const dataset = { ...state.mappedDatasets[datasetId], ...styleChanges, style }
159
+
160
+ return addAction('applyStyle', [datasetId, mapStyle], {
161
+ ...state,
162
+ mappedDatasets: { ...state.mappedDatasets, [datasetId]: dataset }
163
+ })
164
+ }
165
+
166
+ const setOpacity = (state, payload) => {
167
+ const { datasetId, opacity } = payload
168
+ if (!validateDatasetExists(state, datasetId, 'setOpacity')) {
169
+ return state
170
+ }
171
+ const style = { ...state.mappedDatasets[datasetId].style, opacity }
172
+ const dataset = { ...state.mappedDatasets[datasetId], style }
173
+
174
+ return addAction('applyDatasetOpacity', [datasetId], {
175
+ ...state,
176
+ mappedDatasets: { ...state.mappedDatasets, [datasetId]: dataset }
177
+ })
178
+ }
179
+
180
+ const setGlobalOpacity = (state, payload) => {
181
+ const { opacity } = payload
182
+ return addAction('applyGlobalOpacity', [], {
183
+ ...state,
184
+ globals: { ...state.globals, opacity }
185
+ })
186
+ }
187
+
188
+ const actions = {
189
+ SET_DATASETS: setDatasets,
190
+ ADD_DATASET: addDataset,
191
+ REMOVE_DATASET: removeDataset,
192
+ SET_DATASET_VISIBILITY: setDatasetVisibility,
193
+ SET_GLOBAL_VISIBILITY: setGlobalVisibility,
194
+ SET_DATASET_STYLE: setDatasetStyle,
195
+ SET_OPACITY: setOpacity,
196
+ SET_GLOBAL_OPACITY: setGlobalOpacity,
197
+ HIDE_FEATURES: hideFeatures,
198
+ SHOW_FEATURES: showFeatures,
199
+ REMOVE_ADAPTER_ACTIONS: removeAdapterActions,
200
+ SET_GLOBAL_STATE: setGlobalState
201
+ }
202
+
203
+ export {
204
+ initialState,
205
+ actions
206
+ }