From c3683c98db01dc4ba177e1235e90190c46f6f414 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 23 Apr 2026 16:38:43 +0100 Subject: [PATCH 01/12] IM-224 added mappedDatasetsReducer tests --- .../src/reducers/mappedDatasetsReducer.js | 4 +- .../reducers/mappedDatasetsReducer.test.js | 116 ++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js diff --git a/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js b/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js index 42defca6..6666b1d4 100644 --- a/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +++ b/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js @@ -1,6 +1,9 @@ const flattenSublayer = (parentId, sublayer) => { const id = `${parentId}-${sublayer.id}` const sublayerId = sublayer.id + if (sublayer.visibility !== 'hidden') { + sublayer.visibility = 'visible' + } return { ...sublayer, id, parentId, sublayerId } } @@ -13,7 +16,6 @@ const reduceDatasets = (acc, dataset) => { if (flattenedSublayers?.length) { const sublayerIds = flattenedSublayers?.map(sublayer => sublayer.id) const sublayers = flattenedSublayers?.reduce(reduceDatasets, { orderedDatasets }) - // orderedDatasets.push(...sublayerIds) acc[id].sublayerIds = sublayerIds delete acc[id].sublayers return { ...acc, ...sublayers, orderedDatasets } diff --git a/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js b/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js new file mode 100644 index 00000000..116be00f --- /dev/null +++ b/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js @@ -0,0 +1,116 @@ +import { mappedDatasetsReducer } from './mappedDatasetsReducer' + +describe('mappedDatasetsReducer', () => { + it('handles empty datasets', () => { + const result = mappedDatasetsReducer({ datasets: [] }) + expect(result.mappedDatasets).toEqual({}) + expect(result.orderedDatasets).toEqual([]) + }) + + it('handles missing datasets', () => { + const result = mappedDatasetsReducer({}) + expect(result.mappedDatasets).toEqual({}) + expect(result.orderedDatasets).toEqual([]) + }) + + it('maps a single dataset with no sublayers', () => { + const state = { + datasets: [{ id: 'roads', label: 'Roads', minZoom: 10 }] + } + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets).toEqual({ + roads: { id: 'roads', label: 'Roads', minZoom: 10 } + }) + expect(result.orderedDatasets).toEqual(['roads']) + }) + + it('maps multiple datasets preserving order', () => { + const state = { + datasets: [ + { id: 'alpha', label: 'Alpha' }, + { id: 'beta', label: 'Beta' }, + { id: 'gamma', label: 'Gamma' } + ] + } + const result = mappedDatasetsReducer(state) + expect(result.orderedDatasets).toEqual(['alpha', 'beta', 'gamma']) + expect(Object.keys(result.mappedDatasets)).toEqual(['alpha', 'beta', 'gamma']) + }) + + it('preserves other state properties', () => { + const state = { + datasets: [], + someOtherProp: 'value', + nested: { foo: 'bar' } + } + const result = mappedDatasetsReducer(state) + expect(result.someOtherProp).toBe('value') + expect(result.nested).toEqual({ foo: 'bar' }) + }) + + describe('with sublayers', () => { + const state = { + datasets: [{ + id: 'land-covers', + label: 'Land covers', + sublayers: [ + { id: 'grassland', label: 'Grassland' }, + { id: 'woodland', label: 'Woodland', visibility: 'hidden' } + ] + }] + } + + it('removes the sublayers property from the parent dataset', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers'].sublayers).toBeUndefined() + }) + + it('adds sublayerIds to the parent dataset', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers'].sublayerIds).toEqual([ + 'land-covers-grassland', + 'land-covers-woodland' + ]) + }) + + it('adds flattened sublayers to mappedDatasets', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers-grassland']).toBeDefined() + expect(result.mappedDatasets['land-covers-woodland']).toBeDefined() + }) + + it('sets compound id on flattened sublayer', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers-grassland'].id).toBe('land-covers-grassland') + }) + + it('sets parentId on flattened sublayer', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers-grassland'].parentId).toBe('land-covers') + }) + + it('sets sublayerId to the original sublayer id', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers-grassland'].sublayerId).toBe('grassland') + }) + + it('sets visibility to visible for sublayers without explicit visibility', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers-grassland'].visibility).toBe('visible') + }) + + it('preserves hidden visibility on sublayers', () => { + const result = mappedDatasetsReducer(state) + expect(result.mappedDatasets['land-covers-woodland'].visibility).toBe('hidden') + }) + + it('includes sublayers in orderedDatasets after their parent', () => { + const result = mappedDatasetsReducer(state) + expect(result.orderedDatasets).toEqual([ + 'land-covers', + 'land-covers-grassland', + 'land-covers-woodland' + ]) + }) + }) +}) From 5e51a1ebe864a56fa385bc0f9806befeede94897 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Fri, 24 Apr 2026 12:58:46 +0100 Subject: [PATCH 02/12] IM-224 changed signature parameter name on getPatternImageId --- src/utils/patternUtils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils/patternUtils.js b/src/utils/patternUtils.js index 31a758be..e4dbe803 100644 --- a/src/utils/patternUtils.js +++ b/src/utils/patternUtils.js @@ -54,7 +54,7 @@ export const getPatternInnerContent = (dataset, patternRegistry) => { /** * Returns a deterministic image ID for a pattern + resolved colour + pixel ratio combination. * - * @param {Object} dataset + * @param {Object} style * @param {string} mapStyleId * @param {Object} patternRegistry * @param {number} [pixelRatio=1] @@ -63,13 +63,13 @@ export const getPatternInnerContent = (dataset, patternRegistry) => { // Minimum oversampling — keeps 16×16 physical pixels as the floor so patterns remain crisp. export const PATTERN_MIN_PIXEL_RATIO = 2 -export const getPatternImageId = (dataset, mapStyleId, patternRegistry, pixelRatio = 1) => { - const innerContent = getPatternInnerContent(dataset, patternRegistry) +export const getPatternImageId = (style, mapStyleId, patternRegistry, pixelRatio = 1) => { + const innerContent = getPatternInnerContent(style, patternRegistry) if (!innerContent) { return null } - const fg = getValueForStyle(dataset.fillPatternForegroundColor, mapStyleId) || 'black' - const bg = getValueForStyle(dataset.fillPatternBackgroundColor, mapStyleId) || 'transparent' + const fg = getValueForStyle(style.fillPatternForegroundColor, mapStyleId) || 'black' + const bg = getValueForStyle(style.fillPatternBackgroundColor, mapStyleId) || 'transparent' const effectiveRatio = Math.max(PATTERN_MIN_PIXEL_RATIO, pixelRatio) return `pattern-${hashString(innerContent + fg + bg)}-${effectiveRatio}x` } From cc5ea0c29ff425a73b8e006fc00bf60d0f5a6930 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Fri, 24 Apr 2026 13:01:23 +0100 Subject: [PATCH 03/12] IM-224 Temp console.log effect in Layers.jsx --- plugins/beta/datasets/src/panels/Layers.jsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/beta/datasets/src/panels/Layers.jsx b/plugins/beta/datasets/src/panels/Layers.jsx index c5273e5d..8091674c 100755 --- a/plugins/beta/datasets/src/panels/Layers.jsx +++ b/plugins/beta/datasets/src/panels/Layers.jsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useEffect } from 'react' import { setDatasetVisibility } from '../api/setDatasetVisibility' const CHECKBOX_LABEL_CLASS = 'im-c-datasets-layers__item-label govuk-label govuk-checkboxes__label' @@ -70,6 +70,13 @@ export const Layers = ({ pluginState }) => { ) } + // TODO - remove this useEffect - it's useful while refactoring the state + useEffect(() => { + // console.log('menu:', pluginState.menu) + console.log('datasets:', pluginState.datasets) + console.log('mappedDatasets:', pluginState.mappedDatasets) + // console.log('orderedDatasets:', pluginState.orderedDatasets) + }, [pluginState.datasets, pluginState.mappedDatasets]) const visibleDatasets = (pluginState.datasets || []) .filter(dataset => dataset.showInMenu || hasToggleableSublayers(dataset)) From c93aed7542a33de7f8300ff2498bb0bf487c291e Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Fri, 24 Apr 2026 13:02:37 +0100 Subject: [PATCH 04/12] IM-224 added some timeout changes to styles/visibility to test state changes --- demo/js/index.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/demo/js/index.js b/demo/js/index.js index cebe9211..096fef07 100755 --- a/demo/js/index.js +++ b/demo/js/index.js @@ -314,7 +314,25 @@ interactiveMap.on('map:ready', function (e) { interactiveMap.on('datasets:ready', function () { // setTimeout(() => datasetsPlugin.setFeatureVisibility(false, [55], { datasetId: 'land-covers', idProperty: null }), 2000) // setTimeout(() => datasetsPlugin.setFeatureVisibility(true, [55], { datasetId: 'land-covers', idProperty: null }), 4000) - // setTimeout(() => datasetsPlugin.setStyle({ stroke: { outdoor: '#ff0000', dark: '#ffffff' }, fillPattern: 'horizontal-hatch', fillPatternForegroundColor: { outdoor: '#ff0000', dark: '#ffffff' } }, { datasetId: 'land-covers', sublayerId: '130' }), 2000) + + // style: { + // stroke: { outdoor: '#00897B', dark: '#ffffff' }, + // fillPattern: 'diagonal-cross-hatch', + // fillPatternForegroundColor: { outdoor: '#00897B', dark: '#ffffff' }, + // fillPatternBackgroundColor: 'transparent' + // } + + + setTimeout(() => datasetsPlugin.setStyle( + { + stroke: { outdoor: '#ff0000', dark: '#ffffff' }, + fillPattern: 'diagonal-cross-hatch', + fillPatternForegroundColor: { outdoor: '#ff0000', dark: '#ffffff' }, + fillPatternBackgroundColor: 'transparent' + }, + { datasetId: 'land-covers', sublayerId: '130-131' }), 2000) + setTimeout(() => datasetsPlugin.setDatasetVisibility(true, { datasetId: 'hedge-control' }), 500) + setTimeout(() => datasetsPlugin.setStyle({ stroke: { outdoor: '#ffff00' }, }, { datasetId: 'hedge-control' }), 1000) }) // Ref to the selected features From a196518666bedde01f744c04dabded36357ec113 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Fri, 24 Apr 2026 13:05:41 +0100 Subject: [PATCH 05/12] IM-224 WIP - attempt to refactor setStyle to use mappedDatasets --- .../adapters/maplibre/maplibreLayerAdapter.js | 32 +++++++++++++------ plugins/beta/datasets/src/api/setStyle.js | 27 +++++++++------- plugins/beta/datasets/src/reducer.js | 17 ++++++++-- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js index 961c6b64..38dfa7f4 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +++ b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js @@ -292,28 +292,42 @@ export default class MaplibreLayerAdapter { * @param {Object} mapStyle * @returns {Promise} */ - async setSublayerStyle (dataset, sublayerId, mapStyle) { + async setSublayerStyle (dataset, sublayer, mapStyle) { + console.log('adapter setSublayerStyle started - dataset, sublayer:', dataset, sublayer) const mapStyleId = mapStyle.id const pixelRatio = this._pixelRatio - const { fillLayerId, strokeLayerId, symbolLayerId } = getSublayerLayerIds(dataset.id, sublayerId) + const { fillLayerId, strokeLayerId, symbolLayerId } = getSublayerLayerIds(dataset.id, sublayer.sublayerId) ;[fillLayerId, strokeLayerId, symbolLayerId].forEach(layerId => { if (this._map.getLayer(layerId)) { this._map.removeLayer(layerId) } this._symbolLayerIds.delete(layerId) }) - const sublayer = dataset.sublayers?.find(s => s.id === sublayerId) - if (!sublayer) { - return - } + // const legacySublayer = dataset.sublayers?.find(s => s.id === sublayer.sublayerId) + // if (!legacySublayer) { + // console.log('mapLibreAdapter._patternRegistry.list()', this._patternRegistry.list()) + // console.log('mapLibreAdapter._symbolRegistry.list()', this._symbolRegistry.list()) + // console.log('adapter setSublayerStyle returning early - no legacySublayer') + // return + // } + // Here we only need to registerPatterns + // if a new pattern or changed pattern. + // if its just a different foreground/background colour + // we can skip this step as the pattern id + // is the same and the registry will return the + // same imageData which is coloured at render time + // based on the current style (see injectColors in patternImages.js). await Promise.all([ - this._mapProvider.registerPatterns(getPatternConfigs([dataset], this._patternRegistry), mapStyleId, this._patternRegistry), - this._mapProvider.registerSymbols(getSymbolConfigs([dataset]), mapStyle, this._symbolRegistry) + this._mapProvider.registerPatterns([sublayer.style], mapStyleId, this._patternRegistry), + // this._mapProvider.registerPatterns(getPatternConfigs([dataset], this._patternRegistry), mapStyleId, this._patternRegistry), + // this._mapProvider.registerSymbols(getSymbolConfigs([dataset]), mapStyle, this._symbolRegistry) + this._mapProvider.registerSymbols([sublayer.style], mapStyle, this._symbolRegistry) ]) const sourceId = this._datasetSourceMap.get(dataset.id) const sourceLayer = dataset.tiles?.length ? dataset.sourceLayer : undefined - addSublayerLayers(this._map, dataset, sublayer, sourceId, sourceLayer, { mapStyle, symbolRegistry: this._symbolRegistry, patternRegistry: this._patternRegistry, pixelRatio }) + addSublayerLayers(this._map, dataset, sublayer.sublayerId, sourceId, sourceLayer, { mapStyle, symbolRegistry: this._symbolRegistry, patternRegistry: this._patternRegistry, pixelRatio }) this._maintainSymbolOrdering(dataset) + console.log('adapter setSublayerStyle completed') } /** diff --git a/plugins/beta/datasets/src/api/setStyle.js b/plugins/beta/datasets/src/api/setStyle.js index 7da65bd6..4b32eaad 100644 --- a/plugins/beta/datasets/src/api/setStyle.js +++ b/plugins/beta/datasets/src/api/setStyle.js @@ -5,18 +5,23 @@ export const setStyle = ({ pluginState, mapState }, style, { datasetId, sublayer } if (sublayerId) { - pluginState.dispatch({ type: 'SET_SUBLAYER_STYLE', payload: { datasetId, sublayerId, styleChanges: style } }) - const updatedSublayerDataset = { - ...dataset, - sublayers: dataset.sublayers?.map(sublayer => - sublayer.id === sublayerId ? { ...sublayer, style: { ...sublayer.style, ...style } } : sublayer - ) - } - pluginState.layerAdapter?.setSublayerStyle(updatedSublayerDataset, sublayerId, mapState.mapStyle) + pluginState.dispatch({ + type: 'SET_SUBLAYER_STYLE', + payload: { + datasetId, sublayerId, styleChanges: style, mapStyle: mapState.mapStyle + } + }) + // const updatedSublayerDataset = { + // ...dataset, + // sublayers: dataset.sublayers?.map(sublayer => + // sublayer.id === sublayerId ? { ...sublayer, style: { ...sublayer.style, ...style } } : sublayer + // ) + // } + // pluginState.layerAdapter?.setSublayerStyle(updatedSublayerDataset, sublayerId, mapState.mapStyle) return } - pluginState.dispatch({ type: 'SET_DATASET_STYLE', payload: { datasetId, styleChanges: style } }) - const updatedDataset = { ...dataset, ...style } - pluginState.layerAdapter?.setStyle(updatedDataset, mapState.mapStyle) + pluginState.dispatch({ type: 'SET_DATASET_STYLE', payload: { datasetId, styleChanges: style, mapStyle: mapState.mapStyle } }) + // const updatedDataset = { ...dataset, ...style } + // pluginState.layerAdapter?.setStyle(updatedDataset, mapState.mapStyle) } diff --git a/plugins/beta/datasets/src/reducer.js b/plugins/beta/datasets/src/reducer.js index addf7410..3a62be1a 100755 --- a/plugins/beta/datasets/src/reducer.js +++ b/plugins/beta/datasets/src/reducer.js @@ -137,9 +137,14 @@ const setSublayerVisibility = (state, payload) => { } const setDatasetStyle = (state, payload) => { - const { datasetId, styleChanges } = payload + const { datasetId, styleChanges, mapStyle } = payload + const { layerAdapter } = state + const dataset = { ...state.mappedDatasets[datasetId], ...styleChanges } + // TODO - handle this side effect better + layerAdapter?.setStyle(dataset, mapStyle) return { ...state, + mappedDatasets: { ...state.mappedDatasets, [datasetId]: dataset }, datasets: state.datasets?.map(dataset => dataset.id === datasetId ? { ...dataset, ...styleChanges } : dataset ) @@ -147,9 +152,17 @@ const setDatasetStyle = (state, payload) => { } const setSublayerStyle = (state, payload) => { - const { datasetId, sublayerId, styleChanges } = payload + const { datasetId, sublayerId, styleChanges, mapStyle } = payload + const { layerAdapter } = state + const id = `${datasetId}-${sublayerId}` + const dataset = state.mappedDatasets[datasetId] + const subLayer = { ...state.mappedDatasets[id], ...styleChanges } + // TODO - handle this side effect better + layerAdapter.setSublayerStyle(dataset, subLayer, mapStyle) + console.log('reducer setSublayerStyle completed') return { ...state, + mappedDatasets: { ...state.mappedDatasets, [id]: subLayer }, datasets: state.datasets?.map(dataset => { if (dataset.id !== datasetId) { return dataset From 70a944287317b36809de8d384ccb096b7f2f317c Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Mon, 27 Apr 2026 16:56:18 +0100 Subject: [PATCH 06/12] Revert IM-224 changed signature parameter name on getPatternImageId --- src/utils/patternUtils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils/patternUtils.js b/src/utils/patternUtils.js index e4dbe803..31a758be 100644 --- a/src/utils/patternUtils.js +++ b/src/utils/patternUtils.js @@ -54,7 +54,7 @@ export const getPatternInnerContent = (dataset, patternRegistry) => { /** * Returns a deterministic image ID for a pattern + resolved colour + pixel ratio combination. * - * @param {Object} style + * @param {Object} dataset * @param {string} mapStyleId * @param {Object} patternRegistry * @param {number} [pixelRatio=1] @@ -63,13 +63,13 @@ export const getPatternInnerContent = (dataset, patternRegistry) => { // Minimum oversampling — keeps 16×16 physical pixels as the floor so patterns remain crisp. export const PATTERN_MIN_PIXEL_RATIO = 2 -export const getPatternImageId = (style, mapStyleId, patternRegistry, pixelRatio = 1) => { - const innerContent = getPatternInnerContent(style, patternRegistry) +export const getPatternImageId = (dataset, mapStyleId, patternRegistry, pixelRatio = 1) => { + const innerContent = getPatternInnerContent(dataset, patternRegistry) if (!innerContent) { return null } - const fg = getValueForStyle(style.fillPatternForegroundColor, mapStyleId) || 'black' - const bg = getValueForStyle(style.fillPatternBackgroundColor, mapStyleId) || 'transparent' + const fg = getValueForStyle(dataset.fillPatternForegroundColor, mapStyleId) || 'black' + const bg = getValueForStyle(dataset.fillPatternBackgroundColor, mapStyleId) || 'transparent' const effectiveRatio = Math.max(PATTERN_MIN_PIXEL_RATIO, pixelRatio) return `pattern-${hashString(innerContent + fg + bg)}-${effectiveRatio}x` } From 4f6ac310306098f30b9c3c4ffefe5a18dc2c65e0 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Mon, 27 Apr 2026 16:58:45 +0100 Subject: [PATCH 07/12] IM-224 added a demo timeout change of style --- demo/js/index.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/demo/js/index.js b/demo/js/index.js index 096fef07..47e29c4a 100755 --- a/demo/js/index.js +++ b/demo/js/index.js @@ -315,24 +315,16 @@ interactiveMap.on('datasets:ready', function () { // setTimeout(() => datasetsPlugin.setFeatureVisibility(false, [55], { datasetId: 'land-covers', idProperty: null }), 2000) // setTimeout(() => datasetsPlugin.setFeatureVisibility(true, [55], { datasetId: 'land-covers', idProperty: null }), 4000) - // style: { - // stroke: { outdoor: '#00897B', dark: '#ffffff' }, - // fillPattern: 'diagonal-cross-hatch', - // fillPatternForegroundColor: { outdoor: '#00897B', dark: '#ffffff' }, - // fillPatternBackgroundColor: 'transparent' - // } - - setTimeout(() => datasetsPlugin.setStyle( { stroke: { outdoor: '#ff0000', dark: '#ffffff' }, - fillPattern: 'diagonal-cross-hatch', + fillPattern: 'horizontal-hatch', fillPatternForegroundColor: { outdoor: '#ff0000', dark: '#ffffff' }, fillPatternBackgroundColor: 'transparent' }, { datasetId: 'land-covers', sublayerId: '130-131' }), 2000) - setTimeout(() => datasetsPlugin.setDatasetVisibility(true, { datasetId: 'hedge-control' }), 500) - setTimeout(() => datasetsPlugin.setStyle({ stroke: { outdoor: '#ffff00' }, }, { datasetId: 'hedge-control' }), 1000) + // setTimeout(() => datasetsPlugin.setDatasetVisibility(true, { datasetId: 'hedge-control' }), 500) + // setTimeout(() => datasetsPlugin.setStyle({ stroke: { outdoor: '#ffff00' }, }, { datasetId: 'hedge-control' }), 1000) }) // Ref to the selected features From e2f7014a51e5e7fd80796a2d1f4009a98aab6e39 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Tue, 28 Apr 2026 09:07:35 +0100 Subject: [PATCH 08/12] IM-224 setStyle and setSubLayerStyle use mappedDatasets --- .../src/adapters/maplibre/layerBuilders.js | 2 +- .../adapters/maplibre/maplibreLayerAdapter.js | 22 ++----------------- .../maplibre/maplibreLayerAdapter.test.js | 2 +- plugins/beta/datasets/src/reducer.js | 4 ++-- 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js b/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js index bdd99ed6..3f731777 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +++ b/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js @@ -108,7 +108,7 @@ export const addSymbolLayer = (map, dataset, layerId, sourceId, sourceLayer, vis export const addSublayerLayers = (map, dataset, sublayer, sourceId, sourceLayer, { mapStyle, symbolRegistry, patternRegistry, pixelRatio }) => { const mapStyleId = mapStyle.id const merged = mergeSublayer(dataset, sublayer) - const { fillLayerId, strokeLayerId, symbolLayerId } = getSublayerLayerIds(dataset.id, sublayer.id) + const { fillLayerId, strokeLayerId, symbolLayerId } = getSublayerLayerIds(dataset.id, sublayer.sublayerId ? sublayer.sublayerId : sublayer.id) const parentHidden = dataset.visibility === 'hidden' const sublayerHidden = dataset.sublayerVisibility?.[sublayer.id] === 'hidden' const visibility = (parentHidden || sublayerHidden) ? 'none' : 'visible' diff --git a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js index 38dfa7f4..31790c1d 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +++ b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js @@ -293,7 +293,6 @@ export default class MaplibreLayerAdapter { * @returns {Promise} */ async setSublayerStyle (dataset, sublayer, mapStyle) { - console.log('adapter setSublayerStyle started - dataset, sublayer:', dataset, sublayer) const mapStyleId = mapStyle.id const pixelRatio = this._pixelRatio const { fillLayerId, strokeLayerId, symbolLayerId } = getSublayerLayerIds(dataset.id, sublayer.sublayerId) @@ -303,31 +302,14 @@ export default class MaplibreLayerAdapter { } this._symbolLayerIds.delete(layerId) }) - // const legacySublayer = dataset.sublayers?.find(s => s.id === sublayer.sublayerId) - // if (!legacySublayer) { - // console.log('mapLibreAdapter._patternRegistry.list()', this._patternRegistry.list()) - // console.log('mapLibreAdapter._symbolRegistry.list()', this._symbolRegistry.list()) - // console.log('adapter setSublayerStyle returning early - no legacySublayer') - // return - // } - // Here we only need to registerPatterns - // if a new pattern or changed pattern. - // if its just a different foreground/background colour - // we can skip this step as the pattern id - // is the same and the registry will return the - // same imageData which is coloured at render time - // based on the current style (see injectColors in patternImages.js). - await Promise.all([ + await Promise.all([ // Add pattern and symbol images to the map before re-adding layers, so they're available for use in the new style. this._mapProvider.registerPatterns([sublayer.style], mapStyleId, this._patternRegistry), - // this._mapProvider.registerPatterns(getPatternConfigs([dataset], this._patternRegistry), mapStyleId, this._patternRegistry), - // this._mapProvider.registerSymbols(getSymbolConfigs([dataset]), mapStyle, this._symbolRegistry) this._mapProvider.registerSymbols([sublayer.style], mapStyle, this._symbolRegistry) ]) const sourceId = this._datasetSourceMap.get(dataset.id) const sourceLayer = dataset.tiles?.length ? dataset.sourceLayer : undefined - addSublayerLayers(this._map, dataset, sublayer.sublayerId, sourceId, sourceLayer, { mapStyle, symbolRegistry: this._symbolRegistry, patternRegistry: this._patternRegistry, pixelRatio }) + addSublayerLayers(this._map, dataset, sublayer, sourceId, sourceLayer, { mapStyle, symbolRegistry: this._symbolRegistry, patternRegistry: this._patternRegistry, pixelRatio }) this._maintainSymbolOrdering(dataset) - console.log('adapter setSublayerStyle completed') } /** diff --git a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js index a415f683..983c3bb1 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +++ b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js @@ -365,7 +365,7 @@ describe('setSublayerStyle', () => { it('removes existing sublayer layers before re-adding', async () => { const { adapter, map } = makeAdapter({ 'ds-sl': 'fill', 'ds-sl-stroke': 'line', 'ds-sl-symbol': 'symbol' }) adapter._datasetSourceMap.set('ds', 'source-ds') - const ds = { ...dataset, sublayers: [{ id: 'sl' }] } + const ds = { ...dataset, sublayers: [{ id: 'sl', sublayerId: 'sl' }] } await adapter.setSublayerStyle(ds, 'sl', mapStyle) expect(map.removeLayer).toHaveBeenCalledWith('ds-sl') expect(map.removeLayer).toHaveBeenCalledWith('ds-sl-stroke') diff --git a/plugins/beta/datasets/src/reducer.js b/plugins/beta/datasets/src/reducer.js index 3a62be1a..5b05a108 100755 --- a/plugins/beta/datasets/src/reducer.js +++ b/plugins/beta/datasets/src/reducer.js @@ -156,10 +156,10 @@ const setSublayerStyle = (state, payload) => { const { layerAdapter } = state const id = `${datasetId}-${sublayerId}` const dataset = state.mappedDatasets[datasetId] - const subLayer = { ...state.mappedDatasets[id], ...styleChanges } + const style = { ...state.mappedDatasets[id].style, ...styleChanges } + const subLayer = { ...state.mappedDatasets[id], style } // TODO - handle this side effect better layerAdapter.setSublayerStyle(dataset, subLayer, mapStyle) - console.log('reducer setSublayerStyle completed') return { ...state, mappedDatasets: { ...state.mappedDatasets, [id]: subLayer }, From 3334c9c8c30eeb180a2412cc61b2aeca5593635e Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Tue, 28 Apr 2026 09:24:34 +0100 Subject: [PATCH 09/12] IM-224 fixed tests after change to setSublayerStyle --- .../src/adapters/maplibre/maplibreLayerAdapter.js | 3 +++ .../adapters/maplibre/maplibreLayerAdapter.test.js | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js index 31790c1d..d2f49d83 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +++ b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js @@ -293,6 +293,9 @@ export default class MaplibreLayerAdapter { * @returns {Promise} */ async setSublayerStyle (dataset, sublayer, mapStyle) { + if (!sublayer) { + return + } const mapStyleId = mapStyle.id const pixelRatio = this._pixelRatio const { fillLayerId, strokeLayerId, symbolLayerId } = getSublayerLayerIds(dataset.id, sublayer.sublayerId) diff --git a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js index 983c3bb1..d579fec1 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +++ b/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js @@ -365,8 +365,8 @@ describe('setSublayerStyle', () => { it('removes existing sublayer layers before re-adding', async () => { const { adapter, map } = makeAdapter({ 'ds-sl': 'fill', 'ds-sl-stroke': 'line', 'ds-sl-symbol': 'symbol' }) adapter._datasetSourceMap.set('ds', 'source-ds') - const ds = { ...dataset, sublayers: [{ id: 'sl', sublayerId: 'sl' }] } - await adapter.setSublayerStyle(ds, 'sl', mapStyle) + const sublayer = { id: 'ds-sl', sublayerId: 'sl' } + await adapter.setSublayerStyle(dataset, sublayer, mapStyle) expect(map.removeLayer).toHaveBeenCalledWith('ds-sl') expect(map.removeLayer).toHaveBeenCalledWith('ds-sl-stroke') expect(map.removeLayer).toHaveBeenCalledWith('ds-sl-symbol') @@ -380,10 +380,9 @@ describe('setSublayerStyle', () => { expect(addSublayerLayers).toHaveBeenCalled() }) - it('does nothing if sublayer is not found', async () => { + it('does nothing if sublayer does not exist', async () => { const { adapter } = makeAdapter() - const ds = { ...dataset, sublayers: [] } - await adapter.setSublayerStyle(ds, 'missing', mapStyle) + await adapter.setSublayerStyle(dataset, null, mapStyle) expect(addSublayerLayers).not.toHaveBeenCalled() }) }) @@ -743,9 +742,10 @@ describe('setSublayerStyle — tiled dataset', () => { const { adapter } = makeAdapter() const tiledDataset = { ...dataset, tiles: ['https://tiles/{z}/{x}/{y}'], sourceLayer: 'buildings', sublayers: [{ id: 'sl' }] } adapter._datasetSourceMap.set('ds', 'source-ds') - await adapter.setSublayerStyle(tiledDataset, 'sl', mapStyle) + const sublayer = { id: 'ds-sl', sublayerId: 'sl' } + await adapter.setSublayerStyle(tiledDataset, sublayer, mapStyle) expect(addSublayerLayers).toHaveBeenCalledWith( - adapter._map, tiledDataset, { id: 'sl' }, 'source-ds', 'buildings', expect.any(Object) + adapter._map, tiledDataset, sublayer, 'source-ds', 'buildings', expect.any(Object) ) }) }) From 319bf659cda103256cf59d3b3b5547ff78d5d92d Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Tue, 28 Apr 2026 09:37:30 +0100 Subject: [PATCH 10/12] IM-224 simplified setStyle --- plugins/beta/datasets/src/api/setStyle.js | 27 +++++------------------ 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/plugins/beta/datasets/src/api/setStyle.js b/plugins/beta/datasets/src/api/setStyle.js index 4b32eaad..0753ed3c 100644 --- a/plugins/beta/datasets/src/api/setStyle.js +++ b/plugins/beta/datasets/src/api/setStyle.js @@ -1,27 +1,10 @@ -export const setStyle = ({ pluginState, mapState }, style, { datasetId, sublayerId } = {}) => { +export const setStyle = ({ pluginState, mapState }, styleChanges, { datasetId, sublayerId } = {}) => { const dataset = pluginState.datasets?.find(d => d.id === datasetId) if (!dataset) { return } - - if (sublayerId) { - pluginState.dispatch({ - type: 'SET_SUBLAYER_STYLE', - payload: { - datasetId, sublayerId, styleChanges: style, mapStyle: mapState.mapStyle - } - }) - // const updatedSublayerDataset = { - // ...dataset, - // sublayers: dataset.sublayers?.map(sublayer => - // sublayer.id === sublayerId ? { ...sublayer, style: { ...sublayer.style, ...style } } : sublayer - // ) - // } - // pluginState.layerAdapter?.setSublayerStyle(updatedSublayerDataset, sublayerId, mapState.mapStyle) - return - } - - pluginState.dispatch({ type: 'SET_DATASET_STYLE', payload: { datasetId, styleChanges: style, mapStyle: mapState.mapStyle } }) - // const updatedDataset = { ...dataset, ...style } - // pluginState.layerAdapter?.setStyle(updatedDataset, mapState.mapStyle) + const mapStyle = mapState.mapStyle + const type = sublayerId ? 'SET_SUBLAYER_STYLE' : 'SET_DATASET_STYLE' + const payload = { datasetId, styleChanges, mapStyle, sublayerId } + pluginState.dispatch({ type, payload }) } From 04a79c3bf302bd030912e04a41d604807a2bf15e Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Tue, 28 Apr 2026 09:40:43 +0100 Subject: [PATCH 11/12] IM-224 altered test to cover new sublayer format too --- .../beta/datasets/src/adapters/maplibre/layerBuilders.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.test.js b/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.test.js index 0b973a2a..61843233 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.test.js +++ b/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.test.js @@ -386,7 +386,7 @@ describe('addSublayerLayers', () => { getSymbolDef.mockReturnValue({ id: 'marker' }) getSymbolImageId.mockReturnValue('marker-img') const dataset = { id: 'ds', visibility: 'visible' } - const sublayer = { id: 'sl' } + const sublayer = { id: 'ds-sl', sublayerId: 'sl' } mergeSublayer.mockReturnValue({ symbol: 'marker' }) addSublayerLayers(map, dataset, sublayer, 'source-id', undefined, { mapStyle, symbolRegistry, patternRegistry, pixelRatio: 1 }) expect(map.addLayer).toHaveBeenCalledWith(expect.objectContaining({ type: 'symbol' })) From 1a56e7353922affa22c3f5eea29730bbf3360d67 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Tue, 28 Apr 2026 09:45:36 +0100 Subject: [PATCH 12/12] IM-224 removed BUILD_MAPPED_DATASETS listener --- plugins/beta/datasets/src/DatasetsInit.jsx | 2 -- plugins/beta/datasets/src/reducer.js | 1 - 2 files changed, 3 deletions(-) diff --git a/plugins/beta/datasets/src/DatasetsInit.jsx b/plugins/beta/datasets/src/DatasetsInit.jsx index b792e71b..b62be658 100755 --- a/plugins/beta/datasets/src/DatasetsInit.jsx +++ b/plugins/beta/datasets/src/DatasetsInit.jsx @@ -1,7 +1,6 @@ // src/plugins/datasets/datasetsInit.jsx import { useEffect, useRef } from 'react' import { EVENTS } from '../../../../src/config/events.js' -import { datasetDefaults } from './defaults.js' import { createDatasets } from './datasets.js' export function DatasetsInit ({ pluginConfig, pluginState, appState, mapState, mapProvider, services }) { @@ -56,7 +55,6 @@ export function DatasetsInit ({ pluginConfig, pluginState, appState, mapState, m }, [isMapStyleReady, appState.mode]) useEffect(() => { - // dispatch({ type: 'BUILD_MAPPED_DATASETS', payload: null }) dispatch({ type: 'BUILD_KEY_GROUPS', payload: null }) }, [pluginState.datasets]) diff --git a/plugins/beta/datasets/src/reducer.js b/plugins/beta/datasets/src/reducer.js index 5b05a108..919e11d3 100755 --- a/plugins/beta/datasets/src/reducer.js +++ b/plugins/beta/datasets/src/reducer.js @@ -220,7 +220,6 @@ const setSublayerOpacity = (state, payload) => { const setLayerAdapter = (state, payload) => ({ ...state, layerAdapter: payload }) const actions = { - BUILD_MAPPED_DATASETS: mappedDatasetsReducer, BUILD_KEY_GROUPS: keyReducer, SET_DATASETS: setDatasets, ADD_DATASET: addDataset,