From f15603b008255798e0fdbd295ce9a2af691de55e Mon Sep 17 00:00:00 2001 From: Rohit Gautam Date: Wed, 4 Dec 2024 19:10:42 +0545 Subject: [PATCH 1/2] fix: allow api call for viewport null and widgets not synced with map widget --- .../enhancers/__tests__/wpsCounter-test.js | 15 ++++++- .../wfsTable/__tests__/triggerFetch-test.js | 17 +++++++- .../enhancers/wfsTable/triggerFetch.js | 8 ++-- .../widgets/enhancers/wpsCounter.js | 8 ++-- web/client/utils/WidgetsUtils.js | 43 +++++++++++++++++++ .../utils/__tests__/WidgetsUtils-test.js | 42 +++++++++++++++++- 6 files changed, 123 insertions(+), 10 deletions(-) diff --git a/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js b/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js index bfee98fe2d..2151561c7d 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,19 @@ 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', 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..3df9c2cc11 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,23 @@ 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 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..72bca0af56 100644 --- a/web/client/utils/WidgetsUtils.js +++ b/web/client/utils/WidgetsUtils.js @@ -992,3 +992,46 @@ 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; + } + // 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); + }); }); From 26525e1eba32a574f52ef781fac90ff17357f93d Mon Sep 17 00:00:00 2001 From: Rohit Gautam Date: Wed, 4 Dec 2024 21:13:50 +0545 Subject: [PATCH 2/2] fix: check mapSync dependencyMap for standard map also --- .../enhancers/__tests__/wpsCounter-test.js | 27 ++++++++++++++++++ .../wfsTable/__tests__/triggerFetch-test.js | 28 +++++++++++++++++++ web/client/utils/WidgetsUtils.js | 5 +++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js b/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js index 2151561c7d..342a9fb99a 100644 --- a/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js +++ b/web/client/components/widgets/enhancers/__tests__/wpsCounter-test.js @@ -101,4 +101,31 @@ describe('wpsChart enhancer', () => { }; 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', + 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")); + }); }); 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 3df9c2cc11..1615ea24a4 100644 --- a/web/client/components/widgets/enhancers/wfsTable/__tests__/triggerFetch-test.js +++ b/web/client/components/widgets/enhancers/wfsTable/__tests__/triggerFetch-test.js @@ -91,5 +91,33 @@ describe('triggerFetch stream', () => { } ); }); + 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 + {...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(); + } + ); + }); }); diff --git a/web/client/utils/WidgetsUtils.js b/web/client/utils/WidgetsUtils.js index 72bca0af56..fc67c431e8 100644 --- a/web/client/utils/WidgetsUtils.js +++ b/web/client/utils/WidgetsUtils.js @@ -994,7 +994,7 @@ export const canTableWidgetBeDependency = (widget, dependencyTableWidget) => { }; function findWidgetById(widgets, widgetId) { - return widgets.find(widget => widget.id === widgetId); + return widgets?.find(widget => widget.id === widgetId); } /** @@ -1014,6 +1014,9 @@ export function checkMapSyncWithWidgetOfMapType(widgets, dependenciesMap) { if (!mapSyncDependencies) { return false; } + if (mapSyncDependencies.includes("map.mapSync")) { + return true; + } // Extract widget ID const widgetId = mapSyncDependencies.match?.(/\[([^\]]+)\]/)?.[1]; if (!widgetId) {