diff --git a/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js b/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js index bfee98fe2d..342a9fb99a 100644 --- a/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js +++ b/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js @@ -64,7 +64,7 @@ describe('wpsChart enhancer', () => { }; ReactDOM.render(, document.getElementById("container")); }); - it('wpsCounter with mapSync and dependencies', (done) => { + it('wpsCounter with mapSync with mapWidget and dependencies', (done) => { const Sink = wpsCounter(createSink( ({data, loading} = {}) => { if (!loading) { expect(data).toExist(); @@ -76,6 +76,46 @@ describe('wpsChart enhancer', () => { dependencies: { viewport: "..." }, + dependenciesMap: { + mapSync: 'widgets[456].mapSync' + }, + widgets: [ + { + id: "123", + widgetType: 'table' + }, + { + id: "456", + widgetType: 'map' + } + ], + layer: { + name: "test", + url: 'base/web/client/test-resources/widgetbuilder/aggregate', + wpsUrl: 'base/web/client/test-resources/widgetbuilder/aggregate', + search: {url: 'base/web/client/test-resources/widgetbuilder/aggregate'}}, + options: { + aggregateFunction: "Count", + aggregationAttribute: "test" + } + }; + ReactDOM.render(, document.getElementById("container")); + }); + it('wpsCounter with mapSync standard Map', (done) => { + const Sink = wpsCounter(createSink( ({data, loading} = {}) => { + if (!loading) { + expect(data).toExist(); + done(); + } + })); + const props = { + mapSync: true, + dependencies: { + viewport: "..." + }, + dependenciesMap: { + mapSync: 'map.mapSync' + }, layer: { name: "test", url: 'base/web/client/test-resources/widgetbuilder/aggregate', diff --git a/web/client/components/widgets/enhancers/wfsTable/__tests__/triggerFetch-test.js b/web/client/components/widgets/enhancers/wfsTable/__tests__/triggerFetch-test.js index 44a125b3c7..1615ea24a4 100644 --- a/web/client/components/widgets/enhancers/wfsTable/__tests__/triggerFetch-test.js +++ b/web/client/components/widgets/enhancers/wfsTable/__tests__/triggerFetch-test.js @@ -55,10 +55,51 @@ describe('triggerFetch stream', () => { } ); }); - it('triggerFetch with mapSync and dependencies.viewport', (done) => { + it('triggerFetch with mapSync with mapWidget and dependencies.viewport', (done) => { const base = { layer: { name: "TEST" }, - mapSync: true + mapSync: true, + dependenciesMap: { + mapSync: 'widgets[456].mapSync' + }, + widgets: [ + { + id: "123", + widgetType: 'table' + }, + { + id: "456", + widgetType: 'map' + } + ] + }; + const propsChanges = [ + base, // does not trigger fetch + {...base, dependencies: { viewport: true }}, // triggers fetch (p1) + {...base, dependencies: { viewport: false }}, // does not trigger fetch + {...base, mapSync: false, filter: "changed"} // triggers fetch (p2) (the filter changes due to the viewport) + ]; + triggerFetch(Rx.Observable.from(propsChanges)) + .bufferCount(4) + .subscribe( + ([p1, p2, p3, p4]) => { + expect(p1?.dependencies?.viewport).toBe(true); + expect(p2).toExist(); + expect(p3).toNotExist(); + expect(p4).toNotExist(); + done(); + } + ); + }); + it('triggerFetch with mapSync with Standard Map and dependencies.viewport', (done) => { + const base = { + layer: { name: "TEST" }, + mapSync: true, + widgets: [ + ], + dependenciesMap: { + mapSync: 'map.mapSync' + } }; const propsChanges = [ base, // does not trigger fetch diff --git a/web/client/components/widgets/enhancers/wfsTable/triggerFetch.js b/web/client/components/widgets/enhancers/wfsTable/triggerFetch.js index 9eb7660a25..4b84a62669 100644 --- a/web/client/components/widgets/enhancers/wfsTable/triggerFetch.js +++ b/web/client/components/widgets/enhancers/wfsTable/triggerFetch.js @@ -6,6 +6,8 @@ * LICENSE file in the root directory of this source tree. */ +import { checkMapSyncWithWidgetOfMapType } from '../../../../utils/WidgetsUtils'; + require('rxjs'); // const { getSearchUrl } = require('../../../../utils/LayersUtils'); const sameFilter = (f1, f2) => f1 === f2; @@ -22,11 +24,11 @@ const sameSortOptions = (o1 = {}, o2 = {}) => * @return {Observable} Stream of props to trigger the data fetch */ export default ($props) => - $props.filter(({ layer = {}, mapSync, dependencies }) => { - // Check if mapSync is enabled (true) and dependencies.viewport is null or falsy + $props.filter(({ layer = {}, mapSync, dependencies, dependenciesMap, widgets }) => { + // Check if mapSync is enabled (true), dependencyMap has mapSync dependency to Map widget and dependencies.viewport is null or falsy // If this condition is true, return false to filter out the event. // This prevents an extra API call from being triggered when the viewport is not available. - if (mapSync && !dependencies?.viewport) { + if (mapSync && checkMapSyncWithWidgetOfMapType(widgets, dependenciesMap) && !dependencies?.viewport) { return false; } return layer.name; diff --git a/web/client/components/widgets/enhancers/wpsCounter.js b/web/client/components/widgets/enhancers/wpsCounter.js index 91ac32c6ee..d35f073b76 100644 --- a/web/client/components/widgets/enhancers/wpsCounter.js +++ b/web/client/components/widgets/enhancers/wpsCounter.js @@ -21,6 +21,8 @@ const sameOptions = (o1 = {}, o2 = {}) => && o1.aggregationAttribute === o2.aggregationAttribute && o1.viewParams === o2.viewParams; import { getWpsUrl } from '../../../utils/LayersUtils'; +import { checkMapSyncWithWidgetOfMapType } from '../../../utils/WidgetsUtils'; + /** * Stream of props -> props to retrieve data from WPS aggregate process on params changes. @@ -30,11 +32,11 @@ import { getWpsUrl } from '../../../utils/LayersUtils'; */ const dataStreamFactory = ($props) => $props - .filter(({layer = {}, options, dependencies, mapSync}) => { - // Check if mapSync is enabled (true) and dependencies.viewport is null or falsy + .filter(({layer = {}, options, dependencies, mapSync, dependenciesMap, widgets}) => { + // Check if mapSync is enabled (true), dependencyMap has mapSync dependency to Map widget and dependencies.viewport is null or falsy // If this condition is true, return false to filter out the event. // This prevents an extra API call from being triggered when the viewport is not available. - if (mapSync && !dependencies?.viewport) { + if (mapSync && checkMapSyncWithWidgetOfMapType(widgets, dependenciesMap) && !dependencies?.viewport) { return false; } return layer.name && getWpsUrl(layer) && options && options.aggregateFunction && options.aggregationAttribute; diff --git a/web/client/utils/WidgetsUtils.js b/web/client/utils/WidgetsUtils.js index 19ff029b78..fc67c431e8 100644 --- a/web/client/utils/WidgetsUtils.js +++ b/web/client/utils/WidgetsUtils.js @@ -992,3 +992,49 @@ export const canTableWidgetBeDependency = (widget, dependencyTableWidget) => { const layerPresent = editingLayer.includes(get(dependencyTableWidget, 'layer.name')); return isChart ? layerPresent && isChartCompatibleWithTableWidget(widget, dependencyTableWidget) : layerPresent; }; + +function findWidgetById(widgets, widgetId) { + return widgets?.find(widget => widget.id === widgetId); +} + +/** + * Checks if a widget, referenced by `mapSync` in the `dependenciesMap`, has `widgetType` set to `'map'`. + * If the widget has a `dependenciesMap`, it will be checked recursively. + * + * @param {Array} widgets - List of widget objects, each containing an `id`, `widgetType`, and optionally `dependenciesMap`. + * @param {Object} dependenciesMap - An object containing a `mapSync` reference to another widget's `mapSync` (e.g., "widgets[widgetId].mapSync"). + * @returns {boolean} - Returns boolean + * + * @example + * checkMapSyncWithWidgetOfMapType(widgets, { mapSync: 'widgets[40fdb720-b228-11ef-974d-8115935269b7].mapSync' }); + */ +export function checkMapSyncWithWidgetOfMapType(widgets, dependenciesMap) { + const mapSyncDependencies = dependenciesMap?.mapSync; + + if (!mapSyncDependencies) { + return false; + } + if (mapSyncDependencies.includes("map.mapSync")) { + return true; + } + // Extract widget ID + const widgetId = mapSyncDependencies.match?.(/\[([^\]]+)\]/)?.[1]; + if (!widgetId) { + return false; + } + // Find the widget using the extracted widgetId + const widget = findWidgetById(widgets, widgetId); + if (!widget) { + return false; + } + // Check if the widget has widgetType 'map' + if (widget.widgetType === 'map') { + return true; + } + // If widget has its own dependenciesMap, recursively check that map + if (widget.dependenciesMap) { + return checkMapSyncWithWidgetOfMapType(widgets, widget.dependenciesMap); + } + // If no match found, return false + return false; +} diff --git a/web/client/utils/__tests__/WidgetsUtils-test.js b/web/client/utils/__tests__/WidgetsUtils-test.js index 7e58d765c9..e7c01b8211 100644 --- a/web/client/utils/__tests__/WidgetsUtils-test.js +++ b/web/client/utils/__tests__/WidgetsUtils-test.js @@ -25,7 +25,8 @@ import { enableBarChartStack, getWidgetLayersNames, isChartCompatibleWithTableWidget, - canTableWidgetBeDependency + canTableWidgetBeDependency, + checkMapSyncWithWidgetOfMapType } from '../WidgetsUtils'; import * as simpleStatistics from 'simple-statistics'; import { createClassifyGeoJSONSync } from '../../api/GeoJSONClassification'; @@ -757,4 +758,43 @@ describe('Test WidgetsUtils', () => { expect(canTableWidgetBeDependency({widgetType: 'chart', charts: [{chartId: "1", traces: [{layer: {name: "layer_1"}}, {layer: {name: "layer_1"}}]}]}, dependencyTableWidget2)).toBeFalsy(); expect(canTableWidgetBeDependency({widgetType: 'chart', charts: [{chartId: "1", traces: [{layer: {name: "layer_1"}}, {layer: {name: "layer_2"}}]}]}, dependencyTableWidget2)).toBeFalsy(); }); + + it("MapSync dependency to mapWidget", () => { + const parameters = { + dependenciesMap: { + mapSync: 'widgets[456].mapSync' + }, + widgets: [ + { + id: "123", + widgetType: 'table' + }, + { + id: "456", + widgetType: 'map' + } + ] + }; + const result = checkMapSyncWithWidgetOfMapType(parameters.widgets, parameters.dependenciesMap); + expect(result).toEqual(true); + }); + it("MapSync dependency not in map widget", () => { + const parameters = { + dependenciesMap: { + mapSync: 'widgets[123].mapSync' + }, + widgets: [ + { + id: "123", + widgetType: 'table' + }, + { + id: "456", + widgetType: 'map' + } + ] + }; + const result = checkMapSyncWithWidgetOfMapType(parameters.widgets, parameters.dependenciesMap); + expect(result).toEqual(false); + }); });