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

geosolutions-it / MapStore2 / 15422041026

03 Jun 2025 03:54PM UTC coverage: 76.96% (+0.03%) from 76.929%
15422041026

Pull #11126

github

web-flow
Merge 30449e34b into f38b5e770
Pull Request #11126: Update User Guide - Configure the light on Cesium map

31021 of 48282 branches covered (64.25%)

38633 of 50199 relevant lines covered (76.96%)

36.08 hits per line

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

90.91
/web/client/plugins/Identify.jsx
1
/*
2
 * Copyright 2016, 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 './identify/identify.css';
10

11
import { isUndefined } from 'lodash';
12
import assign from 'object-assign';
13
import React from 'react';
14
import { Glyphicon } from 'react-bootstrap';
15
import { connect } from 'react-redux';
16
import { compose, defaultProps } from 'recompose';
17
import { createSelector, createStructuredSelector } from 'reselect';
18

19
import { changeMousePointer, zoomToExtent } from '../actions/map';
20
import {
21
    changeFormat,
22
    changeMapInfoFormat,
23
    changePage,
24
    clearWarning,
25
    setShowInMapPopup,
26
    closeIdentify,
27
    editLayerFeatures,
28
    hideMapinfoMarker,
29
    hideMapinfoRevGeocode,
30
    purgeMapInfoResults,
31
    setMapTrigger,
32
    showMapinfoRevGeocode,
33
    toggleHighlightFeature,
34
    toggleMapInfoState,
35
    toggleShowCoordinateEditor,
36
    updateCenterToMarker,
37
    updateFeatureInfoClickPoint,
38
    checkIdentifyIsMounted,
39
    onInitPlugin
40
} from '../actions/mapInfo';
41
import { enableHideEmptyPopupOption } from '../actions/mapPopups';
42
import DefaultViewerComp from '../components/data/identify/DefaultViewer';
43
import { defaultViewerDefaultProps, defaultViewerHandlers } from '../components/data/identify/enhancers/defaultViewer';
44
import { identifyLifecycle } from '../components/data/identify/enhancers/identify';
45
import zoomToFeatureHandler from '../components/data/identify/enhancers/zoomToFeatureHandler';
46
import IdentifyContainer from '../components/data/identify/IdentifyContainer';
47
import loadingState from '../components/misc/enhancers/loadingState';
48
import FeatureInfoFormatSelectorComp from '../components/misc/FeatureInfoFormatSelector';
49
import FeatureInfoTriggerSelectorComp from '../components/misc/FeatureInfoTriggerSelector';
50
import epics from '../epics/identify';
51
import mapInfo from '../reducers/mapInfo';
52
import mapPopups from '../reducers/mapPopups';
53
import { isEditingAllowedSelector } from '../selectors/featuregrid';
54
import { layersSelector } from '../selectors/layers';
55
import { currentLocaleSelector } from '../selectors/locale';
56
import { isMouseMoveIdentifyActiveSelector, mapSelector } from '../selectors/map';
57
import {
58
    clickPointSelector,
59
    currentFeatureCrsSelector,
60
    currentFeatureSelector,
61
    generalInfoFormatSelector,
62
    indexSelector,
63
    isHighlightEnabledSelector,
64
    isLoadedResponseSelector,
65
    requestsSelector,
66
    responsesSelector,
67
    showEmptyMessageGFISelector,
68
    validResponsesSelector,
69
    hoverEnabledSelector,
70
    mapInfoEnabledSelector
71
} from '../selectors/mapInfo';
72
import { mapLayoutValuesSelector } from '../selectors/maplayout';
73
import { isCesium, mapTypeSelector } from '../selectors/maptype';
74
import ConfigUtils from '../utils/ConfigUtils';
75
import { getDefaultInfoFormatValue, getValidator } from '../utils/MapInfoUtils';
76
import getFeatureButtons from './identify/featureButtons';
77
import getToolButtons from './identify/toolButtons';
78
import Message from './locale/Message';
79
import { DEFAULT_PANEL_WIDTH } from '../utils/LayoutUtils';
80

81
const selector = createStructuredSelector({
1✔
82
    enabled: (state) => mapInfoEnabledSelector(state) || state.controls && state.controls.info && state.controls.info.enabled || false,
2!
83
    responses: responsesSelector,
84
    validResponses: validResponsesSelector,
85
    requests: requestsSelector,
86
    format: generalInfoFormatSelector,
87
    map: mapSelector,
88
    layers: layersSelector,
89
    point: clickPointSelector,
90
    showModalReverse: (state) => state.mapInfo && state.mapInfo.showModalReverse,
2✔
91
    reverseGeocodeData: (state) => state.mapInfo && state.mapInfo.reverseGeocodeData,
2✔
92
    warning: (state) => state.mapInfo && state.mapInfo.warning,
2✔
93
    currentLocale: currentLocaleSelector,
94
    dockStyle: (state) => mapLayoutValuesSelector(state, { height: true, right: true }, true),
2✔
95
    formatCoord: (state) => state.mapInfo && state.mapInfo.formatCoord || ConfigUtils.getConfigProp('defaultCoordinateFormat'),
2✔
96
    showCoordinateEditor: (state) => state.mapInfo && state.mapInfo.showCoordinateEditor,
2✔
97
    showEmptyMessageGFI: state => showEmptyMessageGFISelector(state),
2✔
98
    isEditingAllowed: isEditingAllowedSelector,
99
    isCesium,
100
    floatingIdentifyEnabled: (state) => isMouseMoveIdentifyActiveSelector(state)
2✔
101
});
102
// result panel
103

104
/*
105
 * Enhancer to enable set index only if Component has not header in viewerOptions props
106
 */
107
const identifyIndex = compose(
1✔
108
    connect(
109
        createSelector(indexSelector, isLoadedResponseSelector, (state) => state.browser && state.browser.mobile,  (index, loaded, isMobile) => ({ index, loaded, isMobile })),
2!
110
        {
111
            setIndex: changePage
112
        }
113
    )
114
);
115
const DefaultViewer = compose(
1✔
116
    identifyIndex,
117
    defaultViewerDefaultProps,
118
    defaultViewerHandlers,
119
    loadingState(({ loaded }) => isUndefined(loaded))
×
120
)(DefaultViewerComp);
121

122

123
const identifyDefaultProps = defaultProps({
1✔
124
    formatCoord: "decimal",
125
    enabled: false,
126
    draggable: true,
127
    collapsible: false,
128
    format: getDefaultInfoFormatValue(),
129
    requests: [],
130
    responses: [],
131
    viewerOptions: {},
132
    viewer: DefaultViewer,
133
    purgeResults: () => { },
134
    hideMarker: () => { },
135
    clearWarning: () => { },
136
    changeMousePointer: () => { },
137
    showRevGeocode: () => { },
138
    checkIdentifyIsMounted: () => {},
139
    hideRevGeocode: () => { },
140
    containerProps: {
141
        continuous: false
142
    },
143
    enabledCoordEditorButton: true,
144
    showCoordinateEditor: false,
145
    showModalReverse: false,
146
    reverseGeocodeData: {},
147
    enableRevGeocode: true,
148
    wrapRevGeocode: false,
149
    style: {},
150
    point: {},
151
    layer: null,
152
    map: {},
153
    layers: [],
154
    panelClassName: "modal-dialog info-panel modal-content",
155
    headerClassName: "modal-header",
156
    bodyClassName: "modal-body info-wrap",
157
    dock: true,
158
    headerGlyph: "",
159
    closeGlyph: "1-close",
160
    className: "square-button",
161
    currentLocale: 'en-US',
162
    fullscreen: false,
163
    showTabs: true,
164
    showCoords: true,
165
    showLayerTitle: true,
166
    showMoreInfo: true,
167
    showEdit: false,
168
    position: 'right',
169
    size: DEFAULT_PANEL_WIDTH,
170
    getToolButtons,
171
    getFeatureButtons,
172
    showFullscreen: false,
173
    validResponses: [],
174
    validator: getValidator, // TODO: move all validation from the components to the selectors
175
    zIndex: 1050
176
});
177

178
/**
179
 * This plugin allows get information about clicked point. It can be configured to have a mobile or a desktop flavor.
180
 *
181
 * You can configure some of the features of this plugin by setting up the initial mapInfo state, then you need to update the "initialState.defaultState", or by the plugin configuration
182
 * ```
183
 * "mapInfo": {
184
 *   "enabled": true, // enabled by default
185
 *   "disabledAlwaysOn": false, // if true, disable always on setup
186
 *   "configuration": {
187
 *     "showEmptyMessageGFI": false // allow or deny the visibility of message when you have no results from identify request
188
 *     "infoFormat": "text/plain" // default infoformat value, other values are "text/html" for text only or "application/json" for properties
189
 *   }
190
 * }
191
 * ```
192
 *
193
 * @class Identify
194
 * @memberof plugins
195
 * @static
196
 *
197
 * @prop showIn {string[]} List of the plugins where to show the plugin
198
 * @prop cfg.dock {bool} true shows dock panel, false shows modal
199
 * @prop cfg.draggable {boolean} draggable info window, when modal
200
 * @prop cfg.showHighlightFeatureButton {boolean} show the highlight feature button if the interrogation returned valid features (openlayers only)
201
 * @prop cfg.hidePopupIfNoResults {boolean} hide/show the identify popup in case of no results
202
 * @prop cfg.highlightEnabledFromTheStart {boolean} the highlight feature button will be activated by default if true
203
 * @prop cfg.viewerOptions.container {expression} the container of the viewer, expression from the context
204
 * @prop cfg.viewerOptions.header {expression} the header of the viewer, expression from the context{expression}
205
 * @prop cfg.disableCenterToMarker {bool} disable zoom to marker action
206
 * @prop cfg.showAllResponses {bool} if true it will include invalid/empty responses and it will always select the first request/layer
207
 * @prop cfg.zIndex {number} component z index order
208
 * @prop cfg.showInMapPopup {boolean} if true show the identify as popup
209
 * @prop cfg.maxItems {number} the number of features returned by this tool
210
 * @prop cfg.showMoreInfo {boolean} if true shows the more info icon which allow user to show/hide Geocode viewer as popup (true by default)
211
 * @prop cfg.showEdit {boolean} if true, and when the FeatureEditor plugin is present, shows and edit button to edit the current feature(s) clicked in the grid.
212
 * @prop cfg.enableInfoForSelectedLayers {boolean} if true, if some layer is selected in the TOC, the feature info is performed only on the selected ones. if false, the info is queried for all the layers, independently from selection. (default is true).
213
 * @prop cfg.disableCoordinatesRow {boolean} if true the coordinates row is disabled
214
 *
215
 * @example
216
 * {
217
 *   "name": "Identify",
218
 *   "showIn": ["Settings"],
219
 *   "cfg": {
220
 *       "draggable": false,
221
 *       "dock": true,
222
 *       "viewerOptions": {
223
 *          "container": "{context.ReactSwipe}",
224
 *          "header": "{context.SwipeHeader}"
225
 *       }
226
 *    }
227
 * }
228
 *
229
 */
230
const IdentifyPlugin = compose(
1✔
231
    connect(selector, {
232
        onInitPlugin,
233
        purgeResults: purgeMapInfoResults,
234
        closeIdentify,
235
        onSubmitClickPoint: updateFeatureInfoClickPoint,
236
        onToggleShowCoordinateEditor: toggleShowCoordinateEditor,
237
        onChangeFormat: changeFormat,
238
        changeMousePointer,
239
        clearWarning,
240
        hideMarker: hideMapinfoMarker,
241
        showRevGeocode: showMapinfoRevGeocode,
242
        hideRevGeocode: hideMapinfoRevGeocode,
243
        onEnableCenterToMarker: updateCenterToMarker.bind(null, 'enabled'),
244
        onEdit: editLayerFeatures,
245
        checkIdentifyIsMounted
246
    }, (stateProps, dispatchProps, ownProps) => ({
2✔
247
        ...ownProps,
248
        ...stateProps,
249
        ...dispatchProps,
250
        enabled: stateProps.enabled && (stateProps.isCesium || !ownProps.showInMapPopup) && !stateProps.floatingIdentifyEnabled
8✔
251
    })),
252
    // highlight support
253
    compose(
254
        connect(
255
            createStructuredSelector({
256
                highlight: isHighlightEnabledSelector,
257
                currentFeature: currentFeatureSelector,
258
                currentFeatureCrs: currentFeatureCrsSelector
259
            }), {
260
                toggleHighlightFeature,
261
                zoomToExtent
262
            }
263
        ),
264
        zoomToFeatureHandler
265
    ),
266
    // disable with not supported mapTypes. TODO: remove when reproject (leaflet) and features draw available (cesium)
267
    connect(createSelector(mapTypeSelector, mapType => ({mapType})), {}, ({mapType}, _, { showHighlightFeatureButton, ...props }) => ({...props, showHighlightFeatureButton: mapType === 'openlayers' && showHighlightFeatureButton}) ),
2✔
268
    identifyDefaultProps,
269
    identifyIndex,
270
    defaultViewerHandlers,
271
    connect(() => ({}), {
2✔
272
        setShowInMapPopup,
273
        enableHideEmptyPopupOption
274
    }),
275
    identifyLifecycle
276
)(IdentifyContainer);
277

278
// configuration UI
279
const FeatureInfoFormatSelector = connect((state) => ({
1✔
280
    infoFormat: generalInfoFormatSelector(state)
281
}), {
282
    onInfoFormatChange: changeMapInfoFormat
283
})(FeatureInfoFormatSelectorComp);
284

285
const FeatureInfoTriggerSelector = connect((state) => ({
1✔
286
    trigger: isMouseMoveIdentifyActiveSelector(state) ? 'hover' : 'click',
×
287
    hoverEnabled: hoverEnabledSelector(state)
288
}), {
289
    onSetMapTrigger: setMapTrigger,
290
    onPurgeMapInfoResults: purgeMapInfoResults,
291
    onHideMapinfoMarker: hideMapinfoMarker
292
})(FeatureInfoTriggerSelectorComp);
293

294
export default {
295
    IdentifyPlugin: assign(IdentifyPlugin, {
296
        Toolbar: {
297
            name: 'info',
298
            position: 6,
299
            tooltip: "info.tooltip",
300
            icon: <Glyphicon glyph="map-marker" />,
301
            help: <Message msgId="helptexts.infoButton" />,
302
            action: toggleMapInfoState,
303
            selector: (state) => ({
×
304
                bsStyle: state.mapInfo && state.mapInfo.enabled ? "success" : "primary",
×
305
                active: !!(state.mapInfo && state.mapInfo.enabled)
×
306
            })
307
        },
308
        Settings: {
309
            tool: [<FeatureInfoFormatSelector
310
                key="featureinfoformat"
311
                label={<Message msgId="infoFormatLbl" />
312
                } />, <FeatureInfoTriggerSelector
313
                key="featureinfotrigger" />],
314
            position: 3
315
        }
316
    }),
317
    reducers: { mapInfo, mapPopups },
318
    epics
319
};
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