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

geosolutions-it / MapStore2 / 14217089396

02 Apr 2025 10:11AM UTC coverage: 92.673% (+15.7%) from 76.984%
14217089396

push

github

web-flow
Fix #10819 Manager menu is merged into Login/user menu and Manager menu is now deprecated  (#10963)

245 of 385 branches covered (63.64%)

66 of 77 new or added lines in 3 files covered. (85.71%)

18 existing lines in 5 files now uncovered.

2011 of 2170 relevant lines covered (92.67%)

825.05 hits per line

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

80.0
/web/client/plugins/containers/ToolsContainer.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 { partial } from 'lodash';
10
import assign from 'object-assign';
11
import PropTypes from 'prop-types';
12
import React from 'react';
13
import { Collapse, Glyphicon, Panel, Tooltip } from 'react-bootstrap';
14
import { connect } from 'react-redux';
15
import { compose } from 'redux';
16

17
import { setControlProperty, toggleControl } from '../../actions/controls';
18
import { changeHelpText, changeHelpwinVisibility } from '../../actions/help';
19
import HelpBadgeComp from '../../components/help/HelpBadge';
20
import Message from '../../components/I18N/Message';
21
import OverlayTrigger from '../../components/misc/OverlayTrigger';
22
import Button from '../../components/misc/Button';
23
import { MapLibraries } from '../../utils/MapTypeUtils';
24
import { mapTypeSelector } from "../../selectors/maptype";
25

26
const HelpBadge = connect((state) => ({
3✔
27
    isVisible: state.controls && state.controls.help && state.controls.help.enabled
6!
28
}), {
29
    changeHelpText,
30
    changeHelpwinVisibility
31
})(HelpBadgeComp);
32

33

34
/**
35
 * A container for tools.
36
 * @memberof plugins.containers
37
 * @class ToolsContainer
38
 * @deprecated
39
 * @static
40
 * @prop {object[]} tools An array of tools. Each tool have this shape. the first in order wins:
41
 * ```
42
 * {
43
 *    tool: {boolean|node} if boolean and true, renders the plugins itself, if object, renders this object as a react component,
44
 *    exclusive: if true, gets a selector to make it active or not, setting active property of the tool. tool.toggleControl | tool.name is used from controls state to retrieve the status of the tool
45
 *    toggle: same as above, but sets also bsStyle
46
 *    action: if present, this action will be bind to the context and associated to the tool as eventSelector (default onClick)
47
 * }
48
 * ```
49
 *
50
 */
51
class ToolsContainer extends React.Component {
52
    static propTypes = {
1✔
53
        id: PropTypes.string.isRequired,
54
        container: PropTypes.func,
55
        containerWrapperStyle: PropTypes.object,
56
        tool: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
57
        className: PropTypes.string,
58
        style: PropTypes.object,
59
        tools: PropTypes.array,
60
        panels: PropTypes.array,
61
        mapType: PropTypes.string,
62
        toolStyle: PropTypes.string,
63
        activeStyle: PropTypes.string,
64
        toolSize: PropTypes.string,
65
        stateSelector: PropTypes.string.isRequired,
66
        eventSelector: PropTypes.string,
67
        panelStyle: PropTypes.object,
68
        panelClassName: PropTypes.string,
69
        activePanel: PropTypes.string,
70
        toolCfg: PropTypes.object,
71
        toolComponent: PropTypes.any
72
    };
73

74
    static contextTypes = {
1✔
75
        messages: PropTypes.object,
76
        router: PropTypes.object
77
    };
78

79
    static defaultProps = {
1✔
80
        container: Panel,
81
        className: "tools-container",
82
        style: {},
83
        toolStyle: "default",
84
        activeStyle: "primary",
85
        tools: [],
86
        panels: [],
87
        tool: Button,
88
        mapType: MapLibraries.OPENLAYERS,
89
        eventSelector: "onClick",
90
        panelStyle: {},
91
        panelClassName: "tools-container-panel",
92
        toolSize: null,
93
        toolCfg: {}
94
    };
95

96
    getToolConfig = (tool) => {
17✔
97
        if (tool.tool) {
29✔
98
            return {};
14✔
99
        }
100
        return this.props.toolCfg;
15✔
101
    };
102

103
    getTool = (tool) => {
17✔
104
        // tool attribute, if boolean, tells to render directly the plugin
105
        // otherwise tool is the component to render inside this container
106
        if (tool.tool) {
29✔
107
            return tool.tool === true ? tool.plugin : tool.tool;
14✔
108
        }
109
        let selector = () => ({});
15✔
110
        const actions = {};
15✔
111
        if (tool.exclusive) {
15!
112
            selector = (state) => ({
×
113
                active: state.controls && state.controls[this.props.stateSelector] && state.controls[this.props.stateSelector].active === tool.name
×
114
            });
115
            actions[this.props.eventSelector] = setControlProperty.bind(null, this.props.stateSelector, 'active', tool.name, true);
×
116
        } else if (tool.toggle) {
15✔
117
            selector = (state) => ({
3✔
118
                bsStyle: state.controls[tool.toggleControl || tool.name] && state.controls[tool.toggleControl || tool.name][tool.toggleProperty || "enabled"] ? this.props.activeStyle : this.props.toolStyle,
18!
119
                active: state.controls[tool.toggleControl || tool.name] && state.controls[tool.toggleControl || tool.name][tool.toggleProperty || "enabled"] || false
17!
120
            });
121
            actions[this.props.eventSelector] = toggleControl.bind(null, tool.toggleControl || tool.name, tool.toggleProperty || null);
3!
122
        } else if (tool.action) {
12!
123
            actions[this.props.eventSelector] = partial(tool.action, this.context);
×
124
            // action tools can define their own selector
125
            selector = tool.selector || selector;
×
126
        }
127
        return connect(selector, actions, (stateProps, dispatchProps, parentProps) => {
15✔
128
            return this.mergeHandlers({
15✔
129
                ...parentProps,
130
                ...stateProps
131
            }, dispatchProps);
132
        })(this.props.tool);
133
    };
134

135
    renderTool = (tool, i) => {
17✔
136
        if (tool.element) {
33✔
137
            return tool.element;
4✔
138
        }
139
        const help = tool.help ? <HelpBadge className="mapstore-helpbadge" helpText={tool.help}/> : <span/>;
29✔
140
        const tooltip = tool.tooltip ? <Message msgId={tool.tooltip}/> : null;
29✔
141

142
        const Tool = this.getTool(tool);
29✔
143
        const toolCfg = this.getToolConfig(tool);
29✔
144
        const toolChildren = tool.childTools || [];
29✔
145

146
        return this.addTooltip(
29✔
147
            <Tool {...toolCfg} pluginCfg={tool.cfg} tooltip={tooltip} style={tool.style} btnSize={this.props.toolSize} bsStyle={this.props.toolStyle} help={help} key={tool.name || "tool" + i} mapType={this.props.mapType}
29!
148
                {...tool.cfg} items={tool.items || []} component={this.props.toolComponent}>
58✔
149
                {tool.cfg && tool.cfg.glyph ? <Glyphicon glyph={tool.cfg.glyph}/> : tool.icon}{help} {tool.text}
58!
150
                {toolChildren.length > 0 && <ToolsContainer
31✔
151
                    {...tool.innerProps}
152
                    mapType={this.props.mapType}
153
                    tools={toolChildren}
154
                    panels={tool.childPanels}/>}
155
            </Tool>,
156
            tool
157
        );
158
    }
159

160
    renderTools = () => {
17✔
161
        return this.props.tools.map(this.renderTool);
22✔
162
    };
163

164
    renderPanels = () => {
17✔
165
        return this.props.panels
22✔
UNCOV
166
            .filter((panel) => !panel.panel.loadPlugin).map((panel) => {
×
UNCOV
167
                const ToolPanelComponent = panel.panel;
×
UNCOV
168
                const ToolPanel = (<ToolPanelComponent
×
169
                    key={panel.name} mapType={this.props.mapType} {...panel.cfg} {...(panel.props || {})}
×
170
                    items={panel.items || []}/>);
×
UNCOV
171
                const title = panel.title ? <Message msgId={panel.title}/> : null;
×
UNCOV
172
                if (panel.wrap) {
×
173
                    return (
×
174
                        <Collapse key={"mapToolBar-item-collapse-" + panel.name} in={this.props.activePanel === panel.name}>
175
                            <Panel header={title} style={this.props.panelStyle} className={this.props.panelClassName}>
176
                                {ToolPanel}
177
                            </Panel>
178
                        </Collapse>
179
                    );
180
                }
UNCOV
181
                return ToolPanel;
×
182
            });
183
    };
184

185
    render() {
186
        const Container = this.props.container;
22✔
187
        return (
22✔
188
            <span id={this.props.id} style={this.props.containerWrapperStyle}>
189
                <Container id={this.props.id + "-container"} style={this.props.style} className={this.props.className}>
190
                    {this.renderTools()}
191
                </Container>
192
                {this.renderPanels()}
193
            </span>
194
        );
195
    }
196

197
    mergeHandlers = (props, handlers) => {
17✔
198
        return Object.keys(handlers).reduce((previous, event) => {
15✔
199
            return assign(previous, {[event]: props[event] ? compose(props[event], handlers[event]) : handlers[event]});
3!
200
        }, props);
201
    };
202

203
    addTooltip = (button, spec) => {
17✔
204
        if (spec.tooltip) {
29✔
205
            let tooltip = <Tooltip id={this.props.id + "-" + spec.name + "-tooltip"}><Message msgId={spec.tooltip}/></Tooltip>;
6✔
206
            return (
6✔
207
                <OverlayTrigger key={this.props.id + "-" + spec.name + "-overlay"} rootClose placement="left" overlay={tooltip}>
208
                    {button}
209
                </OverlayTrigger>
210
            );
211
        }
212
        return button;
23✔
213
    };
214
}
215

216
export default connect(state => ({
20✔
217
    mapType: mapTypeSelector(state)
218
}))(ToolsContainer);
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

© 2025 Coveralls, Inc