• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geosolutions-it / MapStore2 / 19735587487

27 Nov 2025 09:59AM UTC coverage: 76.667% (-0.3%) from 76.929%
19735587487

Pull #11119

github

web-flow
Fix: #11712 Support for template format on vector layers to visualize embedded conent (#11720)
Pull Request #11119: Layer Selection Plugin on ArcGIS, WFS & WMS layers

32268 of 50209 branches covered (64.27%)

7 of 13 new or added lines in 2 files covered. (53.85%)

3017 existing lines in 248 files now uncovered.

40158 of 52380 relevant lines covered (76.67%)

37.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.35
/web/client/components/data/query/CrossLayerFilter.jsx
1
/*
2
 * Copyright 2017, GeoSolutions Sas.
3
 * All rights reserved.
4
 *
5
 * This source code is licensed under the BSD-style license found in the
6
 * LICENSE file in the root directory of this source tree.
7
 */
8

9
import React from 'react';
10

11
import Message from '../../I18N/Message';
12
import SwitchPanel from '../../misc/switch/SwitchPanel';
13
import { Row, Col } from 'react-bootstrap';
14
import Select from 'react-select';
15
import GeometricOperationSelector from './GeometricOperationSelector';
16
import GroupField from './GroupField';
17
import { isSameUrl } from '../../../utils/URLUtils';
18
import InfoPopover from '../../widgets/widget/InfoPopover';
19
import SwitchButton from '../../misc/switch/SwitchButton';
20

21
const isSameOGCServiceRoot = (origSearchUrl, {search, url} = {}) => isSameUrl(origSearchUrl, url) || isSameUrl(origSearchUrl, (search && search.url));
26!
22
// bbox make not sense with cross layer filter
23
const getAllowedSpatialOperations = (spatialOperations) => (spatialOperations || []).filter( ({id} = {}) => id !== "BBOX");
8!
24

25
/**
26
 * Renders the area of interest toggle control
27
 * @param {boolean} enabled - Current state of area of interest
28
 * @param {function} onToggle - Callback function to handle toggle changes
29
 * @returns {JSX.Element} Area of interest row
30
 */
31
const renderAreaOfInterestToggle = (enabled, onToggle) => (
1✔
32
    <Row className="inline-form filter-field-fixed-row">
7✔
33
        <Col xs={6}>
34
            <div className="pull-left">
35
                <Message msgId="queryform.crossLayerFilter.areaOfInterest"/>
36
                &nbsp;
37
                <InfoPopover bsStyle="link"
38
                    text={<Message msgId="queryform.crossLayerFilter.areaOfInterestTooltip" />}
39
                />
40
            </div>
41
        </Col>
42
        <Col xs={6}>
43
            <SwitchButton
44
                checked={enabled}
45
                onChange={onToggle}
46
                className="pull-right cross-layer-aoi"
47
            />
48
        </Col>
49
    </Row>
50
);
51

52

53
export default ({
×
54
    crossLayerExpanded = true,
6✔
55
    spatialOperations,
56
    expandCrossLayerFilterPanel = () => {},
12✔
57
    layers = [],
2✔
58
    errorObj,
59
    loadingAttributes,
60
    loadingCapabilities,
61
    searchUrl,
62
    queryCollection = {},
4✔
63
    attributes = [],
15✔
64
    operation,
65
    enabledAreaOfInterest = true,
15✔
66
    updateLogicCombo = () => {},
13✔
67
    resetCrossLayerFilter = () => {},
13✔
68
    setOperation = () => {},
13✔
69
    setEnabledAreaOfInterest = () => {},
12✔
70
    setQueryCollectionParameter = () => {},
13✔
71
    addCrossLayerFilterField = () => {},
13✔
72
    updateCrossLayerFilterField = () => {},
13✔
73
    removeCrossLayerFilterField = () => {},
13✔
74
    toggleMenu = () => {}
13✔
75
} = {}) => {
76
    const {typeName, geometryName, filterFields, groupFields = [{
15✔
77
        id: 1,
78
        logic: "OR",
79
        index: 0
80
    }]} = queryCollection;
15✔
81

82
    const unMatchingLayerOptions = layers
15✔
83
        .filter( l => !isSameOGCServiceRoot(searchUrl, l));
13✔
84

85
    const renderUnMatchingLayersInfo = () => {
15✔
86
        if (layers.length && unMatchingLayerOptions.length) {
15✔
87
            return (<InfoPopover id="unmatchingLayersInfo" bsStyle="link" text={<Message msgId="queryform.crossLayerFilter.errors.layersExcluded" />}/>);
1✔
88
        }
89
        return null;
14✔
90
    };
91
    return (<SwitchPanel
15✔
92
        loading={loadingCapabilities}
93
        expanded={crossLayerExpanded && !loadingCapabilities && !errorObj}
42✔
94
        error={errorObj}
95
        errorMsgId={"queryPanel"}
96
        buttons={[
97
            ...(typeName ? [{
15✔
98
                glyph: 'clear-filter',
99
                tooltipId: "queryform.crossLayerFilter.clear",
UNCOV
100
                onClick: () => resetCrossLayerFilter()
×
101
            }] : [])
102
        ]}
103
        onSwitch={expandCrossLayerFilterPanel}
104
        title={<Message msgId="queryform.crossLayerFilter.title" />} >
105
        <Row className="inline-form filter-field-fixed-row">
106
            <Col xs={6}>
107
                <div>
108
                    <Message msgId="queryform.crossLayerFilter.targetLayer"/>&nbsp;
109
                    { renderUnMatchingLayersInfo() }
110
                </div>
111

112
            </Col>
113
            <Col xs={6}>
114
                <Select
115
                    clearable={false}
116
                    disabled={loadingCapabilities || !!errorObj}
29✔
117
                    isLoading={loadingAttributes}
118
                    options={layers
119
                        .filter( l => isSameOGCServiceRoot(searchUrl, l))
13✔
120
                        .map( l => ({
12✔
121
                            label: l.title || l.name,
24✔
122
                            value: l.name
123
                        }))}
124
                    placeholder={<Message msgId="queryform.crossLayerFilter.placeholder" />}
125
                    filter="contains"
126
                    value={typeName}
127
                    onChange={ sel => {
UNCOV
128
                        setQueryCollectionParameter("typeName", sel && sel.value);
×
129
                    }}/>
130
            </Col>
131
        </Row>
132
        {(typeName && geometryName)
41✔
133
            ? (<Row className="inline-form filter-field-fixed-row">
134
                <Col xs={6}>
135
                    <div><Message msgId="queryform.crossLayerFilter.operation"/></div>
136
                </Col>
137
                <Col xs={6}>
138
                    <GeometricOperationSelector
139
                        value={operation}
UNCOV
140
                        onChange={({id} = {}) => setOperation(id)}
×
141
                        spatialOperations={getAllowedSpatialOperations(spatialOperations)}
142
                    />
143
                </Col>
144
            </Row>)
145
            : null}
146
        {(typeName && geometryName && operation)
49✔
147
            ? renderAreaOfInterestToggle(enabledAreaOfInterest, setEnabledAreaOfInterest)
148
            : null}
149
        {(typeName && geometryName && operation)
49✔
150
            ? (<Row className="filter-field-fixed-row">
151
                <Col xs={12}>
152
                    <GroupField
153
                        dropUp
154
                        autocompleteEnabled
155
                        withContainer={false}
156
                        attributes={attributes}
157
                        groupLevels={-1}
158
                        filterFields={filterFields}
159
                        actions={{
160
                            onUpdateLogicCombo: updateLogicCombo,
161
                            onAddFilterField: addCrossLayerFilterField,
162
                            onUpdateFilterField: updateCrossLayerFilterField,
163
                            onRemoveFilterField: removeCrossLayerFilterField,
164
                            toggleMenu: toggleMenu
165
                        }}
166
                        groupFields={groupFields} filterField/>
167
                </Col>
168
            </Row>)
169
            : null}
170
    </SwitchPanel>);
171
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc