Skip to content

Commit

Permalink
#9567: handle functionality of zoom to record in table widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
mahmoudadel54 committed Oct 16, 2023
1 parent 2e09d7f commit 90ba37c
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,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';
import { applyDefaultToLocalizedString } from '../../../../I18N/LocalizedString';
Expand All @@ -29,7 +28,6 @@ const AttributeSelector = compose(
withProps(
({ attributes = [], options = {}, layer = {}} = {}) => ({ // TODO manage hide condition
attributes: attributes
.filter(a => !isGeometryType(a))
.map( a => {
const propertyNames = options?.propertyName?.map(p => p.name);
const currPropertyName = options?.propertyName?.find(p => p.name === a.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ describe('widgets dependenciesToExtent enhancer', () => {
it('dependenciesToExtent default', (done) => {
const Sink = dependenciesToExtent(createSink( props => {
expect(props).toExist();
expect(props).toEqual({});
done();
}));
ReactDOM.render(<Sink />, document.getElementById("container"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2020, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import ReactDOM from 'react-dom';
import {createSink} from 'recompose';
import expect from 'expect';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';

import dependenciesToZoomTo from '../dependenciesToZoomTo';

import MapUtils from '../../../../utils/MapUtils';


describe('widgets dependenciesToZoomTo enhancer', () => {
let mockAxios;
const widgetsProps = [{
id: "123",
widgetType: "table",
dependencies: {
extentObj: {
extent: [-10, 0, 0, -10],
crs: "EPSG:3426",
maxZoom: 21
}
},
geomProp: "the_geom",
mapSync: true
},
{
id: "123Map",
widgetType: "map",
maps: [{}],
mapSync: true
}];
beforeEach((done) => {
mockAxios = new MockAdapter(axios);
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});
afterEach((done) => {
mockAxios.restore();
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
document.body.innerHTML = '';
setTimeout(done);
});
it('dependenciesToZoomTo default', (done) => {
const Sink = dependenciesToZoomTo(createSink( props => {
expect(props).toExist();
expect(props).toEqual({ widgets: widgetsProps });
done();
}));
ReactDOM.render(<Sink widgets={widgetsProps} />, document.getElementById("container"));
});

it('dependenciesToZoomTo triggering zoom to extent', (done) => {
let hookRegisterProps = MapUtils.createRegisterHooks();
const Sink = dependenciesToZoomTo(createSink(({
hookRegister = hookRegisterProps, widgets = widgetsProps
}) => {
expect(hookRegister).toExist();
const hook = hookRegister.getHook(MapUtils.ZOOM_TO_EXTENT_HOOK);
expect(hook).toExist();
expect(widgets).toExist();
expect(widgets).toEqual(widgetsProps);
done();
}));
hookRegisterProps.registerHook(MapUtils.ZOOM_TO_EXTENT_HOOK, {hookName: MapUtils.ZOOM_TO_EXTENT_HOOK});
ReactDOM.render(<Sink hookRegister={hookRegisterProps} widgets={widgetsProps} updateProperty={(path) => {
expect(path).toBe("dependencies.extentObj");
done();
}}/>, document.getElementById("container"));

});
});
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,9 @@ 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"));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import xml2js from 'xml2js';

import { Observable } from 'rxjs';
import { mapPropsStream, compose, branch, withPropsOnChange } from 'recompose';
import { mapPropsStream, compose, branch, withPropsOnChange, defaultProps } from 'recompose';
import { isEmpty, isEqual } from 'lodash';
import { composeFilterObject } from './utils';
import wpsBounds from '../../../observables/wps/bounds';
Expand All @@ -22,7 +22,9 @@ import { createRegisterHooks, ZOOM_TO_EXTENT_HOOK } from '../../../utils/MapUtil
* @returns {object} the map with center and zoom updated
*/
export default compose(

defaultProps({
hookRegister: createRegisterHooks() // it is for zoomTo HOC
}),
branch(
({mapSync, dependencies} = {}) => {
return mapSync && (!isEmpty(dependencies.quickFilters) || !isEmpty(dependencies.filter));
Expand Down
25 changes: 25 additions & 0 deletions web/client/components/widgets/enhancers/dependenciesToZoomTo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { useEffect, memo } from 'react';

const dependenciesToZoomTo = (WrappedCompoennet)=>{
function DependenciesToZoomTo(props) {
let tblWidgetWithExtentObj = props.widgets.find(i=>i?.dependencies?.extentObj);
const extentObj = tblWidgetWithExtentObj?.dependencies?.extentObj;
useEffect(()=>{
if ( extentObj && extentObj ) {
const hook = props?.hookRegister?.getHook("ZOOM_TO_EXTENT_HOOK");
if (hook) {
// trigger "internal" zoom to extent
hook(extentObj.extent, {
crs: extentObj.crs, maxZoom: extentObj.maxZoom
});
// removeextentObj from state
props?.updateProperty(tblWidgetWithExtentObj.id, `dependencies.extentObj`, undefined);
}
}

}, [extentObj?.extent?.join(",")]);
return <WrappedCompoennet { ...props } />;
}
return memo(DependenciesToZoomTo);
};
export default dependenciesToZoomTo;
29 changes: 27 additions & 2 deletions web/client/components/widgets/enhancers/tableWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
*/

import { get } from 'lodash';
import { compose, withPropsOnChange } from 'recompose';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import { compose, withPropsOnChange, withProps } from 'recompose';
import debounce from 'lodash/debounce';
import bbox from '@turf/bbox';
import deleteWidget from './deleteWidget';
import { defaultIcons, editableWidget, withHeaderTools } from './tools';

import { gridTools } from '../../../plugins/featuregrid/index';
const withSorting = () => withPropsOnChange(["gridEvents"], ({ gridEvents = {}, updateProperty = () => { }, id } = {}) => ({
gridEvents: {
...gridEvents,
Expand All @@ -23,6 +26,28 @@ const withSorting = () => withPropsOnChange(["gridEvents"], ({ gridEvents = {},
* Moreover enhances it to allow delete.
*/
export default compose(
compose(connect(null, (dispatch, ownProps)=>{
let geoPropName = ownProps?.geomProp;
let hasGeometryProp = !(ownProps?.columnSettings && ownProps?.columnSettings[geoPropName]?.hide);
let isTblDashboard = ownProps?.mapSync && ownProps?.widgetType === 'table' && ownProps?.isDashboardOpened;
let isTblSyncWithMap = ownProps?.mapSync;
return {
gridTools: (hasGeometryProp && isTblSyncWithMap) ? gridTools.map((t) => ({
...t,
events: isTblDashboard ? {
onClick: (p, opts, describe, {crs, maxZoom} = {}) => {
ownProps?.updateProperty(ownProps.id, `dependencies.extentObj`, {
extent: bbox(p),
crs: crs || "EPSG:4326", maxZoom
});
}
} : bindActionCreators(t.events, dispatch)
})) : []
};
})),
withProps(()=>({
showCheckbox: true // for selection
})),
withPropsOnChange(["gridEvents"], ({ gridEvents = {}, updateProperty = () => {}, id } = {}) => {
const _debounceOnAddFilter = debounce((...args) => updateProperty(...args), 500);
return {
Expand Down
7 changes: 6 additions & 1 deletion web/client/components/widgets/widget/DefaultWidget.jsx
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 React from 'react';
import {connect} from 'react-redux';
import { createSelector } from 'reselect';
import {
ChartWidget,
CounterWidget,
Expand All @@ -14,6 +16,7 @@ import {
TextWidget,
LegendWidget
} from './enhancedWidgets';
import { isDashboardAvailable } from '../../../selectors/dashboard';

const getWidgetOpts = (w) => w?.widgetOpts?.[w.widgetType];

Expand All @@ -27,6 +30,7 @@ const DefaultWidget = ({
exportImage = () => {},
onDelete = () => {},
onEdit = () => {},
isDashboardOpened,
...w
} = {}) => w.widgetType === "text"
? (<TextWidget {...w}
Expand All @@ -41,6 +45,7 @@ const DefaultWidget = ({
dependencies={dependencies}
onDelete={onDelete}
onEdit={onEdit}
isDashboardOpened={isDashboardOpened}
/>
: w.widgetType === "counter"
? <CounterWidget {...w}
Expand Down Expand Up @@ -71,4 +76,4 @@ const DefaultWidget = ({
exportImage={exportImage}
onDelete={onDelete}
onEdit={onEdit} />);
export default DefaultWidget;
export default connect(createSelector(isDashboardAvailable, (isDashboardOpened)=>({ isDashboardOpened })))(DefaultWidget);
4 changes: 3 additions & 1 deletion web/client/components/widgets/widget/TableWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export default getWidgetFilterRenderers(({
virtualScroll = true,
gridOpts = defaultGridOpts,
options = {},
dateFormats
dateFormats,
gridTools
}) =>
(<WidgetContainer
id={`widget-chart-${id}`}
Expand Down Expand Up @@ -97,6 +98,7 @@ export default getWidgetFilterRenderers(({
pagination={pagination}
gridOpts={gridOpts}
options={options}
tools={gridTools} // if geom prop is existing show zoom icon
dateFormats={dateFormats}/>
</BorderLayout>
</WidgetContainer>
Expand Down
3 changes: 3 additions & 0 deletions web/client/components/widgets/widget/enhancedWidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import dependenciesToWidget from '../enhancers/dependenciesToWidget';
import dependenciesToExtent from '../enhancers/dependenciesToExtent';
import dependenciesToLayers from '../enhancers/dependenciesToLayers';
import dependenciesToMapProp from '../enhancers/dependenciesToMapProp';
import dependenciesToZoomTo from '../enhancers/dependenciesToZoomTo';


import BaseChartWidget from './ChartWidget';
Expand Down Expand Up @@ -73,6 +74,8 @@ export const MapWidget = compose(
dependenciesToMapProp('center'),
dependenciesToMapProp('zoom'),
dependenciesToExtent,
// add hoc register
dependenciesToZoomTo,
mapWidget
)(BaseMapWidget);

Expand Down

0 comments on commit 90ba37c

Please sign in to comment.