UNPKG

qwc2

Version:
876 lines (874 loc) 42.9 kB
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /** * Copyright 2024 Sourcepole AG * 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 { connect } from 'react-redux'; import axios from 'axios'; import isEmpty from 'lodash.isempty'; import isEqual from 'lodash.isequal'; import PropTypes from 'prop-types'; import { v4 as uuidv4 } from 'uuid'; import { LayerRole, setFilter } from '../actions/layers'; import { setPermalinkParameters } from '../actions/localConfig'; import { setCurrentTask } from '../actions/task'; import Icon from '../components/Icon'; import MapButton from '../components/MapButton'; import MapSelection from '../components/MapSelection'; import PickFeature from '../components/PickFeature'; import SideBar from '../components/SideBar'; import ButtonBar from '../components/widgets/ButtonBar'; import ComboBox from '../components/widgets/ComboBox'; import DateTimeInput from '../components/widgets/DateTimeInput'; import TextInput from '../components/widgets/TextInput'; import ToggleSwitch from '../components/widgets/ToggleSwitch'; import ConfigUtils from '../utils/ConfigUtils'; import LayerUtils from '../utils/LayerUtils'; import LocaleUtils from '../utils/LocaleUtils'; import MiscUtils from '../utils/MiscUtils'; import './style/MapFilter.css'; /** * Allows filtering the map content via QGIS Server WMS FILTER. * * See [Map filtering](../../topics/MapFilter). */ var MapFilter = /*#__PURE__*/function (_React$Component) { function MapFilter(props) { var _this; _classCallCheck(this, MapFilter); _this = _callSuper(this, MapFilter, [props]); _defineProperty(_this, "state", { filters: {}, geomFilter: {}, customFilters: {}, filterEditor: null, filterInvalid: false }); _defineProperty(_this, "collectPredefinedFilters", function (layers) { return layers.reduce(function (res, layer) { return _objectSpread(_objectSpread({}, res), (layer.predefinedFilters || []).reduce(function (res2, config) { return _objectSpread(_objectSpread({}, res2), {}, _defineProperty({}, config.id, config)); }, {})); }, {}); }); _defineProperty(_this, "initializeFilters", function (predefinedFilters, prevFilters) { clearTimeout(_this.applyFilterTimeout); _this.applyFilterTimeout = null; var filters = Object.values(predefinedFilters).reduce(function (res, filterConfig) { var _prevFilters$filterCo; return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, filterConfig.id, (_prevFilters$filterCo = prevFilters === null || prevFilters === void 0 ? void 0 : prevFilters[filterConfig.id]) !== null && _prevFilters$filterCo !== void 0 ? _prevFilters$filterCo : { active: false, filter: filterConfig.filter, values: filterConfig.fields.reduce(function (values, valueConfig) { return _objectSpread(_objectSpread({}, values), {}, _defineProperty({}, valueConfig.id, valueConfig.defaultValue)); }, {}) })); }, {}); var timeFilter = {}; _this.props.layers.forEach(function (layer) { return _this.buildTimeFilter(layer, timeFilter); }); if (!isEmpty(timeFilter) && _this.props.allowFilterByTime) { var _prevFilters$__timefi, _prevFilters$__timefi2, _prevFilters$__timefi3, _prevFilters$__timefi4; filters.__timefilter = { active: (_prevFilters$__timefi = (_prevFilters$__timefi2 = prevFilters.__timefilter) === null || _prevFilters$__timefi2 === void 0 ? void 0 : _prevFilters$__timefi2.active) !== null && _prevFilters$__timefi !== void 0 ? _prevFilters$__timefi : false, filter: timeFilter, values: (_prevFilters$__timefi3 = (_prevFilters$__timefi4 = prevFilters.__timefilter) === null || _prevFilters$__timefi4 === void 0 ? void 0 : _prevFilters$__timefi4.values) !== null && _prevFilters$__timefi3 !== void 0 ? _prevFilters$__timefi3 : { tstart: "", tend: "" }, defaultValues: { tstart: '1800-01-01', tend: '9999-12-31' } }; } return filters; }); _defineProperty(_this, "applyFilter", function () { var _this$state$filters$_; _this.applyFilterTimeout = null; var layerExpressions = {}; // Recompute filter expressions Object.values(_this.state.filters).forEach(function (entry) { if (entry.active) { Object.entries(entry.filter).forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), layer = _ref2[0], expression = _ref2[1]; var replacedExpr = _this.replaceExpressionVariables(expression, entry.values, entry.defaultValues || {}); if (replacedExpr === null) { /* eslint-disable-next-line */ console.warn("Invalid filter expression: " + JSON.stringify(expression)); } else if (layerExpressions[layer]) { layerExpressions[layer].push('and', replacedExpr); } else { layerExpressions[layer] = [replacedExpr]; } }); } }, {}); Object.values(_this.state.customFilters).forEach(function (entry) { if (entry.active && entry.layer) { var expr = ''; try { expr = JSON.parse(entry.expr); } catch (e) { return; } if (layerExpressions[entry.layer]) { layerExpressions[entry.layer].push('and', expr); } else { layerExpressions[entry.layer] = [expr]; } } }); var timeRange = (_this$state$filters$_ = _this.state.filters.__timefilter) !== null && _this$state$filters$_ !== void 0 && _this$state$filters$_.active ? { tstart: _this.state.filters.__timefilter.values.tstart, tend: _this.state.filters.__timefilter.values.tend } : null; _this.props.setFilter(layerExpressions, _this.state.geomFilter.geom, timeRange); // Validate parameters with test request var themeLayer = _this.props.layers.find(function (layer) { return layer.role === LayerRole.THEME; }); if (themeLayer) { var wmsParams = LayerUtils.buildWMSLayerParams(themeLayer, { filterParams: layerExpressions, filterGeom: _this.state.geomFilter.geom }).params; var wmsLayers = wmsParams.LAYERS.split(","); var reqParams = { SERVICE: 'WMS', REQUEST: 'GetMap', VERSION: '1.3.0', CRS: 'EPSG:4326', WIDTH: 10, HEIGHT: 10, BBOX: "-0.5,-0.5,0.5,0.5", LAYERS: Object.keys(layerExpressions).filter(function (layer) { return wmsLayers.includes(layer); }).join(","), csrf_token: MiscUtils.getCsrfToken() }; if (wmsParams.FILTER) { reqParams.FILTER = wmsParams.FILTER; } if (wmsParams.FILTER_GEOM) { reqParams.FILTER_GEOM = wmsParams.FILTER_GEOM; } var options = { headers: { 'content-type': 'application/x-www-form-urlencoded' }, responseType: "blob" }; axios.post(themeLayer.url, new URLSearchParams(reqParams).toString(), options).then(function () { _this.setState({ filterInvalid: false }); })["catch"](function () { _this.setState({ filterInvalid: true }); }); } var permalinkState = Object.entries(_this.state.filters).reduce(function (res, _ref3) { var _ref4 = _slicedToArray(_ref3, 2), key = _ref4[0], value = _ref4[1]; if (value.active) { return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, key, value.values)); } else { return res; } }, {}); if (_this.state.geomFilter.geom) { permalinkState.__geomfilter = _this.state.geomFilter.geom.coordinates; } permalinkState.__custom = Object.values(_this.state.customFilters).map(function (entry) { if (!entry.active) { return null; } var expr = null; try { expr = JSON.parse(entry.expr); } catch (e) { return null; } return { title: entry.title, layer: entry.layer, expr: expr }; }).filter(Boolean); _this.props.setPermalinkParameters({ f: JSON.stringify(permalinkState) }); }); _defineProperty(_this, "buildTimeFilter", function (layer, filters) { if (layer.sublayers) { layer.sublayers.forEach(function (sublayer) { return _this.buildTimeFilter(sublayer, filters); }); } else { var timeDimension = (layer.dimensions || []).find(function (dimension) { return dimension.units === "ISO8601"; }); if (timeDimension) { filters[layer.name] = [[[timeDimension.fieldName, '>=', "$tstart$"], 'or', [timeDimension.fieldName, 'IS', null]], 'and', [[timeDimension.endFieldName, '<=', "$tend$"], 'or', [timeDimension.endFieldName, 'IS', null]]]; } } }); _defineProperty(_this, "filterMapButtonClicked", function () { var mapClickAction = ConfigUtils.getPluginConfig("MapFilter").mapClickAction; _this.props.setCurrentTask(_this.props.currentTask === "MapFilter" ? null : "MapFilter", null, mapClickAction); }); _defineProperty(_this, "onSidebarHide", function () { _this.setState(function (state) { var newState = _objectSpread({}, state); if (!state.geomFilter.geom && state.geomFilter.geomType) { newState.geomFilter.geomType = null; } if (state.geomFilter.picking) { newState.geomFilter.picking = false; } return newState; }); }); _defineProperty(_this, "renderBody", function () { if (_this.state.filterEditor) { return _this.renderFilterEditor(); } else { return [_this.renderInvalidWarning()].concat(_toConsumableArray(_this.renderPredefinedFilters()), [_this.props.allowFilterByTime ? _this.renderTimeFilter() : null, _this.props.allowFilterByGeom ? _this.renderGeomFilter() : null], _toConsumableArray(_this.renderCustomFilters())); } }); _defineProperty(_this, "renderInvalidWarning", function () { if (_this.state.filterInvalid) { return /*#__PURE__*/React.createElement("div", { className: "map-filter-invalid-warning", key: "InvalidFilterWarning" }, /*#__PURE__*/React.createElement(Icon, { icon: "warning" }), " ", /*#__PURE__*/React.createElement("div", null, LocaleUtils.tr("mapfilter.brokenrendering"))); } return null; }); _defineProperty(_this, "renderFilterEditor", function () { var commitButtons = [{ key: 'Save', icon: 'ok', label: LocaleUtils.tr("common.save"), extraClasses: "button-accept" }, { key: 'Cancel', icon: 'remove', label: LocaleUtils.tr("common.cancel"), extraClasses: "button-reject" }]; var sampleFilters = '["field", "=", "val"]\n' + '[["field", ">", "val1"], "and", ["field", "<", "val2"]]'; return /*#__PURE__*/React.createElement("div", { className: "map-filter-editor-container" }, /*#__PURE__*/React.createElement(TextInput, { className: "map-filter-editor " + (_this.state.filterEditor.invalid ? "map-filter-editor-invalid" : ""), multiline: true, onChange: function onChange(value) { return _this.setState(function (state) { return { filterEditor: _objectSpread(_objectSpread({}, state.filterEditor), {}, { value: value, invalid: false }) }; }); }, placeholder: sampleFilters, value: _this.state.filterEditor.value }), _this.state.filterEditor.invalid ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Icon, { icon: "warning" }), " ", /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("mapfilter.invalidfilter"))) : null, /*#__PURE__*/React.createElement(ButtonBar, { buttons: commitButtons, onClick: _this.commitFilterEditor })); }); _defineProperty(_this, "commitFilterEditor", function (action) { if (action === 'Save') { // Validate expression var _validateExpression = function validateExpression(values) { if (Array.isArray(values[0])) { // Even entries must be arrays, odd entries must be 'and' or 'or' return values.every(function (value, idx) { return idx % 2 === 0 ? Array.isArray(value) && _validateExpression(value) : ["and", "or"].includes(value.toLowerCase()); }, true); } else { return values.length === 3 && typeof values[0] === 'string' && typeof values[1] === 'string' && ['string', 'number'].includes(_typeof(values[2])); } }; var filterexpr = null; try { filterexpr = JSON.parse(_this.state.filterEditor.value); } catch (e) { // Pass } if (!Array.isArray(filterexpr) || !_validateExpression(filterexpr)) { _this.setState(function (state) { return { filterEditor: _objectSpread(_objectSpread({}, state.filterEditor), {}, { invalid: true }) }; }); return; } _this.updateCustomFilter(_this.state.filterEditor.filterId, 'expr', _this.state.filterEditor.value); } _this.setState({ filterEditor: null }); }); _defineProperty(_this, "renderPredefinedFilters", function () { var predefinedFilters = _this.collectPredefinedFilters(_this.props.layers); return Object.values(predefinedFilters).map(function (config) { var _config$title, _this$state$filters$c; return /*#__PURE__*/React.createElement("div", { className: "map-filter-entry", key: config.id }, /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-titlebar" }, /*#__PURE__*/React.createElement("span", { className: "map-filter-entry-title" }, (_config$title = config.title) !== null && _config$title !== void 0 ? _config$title : LocaleUtils.tr(config.titlemsgid)), /*#__PURE__*/React.createElement(ToggleSwitch, { active: (_this$state$filters$c = _this.state.filters[config.id]) === null || _this$state$filters$c === void 0 ? void 0 : _this$state$filters$c.active, onChange: function onChange(active) { return _this.toggleFilter(config.id, active); } })), /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-body" }, /*#__PURE__*/React.createElement("table", { className: "map-filter-entry-fields" }, /*#__PURE__*/React.createElement("tbody", null, config.fields.map(function (field) { var _field$title; return /*#__PURE__*/React.createElement("tr", { key: field.id }, /*#__PURE__*/React.createElement("td", null, (_field$title = field.title) !== null && _field$title !== void 0 ? _field$title : LocaleUtils.tr(field.titlemsgid), ": "), /*#__PURE__*/React.createElement("td", null, field.inputConfig.type === 'select' ? /*#__PURE__*/React.createElement("select", { onChange: function onChange(ev) { return _this.updateFieldValue(config.id, field.id, ev.target.value); }, value: _this.state.filters[config.id].values[field.id] }, !field.defaultValue ? /*#__PURE__*/React.createElement("option", { value: "" }, LocaleUtils.tr("common.select")) : null, field.inputConfig.options.map(function (entry) { var _entry$value, _entry$value2, _entry$label; return /*#__PURE__*/React.createElement("option", { key: (_entry$value = entry.value) !== null && _entry$value !== void 0 ? _entry$value : entry, value: (_entry$value2 = entry.value) !== null && _entry$value2 !== void 0 ? _entry$value2 : entry }, (_entry$label = entry.label) !== null && _entry$label !== void 0 ? _entry$label : entry.labelmsgid ? LocaleUtils.tr(entry.labelmsgid) : entry); })) : /*#__PURE__*/React.createElement("input", _extends({ onChange: function onChange(ev) { return _this.updateFieldValue(config.id, field.id, ev.target.value); }, type: "text", value: _this.state.filters[config.id].values[field.id] || "" }, field.inputConfig)))); }))))); }); }); _defineProperty(_this, "renderTimeFilter", function () { var timeFilter = _this.state.filters.__timefilter; if (!timeFilter) { return null; } return /*#__PURE__*/React.createElement("div", { className: "map-filter-entry", key: "__timefilter" }, /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-titlebar" }, /*#__PURE__*/React.createElement("span", { className: "map-filter-entry-title" }, LocaleUtils.tr("mapfilter.timefilter")), /*#__PURE__*/React.createElement(ToggleSwitch, { active: timeFilter.active, onChange: function onChange(active) { return _this.toggleFilter("__timefilter", active); } })), /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-body" }, /*#__PURE__*/React.createElement("table", { className: "map-filter-entry-fields" }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapfilter.timefrom"), ": "), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(DateTimeInput, { onChange: function onChange(value) { return _this.updateFieldValue("__timefilter", "tstart", value); }, value: timeFilter.values.tstart }))), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapfilter.timeto"), ": "), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(DateTimeInput, { onChange: function onChange(value) { return _this.updateFieldValue("__timefilter", "tend", value); }, value: timeFilter.values.tend }))))))); }); _defineProperty(_this, "renderCustomFilters", function () { if (!_this.props.allowCustomFilters) { return []; } var layerNames = _this.props.layers.reduce(function (res, layer) { if (layer.role === LayerRole.THEME) { return [].concat(_toConsumableArray(res), _toConsumableArray(LayerUtils.getSublayerNames(layer, true, function (lyr) { return !!lyr.geometryType; }))); } return res; }, []); var customFilters = Object.entries(_this.state.customFilters).map(function (_ref5) { var _ref6 = _slicedToArray(_ref5, 2), key = _ref6[0], entry = _ref6[1]; return /*#__PURE__*/React.createElement("div", { className: "map-filter-entry", key: key }, /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-titlebar map-filter-custom-entry-titlebar" }, /*#__PURE__*/React.createElement(TextInput, { className: "map-filter-entry-title", onChange: function onChange(value) { return _this.updateCustomFilter(key, 'title', value); }, value: entry.title }), /*#__PURE__*/React.createElement(ToggleSwitch, { active: entry.active, onChange: function onChange(active) { return _this.updateCustomFilter(key, 'active', active); } }), /*#__PURE__*/React.createElement(Icon, { icon: "trash", onClick: function onClick() { return _this.deleteCustomFilter(key); } })), /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-body" }, /*#__PURE__*/React.createElement("table", { className: "map-filter-entry-fields" }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(ComboBox, { onChange: function onChange(value) { return _this.updateCustomFilter(key, 'layer', value); }, placeholder: LocaleUtils.tr("common.selectlayer"), value: entry.layer }, layerNames.map(function (layerName) { return /*#__PURE__*/React.createElement("div", { key: layerName, value: layerName }, layerName); }))), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("input", { className: "map-filter-custom-entry-expr", onChange: function onChange() {}, onClick: function onClick() { return _this.setState({ filterEditor: { filterId: key, value: entry.expr } }); }, readOnly: true, value: entry.expr }))))))); }); return [].concat(_toConsumableArray(customFilters), [/*#__PURE__*/React.createElement("div", { className: "map-filter-add-custom", key: "addcustomfilter" }, /*#__PURE__*/React.createElement("button", { className: "button", onClick: _this.addCustomFilter, type: "button" }, LocaleUtils.tr("mapfilter.addcustomfilter")))]); }); _defineProperty(_this, "renderGeomFilter", function () { var geomFilter = _this.state.geomFilter; var filterButtons = [{ key: "Polygon", tooltip: LocaleUtils.tr("common.polygon"), icon: "polygon", label: LocaleUtils.tr("common.polygon") }, { key: "Circle", tooltip: LocaleUtils.tr("common.circle"), icon: "circle", label: LocaleUtils.tr("common.circle") }, { key: "Pick", tooltip: LocaleUtils.tr("common.pick"), icon: "pick", label: LocaleUtils.tr("common.pick") }]; var active = geomFilter.picking ? "Pick" : geomFilter.geomType || ""; return /*#__PURE__*/React.createElement("div", { className: "map-filter-entry", key: "__geomfilter" }, /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-titlebar" }, /*#__PURE__*/React.createElement("span", { className: "map-filter-entry-title" }, LocaleUtils.tr("mapfilter.geomfilter"))), /*#__PURE__*/React.createElement("div", { className: "map-filter-entry-body" }, /*#__PURE__*/React.createElement(ButtonBar, { active: active, buttons: filterButtons, onClick: _this.triggerGeometryFilter }), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", { checked: !!geomFilter.hideFilterGeom, onChange: _this.toggleHideFilterGeom, type: "checkbox" }), " ", LocaleUtils.tr("mapfilter.hidefiltergeom"))))); }); _defineProperty(_this, "triggerGeometryFilter", function (action) { if (action === 'Pick') { _this.setState(function (state) { return { geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, { geom: null, picking: !state.geomFilter.picking, geomType: null }) }; }); } else { _this.setState(function (state) { return { geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, { geom: null, picking: false, geomType: state.geomFilter.geomType === action ? null : action }) }; }); } }); _defineProperty(_this, "setFilterGeometry", function (geom) { _this.setState(function (state) { return { geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, { geom: geom }) }; }); }); _defineProperty(_this, "filterGeomPicked", function (layer, feature) { _this.setState(function (state) { return { geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, { geom: feature.geometry, geomType: feature.geometry.type }) }; }); }); _defineProperty(_this, "toggleHideFilterGeom", function (ev) { _this.setState(function (state) { return { geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, { hideFilterGeom: ev.target.checked }) }; }); }); _defineProperty(_this, "toggleFilter", function (filterId, active) { _this.setState(function (state) { return { filters: _objectSpread(_objectSpread({}, state.filters), {}, _defineProperty({}, filterId, _objectSpread(_objectSpread({}, state.filters[filterId]), {}, { active: active }))) }; }); }); _defineProperty(_this, "updateFieldValue", function (filterId, fieldId, value) { _this.setState(function (state) { return { filters: _objectSpread(_objectSpread({}, state.filters), {}, _defineProperty({}, filterId, _objectSpread(_objectSpread({}, state.filters[filterId]), {}, { values: _objectSpread(_objectSpread({}, state.filters[filterId].values), {}, _defineProperty({}, fieldId, value)) }))) }; }); }); _defineProperty(_this, "updateCustomFilter", function (filterId, key, value) { _this.setState(function (state) { return { customFilters: _objectSpread(_objectSpread({}, state.customFilters), {}, _defineProperty({}, filterId, _objectSpread(_objectSpread({}, state.customFilters[filterId]), {}, _defineProperty({}, key, value)))) }; }); }); _defineProperty(_this, "addCustomFilter", function () { var key = uuidv4(); _this.setState(function (state) { return { customFilters: _objectSpread(_objectSpread({}, state.customFilters), {}, _defineProperty({}, key, { active: false, title: '', layer: '', expr: '' })) }; }); }); _defineProperty(_this, "deleteCustomFilter", function (key) { _this.setState(function (state) { var newCustomFilters = _objectSpread({}, state.customFilters); delete newCustomFilters[key]; return { customFilters: newCustomFilters }; }); }); _defineProperty(_this, "replaceExpressionVariables", function (expr, values, defaultValues) { if (expr.length < 3 || expr.length % 2 === 0 || typeof expr[1] !== 'string') { // Invalid expression: array must have at least three and odd number of entries, // mid entry must be a string (operator) return null; } var op = expr[1].toLowerCase(); if (typeof expr[0] === 'string') { if (typeof expr[2] === 'string') { var right = Object.entries(values).reduce(function (res, _ref7) { var _ref9; var _ref8 = _slicedToArray(_ref7, 2), key = _ref8[0], value = _ref8[1]; return res.replace("$".concat(key, "$"), (_ref9 = value || defaultValues[key]) !== null && _ref9 !== void 0 ? _ref9 : value); }, expr[2]); return [expr[0], op, right]; } else { return [expr[0], op, expr[2]]; } } else { // Even indices must be arrays, odd and|or strings var isAndOr = function isAndOr(entry) { return ["and", "or"].includes(String(entry).toLowerCase()); }; var invalid = expr.find(function (entry, idx) { return idx % 2 === 0 ? !Array.isArray(entry) : !isAndOr(entry); }); if (invalid) { return null; } return expr.map(function (entry, idx) { return idx % 2 === 0 ? _this.replaceExpressionVariables(entry, values, defaultValues) : entry; }); } }); _this.applyFilterTimeout = null; return _this; } _inherits(MapFilter, _React$Component); return _createClass(MapFilter, [{ key: "componentDidUpdate", value: function componentDidUpdate(prevProps, prevState) { var _this2 = this; if (this.props.theme !== prevProps.theme) { var _this$props$startupPa; // Initialize filter state var predefinedFilters = this.collectPredefinedFilters(this.props.layers); var filters = this.initializeFilters(predefinedFilters, {}); var geomFilter = {}; var customFilters = {}; if (!prevProps.theme && (_this$props$startupPa = this.props.startupParams) !== null && _this$props$startupPa !== void 0 && _this$props$startupPa.f) { try { var startupConfig = JSON.parse(this.props.startupParams.f); Object.entries(startupConfig).forEach(function (_ref10) { var _ref11 = _slicedToArray(_ref10, 2), filterId = _ref11[0], values = _ref11[1]; if (filterId in filters) { filters[filterId].active = true; Object.entries(values).forEach(function (_ref12) { var _ref13 = _slicedToArray(_ref12, 2), fieldId = _ref13[0], value = _ref13[1]; filters[filterId].values[fieldId] = value; }); } }); if ("__geomfilter" in startupConfig) { geomFilter = { geomType: "Polygon", geom: { type: "Polygon", coordinates: startupConfig.__geomfilter } }; } if ("__custom" in startupConfig) { customFilters = startupConfig.__custom.reduce(function (res, entry) { return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, uuidv4(), { title: entry.title || "", layer: entry.layer, expr: JSON.stringify(entry.expr), active: true })); }, {}); } } catch (e) { /* eslint-disable-next-line */ console.log("Error while parsing startup filter"); } } this.setState({ filters: filters, geomFilter: geomFilter, customFilters: customFilters }); } else if (this.props.layers !== prevProps.layers) { var _predefinedFilters = this.collectPredefinedFilters(this.props.layers); var prevPredefinedFilters = this.collectPredefinedFilters(prevProps.layers); if (!isEqual(Object.keys(_predefinedFilters).sort(), Object.keys(prevPredefinedFilters).sort())) { this.setState(function (state) { return { filters: _this2.initializeFilters(_predefinedFilters, state.filters) }; }); } } if (this.state.filters !== prevState.filters || this.state.customFilters !== prevState.customFilters || this.state.geomFilter.geom !== prevState.geomFilter.geom) { clearTimeout(this.applyFilterTimeout); this.applyFilterTimeout = setTimeout(this.applyFilter, 500); } } }, { key: "render", value: function render() { var _this$state$geomFilte, _this$state$geomFilte2, _this3 = this, _this$state$geomFilte3, _this$state$geomFilte4; var button = null; var taskActive = this.props.currentTask === "MapFilter"; if (this.props.position >= 0) { var filterActive = !isEmpty(this.props.filter.filterParams) || !!this.props.filter.filterGeom; var title = LocaleUtils.tr("appmenu.items.MapFilter"); var className = filterActive && this.state.filterInvalid ? "filter-map-button-error" : ""; button = /*#__PURE__*/React.createElement(MapButton, { active: taskActive, className: className, engaged: filterActive && !this.state.filterInvalid, icon: "filter", key: "MapFilterButton", onClick: this.filterMapButtonClicked, position: this.props.position, tooltip: title }); } var selGeomType = (_this$state$geomFilte = this.state.geomFilter) !== null && _this$state$geomFilte !== void 0 && _this$state$geomFilte.picking ? null : (_this$state$geomFilte2 = this.state.geomFilter) === null || _this$state$geomFilte2 === void 0 ? void 0 : _this$state$geomFilte2.geomType; return [button, /*#__PURE__*/React.createElement(SideBar, { icon: "filter", id: "MapFilter", key: "MapFilterSidebar", onHide: this.onSidebarHide, side: this.props.side, title: LocaleUtils.tr("appmenu.items.MapFilter"), width: "20em" }, function () { return { body: _this3.renderBody() }; }), this.state.geomFilter.picking ? /*#__PURE__*/React.createElement(PickFeature, { featureFilter: function featureFilter(feature) { var _feature$geometry; return ((feature === null || feature === void 0 || (_feature$geometry = feature.geometry) === null || _feature$geometry === void 0 ? void 0 : _feature$geometry.type) || "").endsWith("Polygon"); }, featurePicked: this.filterGeomPicked, highlightStyle: this.props.highlightStyle, key: "FeaturePicker" }) : null, /*#__PURE__*/React.createElement(MapSelection, { active: taskActive && !!selGeomType, geomType: selGeomType, geometry: (_this$state$geomFilte3 = this.state.geomFilter) === null || _this$state$geomFilte3 === void 0 ? void 0 : _this$state$geomFilte3.geom, geometryChanged: this.setFilterGeometry, hideGeometry: (_this$state$geomFilte4 = this.state.geomFilter) === null || _this$state$geomFilte4 === void 0 ? void 0 : _this$state$geomFilte4.hideFilterGeom, key: "MapSelection", styleOptions: this.props.highlightStyle })]; } }]); }(React.Component); _defineProperty(MapFilter, "propTypes", { /** Whether to allow custom filters. */ allowCustomFilters: PropTypes.bool, /** Whether to allow filter by geometry. Requires the filter_geom plugin from qwc-qgis-server-plugins, and the filter will only be applied to postgis layers. */ allowFilterByGeom: PropTypes.bool, /** Whether to display the temporal filter if temporal dimensions are found. */ allowFilterByTime: PropTypes.bool, currentTask: PropTypes.string, filter: PropTypes.object, /** The style used for highlighting filter geometries. */ highlightStyle: PropTypes.shape({ /* Stroke color rgba array, i.e. [255, 0, 0, 0.5] */ strokeColor: PropTypes.array, /* Stroke width */ strokeWidth: PropTypes.number, /* Stroke dash/gap pattern array. Empty for solid line. */ strokeDash: PropTypes.array, /* Fill color rgba array, i.e. [255, 0, 0, 0.33] */ fillColor: PropTypes.array }), layers: PropTypes.array, /** The position slot index of the map button, from the bottom (0: bottom slot). Set to -1 to hide the button. */ position: PropTypes.number, setCurrentTask: PropTypes.func, setFilter: PropTypes.func, setPermalinkParameters: PropTypes.func, /** The side of the application on which to display the sidebar. */ side: PropTypes.string, startupParams: PropTypes.object, theme: PropTypes.object }); _defineProperty(MapFilter, "defaultProps", { allowFilterByTime: true, position: 5, predefinedFilters: [], highlightStyle: { strokeColor: [0, 0, 0], fillColor: [255, 255, 0, 0.25] } }); export default connect(function (state) { return { currentTask: state.task.id, theme: state.theme.current, layers: state.layers.flat, filter: state.layers.filter, startupParams: state.localConfig.startupParams }; }, { setFilter: setFilter, setCurrentTask: setCurrentTask, setPermalinkParameters: setPermalinkParameters })(MapFilter);