Skip to content

Commit

Permalink
Dashboards - fix no longer shows counter widgets with table dependency
Browse files Browse the repository at this point in the history
…#10708 (#10714) (#10720)

* fix: allow api call for viewport null and widgets not synced with map widget

* fix: check mapSync dependencyMap for standard map also
  • Loading branch information
rowheat02 authored Dec 5, 2024
1 parent 68e9399 commit c8332de
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('wpsChart enhancer', () => {
};
ReactDOM.render(<Sink {...props} />, 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();
Expand All @@ -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(<Sink {...props} />, 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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions web/client/components/widgets/enhancers/wpsCounter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand Down
46 changes: 46 additions & 0 deletions web/client/utils/WidgetsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<Object>} 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;
}
42 changes: 41 additions & 1 deletion web/client/utils/__tests__/WidgetsUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
enableBarChartStack,
getWidgetLayersNames,
isChartCompatibleWithTableWidget,
canTableWidgetBeDependency
canTableWidgetBeDependency,
checkMapSyncWithWidgetOfMapType
} from '../WidgetsUtils';
import * as simpleStatistics from 'simple-statistics';
import { createClassifyGeoJSONSync } from '../../api/GeoJSONClassification';
Expand Down Expand Up @@ -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);
});
});

0 comments on commit c8332de

Please sign in to comment.