@eeacms/volto-marine-policy 2.0.26 → 2.0.28
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 +19 -0
- package/package.json +1 -1
- package/src/components/Blocks/DemoSitesExplorer/DemoSitesExplorerView.js +1 -1
- package/src/components/Blocks/DemoSitesExplorer/DemoSitesFilters.jsx +60 -7
- package/src/components/Blocks/DemoSitesExplorer/styles.less +1 -1
- package/src/components/theme/NISListingView/NISListingView.jsx +124 -38
- package/src/components/theme/NISListingView/style.less +17 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [2.0.28](https://github.com/eea/volto-marine-policy/compare/2.0.27...2.0.28) - 11 September 2025
|
|
8
|
+
|
|
9
|
+
#### :house: Internal changes
|
|
10
|
+
|
|
11
|
+
- style: Automated code fix [eea-jenkins - [`cbf9e77`](https://github.com/eea/volto-marine-policy/commit/cbf9e77a6fe1d745288792ad83f463ef3c9bec41)]
|
|
12
|
+
|
|
13
|
+
#### :hammer_and_wrench: Others
|
|
14
|
+
|
|
15
|
+
- fix eslint [Laszlo Cseh - [`04b17b2`](https://github.com/eea/volto-marine-policy/commit/04b17b25c5dbbd9d8afd1caf74132e7fca642f39)]
|
|
16
|
+
- NISlistingView fix assign to total count [Laszlo Cseh - [`ef82759`](https://github.com/eea/volto-marine-policy/commit/ef827593308f779e420c4cc3b3b8cae025c1616f)]
|
|
17
|
+
- NISlistingView download button location [Laszlo Cseh - [`22153f4`](https://github.com/eea/volto-marine-policy/commit/22153f422e06f7fbaa7adfa45817cd8ce7199c5a)]
|
|
18
|
+
- NISlistingView fix paths [Laszlo Cseh - [`ffa946e`](https://github.com/eea/volto-marine-policy/commit/ffa946eb83d144ca461af43787faa48f71d545ee)]
|
|
19
|
+
- WiP Nis improvements [Laszlo Cseh - [`c66a5f6`](https://github.com/eea/volto-marine-policy/commit/c66a5f68d3c3d1bc8aa968c98aa12f409e931adc)]
|
|
20
|
+
### [2.0.27](https://github.com/eea/volto-marine-policy/compare/2.0.26...2.0.27) - 5 September 2025
|
|
21
|
+
|
|
22
|
+
#### :hammer_and_wrench: Others
|
|
23
|
+
|
|
24
|
+
- fix eslint [laszlocseh - [`3f90c17`](https://github.com/eea/volto-marine-policy/commit/3f90c17f976fdf48a2e967d2997487ba87a3535d)]
|
|
25
|
+
- Demo Sites Explorer filter Targets facet options by selected objective [laszlocseh - [`3b975ad`](https://github.com/eea/volto-marine-policy/commit/3b975ad4380196cfd71c8fd2919fc717f98528a5)]
|
|
7
26
|
### [2.0.26](https://github.com/eea/volto-marine-policy/compare/2.0.25...2.0.26) - 29 August 2025
|
|
8
27
|
|
|
9
28
|
#### :rocket: Dependency updates
|
package/package.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
3
|
import { clearFilters } from './utils';
|
|
4
|
+
import { objectivesCustomOrder } from './utils';
|
|
5
|
+
|
|
6
|
+
const objectivesTargets = {
|
|
7
|
+
'Objective 1: Protect and restore marine and freshwater ecosystems and biodiversity':
|
|
8
|
+
[
|
|
9
|
+
'Contribute to relevant marine nature restoration targets including degraded seabed habitats and coastal ecosystems',
|
|
10
|
+
"Protect at least 30% of the EU's seas and integrate ecological corridors, as part of a true Trans-European Nature Network",
|
|
11
|
+
"Strictly protect at least 10% of the EU's seas",
|
|
12
|
+
'Restore at least 25,000 km of free/flowing rivers',
|
|
13
|
+
],
|
|
14
|
+
'Objective 2: Prevent and eliminate pollution of our oceans, seas and waters':
|
|
15
|
+
[
|
|
16
|
+
'Reduce nutrient losses by 50%',
|
|
17
|
+
'Reduce the use and risk of chemical pesticides by 50%',
|
|
18
|
+
'Reduce plastic litter at sea by 50%',
|
|
19
|
+
'Reduce by 30% microplastics released into the environment',
|
|
20
|
+
],
|
|
21
|
+
'Objective 3: Make the sustainable blue economy carbon-neutral and circular':
|
|
22
|
+
[
|
|
23
|
+
'Achieve net zero maritime emissions',
|
|
24
|
+
'Promote circular, low-carbon multi-purpose use of marine and water space',
|
|
25
|
+
'Develop zero-carbon and low-impact aquaculture',
|
|
26
|
+
],
|
|
27
|
+
};
|
|
4
28
|
|
|
5
29
|
const normalizeSearchInput = (searchInput) => {
|
|
6
30
|
let normInput = searchInput
|
|
@@ -13,6 +37,25 @@ const normalizeSearchInput = (searchInput) => {
|
|
|
13
37
|
return '\\b' + normInput + '\\b';
|
|
14
38
|
};
|
|
15
39
|
|
|
40
|
+
const filterTargetsByObjective = (filters, filterName, highlightedIndex) => {
|
|
41
|
+
if (filterName !== 'target_filter') return filters;
|
|
42
|
+
if (highlightedIndex < 0 || highlightedIndex > 2) return filters;
|
|
43
|
+
|
|
44
|
+
let selectedObjective = objectivesCustomOrder[highlightedIndex];
|
|
45
|
+
let allowedTargets = objectivesTargets[selectedObjective] || [];
|
|
46
|
+
|
|
47
|
+
// Filter the targets based on the allowed ones
|
|
48
|
+
if (filters['target_filter']) {
|
|
49
|
+
filters['target_filter'] = Object.fromEntries(
|
|
50
|
+
Object.entries(filters['target_filter']).filter(([key]) =>
|
|
51
|
+
allowedTargets.includes(key),
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return filters;
|
|
57
|
+
};
|
|
58
|
+
|
|
16
59
|
export function DemoSitesFilter(props) {
|
|
17
60
|
const {
|
|
18
61
|
filterTitle,
|
|
@@ -20,11 +63,15 @@ export function DemoSitesFilter(props) {
|
|
|
20
63
|
activeFilters,
|
|
21
64
|
setActiveFilters,
|
|
22
65
|
filterName,
|
|
23
|
-
|
|
66
|
+
highlightedIndex,
|
|
24
67
|
} = props;
|
|
25
68
|
|
|
26
69
|
const customOrder = props?.customOrder || [];
|
|
27
|
-
const entries = Object.entries(
|
|
70
|
+
const entries = Object.entries(
|
|
71
|
+
filterTargetsByObjective(filters, filterName, highlightedIndex)?.[
|
|
72
|
+
filterName
|
|
73
|
+
] || {},
|
|
74
|
+
);
|
|
28
75
|
let sortedEntries = [];
|
|
29
76
|
|
|
30
77
|
if (customOrder.length > 0) {
|
|
@@ -112,7 +159,13 @@ export function DemoSitesFilter(props) {
|
|
|
112
159
|
}
|
|
113
160
|
|
|
114
161
|
export function DemoSitesFilters(props) {
|
|
115
|
-
const {
|
|
162
|
+
const {
|
|
163
|
+
filters,
|
|
164
|
+
activeFilters,
|
|
165
|
+
hideFilters,
|
|
166
|
+
setActiveFilters,
|
|
167
|
+
highlightedIndex,
|
|
168
|
+
} = props;
|
|
116
169
|
|
|
117
170
|
React.useEffect(() => {
|
|
118
171
|
window.addEventListener('click', (event) => {
|
|
@@ -148,7 +201,7 @@ export function DemoSitesFilters(props) {
|
|
|
148
201
|
filters={filters}
|
|
149
202
|
activeFilters={activeFilters}
|
|
150
203
|
setActiveFilters={setActiveFilters}
|
|
151
|
-
|
|
204
|
+
highlightedIndex={highlightedIndex}
|
|
152
205
|
/>
|
|
153
206
|
) : (
|
|
154
207
|
''
|
|
@@ -160,7 +213,7 @@ export function DemoSitesFilters(props) {
|
|
|
160
213
|
filters={filters}
|
|
161
214
|
activeFilters={activeFilters}
|
|
162
215
|
setActiveFilters={setActiveFilters}
|
|
163
|
-
|
|
216
|
+
highlightedIndex={highlightedIndex}
|
|
164
217
|
/>
|
|
165
218
|
) : (
|
|
166
219
|
''
|
|
@@ -171,7 +224,7 @@ export function DemoSitesFilters(props) {
|
|
|
171
224
|
filters={filters}
|
|
172
225
|
activeFilters={activeFilters}
|
|
173
226
|
setActiveFilters={setActiveFilters}
|
|
174
|
-
|
|
227
|
+
highlightedIndex={highlightedIndex}
|
|
175
228
|
/>
|
|
176
229
|
<DemoSitesFilter
|
|
177
230
|
filterTitle="Country"
|
|
@@ -179,7 +232,7 @@ export function DemoSitesFilters(props) {
|
|
|
179
232
|
filters={filters}
|
|
180
233
|
activeFilters={activeFilters}
|
|
181
234
|
setActiveFilters={setActiveFilters}
|
|
182
|
-
|
|
235
|
+
highlightedIndex={highlightedIndex}
|
|
183
236
|
/>
|
|
184
237
|
</>
|
|
185
238
|
);
|
|
@@ -1,49 +1,115 @@
|
|
|
1
|
-
// import ProgressWorkflow from '@eeacms/volto-workflow-progress/ProgressWorkflow';
|
|
2
1
|
import ProgressWorkflow from '@eeacms/volto-marine-policy/components/theme/ProgressWorkflow/ProgressWorkflow';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
import qs from 'query-string';
|
|
5
4
|
import PropTypes from 'prop-types';
|
|
6
5
|
import './style.less';
|
|
7
6
|
import { useState, useEffect } from 'react';
|
|
8
7
|
import { useSelector } from 'react-redux';
|
|
9
8
|
import { Checkbox } from 'semantic-ui-react';
|
|
10
|
-
import { Button, Select } from 'semantic-ui-react';
|
|
9
|
+
import { Button, Select, Dimmer, Loader } from 'semantic-ui-react';
|
|
10
|
+
|
|
11
|
+
function normalizeQueryOperators(query) {
|
|
12
|
+
return query.map((q) => {
|
|
13
|
+
// if the operator starts with "paqo", replace with full
|
|
14
|
+
if (q.o && q.o.startsWith('paqo.')) {
|
|
15
|
+
const op = q.o.replace('paqo.', 'plone.app.querystring.operation.');
|
|
16
|
+
return { ...q, o: op };
|
|
17
|
+
}
|
|
18
|
+
return q;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function getCurrentSearchItems() {
|
|
23
|
+
// parse querystring into an object
|
|
24
|
+
const parsed = qs.parse(window.location.search);
|
|
25
|
+
|
|
26
|
+
// decode the `query` param, which is itself a JSON string
|
|
27
|
+
let query = [];
|
|
28
|
+
if (parsed.query) {
|
|
29
|
+
try {
|
|
30
|
+
query = normalizeQueryOperators(JSON.parse(parsed.query));
|
|
31
|
+
} catch (e) {
|
|
32
|
+
// console.error('Invalid query param JSON', e);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// build payload
|
|
37
|
+
const payload = {
|
|
38
|
+
metadata_fields: '_all',
|
|
39
|
+
b_size: parsed.b_size ? parseInt(parsed.b_size, 10) : 25,
|
|
40
|
+
limit: parsed.limit ? parseInt(parsed.limit, 10) : 3000,
|
|
41
|
+
query,
|
|
42
|
+
sort_on: parsed.sort_on || 'effective',
|
|
43
|
+
sort_order: parsed.sort_order || 'ascending',
|
|
44
|
+
b_start: parsed.b_start ? parseInt(parsed.b_start, 10) : 0,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// call Plone
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch('/marine/++api++/@querystring-search', {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
},
|
|
54
|
+
body: JSON.stringify(payload),
|
|
55
|
+
});
|
|
56
|
+
return response;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
// console.error('Querystring search failed:', err);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
11
61
|
|
|
12
62
|
const NISListingView = ({ items, isEditMode }) => {
|
|
63
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
13
64
|
const [selectedItems, setSelectedItems] = useState([]);
|
|
65
|
+
const [itemsTotal, setItemsTotal] = useState(0);
|
|
14
66
|
const [users, setUsers] = useState([]);
|
|
15
67
|
const [assignee, setAssignee] = useState(null);
|
|
16
68
|
const actions = useSelector((state) => state.actions.actions);
|
|
17
69
|
const canEditPage = actions?.object?.some((action) => action.id === 'edit');
|
|
18
|
-
// console.log('actions', actions);
|
|
19
70
|
|
|
20
71
|
const toggleSelection = (id) => {
|
|
72
|
+
setItemsTotal(0);
|
|
21
73
|
setSelectedItems((prev) =>
|
|
22
|
-
prev.includes(id)
|
|
74
|
+
prev.includes(id)
|
|
75
|
+
? prev.filter((x) => x !== id && x !== 'All')
|
|
76
|
+
: [...prev.filter((x) => x !== 'All'), id],
|
|
23
77
|
);
|
|
24
78
|
};
|
|
25
79
|
|
|
26
80
|
const handleBulkAssign = () => {
|
|
81
|
+
setItemsTotal(0);
|
|
27
82
|
onBulkAssign(selectedItems, assignee);
|
|
28
83
|
setSelectedItems([]);
|
|
29
84
|
setAssignee(null);
|
|
30
85
|
};
|
|
31
86
|
|
|
87
|
+
const handleBulkAssignAll = async () => {
|
|
88
|
+
const items = await getCurrentSearchItems();
|
|
89
|
+
const itemsTotal = await items.json();
|
|
90
|
+
setItemsTotal(itemsTotal.items_total);
|
|
91
|
+
setSelectedItems(['All']);
|
|
92
|
+
};
|
|
93
|
+
|
|
32
94
|
const onBulkAssign = async (ids, assignee) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
95
|
+
setIsLoading(true);
|
|
96
|
+
await fetch(
|
|
97
|
+
`${window.location.origin}/marine/++api++/@bulk-assign${window.location.search}`,
|
|
98
|
+
{
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: {
|
|
101
|
+
'Content-Type': 'application/json',
|
|
102
|
+
Accept: 'application/json',
|
|
103
|
+
},
|
|
104
|
+
credentials: 'include',
|
|
105
|
+
body: JSON.stringify({
|
|
106
|
+
items: ids,
|
|
107
|
+
assigned_to: assignee,
|
|
108
|
+
search: window.location.search,
|
|
109
|
+
}),
|
|
38
110
|
},
|
|
39
|
-
|
|
40
|
-
body: JSON.stringify({
|
|
41
|
-
items: ids,
|
|
42
|
-
assigned_to: assignee,
|
|
43
|
-
}),
|
|
44
|
-
});
|
|
111
|
+
);
|
|
45
112
|
|
|
46
|
-
// const result = await res.json();
|
|
47
113
|
window.location.reload();
|
|
48
114
|
};
|
|
49
115
|
|
|
@@ -74,6 +140,37 @@ const NISListingView = ({ items, isEditMode }) => {
|
|
|
74
140
|
|
|
75
141
|
return (
|
|
76
142
|
<>
|
|
143
|
+
{isLoading && (
|
|
144
|
+
<Dimmer active inverted>
|
|
145
|
+
<Loader>Assigning...</Loader>
|
|
146
|
+
</Dimmer>
|
|
147
|
+
)}
|
|
148
|
+
{canEditPage && (
|
|
149
|
+
<div className="download-button-wrapper">
|
|
150
|
+
<Button
|
|
151
|
+
className="primary"
|
|
152
|
+
size="small"
|
|
153
|
+
onClick={handleBulkAssignAll}
|
|
154
|
+
>
|
|
155
|
+
<i className="ri-user-add-line"></i>Assign search results
|
|
156
|
+
</Button>
|
|
157
|
+
<div>
|
|
158
|
+
<a
|
|
159
|
+
href={`/marine/++api++${window.location.pathname.replace(
|
|
160
|
+
'/marine',
|
|
161
|
+
'',
|
|
162
|
+
)}/nis-export${window.location.search}`}
|
|
163
|
+
title="Download"
|
|
164
|
+
target="_blank"
|
|
165
|
+
rel="noopener"
|
|
166
|
+
className="ui button primary download-as-xls"
|
|
167
|
+
>
|
|
168
|
+
<i className="ri-file-download-line"></i>
|
|
169
|
+
Download search results
|
|
170
|
+
</a>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
77
174
|
<table className="ui table">
|
|
78
175
|
<thead>
|
|
79
176
|
<tr>
|
|
@@ -82,28 +179,11 @@ const NISListingView = ({ items, isEditMode }) => {
|
|
|
82
179
|
<th>Scientific name accepted</th>
|
|
83
180
|
<th>Region</th>
|
|
84
181
|
<th>Subregion</th>
|
|
182
|
+
<th>Country</th>
|
|
85
183
|
<th>Status</th>
|
|
86
184
|
<th>Group</th>
|
|
87
185
|
<th>Assigned to</th>
|
|
88
|
-
<th>
|
|
89
|
-
{canEditPage && (
|
|
90
|
-
<div>
|
|
91
|
-
<a
|
|
92
|
-
href={`/marine/++api++${window.location.pathname.replace(
|
|
93
|
-
'/marine',
|
|
94
|
-
'',
|
|
95
|
-
)}/nis-export${window.location.search}`}
|
|
96
|
-
title="Download"
|
|
97
|
-
target="_blank"
|
|
98
|
-
rel="noopener"
|
|
99
|
-
className="ui button primary download-as-xls"
|
|
100
|
-
>
|
|
101
|
-
<i className="ri-file-download-line"></i>
|
|
102
|
-
Download
|
|
103
|
-
</a>
|
|
104
|
-
</div>
|
|
105
|
-
)}
|
|
106
|
-
</th>
|
|
186
|
+
<th></th>
|
|
107
187
|
</tr>
|
|
108
188
|
</thead>
|
|
109
189
|
<tbody>
|
|
@@ -114,6 +194,7 @@ const NISListingView = ({ items, isEditMode }) => {
|
|
|
114
194
|
<td>{item.nis_scientificname_accepted}</td>
|
|
115
195
|
<td>{item.nis_region}</td>
|
|
116
196
|
<td>{item.nis_subregion}</td>
|
|
197
|
+
<td>{item.nis_country && item.nis_country.join(', ')}</td>
|
|
117
198
|
<td>{item.nis_status}</td>
|
|
118
199
|
<td>{item.nis_group}</td>
|
|
119
200
|
<td>
|
|
@@ -163,8 +244,13 @@ const NISListingView = ({ items, isEditMode }) => {
|
|
|
163
244
|
{selectedItems.length > 0 && (
|
|
164
245
|
<div className="users-assign-container">
|
|
165
246
|
<h4>
|
|
166
|
-
|
|
167
|
-
|
|
247
|
+
{itemsTotal > 0 &&
|
|
248
|
+
selectedItems[0] === 'All' &&
|
|
249
|
+
`Assign ${itemsTotal} search result items`}
|
|
250
|
+
{itemsTotal === 0 &&
|
|
251
|
+
`Assign ${selectedItems.length} selected item${
|
|
252
|
+
selectedItems.length > 1 ? 's' : ''
|
|
253
|
+
}`}
|
|
168
254
|
</h4>
|
|
169
255
|
<Select
|
|
170
256
|
placeholder="Select expert"
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
font-size: 0.9em;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
.ui.text.loader {
|
|
15
|
+
position: fixed;
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
.ui.table tr {
|
|
15
19
|
td,
|
|
16
20
|
th {
|
|
@@ -145,3 +149,16 @@
|
|
|
145
149
|
.download-as-xls {
|
|
146
150
|
padding: 0.6em 0.5em !important;
|
|
147
151
|
}
|
|
152
|
+
|
|
153
|
+
.download-button-wrapper {
|
|
154
|
+
display: flex;
|
|
155
|
+
|
|
156
|
+
button {
|
|
157
|
+
padding: 0.6em 0.5em !important;
|
|
158
|
+
font-size: 1em !important;
|
|
159
|
+
|
|
160
|
+
i {
|
|
161
|
+
margin-right: 5px;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|