Skip to content

Commit

Permalink
Change restricted area setter
Browse files Browse the repository at this point in the history
restricted area documentation

Lint and clean
  • Loading branch information
Gaetanbrl committed Aug 21, 2024
1 parent 1cfb2b1 commit dbb2fd3
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 40 deletions.
8 changes: 8 additions & 0 deletions docs/user-guide/attributes-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,11 @@ With a click on the <img src="../img/button/export_at.jpg" class="ms-docbutton"/
* Deciding which columns to show and which to hide through the <img src="../img/button/hide_show_col.jpg" class="ms-docbutton"/> button:

<video class="ms-docimage" controls><source src="../img/attributes-table/show_hide_columns.mp4"/></video>

## Restriction by area

MapStore [allows to configure](https://mapstore.geosolutionsgroup.com/mapstore/docs/api/plugins#plugins.FeatureEditor) attribute table in order to limit features consultation by a geometric area.

Note that this restriction is never active for adminstrators. If active, the user see an icon to the left of the attribute table toolbar :

<img src="../img/attributes-table/restricted_area_icon.png" class="ms-docbutton"/>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 8 additions & 8 deletions web/client/components/data/featuregrid/toolbars/Toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,21 @@ const standardButtons = {
onClick={events.switchEditMode}
glyph="pencil" />),
isRestrictedByArea: ({ restrictedArea }) => {
return <Button
return (<Button
id="fg-isRestrictedByArea-button"
keyProp="fg-restrictedarea-button"
className="square-button-md"
bsStyle="warning"
tooltipId="featuregrid.toolbar.restrictedByArea"
disabled
style={isEmpty(restrictedArea) ? {
width: 0,
padding: 0,
borderWidth: 0
} : {}}>
<Glyphicon glyph="1-point-dashed" />
</Button>
},
width: 0,
padding: 0,
borderWidth: 0
} : {}}>
<Glyphicon glyph="1-point-dashed" />
</Button>);
},
filter: ({isFilterActive = false, viewportFilter, disabled, isSearchAllowed, mode, showAdvancedFilterButton = true, events = {}}) => (<TButton
id="search"
keyProp="search"
Expand Down
44 changes: 20 additions & 24 deletions web/client/epics/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import axios from '../libs/ajax';
import bbox from '@turf/bbox';
import booleanIntersects from "@turf/boolean-intersects";
import { fidFilter } from '../utils/ogc/Filter/filter';
import { getDefaultFeatureProjection, getPagesToLoad, gridUpdateToQueryUpdate, updatePages } from '../utils/FeatureGridUtils';
import { getDefaultFeatureProjection, getPagesToLoad, gridUpdateToQueryUpdate, rawAsGeoJson, updatePages } from '../utils/FeatureGridUtils';

import assign from 'object-assign';
import {
Expand All @@ -26,7 +26,7 @@ import {
import requestBuilder from '../utils/ogc/WFST/RequestBuilder';
import { findGeometryProperty } from '../utils/ogc/WFS/base';
import { FEATURE_INFO_CLICK, HIDE_MAPINFO_MARKER, closeIdentify, hideMapinfoMarker } from '../actions/mapInfo';
import { LOGIN_SUCCESS, LOGOUT } from "../actions/security"
import { LOGIN_SUCCESS, LOGOUT } from "../actions/security";

import {
query,
Expand Down Expand Up @@ -113,7 +113,7 @@ import {
launchUpdateFilterFunc,
LAUNCH_UPDATE_FILTER_FUNC, SET_LAYER,
SET_VIEWPORT_FILTER, setViewportFilter,
setRestrictedArea,
setRestrictedArea
} from '../actions/featuregrid';

import {
Expand Down Expand Up @@ -213,14 +213,13 @@ const setupDrawSupport = (state, original) => {

// Remove features with geometry null or id "empty_row"
const cleanFeatures = features.filter(ft => {
console.log("clean features");
const restrictedArea = restrictedAreaSelector(state);
let isValidFeature = ft.geometry !== null || ft.id !== 'empty_row';
if (isValidFeature && !isEmpty(restrictedArea)) {
// allow only feature inside restricted area
isValidFeature = booleanIntersects(restrictedArea, ft.geometry);
}
return isValidFeature
return isValidFeature;
});

if (cleanFeatures.length > 0) {
Expand Down Expand Up @@ -503,7 +502,6 @@ export const enableGeometryFilterOnEditMode = (action$, store) =>
action$.ofType(TOGGLE_MODE)
.filter(() => modeSelector(store.getState()) === MODES.EDIT)
.switchMap(() => {
console.log("enableGeometryFilterOnEditMode")
const currentFilter = find(getAttributeFilters(store.getState()), f => f.type === 'geometry') || {};
return currentFilter.value ? Rx.Observable.empty() : Rx.Observable.of(updateFilter({
attribute: findGeometryProperty(describeSelector(store.getState())).name,
Expand Down Expand Up @@ -1301,35 +1299,33 @@ export const resetViewportFilter = (action$, store) =>
: Rx.Observable.empty();
});

export const requestRestrictedArea = (action$, store) =>
export const requestRestrictedArea = (action$, store) =>
action$.ofType(OPEN_FEATURE_GRID, LOGIN_SUCCESS)
.filter(() =>
{
.filter(() => {
return !isAdminUserSelector(store.getState())
&& isLoggedIn(store.getState())
&& !isEmpty(restrictedAreaSrcSelector(store.getState()))}
)
.switchMap((action) => {
&& isLoggedIn(store.getState())
&& !isEmpty(restrictedAreaSrcSelector(store.getState()));
})
.switchMap(() => {
const src = restrictedAreaSrcSelector(store.getState());
if (src.url) {
return Rx.Observable.defer(() => fetch(src?.url).then(r => r?.json?.()))
.switchMap(result => {
return Rx.Observable.of(
setRestrictedArea(result),
setRestrictedArea(rawAsGeoJson(result)),
changePage(0)
)
})
} else {
return Rx.Observable.of(
setRestrictedArea(src?.raw || {}),
changePage(0)
)
);
});
}
})
return Rx.Observable.of(
setRestrictedArea(rawAsGeoJson(src.raw) || {}),
changePage(0)
);
});

export const resetRestrictedArea = (action$, store) =>
action$.ofType(LOGOUT, CLOSE_FEATURE_GRID)
.filter((a) => !isEmpty(restrictedAreaSrcSelector(store.getState())))
.filter(() => !isEmpty(restrictedAreaSrcSelector(store.getState())))
.switchMap(() => Rx.Observable.of(
setRestrictedArea({})
))
));
8 changes: 8 additions & 0 deletions web/client/plugins/FeatureEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ import {isViewportFilterActive} from "../selectors/featuregrid";
* @prop {array} cfg.showFilterByViewportTool Show button to toggle filter by viewport in toolbar.
* @prop {object} cfg.dateFormats Allows to specify custom date formats ( in [ISO_8601](https://en.wikipedia.org/wiki/ISO_8601) format) to use to display dates in the table. `date` `date-time` and `time` are the supported entries for the date format. Example:
* @prop {boolean} cfg.showPopoverSync default false. Hide the popup of map sync if false, shows the popup of map sync if true
* @prop {string} cfg.restrictedArea.url Geometry definition as WKT or GeoJSON loaded from URL or path.
* @prop {string} cfg.restrictedArea.raw Geometry definition as WKT or GeoJSON.
* @prop {string} cfg.restrictedArea.operator Spatial operation to performed between features and the given geometry.
* ```
* "dateFormats": {
* "date-time": "MM DD YYYY - HH:mm:ss",
Expand Down Expand Up @@ -114,6 +117,11 @@ import {isViewportFilterActive} from "../selectors/featuregrid";
* },
* "editingAllowedRoles": ["ADMIN"],
* "snapTool": true,
* "restrictedArea": {
* "url": "/wkt_or_geojson_geometry",
* "raw": "POLYGON ((-64.8 32.3, -65.5 18.3, -80.3 25.2, -64.8 32.3))",
* "operator": "WITHIN"
* },
* "snapConfig": {
* "vertex": true,
* "edge": true,
Expand Down
8 changes: 8 additions & 0 deletions web/client/plugins/featuregrid/FeatureEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ const Dock = connect(createSelector(
* @prop {array} cfg.snapConfig.additionalLayers Array of additional layers to include into snapping layers list. Provides a way to include layers from "state.additionallayers"
* @prop {object} cfg.dateFormats object containing custom formats for one of the date/time attribute types. Following keys are supported: "date-time", "date", "time"
* @prop {boolean} cfg.showPopoverSync default false. Hide the popup of map sync if false, shows the popup of map sync if true
* @prop {string} cfg.restrictedArea.url Geometry definition as WKT or GeoJSON loaded from URL or path.
* @prop {string} cfg.restrictedArea.raw Geometry definition as WKT or GeoJSON.
* @prop {string} cfg.restrictedArea.operator Spatial operation to performed between features and the given geometry.
*
* @classdesc
* `FeatureEditor` Plugin, also called *FeatureGrid*, provides functionalities to browse/edit data via WFS. The grid can be configured to use paging or
Expand Down Expand Up @@ -124,6 +127,11 @@ const Dock = connect(createSelector(
* },
* "editingAllowedRoles": ["ADMIN"],
* "snapTool": true,
* "restrictedArea": {
* "url": "/wkt_or_geojson_geometry",
* "raw": "POLYGON ((-64.8 32.3, -65.5 18.3, -80.3 25.2, -64.8 32.3))",
* "operator": "WITHIN"
* },
* "snapConfig": {
* "vertex": true,
* "edge": true,
Expand Down
4 changes: 2 additions & 2 deletions web/client/reducers/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
UPDATE_EDITORS_OPTIONS,
SET_PAGINATION,
SET_VIEWPORT_FILTER,
SET_RESTRICTED_AREA,
SET_RESTRICTED_AREA
} from '../actions/featuregrid';
import { MAP_CONFIG_LOADED } from '../actions/config';

Expand Down Expand Up @@ -443,7 +443,7 @@ function featuregrid(state = emptyResultsState, action) {
}
case MAP_CONFIG_LOADED: {
return {...state, ...get(action, 'config.featureGrid', {})};
}
}
case SET_RESTRICTED_AREA: {
return { ...state, restrictedArea: { ...state.restrictedArea, geometry: action.area } };
}
Expand Down
12 changes: 6 additions & 6 deletions web/client/selectors/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,12 @@ export const restrictedAreaFilter = createShallowSelectorCreator(isEqual)(
projectionSelector,
describeSelector,
state => restrictedAreaOperatorSelector(state),
(restrictedArea, spatialField = [], viewportFilter, projection, describeLayer, operator) => {
(restrictedArea, spatialField = [], viewPortFilter, projection, describeLayer, operator) => {
const attribute = findGeometryProperty(describeLayer)?.name;
let existingFilter = [];
// if activate, viewportFilter already get existing filter
if(isEmpty(viewportFilter) && !isEmpty(spatialField)) {
existingFilter = spatialField?.operation ? [spatialField] : spatialField
if (isEmpty(viewPortFilter) && !isEmpty(spatialField)) {
existingFilter = spatialField?.operation ? [spatialField] : spatialField;
}
return !isEmpty(restrictedArea) ? {
spatialField: [
Expand All @@ -275,7 +275,7 @@ export const restrictedAreaFilter = createShallowSelectorCreator(isEqual)(
]
} : {};
}
)
);

/**
* Create spatialField filters array.
Expand All @@ -284,5 +284,5 @@ export const restrictedAreaFilter = createShallowSelectorCreator(isEqual)(
export const additionnalGridFilters = (state) => {
const restrictedArea = restrictedAreaFilter(state)?.spatialField || [];
const viewport = viewportFilter(state)?.spatialField || [];
return {spatialField: [...restrictedArea, ...viewport]}
}
return {spatialField: [...restrictedArea, ...viewport]};
};
37 changes: 37 additions & 0 deletions web/client/utils/FeatureGridUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
isValidValueForPropertyName as isValidValueForPropertyNameBase
} from './ogc/WFS/base';

import { WKT } from 'ol/format';

import { applyDefaultToLocalizedString } from '../components/I18N/LocalizedString';

const getGeometryName = (describe) => get(findGeometryProperty(describe), "name");
Expand Down Expand Up @@ -392,3 +394,38 @@ export const supportsFeatureEditing = (layer) => includes(supportedEditLayerType
* @returns {boolean} flag
*/
export const areLayerFeaturesEditable = (layer) => !layer?.disableFeaturesEditing && supportsFeatureEditing(layer);

export const isWKT = (wktString) => {
let isWKTGeom = false;
try {
const reader = new WKT();
const feature = reader.readFeature(wktString);
if (feature) {
isWKTGeom = true;
}
} catch (e) {
isWKTGeom = false;
}
return isWKTGeom;
};

export const wktToGeoJson = (wktString) => {
const reader = new WKT();
const feature = reader.readFeature(wktString);
return {
type: feature.getGeometry().getType(),
coordinates: feature.getGeometry().getCoordinates()
};
};

/**
* Return GeoJSON geometry. Transform WKT to GeoJSON if necessary.
* @param {string} raw - geometry
* @returns geometry object
*/
export const rawAsGeoJson = (raw) => {
if (isWKT(raw)) {
return wktToGeoJson(raw);
}
return raw;
};

0 comments on commit dbb2fd3

Please sign in to comment.