Skip to content

Commit

Permalink
#9567: handle functionality of zoom to record in table widgets (#9608)
Browse files Browse the repository at this point in the history
* #9567: handle functionality of zoom to record in table widgets

* Fix: Correct failing test cases for zoom records issue in table widgets (#9567)
This commit addresses the failing test cases related to the issue of zoom records in table widgets.
* #9567: implement the new approach in zoom to records in table widgets + writing unit tests
* #9567: handle adding flag into config file to show/hide zoom icon for tblWidget
* #9567: reset flag enableZoomInTblWidget to be true for dashboard and map viewer
* #9567: resolve comments' review:
- put flag of zoomInTblWidget as a default prop
- add translations
- edit zoomToExtent enhancer to use internal zoom
- remove selector "getFlagOfShowingTblWidgetZoom " and use plugin prop instead
  • Loading branch information
mahmoudadel54 committed Nov 27, 2023
1 parent e654fba commit b3fa4bc
Show file tree
Hide file tree
Showing 23 changed files with 316 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,27 @@ describe('onMapViewChanges enhancer', () => {
expect(map.mapStateSource).toExist();
expect(map.projection).toExist();
});
it('onMapViewChanges rendering with zoomToExtentHandler', () => {
const Sink = onMapViewChanges(createSink( props => {
expect(props.eventHandlers.onMapViewChanges).toExist();
setTimeout(props.eventHandlers.onMapViewChanges("CENTER", "ZOOM", { bbox: { x: 2 } }, "SIZE", "mapStateSource", "projection", {}, "RESOLUTION", "ORINATE", () => {}));

}));
const actions = {
onMapViewChanges: () => {}
};
const spy = expect.spyOn(actions, 'onMapViewChanges');
ReactDOM.render(<Sink map={{ bbox: { x: 1, y: 1 }, test: "TEST" }} onMapViewChanges={actions.onMapViewChanges} />, document.getElementById("container"));
expect(spy).toHaveBeenCalled();
const map = spy.calls[0].arguments[0];
expect(map).toExist();
expect(map.center).toExist();
expect(map.zoom).toExist();
expect(map.bbox).toExist();
expect(map.size).toExist();
expect(map.mapStateSource).toExist();
expect(map.projection).toExist();
expect(map.zoomToExtentHandler).toExist();
});

});
5 changes: 3 additions & 2 deletions web/client/components/map/enhancers/onMapViewChanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { compose, withHandlers, withPropsOnChange } from 'recompose';
*/
export default compose(
withHandlers({
onMapViewChanges: ({ map = {}, onMapViewChanges = () => {}}) => (center, zoom, bbox, size, mapStateSource, projection, viewerOptions, resolution, orientate) => {
onMapViewChanges: ({ map = {}, onMapViewChanges = () => {}}) => (center, zoom, bbox, size, mapStateSource, projection, viewerOptions, resolution, orientate, zoomToExtentHandler) => {
onMapViewChanges({
...map,
center,
Expand All @@ -27,7 +27,8 @@ export default compose(
mapStateSource,
projection,
resolution,
orientate
orientate,
zoomToExtentHandler
});
}
}),
Expand Down
42 changes: 21 additions & 21 deletions web/client/components/map/openlayers/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,26 @@ class OpenlayersMap extends React.Component {
}
};

zoomToExtentHandler = (extent, { padding, crs, maxZoom: zoomLevel, duration, nearest} = {})=> {
let bounds = reprojectBbox(extent, crs, this.props.projection);
// TODO: improve this to manage all degenerated bounding boxes.
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] &&
crs === "EPSG:4326" && isArray(extent) && extent[0] === -180 && extent[1] === -90) {
bounds = this.map.getView().getProjection().getExtent();
}
let maxZoom = zoomLevel;
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] && isNil(maxZoom)) {
maxZoom = 21; // TODO: allow to this maxZoom to be customizable
}
this.map.getView().fit(bounds, {
size: this.map.getSize(),
padding: padding && [padding.top || 0, padding.right || 0, padding.bottom || 0, padding.left || 0],
maxZoom,
duration,
nearest
});
}

registerHooks = () => {
this.props.hookRegister.registerHook(mapUtils.RESOLUTIONS_HOOK, (srs) => {
return this.getResolutions(srs);
Expand Down Expand Up @@ -581,27 +601,7 @@ class OpenlayersMap extends React.Component {
this.props.hookRegister.registerHook(mapUtils.GET_COORDINATES_FROM_PIXEL_HOOK, (pixel) => {
return this.map.getCoordinateFromPixel(pixel);
});
this.props.hookRegister.registerHook(mapUtils.ZOOM_TO_EXTENT_HOOK, (extent, { padding, crs, maxZoom: zoomLevel, duration, nearest} = {}) => {
let bounds = reprojectBbox(extent, crs, this.props.projection);
// if EPSG:4326 with max extent (-180, -90, 180, 90) bounds are 0,0,0,0. In this case zoom to max extent
// TODO: improve this to manage all degenerated bounding boxes.
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] &&
crs === "EPSG:4326" && isArray(extent) && extent[0] === -180 && extent[1] === -90) {
bounds = this.map.getView().getProjection().getExtent();
}
let maxZoom = zoomLevel;
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] && isNil(maxZoom)) {
maxZoom = 21; // TODO: allow to this maxZoom to be customizable
}

this.map.getView().fit(bounds, {
size: this.map.getSize(),
padding: padding && [padding.top || 0, padding.right || 0, padding.bottom || 0, padding.left || 0],
maxZoom,
duration,
nearest
});
});
this.props.hookRegister.registerHook(mapUtils.ZOOM_TO_EXTENT_HOOK, this.zoomToExtentHandler);
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1463,7 +1463,7 @@ describe('OpenlayersMap', () => {
expect(MapUtils.getHook(MapUtils.ZOOM_TO_EXTENT_HOOK)).toBeTruthy();
});
it("with custom hookRegister", () => {
const customHooRegister = MapUtils.createRegisterHooks();
const customHooRegister = MapUtils.createRegisterHooks("mymap");
const map = ReactDOM.render(<OpenlayersMap hookRegister={customHooRegister} id="mymap" center={{y: 43.9, x: 10.3}} zoom={11}/>, document.getElementById("map"));
expect(map).toBeTruthy();
expect(ReactDOM.findDOMNode(map).id).toBe('mymap');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import React from 'react';
import { Col, Form, Row } from 'react-bootstrap';
import {compose, withProps} from 'recompose';

import { isGeometryType } from '../../../../../utils/ogc/WFS/base';
import AttributeTable from '../../../../data/featuregrid/AttributeTable';
import Message from '../../../../I18N/Message';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('widgets dependenciesToExtent enhancer', () => {
it('dependenciesToExtent default', (done) => {
const Sink = dependenciesToExtent(createSink( props => {
expect(props).toExist();
expect(props).toEqual({});
expect(props.hookRegister).toEqual(null);
done();
}));
ReactDOM.render(<Sink />, document.getElementById("container"));
Expand All @@ -55,7 +55,7 @@ describe('widgets dependenciesToExtent enhancer', () => {
'<?xml version="1.0" encoding="UTF-8"?><ows:BoundingBox xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ows="http://www.opengis.net/ows/1.1" crs="EPSG:4326"><ows:LowerCorner>-124.731422 24.955967</ows:LowerCorner><ows:UpperCorner>-66.969849 49.371735</ows:UpperCorner></ows:BoundingBox>'
);

const hookRegister = MapUtils.createRegisterHooks();
const hookRegister = MapUtils.createRegisterHooks("id");
hookRegister.registerHook(MapUtils.ZOOM_TO_EXTENT_HOOK, {hookName: MapUtils.ZOOM_TO_EXTENT_HOOK});
ReactDOM.render(<Sink
id="id"
Expand Down Expand Up @@ -85,7 +85,7 @@ describe('widgets dependenciesToExtent enhancer', () => {
'<?xml version="1.0" encoding="UTF-8"?><ows:BoundingBox xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ows="http://www.opengis.net/ows/1.1" crs="EPSG:4326"><ows:LowerCorner>-124.731422 24.955967</ows:LowerCorner><ows:UpperCorner>-66.969849 49.371735</ows:UpperCorner></ows:BoundingBox>'
);

const hookRegister = MapUtils.createRegisterHooks();
const hookRegister = MapUtils.createRegisterHooks("id");
hookRegister.registerHook(MapUtils.ZOOM_TO_EXTENT_HOOK, {hookName: MapUtils.ZOOM_TO_EXTENT_HOOK});
ReactDOM.render(<Sink
id="id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ import expect from 'expect';
import React from 'react';
import ReactDOM from 'react-dom';
import {createSink} from 'recompose';
import {Provider} from 'react-redux';
import configureMockStore from 'redux-mock-store';

import tableWidget from '../tableWidget';

const mockStore = configureMockStore();

describe('widgets tableWidget enhancer', () => {
let store;
beforeEach((done) => {
store = mockStore();
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});
Expand All @@ -34,9 +40,93 @@ describe('widgets tableWidget enhancer', () => {
props.gridEvents.onAddFilter(someFilter);
done();
}));
ReactDOM.render(<Sink updateProperty={(path, filter) => {
ReactDOM.render( <Provider store={store}><Sink updateProperty={(path, filter) => {
expect(path).toBe("quickFilters.state");
expect(filter).toBe(someFilter);
}}/>, document.getElementById("container"));
}}/></Provider>, document.getElementById("container"));
});

it('tableWidget with gridTools including zoom icon for dashboard viewer [enable zoom in config]', (done) => {
const Sink = tableWidget(createSink( props => {
expect(props).toExist();
expect(props.gridTools.length).toEqual(1);
props.gridTools[0].events.onClick(
{
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "", maxZoom: null }
);
done();
}));
ReactDOM.render( <Provider store={store}><Sink enableZoomInTblWidget ={"true"} id="123456" mapSync={"true"} widgetType={"table"} isDashboardOpened={"true"} updateProperty={(id, path, value) => {
expect(path).toBe("dependencies.extentObj");
expect(id).toBe("123456");
expect(value).toEqual({
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "EPSG:4326", maxZoom: null });
}}/></Provider>, document.getElementById("container"));
const container = document.getElementById('container');
expect(container).toExist();

});
it('tableWidget with gridTools including zoom icon for dashboard viewer in case of just table is added [No maps added]', (done) => {
const Sink = tableWidget(createSink( props => {
expect(props).toExist();
expect(props.gridTools.length).toEqual(0);
done();
}));
ReactDOM.render( <Provider store={store}><Sink enableZoomInTblWidget={"true"} id="123456" mapSync={false} widgetType={"table"} isDashboardOpened={"true"} updateProperty={(id, path, value) => {
expect(path).toBe("dependencies.extentObj");
expect(id).toBe("123456");
expect(value).toEqual({
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "EPSG:4326", maxZoom: null });
}}/></Provider>, document.getElementById("container"));
const container = document.getElementById('container');
expect(container).toExist();

});
it('tableWidget with gridTools including zoom icon for dashboard viewer [not enable zoom in config]', (done) => {
const Sink = tableWidget(createSink( props => {
expect(props).toExist();
expect(props.gridTools.length).toEqual(0);
done();
}));
ReactDOM.render( <Provider store={store}><Sink enableZoomInTblWidget={false} id="123456" mapSync={"true"} widgetType={"table"} isDashboardOpened={"true"} updateProperty={(id, path, value) => {
expect(path).toBe("dependencies.extentObj");
expect(id).toBe("123456");
expect(value).toEqual({
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "EPSG:4326", maxZoom: null });
}}/></Provider>, document.getElementById("container"));
const container = document.getElementById('container');
expect(container).toExist();

});
it('tableWidget with gridTools including zoom icon for mapViewer [enable zoom in config]', (done) => {
const Sink = tableWidget(createSink( props => {
expect(props).toExist();
expect(props.gridTools.length).toEqual(1);
props.gridTools[0].events.onClick(
{
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "", maxZoom: null }
);
done();
}));
ReactDOM.render( <Provider store={store}><Sink enableZoomInTblWidget={"true"} id="123456" widgetType={"table"} /></Provider>, document.getElementById("container"));
const container = document.getElementById('container');
expect(container).toExist();

});
it('tableWidget with gridTools including zoom icon for mapViewer [not enable zoom in config]', (done) => {
const Sink = tableWidget(createSink( props => {
expect(props).toExist();
expect(props.gridTools.length).toEqual(0);
done();
}));
ReactDOM.render( <Provider store={store}><Sink enableZoomInTblWidget={false} id="123456" widgetType={"table"} /></Provider>, document.getElementById("container"));
const container = document.getElementById('container');
expect(container).toExist();

});
});
33 changes: 30 additions & 3 deletions web/client/components/widgets/enhancers/dependenciesToExtent.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,42 @@ import { createRegisterHooks, ZOOM_TO_EXTENT_HOOK } from '../../../utils/MapUtil
* @returns {object} the map with center and zoom updated
*/
export default compose(

withPropsOnChange(["id"],
({hookRegister = null, id}) => ({
hookRegister: hookRegister?.id !== id ? createRegisterHooks(id) : hookRegister
})),
compose(
withPropsOnChange((props = {}, nextProps = {}) => {
const currentExtentObj = props.widgets?.find(i=>i?.dependencies?.extentObj);
const nextExtentObj = nextProps.widgets?.find(i=>i?.dependencies?.extentObj);
return !(isEqual(currentExtentObj, nextExtentObj)) && nextExtentObj;
},
({ id, widgets, updateProperty, hookRegister })=>{
const tblWidgetWithExtentObj = widgets?.find(i=>i?.dependencies?.extentObj);
const extentObj = tblWidgetWithExtentObj?.dependencies?.extentObj;
const mapWidgetID = id;
const mapWidget = widgets?.find(i=>tblWidgetWithExtentObj?.dependenciesMap?.mapSync.includes(i.id) && i.id === mapWidgetID);
const connectedMap = mapWidget?.maps.find(i=>i.mapStateSource === mapWidget.id);
const hook = hookRegister?.getHook("ZOOM_TO_EXTENT_HOOK");
if (hook && hookRegister?.id === id && connectedMap) { // a condition to detect which connected map with its id to zoom within
// trigger "internal" zoom to extent
hook(extentObj.extent, {
crs: extentObj.crs, maxZoom: extentObj.maxZoom
});
// remove extentObj from state
updateProperty(tblWidgetWithExtentObj.id, `dependencies.extentObj`, undefined);
}
return {};
})
),
branch(
({mapSync, dependencies} = {}) => {
return mapSync && (!isEmpty(dependencies.quickFilters) || !isEmpty(dependencies.filter));
},
compose(
withPropsOnChange(["id"],
({hookRegister = null}) => ({
hookRegister: hookRegister || createRegisterHooks()
({hookRegister = null, id}) => ({
hookRegister: hookRegister?.id !== id ? createRegisterHooks(id) : hookRegister
})),
mapPropsStream(props$ => {
return props$
Expand Down
Loading

0 comments on commit b3fa4bc

Please sign in to comment.