@eeacms/volto-eea-map 0.1.11 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/package.json +1 -1
- package/src/actionTypes.js +1 -0
- package/src/actions.js +1 -1
- package/src/components/Blocks/EEAMap/Edit.jsx +33 -2
- package/src/components/Blocks/EEAMap/Schema.js +7 -4
- package/src/components/Blocks/EEAMap/View.jsx +6 -5
- package/src/components/Blocks/EmbedEEAMap/Edit.jsx +36 -4
- package/src/components/Blocks/EmbedEEAMap/Schema.js +16 -5
- package/src/components/Blocks/EmbedEEAMap/View.jsx +75 -11
- package/src/components/ExtraViews.jsx +85 -0
- package/src/components/{Blocks/EEAMap/components/Webmap.jsx → Webmap.jsx} +33 -31
- package/src/components/index.js +6 -6
- package/src/components/visualization/VisualizationEditorWidget.jsx +120 -0
- package/src/components/{Blocks/EEAMap/components/widgets → visualization}/VisualizationView.jsx +0 -0
- package/src/components/{Blocks/EEAMap/components/widgets → visualization}/panelsSchema.js +0 -1
- package/src/components/widgets/DataQueryWidget.jsx +50 -0
- package/src/components/{Blocks/EEAMap/components/widgets → widgets}/LayerSelectWidget.jsx +169 -51
- package/src/components/{Blocks/EEAMap/components/widgets/LayersPanel.jsx → widgets/LayersPanelWidget.jsx} +2 -2
- package/src/components/{Blocks/EEAMap/components/widgets → widgets}/LegendWidget.jsx +45 -31
- package/src/components/{Blocks/EEAMap/components/widgets → widgets}/MapEditorWidget.jsx +1 -1
- package/src/components/{Blocks/EEAMap/components/widgets → widgets}/ObjectTypesWidget.jsx +11 -3
- package/src/components/widgets/panelsSchema.js +151 -0
- package/src/constants.js +29 -1
- package/src/index.js +42 -40
- package/src/middlewares/index.js +1 -1
- package/src/reducers/map_visualizations.js +1 -1
- package/src/static/code-line.svg +1 -0
- package/src/{components/Blocks/EEAMap/styles → styles}/map.css +64 -5
- package/src/{components/Blocks/EEAMap/utils.js → utils.js} +18 -2
- package/src/components/Blocks/EEAMap/components/widgets/ExtraViews.jsx +0 -86
- package/src/components/Blocks/EEAMap/components/widgets/VisualizationEditorWidget.jsx +0 -94
- package/src/components/Blocks/EEAMap/constants.js +0 -29
- package/src/components/Blocks/EmbedEEAMap/styles/map.css +0 -22
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Modal, Button, Grid } from 'semantic-ui-react';
|
|
3
|
+
|
|
4
|
+
import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
|
|
5
|
+
|
|
6
|
+
import PanelsSchema from './panelsSchema';
|
|
7
|
+
import Webmap from '../Webmap';
|
|
8
|
+
|
|
9
|
+
const VisualizationEditorWidget = (props) => {
|
|
10
|
+
const [open, setOpen] = React.useState(false);
|
|
11
|
+
const { onChange = {}, id } = props;
|
|
12
|
+
const block = React.useMemo(() => props.block, [props.block]);
|
|
13
|
+
const value = React.useMemo(() => props.value, [props.value]);
|
|
14
|
+
|
|
15
|
+
const [intValue, setIntValue] = React.useState(value);
|
|
16
|
+
|
|
17
|
+
const dataForm = { map_data: intValue };
|
|
18
|
+
const handleApplyChanges = () => {
|
|
19
|
+
onChange(id, intValue);
|
|
20
|
+
setOpen(false);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const handleClose = () => {
|
|
24
|
+
setIntValue(value);
|
|
25
|
+
setOpen(false);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const handleChangeField = (val) => {
|
|
29
|
+
setIntValue(val);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let schema = PanelsSchema({ data: dataForm });
|
|
33
|
+
|
|
34
|
+
React.useEffect(() => {
|
|
35
|
+
if (!intValue.general) {
|
|
36
|
+
setIntValue({
|
|
37
|
+
...intValue,
|
|
38
|
+
general: {
|
|
39
|
+
print_position: 'top-right',
|
|
40
|
+
zoom_position: 'top-right',
|
|
41
|
+
centerOnExtent: true,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (!intValue.base) {
|
|
46
|
+
setIntValue({
|
|
47
|
+
...intValue,
|
|
48
|
+
base: {
|
|
49
|
+
base_layer: 'gray-vector',
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}, [intValue]);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<FormFieldWrapper {...props}>
|
|
57
|
+
<div className="wrapper">
|
|
58
|
+
<Button
|
|
59
|
+
floated="right"
|
|
60
|
+
size="tiny"
|
|
61
|
+
onClick={(e) => {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
e.stopPropagation();
|
|
64
|
+
setOpen(true);
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
Open Map Editor
|
|
68
|
+
</Button>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
{open && (
|
|
72
|
+
<Modal
|
|
73
|
+
id="map-editor-modal"
|
|
74
|
+
style={{ width: '95% !important' }}
|
|
75
|
+
open={true}
|
|
76
|
+
>
|
|
77
|
+
<Modal.Content scrolling>
|
|
78
|
+
<Grid stackable reversed="mobile vertically tablet vertically">
|
|
79
|
+
<Grid.Column
|
|
80
|
+
mobile={12}
|
|
81
|
+
tablet={12}
|
|
82
|
+
computer={5}
|
|
83
|
+
className="map-editor-column"
|
|
84
|
+
>
|
|
85
|
+
<InlineForm
|
|
86
|
+
block={block}
|
|
87
|
+
schema={schema}
|
|
88
|
+
onChangeField={(id, value) => {
|
|
89
|
+
handleChangeField(value);
|
|
90
|
+
}}
|
|
91
|
+
formData={dataForm}
|
|
92
|
+
/>
|
|
93
|
+
</Grid.Column>
|
|
94
|
+
<Grid.Column mobile={12} tablet={12} computer={7}>
|
|
95
|
+
<div className="webmap-container">
|
|
96
|
+
<Webmap data={intValue} editMode={true} />
|
|
97
|
+
</div>
|
|
98
|
+
</Grid.Column>
|
|
99
|
+
</Grid>
|
|
100
|
+
</Modal.Content>
|
|
101
|
+
<Modal.Actions>
|
|
102
|
+
<Grid>
|
|
103
|
+
<Grid.Row>
|
|
104
|
+
<div className="map-edit-actions-container">
|
|
105
|
+
<Button onClick={handleClose}>Close</Button>
|
|
106
|
+
<Button color="green" onClick={handleApplyChanges}>
|
|
107
|
+
Apply changes
|
|
108
|
+
</Button>
|
|
109
|
+
</div>
|
|
110
|
+
</Grid.Row>
|
|
111
|
+
</Grid>
|
|
112
|
+
</Modal.Actions>
|
|
113
|
+
</Modal>
|
|
114
|
+
)}
|
|
115
|
+
<Webmap data={value} editMode={true} />
|
|
116
|
+
</FormFieldWrapper>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export default VisualizationEditorWidget;
|
package/src/components/{Blocks/EEAMap/components/widgets → visualization}/VisualizationView.jsx
RENAMED
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FormFieldWrapper, Field } from '@plone/volto/components';
|
|
3
|
+
import { Accordion, Segment } from 'semantic-ui-react';
|
|
4
|
+
|
|
5
|
+
const DataQueryWidget = (props) => {
|
|
6
|
+
const { value, onChange, id } = props;
|
|
7
|
+
|
|
8
|
+
const onChangeAlias = (fieldId, fieldValue) => {
|
|
9
|
+
let altValue = value;
|
|
10
|
+
value[fieldId] = { ...value[fieldId], alias: fieldValue };
|
|
11
|
+
onChange(id, altValue);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div>
|
|
16
|
+
<FormFieldWrapper {...props} noForInFieldLabel></FormFieldWrapper>
|
|
17
|
+
<div className="data-query-widget-field">
|
|
18
|
+
{value && value.length > 0 ? (
|
|
19
|
+
value.map((param, i) => (
|
|
20
|
+
<Accordion
|
|
21
|
+
key={i}
|
|
22
|
+
fluid
|
|
23
|
+
styled
|
|
24
|
+
style={{ border: '1px solid lightgray', marginBottom: '15px' }}
|
|
25
|
+
>
|
|
26
|
+
<Accordion.Content active={true}>
|
|
27
|
+
<Segment>
|
|
28
|
+
<p className="data-param-title">
|
|
29
|
+
<strong>{param.i}:</strong> {param.v.join(', ')}
|
|
30
|
+
</p>
|
|
31
|
+
<Field
|
|
32
|
+
id={i}
|
|
33
|
+
title="Map to"
|
|
34
|
+
type="string"
|
|
35
|
+
onChange={onChangeAlias}
|
|
36
|
+
value={param?.alias}
|
|
37
|
+
/>
|
|
38
|
+
</Segment>
|
|
39
|
+
</Accordion.Content>
|
|
40
|
+
</Accordion>
|
|
41
|
+
))
|
|
42
|
+
) : (
|
|
43
|
+
<p style={{ textAlign: 'center' }}>No parameters set</p>
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default DataQueryWidget;
|
|
@@ -4,15 +4,22 @@ import { Input, Select, Button, Grid } from 'semantic-ui-react';
|
|
|
4
4
|
import { QueryBuilder } from 'react-querybuilder';
|
|
5
5
|
import 'react-querybuilder/dist/query-builder.css';
|
|
6
6
|
|
|
7
|
+
import RichTextWidget from 'volto-slate/widgets/RichTextWidget';
|
|
8
|
+
|
|
9
|
+
import { connect } from 'react-redux';
|
|
10
|
+
import { compose } from 'redux';
|
|
11
|
+
|
|
12
|
+
import { getContent } from '@plone/volto/actions';
|
|
13
|
+
|
|
7
14
|
import checkSVG from '@plone/volto/icons/check.svg';
|
|
8
15
|
import closeSVG from '@plone/volto/icons/clear.svg';
|
|
9
16
|
import aheadSVG from '@plone/volto/icons/ahead.svg';
|
|
10
17
|
import resetSVG from '@plone/volto/icons/reset.svg';
|
|
11
18
|
|
|
12
|
-
import {
|
|
19
|
+
import { fetchArcGISData } from '../../utils';
|
|
13
20
|
|
|
14
21
|
const LayerSelectWidget = (props) => {
|
|
15
|
-
const { onChange, id } = props;
|
|
22
|
+
const { onChange, id, data_query } = props;
|
|
16
23
|
|
|
17
24
|
const value = React.useMemo(() => props.value || {}, [props.value]);
|
|
18
25
|
|
|
@@ -23,6 +30,7 @@ const LayerSelectWidget = (props) => {
|
|
|
23
30
|
layer,
|
|
24
31
|
fields = [],
|
|
25
32
|
query = '',
|
|
33
|
+
description = '',
|
|
26
34
|
} = value;
|
|
27
35
|
|
|
28
36
|
const [mapData, setMapData] = React.useState(map_data);
|
|
@@ -30,6 +38,7 @@ const LayerSelectWidget = (props) => {
|
|
|
30
38
|
const [serviceUrlError, setServiceUrlError] = React.useState('');
|
|
31
39
|
const [serviceUrl, setServiceUrl] = React.useState(map_service_url);
|
|
32
40
|
const [selectedLayer, setSelectedLayer] = React.useState(layer);
|
|
41
|
+
|
|
33
42
|
const [availableLayers, setAvailableLayers] = React.useState(
|
|
34
43
|
available_layers,
|
|
35
44
|
);
|
|
@@ -39,7 +48,7 @@ const LayerSelectWidget = (props) => {
|
|
|
39
48
|
const handleServiceUrlCheck = async () => {
|
|
40
49
|
// fetch url, save it, populate layers options
|
|
41
50
|
try {
|
|
42
|
-
let mapData = await
|
|
51
|
+
let mapData = await fetchArcGISData(serviceUrl);
|
|
43
52
|
setCheckColor('green');
|
|
44
53
|
setMapData(mapData);
|
|
45
54
|
setServiceUrlError('');
|
|
@@ -56,6 +65,7 @@ const LayerSelectWidget = (props) => {
|
|
|
56
65
|
map_service_url: serviceUrl,
|
|
57
66
|
available_layers: availableLayers,
|
|
58
67
|
map_data: mapData,
|
|
68
|
+
description,
|
|
59
69
|
});
|
|
60
70
|
} catch (e) {
|
|
61
71
|
setCheckColor('youtube');
|
|
@@ -63,9 +73,58 @@ const LayerSelectWidget = (props) => {
|
|
|
63
73
|
}
|
|
64
74
|
};
|
|
65
75
|
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
props.getContent('', null, id);
|
|
78
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
79
|
+
}, []);
|
|
80
|
+
|
|
81
|
+
React.useEffect(() => {
|
|
82
|
+
if (query && !builtQuery) {
|
|
83
|
+
setBuiltQuery(query);
|
|
84
|
+
}
|
|
85
|
+
}, [query, builtQuery]);
|
|
86
|
+
|
|
87
|
+
React.useEffect(() => {
|
|
88
|
+
//detect existing queries in block content. If it exists. Apply matching queries to layer on fresh layer load
|
|
89
|
+
if (
|
|
90
|
+
map_service_url &&
|
|
91
|
+
layer &&
|
|
92
|
+
!query &&
|
|
93
|
+
data_query &&
|
|
94
|
+
data_query.length > 0
|
|
95
|
+
) {
|
|
96
|
+
let autoQuery = {
|
|
97
|
+
combinator: 'or',
|
|
98
|
+
rules: [],
|
|
99
|
+
};
|
|
100
|
+
data_query.forEach((param, i) => {
|
|
101
|
+
if (
|
|
102
|
+
fields &&
|
|
103
|
+
fields.length > 0 &&
|
|
104
|
+
fields.filter(
|
|
105
|
+
(field, j) => field.name === param.alias || field.name === param.i,
|
|
106
|
+
).length > 0
|
|
107
|
+
) {
|
|
108
|
+
autoQuery.rules = [
|
|
109
|
+
...autoQuery.rules,
|
|
110
|
+
{ field: param.alias || param.i, operator: '=', value: param.v[0] },
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
if (autoQuery.rules.length > 0) {
|
|
115
|
+
onChange(id, {
|
|
116
|
+
...value,
|
|
117
|
+
query: autoQuery,
|
|
118
|
+
});
|
|
119
|
+
setBuiltQuery(autoQuery);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
123
|
+
}, [map_service_url, layer, query, data_query, fields]);
|
|
124
|
+
|
|
66
125
|
const handleLayerFetch = async (service_url, id) => {
|
|
67
126
|
try {
|
|
68
|
-
let fullLayer = await
|
|
127
|
+
let fullLayer = await fetchArcGISData(`${service_url}/${id}`);
|
|
69
128
|
return fullLayer;
|
|
70
129
|
} catch (e) {}
|
|
71
130
|
};
|
|
@@ -94,13 +153,24 @@ const LayerSelectWidget = (props) => {
|
|
|
94
153
|
}
|
|
95
154
|
};
|
|
96
155
|
|
|
156
|
+
const handleChangeDescription = (val) => {
|
|
157
|
+
if (val) {
|
|
158
|
+
onChange(id, {
|
|
159
|
+
...value,
|
|
160
|
+
description: val,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
97
165
|
const handleChangeServiceUrl = (value) => {
|
|
98
166
|
setServiceUrlError('');
|
|
99
167
|
setCheckColor('');
|
|
100
|
-
setServiceUrl(value);
|
|
101
168
|
setAvailableLayers('');
|
|
102
169
|
setBuiltQuery('');
|
|
103
170
|
setSelectedLayer('');
|
|
171
|
+
setMapData('');
|
|
172
|
+
|
|
173
|
+
setServiceUrl(value);
|
|
104
174
|
};
|
|
105
175
|
|
|
106
176
|
const handleReset = () => {
|
|
@@ -110,8 +180,8 @@ const LayerSelectWidget = (props) => {
|
|
|
110
180
|
setAvailableLayers(available_layers);
|
|
111
181
|
setBuiltQuery('');
|
|
112
182
|
setSelectedLayer(layer);
|
|
183
|
+
setMapData(map_data);
|
|
113
184
|
};
|
|
114
|
-
|
|
115
185
|
return (
|
|
116
186
|
<div
|
|
117
187
|
style={{
|
|
@@ -119,54 +189,71 @@ const LayerSelectWidget = (props) => {
|
|
|
119
189
|
}}
|
|
120
190
|
>
|
|
121
191
|
<Grid>
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
style={{ width: '100%' }}
|
|
130
|
-
error={serviceUrlError}
|
|
131
|
-
value={serviceUrl}
|
|
132
|
-
// action
|
|
133
|
-
// actionPosition="right"
|
|
134
|
-
></Input>
|
|
135
|
-
|
|
136
|
-
<span style={{ fontSize: '12px', color: 'darkred' }}>
|
|
137
|
-
{serviceUrlError.error}
|
|
138
|
-
</span>
|
|
139
|
-
</Grid.Row>
|
|
140
|
-
{serviceUrl && (
|
|
192
|
+
<div className="spaced-row">
|
|
193
|
+
<Grid.Row stretched>
|
|
194
|
+
<h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
|
|
195
|
+
Service URL
|
|
196
|
+
</h5>
|
|
197
|
+
</Grid.Row>
|
|
198
|
+
|
|
141
199
|
<Grid.Row>
|
|
142
|
-
|
|
200
|
+
<Input
|
|
201
|
+
type="text"
|
|
202
|
+
onChange={(e, { value }) => handleChangeServiceUrl(value)}
|
|
203
|
+
style={{ width: '100%' }}
|
|
204
|
+
error={serviceUrlError}
|
|
205
|
+
value={serviceUrl}
|
|
206
|
+
></Input>
|
|
207
|
+
|
|
208
|
+
<span style={{ fontSize: '12px', color: 'darkred' }}>
|
|
209
|
+
{serviceUrlError.error}
|
|
210
|
+
</span>
|
|
211
|
+
</Grid.Row>
|
|
212
|
+
{serviceUrl && (
|
|
213
|
+
<Grid.Row style={{ display: 'flex' }}>
|
|
214
|
+
{serviceUrl !== map_service_url && (
|
|
215
|
+
<Button
|
|
216
|
+
size="small"
|
|
217
|
+
compact
|
|
218
|
+
className="layer-reset-button"
|
|
219
|
+
onClick={handleReset}
|
|
220
|
+
>
|
|
221
|
+
<Icon name={resetSVG} title="Reset" size="20px" />
|
|
222
|
+
</Button>
|
|
223
|
+
)}
|
|
143
224
|
<Button
|
|
144
225
|
size="small"
|
|
226
|
+
color={checkColor}
|
|
145
227
|
compact
|
|
146
|
-
className="layer-
|
|
147
|
-
onClick={
|
|
228
|
+
className="layer-check-button"
|
|
229
|
+
onClick={handleServiceUrlCheck}
|
|
148
230
|
>
|
|
149
|
-
<Icon
|
|
231
|
+
<Icon
|
|
232
|
+
name={serviceUrlError ? closeSVG : checkSVG}
|
|
233
|
+
title="Submit"
|
|
234
|
+
size="20px"
|
|
235
|
+
/>
|
|
150
236
|
</Button>
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
/>
|
|
164
|
-
</Button>
|
|
165
|
-
</Grid.Row>
|
|
237
|
+
</Grid.Row>
|
|
238
|
+
)}
|
|
239
|
+
</div>
|
|
240
|
+
{mapData && mapData.mapName && (
|
|
241
|
+
<div className="spaced-row">
|
|
242
|
+
<Grid.Row>
|
|
243
|
+
<h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
|
|
244
|
+
Map name:
|
|
245
|
+
</h5>
|
|
246
|
+
<p>{mapData.mapName}</p>
|
|
247
|
+
</Grid.Row>
|
|
248
|
+
</div>
|
|
166
249
|
)}
|
|
167
250
|
{availableLayers && availableLayers.length > 0 && (
|
|
168
|
-
|
|
169
|
-
<
|
|
251
|
+
<div className="spaced-row">
|
|
252
|
+
<Grid.Row>
|
|
253
|
+
<h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
|
|
254
|
+
Layer
|
|
255
|
+
</h5>
|
|
256
|
+
</Grid.Row>
|
|
170
257
|
<Grid.Row>
|
|
171
258
|
<Select
|
|
172
259
|
onChange={(e, { value }) => handleSelectLayer(value)}
|
|
@@ -176,10 +263,31 @@ const LayerSelectWidget = (props) => {
|
|
|
176
263
|
value={selectedLayer}
|
|
177
264
|
/>
|
|
178
265
|
</Grid.Row>
|
|
179
|
-
|
|
266
|
+
</div>
|
|
267
|
+
)}
|
|
268
|
+
{availableLayers && availableLayers.length > 0 && (
|
|
269
|
+
<div className="spaced-row">
|
|
270
|
+
<Grid.Row stretched>
|
|
271
|
+
<h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
|
|
272
|
+
Description
|
|
273
|
+
</h5>
|
|
274
|
+
</Grid.Row>
|
|
275
|
+
<Grid.Row stretched>
|
|
276
|
+
<div className="map-layer-description-field">
|
|
277
|
+
<RichTextWidget
|
|
278
|
+
title="description"
|
|
279
|
+
onChange={(name, value) => {
|
|
280
|
+
handleChangeDescription(value);
|
|
281
|
+
}}
|
|
282
|
+
value={value.description}
|
|
283
|
+
placeholder="Set Description"
|
|
284
|
+
/>
|
|
285
|
+
</div>
|
|
286
|
+
</Grid.Row>
|
|
287
|
+
</div>
|
|
180
288
|
)}
|
|
181
289
|
{availableLayers && fields && fields.length > 0 && (
|
|
182
|
-
|
|
290
|
+
<div className="spaced-row">
|
|
183
291
|
<h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
|
|
184
292
|
Query Layer
|
|
185
293
|
</h5>
|
|
@@ -194,7 +302,7 @@ const LayerSelectWidget = (props) => {
|
|
|
194
302
|
/>
|
|
195
303
|
</Grid.Row>
|
|
196
304
|
{builtQuery && (
|
|
197
|
-
<Grid.Row>
|
|
305
|
+
<Grid.Row style={{ display: 'flex' }}>
|
|
198
306
|
<Button
|
|
199
307
|
type="submit"
|
|
200
308
|
size="tiny"
|
|
@@ -223,11 +331,21 @@ const LayerSelectWidget = (props) => {
|
|
|
223
331
|
<strong>{field.alias}</strong> ({field.type})
|
|
224
332
|
</p>
|
|
225
333
|
))}
|
|
226
|
-
|
|
334
|
+
</div>
|
|
227
335
|
)}
|
|
228
336
|
</Grid>
|
|
229
337
|
</div>
|
|
230
338
|
);
|
|
231
339
|
};
|
|
232
340
|
|
|
233
|
-
export default
|
|
341
|
+
export default compose(
|
|
342
|
+
connect(
|
|
343
|
+
(state, props) => ({
|
|
344
|
+
content: state.content.data,
|
|
345
|
+
data_query: state.content.data.data_query,
|
|
346
|
+
}),
|
|
347
|
+
{
|
|
348
|
+
getContent,
|
|
349
|
+
},
|
|
350
|
+
),
|
|
351
|
+
)(LayerSelectWidget);
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { Button } from 'semantic-ui-react';
|
|
3
3
|
import LayerSelectWidget from './LayerSelectWidget';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const LayersPanelWidget = ({ data, onChange, block }) => {
|
|
6
6
|
const map_layers = React.useMemo(() => data.map_layers || [], [
|
|
7
7
|
data.map_layers,
|
|
8
8
|
]);
|
|
@@ -55,4 +55,4 @@ const LayersPanel = ({ data, onChange, block }) => {
|
|
|
55
55
|
);
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
export default
|
|
58
|
+
export default LayersPanelWidget;
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Grid } from 'semantic-ui-react';
|
|
3
|
-
import {
|
|
3
|
+
import { fetchArcGISData, setLegendColumns } from '../../utils';
|
|
4
4
|
import { Icon } from '@plone/volto/components';
|
|
5
|
+
import { serializeNodes } from 'volto-slate/editor/render';
|
|
5
6
|
|
|
6
7
|
import rightKeySVG from '@plone/volto/icons/right-key.svg';
|
|
7
8
|
import downKeySVG from '@plone/volto/icons/down-key.svg';
|
|
9
|
+
import { withDeviceSize } from '../../hocs';
|
|
8
10
|
|
|
9
11
|
const LayerLegend = ({ data }) => {
|
|
10
|
-
const [expand, setExpand] = React.useState(true);
|
|
11
12
|
const [legendRows, setLegendRows] = React.useState([]);
|
|
12
13
|
|
|
13
14
|
const { id, name } = data.layer || {};
|
|
14
15
|
|
|
15
16
|
const fetchLegend = async (url, activeLayerID) => {
|
|
16
|
-
let legendData = await
|
|
17
|
+
let legendData = await fetchArcGISData(url);
|
|
17
18
|
|
|
18
19
|
const { layers = [] } = legendData;
|
|
19
20
|
const selectedLayer = layers.filter((l, i) => l.layerId === activeLayerID);
|
|
@@ -27,27 +28,18 @@ const LayerLegend = ({ data }) => {
|
|
|
27
28
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
29
|
}, [id, data.map_service_url]);
|
|
29
30
|
return (
|
|
30
|
-
<
|
|
31
|
+
<Grid.Column>
|
|
31
32
|
<h5
|
|
32
|
-
role="presentation"
|
|
33
|
-
onClick={() => setExpand(!expand)}
|
|
34
33
|
style={{
|
|
35
34
|
marginTop: '15px',
|
|
36
35
|
marginBottom: '5px',
|
|
37
|
-
cursor: 'pointer',
|
|
38
|
-
display: 'flex',
|
|
39
36
|
}}
|
|
40
37
|
>
|
|
41
|
-
<Icon
|
|
42
|
-
name={expand ? downKeySVG : rightKeySVG}
|
|
43
|
-
title={expand ? 'Collapse' : 'Expand'}
|
|
44
|
-
size="17px"
|
|
45
|
-
/>
|
|
46
38
|
{name}
|
|
47
39
|
</h5>
|
|
40
|
+
{data.description && serializeNodes(data.description)}
|
|
48
41
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
49
|
-
{
|
|
50
|
-
legendRows.length > 0 &&
|
|
42
|
+
{legendRows.length > 0 &&
|
|
51
43
|
legendRows.map((item, i) => {
|
|
52
44
|
return (
|
|
53
45
|
<span key={i} style={{ display: 'flex', alignItems: 'center' }}>
|
|
@@ -62,39 +54,61 @@ const LayerLegend = ({ data }) => {
|
|
|
62
54
|
);
|
|
63
55
|
})}
|
|
64
56
|
</div>
|
|
65
|
-
</
|
|
57
|
+
</Grid.Column>
|
|
66
58
|
);
|
|
67
59
|
};
|
|
68
60
|
|
|
69
61
|
const LegendWidget = (props) => {
|
|
70
62
|
const data = React.useMemo(() => props.data, [props.data]);
|
|
63
|
+
const { device = '' } = props;
|
|
64
|
+
|
|
65
|
+
const [expand, setExpand] = React.useState(true);
|
|
66
|
+
|
|
71
67
|
const { layers = {} } = data;
|
|
72
|
-
const
|
|
68
|
+
const map_layers =
|
|
69
|
+
layers &&
|
|
70
|
+
layers.map_layers &&
|
|
71
|
+
layers.map_layers.length > 0 &&
|
|
72
|
+
layers.map_layers.length > 3
|
|
73
|
+
? layers?.map_layers.slice(0, 3)
|
|
74
|
+
: layers?.map_layers;
|
|
73
75
|
|
|
76
|
+
const legendColumns =
|
|
77
|
+
map_layers && setLegendColumns(map_layers.length, device);
|
|
74
78
|
return (
|
|
75
79
|
<>
|
|
76
|
-
<div
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
<div className="legend-container">
|
|
81
|
+
<h4
|
|
82
|
+
role="presentation"
|
|
83
|
+
className="legend-title"
|
|
84
|
+
onClick={() => setExpand(!expand)}
|
|
85
|
+
>
|
|
86
|
+
<Icon
|
|
87
|
+
name={expand ? downKeySVG : rightKeySVG}
|
|
88
|
+
title={expand ? 'Collapse' : 'Expand'}
|
|
89
|
+
size="17px"
|
|
90
|
+
/>
|
|
91
|
+
Legend:
|
|
92
|
+
</h4>
|
|
93
|
+
<Grid columns={legendColumns}>
|
|
94
|
+
{(!map_layers || map_layers.length === 0) && (
|
|
95
|
+
<p>
|
|
96
|
+
No layer found for legend. Please add a map layer from editor.
|
|
97
|
+
</p>
|
|
98
|
+
)}
|
|
99
|
+
{expand && (
|
|
100
|
+
<Grid.Row divided>
|
|
87
101
|
{map_layers &&
|
|
88
102
|
map_layers.length > 0 &&
|
|
89
103
|
map_layers.map((l, i) => (
|
|
90
104
|
<LayerLegend key={i} data={l.map_layer} />
|
|
91
105
|
))}
|
|
92
|
-
</Grid.
|
|
93
|
-
|
|
106
|
+
</Grid.Row>
|
|
107
|
+
)}
|
|
94
108
|
</Grid>
|
|
95
109
|
</div>
|
|
96
110
|
</>
|
|
97
111
|
);
|
|
98
112
|
};
|
|
99
113
|
|
|
100
|
-
export default React.memo(LegendWidget);
|
|
114
|
+
export default withDeviceSize(React.memo(LegendWidget));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Modal, Button, Grid } from 'semantic-ui-react';
|
|
3
3
|
import Webmap from '../Webmap';
|
|
4
|
+
|
|
4
5
|
import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
|
|
5
6
|
|
|
6
7
|
import PanelsSchema from './panelsSchema';
|
|
@@ -37,7 +38,6 @@ const MapEditorWidget = (props) => {
|
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
let schema = PanelsSchema({ data: dataForm });
|
|
40
|
-
|
|
41
41
|
return (
|
|
42
42
|
<FormFieldWrapper {...props}>
|
|
43
43
|
<Modal
|