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

geosolutions-it / MapStore2 / 14383513045

10 Apr 2025 02:49PM UTC coverage: 76.937% (-0.004%) from 76.941%
14383513045

push

github

web-flow
Fix #10944 Remove primary color and shadow from panels headers (#10956) (#11006)

---------

Co-authored-by: allyoucanmap <stefano.bovio@geosolutionsgroup.com>

31007 of 48270 branches covered (64.24%)

6 of 6 new or added lines in 4 files covered. (100.0%)

5 existing lines in 2 files now uncovered.

38526 of 50075 relevant lines covered (76.94%)

35.83 hits per line

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

72.0
/web/client/plugins/MetadataExplorer.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 './metadataexplorer/css/style.css';
10

11
import assign from 'object-assign';
12
import PropTypes from 'prop-types';
13
import React from 'react';
14
import { Glyphicon, Panel } from 'react-bootstrap';
15
import { connect } from 'react-redux';
16
import { branch, compose, defaultProps, renderComponent, withProps } from 'recompose';
17
import { createStructuredSelector } from 'reselect';
18

19
import { addBackgroundProperties, backgroundAdded, clearModalParameters } from '../actions/backgroundselector';
20
import {
21
    addLayer,
22
    addLayerError,
23
    addService,
24
    catalogClose,
25
    changeCatalogFormat,
26
    changeCatalogMode,
27
    changeMetadataTemplate,
28
    changeSelectedService,
29
    changeServiceFormat,
30
    changeServiceProperty,
31
    changeText,
32
    changeTitle,
33
    changeType,
34
    changeUrl,
35
    deleteService,
36
    focusServicesList,
37
    formatOptionsFetch,
38
    textSearch,
39
    toggleAdvancedSettings,
40
    toggleTemplate,
41
    toggleThumbnail,
42
    setNewServiceStatus,
43
    initPlugin
44
} from '../actions/catalog';
45
import { setControlProperty, toggleControl, setControlProperties } from '../actions/controls';
46
import { changeLayerProperties } from '../actions/layers';
47
import API from '../api/catalog';
48
import CatalogComp from '../components/catalog/Catalog';
49
import CatalogServiceEditor from '../components/catalog/CatalogServiceEditor';
50
import Message from '../components/I18N/Message';
51
import { metadataSourceSelector, modalParamsSelector } from '../selectors/backgroundselector';
52
import {
53
    isActiveSelector,
54
    authkeyParamNameSelector,
55
    groupSelector,
56
    layerErrorSelector,
57
    loadingErrorSelector,
58
    loadingSelector,
59
    modeSelector,
60
    newServiceSelector,
61
    newServiceTypeSelector,
62
    pageSizeSelector,
63
    resultSelector,
64
    savingSelector,
65
    searchOptionsSelector,
66
    searchTextSelector,
67
    selectedServiceLayerOptionsSelector,
68
    selectedServiceSelector,
69
    selectedServiceTypeSelector,
70
    serviceListOpenSelector,
71
    servicesSelector,
72
    servicesSelectorWithBackgrounds,
73
    tileSizeOptionsSelector,
74
    formatsLoadingSelector,
75
    getSupportedFormatsSelector,
76
    getSupportedGFIFormatsSelector,
77
    getNewServiceStatusSelector,
78
    showFormatErrorSelector,
79
    canEditServiceSelector
80
} from '../selectors/catalog';
81
import { layersSelector } from '../selectors/layers';
82
import { currentLocaleSelector, currentMessagesSelector } from '../selectors/locale';
83
import {burgerMenuSelector} from "../selectors/controls";
84
import { isLocalizedLayerStylesEnabledSelector } from '../selectors/localizedLayerStyles';
85
import { projectionSelector } from '../selectors/map';
86
import { mapLayoutValuesSelector } from '../selectors/maplayout';
87
import ResponsivePanel from "../components/misc/panels/ResponsivePanel";
88

89
export const DEFAULT_ALLOWED_PROVIDERS = ["OpenStreetMap", "OpenSeaMap", "Stamen"];
1✔
90

91
const metadataExplorerSelector = createStructuredSelector({
1✔
92
    searchOptions: searchOptionsSelector,
93
    showFormatError: showFormatErrorSelector,
94
    result: resultSelector,
95
    loadingError: loadingErrorSelector,
96
    selectedService: selectedServiceSelector,
97
    mode: modeSelector,
98
    services: servicesSelector,
99
    servicesWithBackgrounds: servicesSelectorWithBackgrounds,
100
    layerError: layerErrorSelector,
101
    active: isActiveSelector,
102
    dockStyle: state => mapLayoutValuesSelector(state, { height: true, right: true }, true),
6✔
103
    searchText: searchTextSelector,
104
    group: groupSelector,
105
    source: metadataSourceSelector,
106
    layers: layersSelector,
107
    modalParams: modalParamsSelector,
108
    authkeyParamNames: authkeyParamNameSelector,
109
    saving: savingSelector,
110
    openCatalogServiceList: serviceListOpenSelector,
111
    service: newServiceSelector,
112
    format: newServiceTypeSelector,
113
    selectedFormat: selectedServiceTypeSelector,
114
    options: searchOptionsSelector,
115
    layerOptions: selectedServiceLayerOptionsSelector,
116
    tileSizeOptions: tileSizeOptionsSelector,
117
    currentLocale: currentLocaleSelector,
118
    locales: currentMessagesSelector,
119
    pageSize: pageSizeSelector,
120
    loading: loadingSelector,
121
    crs: projectionSelector,
122
    isLocalizedLayerStylesEnabled: isLocalizedLayerStylesEnabledSelector,
123
    formatsLoading: formatsLoadingSelector,
124
    formatOptions: getSupportedFormatsSelector,
125
    infoFormatOptions: getSupportedGFIFormatsSelector,
126
    isNewServiceAdded: getNewServiceStatusSelector,
127
    canEdit: canEditServiceSelector
128
});
129

130

131
const Catalog = compose(
1✔
132
    withProps(({ result, selectedFormat, options, layerOptions, services, selectedService, locales}) => ({
×
133
        records: result && API[selectedFormat].getCatalogRecords(result, { ...options, layerOptions, service: services[selectedService] }, locales) || []
×
134
    })),
135
    defaultProps({
136
        buttonStyle: {
137
            marginBottom: "10px",
138
            marginRight: "5px"
139
        },
140
        formatOptions: [],
141
        advancedRasterStyles: {
142
            display: 'flex',
143
            alignItems: 'center',
144
            paddingTop: 15,
145
            borderTop: '1px solid #ddd'
146
        }
147
    }),
148
    branch(
149
        ({mode}) => mode === "edit",
×
150
        renderComponent(CatalogServiceEditor)
151
    )
152
)(CatalogComp);
153

154

155
class MetadataExplorerComponent extends React.Component {
156
    static propTypes = {
1✔
157
        id: PropTypes.string,
158
        source: PropTypes.string,
159
        active: PropTypes.bool,
160
        searchOnStartup: PropTypes.bool,
161
        serviceTypes: PropTypes.array,
162
        wrap: PropTypes.bool,
163
        wrapWithPanel: PropTypes.bool,
164
        panelStyle: PropTypes.object,
165
        panelClassName: PropTypes.string,
166
        closeCatalog: PropTypes.func,
167
        closeGlyph: PropTypes.string,
168
        buttonStyle: PropTypes.object,
169
        services: PropTypes.object,
170
        servicesWithBackgrounds: PropTypes.object,
171
        selectedService: PropTypes.string,
172
        style: PropTypes.object,
173
        dockProps: PropTypes.object,
174
        zoomToLayer: PropTypes.bool,
175
        isLocalizedLayerStylesEnabled: PropTypes.bool,
176

177
        // side panel properties
178
        width: PropTypes.number,
179
        dockStyle: PropTypes.object,
180
        group: PropTypes.string,
181
        onInitPlugin: PropTypes.func,
182
        editingAllowedRoles: PropTypes.array,
183
        editingAllowedGroups: PropTypes.array
184
    };
185

186
    static defaultProps = {
1✔
187
        id: "mapstore-metadata-explorer",
188
        serviceTypes: [{ name: "csw", label: "CSW" }, { name: "wms", label: "WMS" }, { name: "wmts", label: "WMTS" }, { name: "tms", label: "TMS", allowedProviders: DEFAULT_ALLOWED_PROVIDERS }, { name: "wfs", label: "WFS" }, { name: "3dtiles", label: "3D Tiles" }, {name: "model", label: "IFC Model"}, { name: "arcgis", label: "ArcGIS" }],
189
        active: false,
190
        wrap: false,
191
        modal: true,
192
        wrapWithPanel: false,
193
        panelStyle: {
194
            zIndex: 100,
195
            overflow: "hidden",
196
            height: "100%"
197
        },
198
        panelClassName: "catalog-panel",
199
        closeCatalog: () => {},
200
        onInitPlugin: () => {},
201
        closeGlyph: "1-close",
202
        zoomToLayer: true,
203

204
        // side panel properties
205
        width: 550,
206
        dockProps: {
207
            dimMode: "none",
208
            fluid: false,
209
            position: "right",
210
            zIndex: 1030
211
        },
212
        dockStyle: {},
213
        group: null,
214
        services: {},
215
        servicesWithBackgrounds: {},
216
        editingAllowedRoles: ["ALL"]
217
    };
218

219
    componentDidMount() {
220
        this.props.onInitPlugin({
3✔
221
            editingAllowedRoles: this.props.editingAllowedRoles,
222
            editingAllowedGroups: this.props.editingAllowedGroups
223
        });
224
    }
225

226
    componentWillUnmount() {
227
        this.props.closeCatalog();
3✔
228
    }
229
    render() {
230
        // TODO: separate catalog props from Container props (and handlers)
231
        const layerBaseConfig = {
6✔
232
            group: this.props.group || undefined
12✔
233
        };
234
        const panel = (
235
            <Catalog
6✔
236
                layerBaseConfig={layerBaseConfig}
237
                {...this.props}
238
                services={this.props.source === 'backgroundSelector' ? this.props.servicesWithBackgrounds : this.props.services}
6!
239
            />
240
        );
241
        return (
6✔
242
            <ResponsivePanel
243
                containerStyle={this.props.dockStyle}
244
                containerId="catalog-root"
245
                containerClassName={this.props.active ? 'catalog-active' : ''}
6!
246
                open={this.props.active}
247
                size={this.props.width}
248
                position="right"
249
                title={<Message msgId="catalog.title"/>}
UNCOV
250
                onClose={() => this.props.closeCatalog()}
×
251
                glyph="folder-open"
252
                style={this.props.dockStyle}
253
            >
254
                <Panel id={this.props.id} style={this.props.panelStyle} className={this.props.panelClassName}>
255
                    {panel}
256
                </Panel>
257
            </ResponsivePanel>
258
        );
259
    }
260
}
261

262
const MetadataExplorerPlugin = connect(metadataExplorerSelector, {
1✔
263
    clearModal: clearModalParameters,
264
    onSearch: textSearch,
265
    onLayerAdd: addLayer,
266
    closeCatalog: catalogClose,
267
    onChangeFormat: changeCatalogFormat,
268
    onChangeServiceFormat: changeServiceFormat,
269
    onChangeUrl: changeUrl,
270
    onChangeType: changeType,
271
    onChangeTitle: changeTitle,
272
    onChangeMetadataTemplate: changeMetadataTemplate,
273
    onChangeText: changeText,
274
    onChangeServiceProperty: changeServiceProperty,
275
    onChangeSelectedService: changeSelectedService,
276
    onChangeCatalogMode: changeCatalogMode,
277
    onAddService: addService,
278
    onToggleAdvancedSettings: toggleAdvancedSettings,
279
    onToggleThumbnail: toggleThumbnail,
280
    onToggleTemplate: toggleTemplate,
281
    onDeleteService: deleteService,
282
    onError: addLayerError,
283
    // add layer action to pass to the layers
284
    onAddBackgroundProperties: addBackgroundProperties,
285
    onFocusServicesList: focusServicesList,
286
    onPropertiesChange: changeLayerProperties,
287
    onAddBackground: backgroundAdded,
288
    onFormatOptionsFetch: formatOptionsFetch,
289
    onToggle: toggleControl.bind(null, 'backgroundSelector', null),
290
    onLayerChange: setControlProperty.bind(null, 'backgroundSelector'),
291
    onStartChange: setControlProperty.bind(null, 'backgroundSelector', 'start'),
292
    setNewServiceStatus,
293
    onInitPlugin: initPlugin
294
})(MetadataExplorerComponent);
295

296
const AddLayerButton = connect(() => ({}), {
3✔
297
    onClick: setControlProperties.bind(null, 'metadataexplorer', 'enabled', true, 'group')
298
})(({
299
    onClick,
300
    selectedNodes,
301
    status,
302
    itemComponent,
303
    statusTypes,
304
    config,
305
    ...props
306
}) => {
307
    const ItemComponent = itemComponent;
3✔
308

309
    // deprecated TOC configuration
310
    if (config.activateAddLayerButton === false) {
3!
311
        return null;
×
312
    }
313

314
    if ([statusTypes.DESELECT, statusTypes.GROUP].includes(status)) {
3!
315
        const group = selectedNodes?.[0]?.id;
3✔
316
        return (
3✔
317
            <ItemComponent
318
                {...props}
319
                glyph="add-layer"
320
                tooltipId={status === statusTypes.GROUP ? 'toc.addLayerToGroup' : 'toc.addLayer'}
3!
321
                onClick={() => onClick(group)}
×
322
            />
323
        );
324
    }
325
    return null;
×
326
});
327

328
/**
329
 * MetadataExplorer (Catalog) plugin. Shows the catalogs results (CSW, WMS, WMTS, TMS, WFS and COG).
330
 * Some useful flags in `localConfig.json`:
331
 * - `noCreditsFromCatalog`: avoid add credits (attribution) from catalog
332
 *
333
 * @class
334
 * @name MetadataExplorer
335
 * @memberof plugins
336
 * @prop {string} cfg.hideThumbnail shows/hides thumbnail
337
 * @prop {object[]} cfg.serviceTypes Service types available to add a new catalog. default: `[{ name: "csw", label: "CSW" }, { name: "wms", label: "WMS" }, { name: "wmts", label: "WMTS" }, { name: "tms", label: "TMS", allowedProviders },{ name: "wfs", label: "WFS" }]`.
338
 * `allowedProviders` is a whitelist of tileProviders from ConfigProvider.js. you can set a global variable allowedProviders in localConfig.json to set it up globally. You can configure it to "ALL" to get all the list (at your own risk, some services could change or not be available anymore)
339
 * @prop {object} cfg.hideIdentifier shows/hides identifier
340
 * @prop {boolean} cfg.hideExpand shows/hides full description button
341
 * @prop {number} cfg.zoomToLayer enable/disable zoom to layer when added
342
 * @prop {number} cfg.autoSetVisibilityLimits if true, allows fetching and setting visibility limits of the layer from capabilities on layer add (Note: The default configuration value is applied only on new catalog service (WMS/CSW))
343
 * @prop {number} [delayAutoSearch] time in ms passed after a search is triggered by filter changes, default 1000
344
 */
345
export default {
346
    MetadataExplorerPlugin: assign(MetadataExplorerPlugin, {
347
        BurgerMenu: {
348
            name: 'metadataexplorer',
349
            position: 5,
350
            text: <Message msgId="catalog.title"/>,
351
            tooltip: "catalog.tooltip",
352
            icon: <Glyphicon glyph="folder-open"/>,
353
            action: setControlProperty.bind(null, "metadataexplorer", "enabled", true, true),
354
            doNotHide: true,
355
            priority: 1
356
        },
357
        BackgroundSelector: {
358
            name: 'MetadataExplorer',
359
            doNotHide: true,
360
            priority: 1
361
        },
362
        TOC: {
363
            name: 'MetadataExplorer',
364
            doNotHide: true,
365
            priority: 1,
366
            target: 'toolbar',
367
            Component: AddLayerButton,
368
            position: 2
369
        },
370
        SidebarMenu: {
371
            name: 'metadataexplorer',
372
            position: 5,
373
            text: <Message msgId="catalog.title"/>,
374
            tooltip: "catalog.tooltip",
375
            icon: <Glyphicon glyph="folder-open"/>,
376
            action: setControlProperty.bind(null, "metadataexplorer", "enabled", true, true),
377
            selector: (state) => ({
×
378
                style: { display: burgerMenuSelector(state) ? 'none' : null }
×
379
            }),
380
            toggle: true,
381
            doNotHide: true,
382
            priority: 1
383
        }
384
    }),
385
    reducers: {catalog: require('../reducers/catalog').default},
386
    epics: require("../epics/catalog").default(API)
387
};
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