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

geosolutions-it / MapStore2 / 12831531306

17 Jan 2025 03:01PM UTC coverage: 77.182% (+0.07%) from 77.115%
12831531306

Pull #10746

github

web-flow
Merge 501dbaeea into 4e4dabc03
Pull Request #10746: Fix #10739 Changing correctly resolutions limits when switching map CRS

30373 of 47156 branches covered (64.41%)

34 of 43 new or added lines in 2 files covered. (79.07%)

126 existing lines in 15 files now uncovered.

37769 of 48935 relevant lines covered (77.18%)

35.14 hits per line

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

76.19
/web/client/plugins/TOC/components/DefaultGroup.jsx
1

2
/*
3
 * Copyright 2022, GeoSolutions Sas.
4
 * All rights reserved.
5
 *
6
 * This source code is licensed under the BSD-style license found in the
7
 * LICENSE file in the root directory of this source tree.
8
*/
9

10
import React, { cloneElement } from 'react';
11
import { Glyphicon } from 'react-bootstrap';
12
import DropNode from './DropNode';
13
import DragNode from './DragNode';
14
import VisibilityCheck from './VisibilityCheck';
15
import NodeHeader from './NodeHeader';
16
import NodeTool from './NodeTool';
17
import ExpandButton from './ExpandButton';
18
import InlineLoader from './InlineLoader';
19

20
/**
21
 * DefaultGroupNode renders internal part of the group node
22
 * @prop {string} node group node properties
23
 * @prop {function} onChange return the changes of a specific node
24
 * @prop {object} config optional configuration available for the nodes
25
 * @prop {array} nodeToolItems list of node tool component to customize specific tool available on a node, expected structure [ { name, Component } ]
26
 * @prop {function} onSelect return the current selected node on click event
27
 * @prop {string} nodeType node type
28
 * @prop {object} nodeTypes constant values for node types
29
 * @prop {component} sortHandler component for the sort handler
30
 * @prop {component} expandButton component for the expand button
31
 * @prop {component} visibilityCheck component for the visibility check
32
 * @prop {component} nodeIcon component for the node icon
33
 */
34
const DefaultGroupNode = ({
1✔
35
    node,
36
    nodeType,
37
    nodeTypes,
38
    config,
39
    onSelect,
40
    onChange,
41
    nodeToolItems = [],
×
42
    sortHandler,
43
    expandButton,
44
    visibilityCheck,
45
    nodeIcon
46
}) => {
47
    const componentProps = {
39✔
48
        node,
49
        onChange,
50
        nodeType,
51
        nodeTypes,
52
        config,
53
        itemComponent: NodeTool
54
    };
55
    return (
39✔
56
        <>
57
            <NodeHeader
58
                node={node}
59
                nodeType={nodeType}
60
                currentLocale={config?.currentLocale}
61
                tooltipOptions={config?.groupOptions?.tooltipOptions}
62
                showFullTitle={config?.showFullTitle}
63
                onClick={onSelect}
64
                showTitleTooltip={config?.showTitleTooltip}
65
                beforeTitle={<>
66
                    {sortHandler}
67
                    {expandButton}
68
                    {visibilityCheck}
69
                    {nodeIcon}
70
                </>}
71
                afterTitle={
72
                    <>
73
                        {node.error ? <NodeTool tooltipId="toc.loadingerror" glyph="exclamation-mark" /> : null}
39!
74
                        {nodeToolItems.filter(({ selector = () => true }) => selector(componentProps)).map(({ Component, name }) => {
9✔
75
                            return (<Component key={name} {...componentProps}/>);
9✔
76
                        })}
77
                    </>
78
                }
79
            />
80
        </>
81
    );
82
};
83
/**
84
 * DefaultGroup renders the group node representation
85
 * @prop {string} node group node properties
86
 * @prop {string} parentId id of the parent node
87
 * @prop {number} index index of the node
88
 * @prop {object} sort sorting handlers
89
 * @prop {function} sort.beginDrag begin drag event
90
 * @prop {function} sort.hover hover dragging event
91
 * @prop {function} sort.drop drop event
92
 * @prop {function} filter if false hides the component
93
 * @prop {string} filterText filter to apply to the layer title
94
 * @prop {function} replaceNodeOptions function to change the node properties (used by LayersTree)
95
 * @prop {function} onChange return the changes of a specific node
96
 * @prop {function} onContextMenu return the context menu event of a specific node
97
 * @prop {function} onSelect return the current selected node on click event
98
 * @prop {function} getNodeStyle function to create a custom style (used by LayersTree)
99
 * @prop {function} getNodeClassName function to create a custom class name (used by LayersTree)
100
 * @prop {boolean} mutuallyExclusive if true changes the visibility icon to radio button
101
 * @prop {string} nodeType type of the current node
102
 * @prop {boolean} sortable if false hides the sort handler components
103
 * @prop {array} nodeItems list of node component to customize specific nodes, expected structure [ { name, Component, selector } ]
104
 * @prop {array} nodeToolItems list of node tool component to customize specific tool available on a node, expected structure [ { name, Component } ]
105
 * @prop {object} config optional configuration available for the node
106
 * @prop {string} config.currentLocale current language code
107
 * @prop {boolean} config.showTitleTooltip show the title tooltip
108
 * @prop {object} config.groupOptions specific options for group nodes
109
 * @prop {object} config.groupOptions.tooltipOptions options for group title tooltip
110
 */
111
const DefaultGroup = ({
1✔
112
    node: nodeProp,
113
    parentId,
114
    children,
115
    connectDragPreview = cmp => cmp,
×
UNCOV
116
    connectDragSource = cmp => cmp,
×
117
    mutuallyExclusive,
118
    sortable,
119
    nodeType,
120
    ...props
121
}) => {
122

123
    const {
124
        sort,
125
        index,
126
        filter = () => true,
5✔
127
        replaceNodeOptions = (node) => node,
6✔
128
        filterText,
129
        onChange = () => {},
4✔
130
        onContextMenu = () => {},
6✔
131
        onSelect = () => {},
6✔
132
        getNodeStyle = () => {},
6✔
133
        getNodeClassName = () => '',
6✔
134
        nodeTypes,
135
        config,
136
        nodeItems = [],
36✔
137
        nodeToolItems = [],
27✔
138
        theme
139
    } = props;
43✔
140

141
    const node = replaceNodeOptions(nodeProp, nodeType);
43✔
142

143
    function handleOnChange(options) {
144
        onChange({ node: nodeProp, nodeType, parentId, options });
7✔
145
    }
146

147
    function handleOnContextMenu(event) {
148
        event.stopPropagation();
1✔
149
        event.preventDefault();
1✔
150
        onContextMenu({ node: nodeProp, nodeType, parentId, event });
1✔
151
    }
152

153
    function handleOnSelect(event) {
154
        event.stopPropagation();
2✔
155
        event.preventDefault();
2✔
156
        onSelect({ node: nodeProp, nodeType, parentId, event });
2✔
157
    }
158

159
    if (!filter(node, nodeType, parentId)) {
43✔
160
        return null;
4✔
161
    }
162
    const forceExpanded = config?.expanded !== undefined;
39✔
163
    const expanded = forceExpanded
39!
164
        ? config?.expanded
165
        : node?.expanded ?? true;
65✔
166

167
    const style = getNodeStyle(nodeProp, nodeType);
39✔
168
    const className = getNodeClassName(nodeProp, nodeType);
39✔
169

170
    const groupNodeProp = {
39✔
171
        index,
172
        parentId,
173
        theme,
174
        node,
175
        filterText,
176
        nodeType,
177
        nodeTypes,
178
        config,
179
        onSelect: handleOnSelect,
180
        onChange: handleOnChange,
181
        nodeToolItems,
182
        mutuallyExclusive,
183
        visibilityCheck: (
184
            <VisibilityCheck
185
                hide={config?.hideVisibilityButton}
186
                mutuallyExclusive={mutuallyExclusive}
187
                value={node?.visibility}
188
                onChange={(visibility) => {
189
                    handleOnChange({ visibility });
5✔
190
                }}
191
            />
192
        ),
193
        expandButton: (
194
            <ExpandButton
195
                hide={!!forceExpanded}
196
                expanded={expanded}
197
                onChange={handleOnChange}
198
                disabled={!!filterText}
199
            />
200
        ),
201
        sortHandler:
202
            sortable ? connectDragSource(
39✔
UNCOV
203
                <div className="grab-handle" onClick={(event) => event.stopPropagation()}>
×
204
                    <Glyphicon glyph="grab-handle" />
205
                </div>
206
            ) : <div className="grab-handle disabled" />,
207
        nodeIcon: (
208
            <Glyphicon className="ms-node-icon" glyph={expanded ? 'folder-open' : 'folder-close'} />
39✔
209
        )
210
    };
211

212
    const filteredNodeItems = nodeItems
39✔
UNCOV
213
        .filter(({ selector = () => false }) => selector(groupNodeProp));
×
214

215
    return (
39✔
216
        connectDragPreview(
217
            <li
218
                className={`ms-node ms-node-group${node?.dragging ? ' dragging' : ''}${className ? ` ${className}` : ''}`}
78!
219
                style={style}
UNCOV
220
                onClick={event => event.stopPropagation()}
×
221
                onContextMenu={handleOnContextMenu}
222
            >
223
                <DropNode
224
                    nodeType={nodeType}
225
                    index={index}
226
                    id={node.id}
227
                    parentId={parentId}
228
                    sort={sort}
229
                    sortable={sortable}
230
                >
231
                    <InlineLoader loading={node?.loading}/>
232
                    {filteredNodeItems.length
39!
233
                        ? filteredNodeItems.map(({ Component, name }) => {
UNCOV
234
                            return (
×
235
                                <Component key={name} {...groupNodeProp} defaultGroupNodeComponent={DefaultGroupNode} />
236
                            );
237
                        })
238
                        : <DefaultGroupNode
239
                            {...groupNodeProp}
240
                        />}
241
                </DropNode>
242
                {expanded ? <ul>
39✔
243
                    <DropNode
244
                        sortable={sortable}
245
                        sort={sort}
246
                        nodeType={nodeType}
247
                        index={index}
248
                        id={node.id}
249
                        position="before"
250
                        parentId={parentId}
251
                    >
252
                        <div style={{ display: 'flex', height: 8 }}></div>
253
                    </DropNode>
254
                    {node?.nodes?.map?.((childNode, _index) => cloneElement(children, {
36✔
255
                        ...props,
256
                        key: childNode.id,
257
                        node: childNode,
258
                        parentId: node.id,
259
                        index: _index,
260
                        mutuallyExclusive: node?.nodesMutuallyExclusive,
261
                        onChange: (value) => {
262
                            if (value?.parentId === node?.id && value?.options?.visibility !== undefined && node?.nodesMutuallyExclusive) {
2!
263
                                node.nodes.forEach((cNode) => {
×
264
                                    if (cNode.id !== value?.node?.id) {
×
UNCOV
265
                                        onChange({
×
266
                                            node: cNode,
267
                                            nodeType: cNode?.nodes ? nodeTypes.GROUP : nodeTypes.LAYER,
×
268
                                            parentId: node?.id,
269
                                            options: { visibility: false }
270
                                        });
271
                                    }
272
                                });
UNCOV
273
                                return onChange({
×
274
                                    ...value,
275
                                    options: { ...value?.options, visibility: true }
276
                                });
277
                            }
278
                            return onChange(value);
2✔
279
                        }
280
                    }))}
281
                </ul> : null}
282
                <DropNode
283
                    sortable={sortable}
284
                    sort={sort}
285
                    nodeType={nodeType}
286
                    index={index}
287
                    id={node.id}
288
                    position="after"
289
                    parentId={parentId}
290
                >
291
                    <div style={{ display: 'flex', height: 8 }}></div>
292
                </DropNode>
293
            </li>
294
        )
295
    );
296
};
297

298
const DraggableDefaultGroup = (props) => <DragNode {...props} component={DefaultGroup} />;
43✔
299

300
export default DraggableDefaultGroup;
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