@eeacms/volto-cca-policy 1.0.31 → 1.0.32
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 +21 -0
- package/package.json +1 -1
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.jsx +11 -5
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.test.jsx +13 -3
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueContentView.jsx +50 -3
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueContentView.test.jsx +194 -0
- package/src/components/Search/NavigatorCatalogue/NavigatorGeographicCoverageFacet.jsx +4 -7
- package/src/components/Search/NavigatorCatalogue/NavigatorGeographicCoverageFacet.test.jsx +6 -1
- package/src/components/theme/TagOverflowPopup.jsx +7 -2
- package/src/components/theme/Views/ExtendedToolView.jsx +2 -2
- package/src/search/cca/config.js +12 -1
- package/src/search/navigator_catalogue/config.js +1 -0
- package/src/search/navigator_catalogue/facets.js +4 -2
- package/src/utils.test.js +30 -0
- package/theme/globals/navigator.less +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,27 @@ 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
|
+
### [1.0.32](https://github.com/eea/volto-cca-policy/compare/1.0.31...1.0.32) - 1 October 2026
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat(navigator): improve cycle elements with titles on hover; show full titles in the popup [kreafox - [`c03313c`](https://github.com/eea/volto-cca-policy/commit/c03313c69dbb5a601016d495286d5d15b5a8da97)]
|
|
12
|
+
- feat(navigator): add default sort configuration for Navigator Catalogue [kreafox - [`934caa6`](https://github.com/eea/volto-cca-policy/commit/934caa658d173430af93b44f6f46fb2e28234b75)]
|
|
13
|
+
|
|
14
|
+
#### :bug: Bug Fixes
|
|
15
|
+
|
|
16
|
+
- fix(search): restore clusters [kreafox - [`7aa88bc`](https://github.com/eea/volto-cca-policy/commit/7aa88bc9d973676cba2a624cd83b1221cee2d6b7)]
|
|
17
|
+
- fix(test): remove unnecessary react import [kreafox - [`3324412`](https://github.com/eea/volto-cca-policy/commit/3324412a884bdfadfb3edba18768c4f123f01ebe)]
|
|
18
|
+
- fix(navigator): change heading from h4 to h3 for "Used in" section [kreafox - [`d366c4a`](https://github.com/eea/volto-cca-policy/commit/d366c4a328ea11322163dba747ffd99e2f2f6ad7)]
|
|
19
|
+
|
|
20
|
+
#### :nail_care: Enhancements
|
|
21
|
+
|
|
22
|
+
- refactor(navigator): update labels for geographic coverage facets [kreafox - [`825ddb8`](https://github.com/eea/volto-cca-policy/commit/825ddb8586fd143fd2e9b9809181ecafd4df9924)]
|
|
23
|
+
|
|
24
|
+
#### :hammer_and_wrench: Others
|
|
25
|
+
|
|
26
|
+
- test(utils): add test for getFilteredBlocks [kreafox - [`932df7e`](https://github.com/eea/volto-cca-policy/commit/932df7e686653ba8be5ec16b3ea34c6fd7e42134)]
|
|
27
|
+
- test(navigator): add unit tests for catalogue sorting functionality [kreafox - [`b78f2bd`](https://github.com/eea/volto-cca-policy/commit/b78f2bdf1714b383bbff034c58f0f896aeaeb62f)]
|
|
7
28
|
### [1.0.31](https://github.com/eea/volto-cca-policy/compare/1.0.30...1.0.31) - 29 September 2026
|
|
8
29
|
|
|
9
30
|
### [1.0.30](https://github.com/eea/volto-cca-policy/compare/1.0.29...1.0.30) - 25 September 2026
|
package/package.json
CHANGED
|
@@ -100,19 +100,23 @@ const CycleElements = ({ intl, values }) => {
|
|
|
100
100
|
<span className="cycle-elements-label">
|
|
101
101
|
{intl.formatMessage(messages.cycle)}
|
|
102
102
|
</span>
|
|
103
|
-
{visible.map((
|
|
103
|
+
{visible.map(({ label, title }, index) => (
|
|
104
104
|
<span
|
|
105
105
|
key={`cycle-element-${index}`}
|
|
106
106
|
className="navigator-tag cycle-element"
|
|
107
|
+
title={title}
|
|
107
108
|
>
|
|
108
|
-
{
|
|
109
|
+
{label}
|
|
109
110
|
</span>
|
|
110
111
|
))}
|
|
111
112
|
{hidden.length > 0 && (
|
|
112
113
|
<TagOverflowPopup
|
|
113
|
-
items={hidden}
|
|
114
|
+
items={hidden.map(({ title }) => title)}
|
|
114
115
|
className="navigator-tag cycle-element more"
|
|
115
|
-
ariaLabel={`${intl.formatMessage(messages.cycle)}: ${hidden
|
|
116
|
+
ariaLabel={`${intl.formatMessage(messages.cycle)}: ${hidden
|
|
117
|
+
.map(({ title }) => title)
|
|
118
|
+
.join(', ')}`}
|
|
119
|
+
title={hidden.map(({ title }) => title).join(', ')}
|
|
116
120
|
/>
|
|
117
121
|
)}
|
|
118
122
|
</div>
|
|
@@ -137,7 +141,9 @@ const NavigatorCatalogueCardItem = (props) => {
|
|
|
137
141
|
)
|
|
138
142
|
.map((value) => {
|
|
139
143
|
const title = value?.title || value;
|
|
140
|
-
return typeof title === 'string'
|
|
144
|
+
return typeof title === 'string'
|
|
145
|
+
? { title, label: title.split(':')[0] }
|
|
146
|
+
: null;
|
|
141
147
|
})
|
|
142
148
|
.filter(Boolean);
|
|
143
149
|
const publicationDate =
|
|
@@ -130,11 +130,21 @@ describe('NavigatorCatalogueCardItem', () => {
|
|
|
130
130
|
expect(screen.getByText('Risk assessment')).toBeInTheDocument();
|
|
131
131
|
expect(screen.getByText('Resilience')).toBeInTheDocument();
|
|
132
132
|
expect(screen.getByText('Adaptation')).toBeInTheDocument();
|
|
133
|
-
expect(screen.getByText('Step 1')).
|
|
133
|
+
expect(screen.getByText('Step 1')).toHaveAttribute(
|
|
134
|
+
'title',
|
|
135
|
+
'Step 1: Preparing the ground',
|
|
136
|
+
);
|
|
134
137
|
expect(
|
|
135
|
-
screen.getByRole('button', {
|
|
138
|
+
screen.getByRole('button', {
|
|
139
|
+
name: 'Cycle: Step 4: Assessing options',
|
|
140
|
+
}),
|
|
136
141
|
).toHaveTextContent('+ 1');
|
|
137
|
-
expect(
|
|
142
|
+
expect(
|
|
143
|
+
screen.getByRole('button', {
|
|
144
|
+
name: 'Cycle: Step 4: Assessing options',
|
|
145
|
+
}),
|
|
146
|
+
).toHaveAttribute('title', 'Step 4: Assessing options');
|
|
147
|
+
expect(screen.getByText('Step 4: Assessing options')).toBeInTheDocument();
|
|
138
148
|
expect(
|
|
139
149
|
screen.getByTitle(
|
|
140
150
|
'Maps and graphs, Reports and decision support, Datasets and indicators',
|
|
@@ -15,7 +15,11 @@ import {
|
|
|
15
15
|
SortingDropdownWithLabel,
|
|
16
16
|
} from '@eeacms/search/components';
|
|
17
17
|
import { NoResults } from '@eeacms/search/components/Result/NoResults';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
useSearchContext,
|
|
20
|
+
useSearchDriver,
|
|
21
|
+
useViews,
|
|
22
|
+
} from '@eeacms/search/lib/hocs';
|
|
19
23
|
import { loadingFamily } from '@eeacms/search/state';
|
|
20
24
|
import registry from '@eeacms/search/registry';
|
|
21
25
|
import { CompareToolsPanel } from '@eeacms/volto-cca-policy/components';
|
|
@@ -72,7 +76,12 @@ const NavigatorCatalogueContentView = (props) => {
|
|
|
72
76
|
const { sortOptions, resultViews } = appConfig;
|
|
73
77
|
const views = useViews();
|
|
74
78
|
const searchContext = useSearchContext();
|
|
79
|
+
const driver = useSearchDriver();
|
|
80
|
+
const { searchTerm, sortField, sortDirection, totalResults, wasSearched } =
|
|
81
|
+
searchContext;
|
|
75
82
|
const intl = useIntl();
|
|
83
|
+
const defaultSortApplied = React.useRef(false);
|
|
84
|
+
const previousSearchTerm = React.useRef(searchTerm);
|
|
76
85
|
|
|
77
86
|
const { showFilters, showFacets, showClusters, showSorting } = appConfig;
|
|
78
87
|
|
|
@@ -90,6 +99,36 @@ const NavigatorCatalogueContentView = (props) => {
|
|
|
90
99
|
}
|
|
91
100
|
}, [activeNavigatorViewId, views]);
|
|
92
101
|
|
|
102
|
+
React.useEffect(() => {
|
|
103
|
+
if (!driver || defaultSortApplied.current) return;
|
|
104
|
+
defaultSortApplied.current = true;
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
searchTerm?.trim() ||
|
|
108
|
+
sortField ||
|
|
109
|
+
sortDirection ||
|
|
110
|
+
!appConfig.defaultSort
|
|
111
|
+
) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const [field, direction] = appConfig.defaultSort.split('|');
|
|
116
|
+
if (field && direction) driver.setSort(field, direction);
|
|
117
|
+
}, [appConfig.defaultSort, driver, searchTerm, sortDirection, sortField]);
|
|
118
|
+
|
|
119
|
+
React.useEffect(() => {
|
|
120
|
+
const hadSearchTerm = Boolean(previousSearchTerm.current?.trim());
|
|
121
|
+
const hasSearchTerm = Boolean(searchTerm?.trim());
|
|
122
|
+
previousSearchTerm.current = searchTerm;
|
|
123
|
+
|
|
124
|
+
if (!driver || !hadSearchTerm || hasSearchTerm || !appConfig.defaultSort) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const [field, direction] = appConfig.defaultSort.split('|');
|
|
129
|
+
if (field && direction) driver.setSort(field, direction);
|
|
130
|
+
}, [appConfig.defaultSort, driver, searchTerm]);
|
|
131
|
+
|
|
93
132
|
const listingViewDef = resultViews.find(
|
|
94
133
|
(view) => view.id === activeNavigatorViewId,
|
|
95
134
|
);
|
|
@@ -100,8 +139,6 @@ const NavigatorCatalogueContentView = (props) => {
|
|
|
100
139
|
const layoutMode =
|
|
101
140
|
activeNavigatorViewId === 'listing' ? 'fixed' : 'fullwidth';
|
|
102
141
|
|
|
103
|
-
const { searchTerm, totalResults, wasSearched } = searchContext;
|
|
104
|
-
|
|
105
142
|
const loadingAtom = loadingFamily(appConfig.appName);
|
|
106
143
|
const isLoading = useAtomValue(loadingAtom);
|
|
107
144
|
|
|
@@ -114,6 +151,15 @@ const NavigatorCatalogueContentView = (props) => {
|
|
|
114
151
|
: item.name,
|
|
115
152
|
}));
|
|
116
153
|
|
|
154
|
+
const handleSortChange = (value) => {
|
|
155
|
+
const selectedOption = sortOptions2.find(
|
|
156
|
+
(option) => `${option.value}|||${option.direction}` === value,
|
|
157
|
+
);
|
|
158
|
+
if (selectedOption && driver) {
|
|
159
|
+
driver.setSort(selectedOption.value, selectedOption.direction);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
117
163
|
if (!ResultViewComponent) return null;
|
|
118
164
|
|
|
119
165
|
return (
|
|
@@ -173,6 +219,7 @@ const NavigatorCatalogueContentView = (props) => {
|
|
|
173
219
|
label=""
|
|
174
220
|
sortOptions={sortOptions2}
|
|
175
221
|
view={SortingDropdownWithLabel}
|
|
222
|
+
onChange={handleSortChange}
|
|
176
223
|
/>
|
|
177
224
|
</>
|
|
178
225
|
)}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import { IntlProvider } from 'react-intl';
|
|
5
|
+
import NavigatorCatalogueContentView from './NavigatorCatalogueContentView';
|
|
6
|
+
import {
|
|
7
|
+
useSearchContext,
|
|
8
|
+
useSearchDriver,
|
|
9
|
+
useViews,
|
|
10
|
+
} from '@eeacms/search/lib/hocs';
|
|
11
|
+
|
|
12
|
+
jest.mock('@elastic/react-search-ui', () => ({
|
|
13
|
+
Sorting: ({ sortOptions, onChange }) => (
|
|
14
|
+
<select
|
|
15
|
+
aria-label="Sort results"
|
|
16
|
+
onChange={(event) => onChange(event.target.value)}
|
|
17
|
+
>
|
|
18
|
+
{sortOptions.map((option) => (
|
|
19
|
+
<option
|
|
20
|
+
key={`${option.value}|${option.direction}`}
|
|
21
|
+
value={`${option.value}|||${option.direction}`}
|
|
22
|
+
>
|
|
23
|
+
{option.name}
|
|
24
|
+
</option>
|
|
25
|
+
))}
|
|
26
|
+
</select>
|
|
27
|
+
),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
jest.mock('semantic-ui-react', () => {
|
|
31
|
+
const Menu = ({ children }) => <nav>{children}</nav>;
|
|
32
|
+
Menu.Item = ({ children }) => <button type="button">{children}</button>;
|
|
33
|
+
return {
|
|
34
|
+
Grid: Object.assign(({ children }) => <div>{children}</div>, {
|
|
35
|
+
Column: ({ children }) => <div>{children}</div>,
|
|
36
|
+
}),
|
|
37
|
+
Icon: () => null,
|
|
38
|
+
Menu,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
jest.mock('jotai', () => ({
|
|
43
|
+
...jest.requireActual('jotai'),
|
|
44
|
+
useAtomValue: () => false,
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
jest.mock(
|
|
48
|
+
'@eeacms/search/components/ResultsPerPageSelector/ResultsPerPageSelector',
|
|
49
|
+
() => () => null,
|
|
50
|
+
);
|
|
51
|
+
jest.mock('@eeacms/search/components/Paging/Paging', () => () => null);
|
|
52
|
+
jest.mock('@eeacms/search/components', () => ({
|
|
53
|
+
ActiveFilterList: () => null,
|
|
54
|
+
Component: () => null,
|
|
55
|
+
DownloadButton: () => null,
|
|
56
|
+
DropdownFacetsList: () => null,
|
|
57
|
+
SectionTabs: () => null,
|
|
58
|
+
SortingDropdownWithLabel: () => null,
|
|
59
|
+
}));
|
|
60
|
+
jest.mock('@eeacms/search/components/Result/NoResults', () => ({
|
|
61
|
+
NoResults: () => null,
|
|
62
|
+
}));
|
|
63
|
+
jest.mock('@eeacms/search/lib/hocs', () => ({
|
|
64
|
+
useSearchContext: jest.fn(),
|
|
65
|
+
useSearchDriver: jest.fn(),
|
|
66
|
+
useViews: jest.fn(),
|
|
67
|
+
}));
|
|
68
|
+
jest.mock('@eeacms/search/state', () => ({
|
|
69
|
+
loadingFamily: jest.fn(() => 'loading'),
|
|
70
|
+
}));
|
|
71
|
+
jest.mock('@eeacms/search/registry', () => ({
|
|
72
|
+
__esModule: true,
|
|
73
|
+
default: {
|
|
74
|
+
resolve: {
|
|
75
|
+
ListingView: { component: ({ children }) => <div>{children}</div> },
|
|
76
|
+
MapView: { component: ({ children }) => <div>{children}</div> },
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
}));
|
|
80
|
+
jest.mock('@eeacms/volto-cca-policy/components', () => ({
|
|
81
|
+
CompareToolsPanel: () => null,
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
const appConfig = {
|
|
85
|
+
appName: 'navigatorCatalogueSearch',
|
|
86
|
+
defaultSort: 'title.index|asc',
|
|
87
|
+
resultViews: [
|
|
88
|
+
{ id: 'listing', factories: { view: 'ListingView' } },
|
|
89
|
+
{ id: 'map', factories: { view: 'MapView' } },
|
|
90
|
+
],
|
|
91
|
+
sortOptions: [
|
|
92
|
+
{ name: { id: 'Relevance' }, value: '', direction: '' },
|
|
93
|
+
{ name: { id: 'Title a-z' }, value: 'title.index', direction: 'asc' },
|
|
94
|
+
{ name: { id: 'Title z-a' }, value: 'title.index', direction: 'desc' },
|
|
95
|
+
],
|
|
96
|
+
showFilters: false,
|
|
97
|
+
showFacets: false,
|
|
98
|
+
showClusters: false,
|
|
99
|
+
showSorting: true,
|
|
100
|
+
showLandingPage: false,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const renderCatalogue = () =>
|
|
104
|
+
render(
|
|
105
|
+
<IntlProvider locale="en">
|
|
106
|
+
<NavigatorCatalogueContentView
|
|
107
|
+
appConfig={appConfig}
|
|
108
|
+
children={[]}
|
|
109
|
+
wasInteracted={true}
|
|
110
|
+
/>
|
|
111
|
+
</IntlProvider>,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
describe('NavigatorCatalogueContentView sorting', () => {
|
|
115
|
+
let driver;
|
|
116
|
+
let searchContext;
|
|
117
|
+
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
jest.clearAllMocks();
|
|
120
|
+
driver = { setSort: jest.fn() };
|
|
121
|
+
searchContext = {
|
|
122
|
+
searchTerm: '',
|
|
123
|
+
sortField: '',
|
|
124
|
+
sortDirection: '',
|
|
125
|
+
totalResults: 0,
|
|
126
|
+
wasSearched: false,
|
|
127
|
+
};
|
|
128
|
+
useSearchContext.mockImplementation(() => searchContext);
|
|
129
|
+
useSearchDriver.mockReturnValue(driver);
|
|
130
|
+
useViews.mockReturnValue({
|
|
131
|
+
activeViewId: 'listing',
|
|
132
|
+
setActiveViewId: jest.fn(),
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('starts with title A-Z when there is no active sort', () => {
|
|
137
|
+
renderCatalogue();
|
|
138
|
+
|
|
139
|
+
expect(driver.setSort).toHaveBeenCalledWith('title.index', 'asc');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('preserves an active relevance sort', () => {
|
|
143
|
+
searchContext = {
|
|
144
|
+
...searchContext,
|
|
145
|
+
searchTerm: 'climate adaptation',
|
|
146
|
+
sortField: '',
|
|
147
|
+
sortDirection: '',
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
renderCatalogue();
|
|
151
|
+
|
|
152
|
+
expect(driver.setSort).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('restores title A-Z when the keyword is cleared', () => {
|
|
156
|
+
searchContext = {
|
|
157
|
+
...searchContext,
|
|
158
|
+
searchTerm: 'climate adaptation',
|
|
159
|
+
sortField: '',
|
|
160
|
+
sortDirection: '',
|
|
161
|
+
};
|
|
162
|
+
const { rerender } = renderCatalogue();
|
|
163
|
+
driver.setSort.mockClear();
|
|
164
|
+
|
|
165
|
+
searchContext = {
|
|
166
|
+
...searchContext,
|
|
167
|
+
searchTerm: '',
|
|
168
|
+
sortField: '',
|
|
169
|
+
sortDirection: '',
|
|
170
|
+
};
|
|
171
|
+
rerender(
|
|
172
|
+
<IntlProvider locale="en">
|
|
173
|
+
<NavigatorCatalogueContentView
|
|
174
|
+
appConfig={appConfig}
|
|
175
|
+
children={[]}
|
|
176
|
+
wasInteracted={true}
|
|
177
|
+
/>
|
|
178
|
+
</IntlProvider>,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(driver.setSort).toHaveBeenCalledWith('title.index', 'asc');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('applies the selected sorting option', () => {
|
|
185
|
+
renderCatalogue();
|
|
186
|
+
driver.setSort.mockClear();
|
|
187
|
+
|
|
188
|
+
fireEvent.change(screen.getByRole('combobox', { name: 'Sort results' }), {
|
|
189
|
+
target: { value: 'title.index|||desc' },
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(driver.setSort).toHaveBeenCalledWith('title.index', 'desc');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
@@ -11,11 +11,6 @@ export const TRANSNATIONAL_REGION_FIELD =
|
|
|
11
11
|
export const COUNTRIES_FIELD = 'cca_geographic_countries.keyword';
|
|
12
12
|
|
|
13
13
|
const messages = defineMessages({
|
|
14
|
-
transnationalRegions: {
|
|
15
|
-
id: 'Macro-Transnational region',
|
|
16
|
-
defaultMessage: 'Macro-Transnational region',
|
|
17
|
-
},
|
|
18
|
-
countries: { id: 'Countries', defaultMessage: 'Countries' },
|
|
19
14
|
noOptionsAvailable: {
|
|
20
15
|
id: 'No options available',
|
|
21
16
|
defaultMessage: 'No options available',
|
|
@@ -187,9 +182,11 @@ const NavigatorActiveFilters = ({ filters, onRemove }) => {
|
|
|
187
182
|
|
|
188
183
|
const NavigatorGeographicCoverageFacet = ({
|
|
189
184
|
className = '',
|
|
185
|
+
countriesLabel,
|
|
190
186
|
onRemove,
|
|
191
187
|
onSelect,
|
|
192
188
|
options = [],
|
|
189
|
+
transnationalRegionsLabel,
|
|
193
190
|
}) => {
|
|
194
191
|
const intl = useIntl();
|
|
195
192
|
const { addFilter, facets, filters = [], removeFilter } = useSearchContext();
|
|
@@ -226,7 +223,7 @@ const NavigatorGeographicCoverageFacet = ({
|
|
|
226
223
|
<ExpandableFacetGroup
|
|
227
224
|
field={COUNTRIES_FIELD}
|
|
228
225
|
id="navigator-geographic-countries"
|
|
229
|
-
label={intl.formatMessage(
|
|
226
|
+
label={intl.formatMessage(countriesLabel)}
|
|
230
227
|
emptyMessage={intl.formatMessage(messages.noOptionsAvailable)}
|
|
231
228
|
options={countryOptions}
|
|
232
229
|
onChange={(option) => updateChildFilter(COUNTRIES_FIELD, option)}
|
|
@@ -234,7 +231,7 @@ const NavigatorGeographicCoverageFacet = ({
|
|
|
234
231
|
<ExpandableFacetGroup
|
|
235
232
|
field={TRANSNATIONAL_REGION_FIELD}
|
|
236
233
|
id="navigator-geographic-transnational-regions"
|
|
237
|
-
label={intl.formatMessage(
|
|
234
|
+
label={intl.formatMessage(transnationalRegionsLabel)}
|
|
238
235
|
emptyMessage={intl.formatMessage(messages.noOptionsAvailable)}
|
|
239
236
|
options={transnationalOptions}
|
|
240
237
|
onChange={(option) =>
|
|
@@ -50,8 +50,13 @@ const renderFacet = ({
|
|
|
50
50
|
render(
|
|
51
51
|
<IntlProvider locale="en">
|
|
52
52
|
<NavigatorGeographicCoverageFacet
|
|
53
|
+
countriesLabel={{ id: 'Countries', defaultMessage: 'Countries' }}
|
|
53
54
|
onRemove={onRemove}
|
|
54
55
|
onSelect={onSelect}
|
|
56
|
+
transnationalRegionsLabel={{
|
|
57
|
+
id: 'Transnational regions',
|
|
58
|
+
defaultMessage: 'Transnational regions',
|
|
59
|
+
}}
|
|
55
60
|
options={[
|
|
56
61
|
{ value: 'Global', count: 5, selected: false },
|
|
57
62
|
{ value: 'Europe', count: 8, selected: false },
|
|
@@ -89,7 +94,7 @@ describe('NavigatorGeographicCoverageFacet', () => {
|
|
|
89
94
|
const { addFilter } = renderFacet();
|
|
90
95
|
|
|
91
96
|
fireEvent.click(
|
|
92
|
-
screen.getByRole('button', { name: '
|
|
97
|
+
screen.getByRole('button', { name: 'Transnational regions' }),
|
|
93
98
|
);
|
|
94
99
|
fireEvent.click(screen.getByLabelText('Outermost regions'));
|
|
95
100
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Popup } from 'semantic-ui-react';
|
|
2
2
|
|
|
3
|
-
const TagOverflowPopup = ({ items, className, ariaLabel }) => {
|
|
3
|
+
const TagOverflowPopup = ({ items, className, ariaLabel, title }) => {
|
|
4
4
|
if (!items.length) return null;
|
|
5
5
|
|
|
6
6
|
return (
|
|
@@ -17,7 +17,12 @@ const TagOverflowPopup = ({ items, className, ariaLabel }) => {
|
|
|
17
17
|
}
|
|
18
18
|
position="bottom left"
|
|
19
19
|
trigger={
|
|
20
|
-
<button
|
|
20
|
+
<button
|
|
21
|
+
type="button"
|
|
22
|
+
className={className}
|
|
23
|
+
aria-label={ariaLabel}
|
|
24
|
+
title={title}
|
|
25
|
+
>
|
|
21
26
|
+ {items.length}
|
|
22
27
|
</button>
|
|
23
28
|
}
|
package/src/search/cca/config.js
CHANGED
|
@@ -16,7 +16,18 @@ const ccaConfig = {
|
|
|
16
16
|
*/
|
|
17
17
|
export const clusters = {
|
|
18
18
|
name: 'op_cluster',
|
|
19
|
-
clusters: [
|
|
19
|
+
clusters: [
|
|
20
|
+
{
|
|
21
|
+
name: 'Climate-ADAPT',
|
|
22
|
+
icon: { name: 'file text' },
|
|
23
|
+
values: ['climate'],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'Health Observatory',
|
|
27
|
+
icon: { name: 'compass' },
|
|
28
|
+
values: ['observatory'],
|
|
29
|
+
},
|
|
30
|
+
].map((cluster) => ({
|
|
20
31
|
...cluster,
|
|
21
32
|
defaultResultView: 'ClusterHorizontalCardItem',
|
|
22
33
|
})),
|
|
@@ -12,8 +12,8 @@ const messages = defineMessages({
|
|
|
12
12
|
defaultMessage: 'Geographic coverage',
|
|
13
13
|
},
|
|
14
14
|
macroTransnationalRegion: {
|
|
15
|
-
id: '
|
|
16
|
-
defaultMessage: '
|
|
15
|
+
id: 'Transnational regions',
|
|
16
|
+
defaultMessage: 'Transnational regions',
|
|
17
17
|
},
|
|
18
18
|
climateHazards: {
|
|
19
19
|
id: 'Climate hazards',
|
|
@@ -73,6 +73,8 @@ const facets = [
|
|
|
73
73
|
isFilterable: false,
|
|
74
74
|
isMulti: true,
|
|
75
75
|
label: messages.geographicCoverage,
|
|
76
|
+
transnationalRegionsLabel: messages.macroTransnationalRegion,
|
|
77
|
+
countriesLabel: geographic_countries.label,
|
|
76
78
|
hideActiveFilters: true,
|
|
77
79
|
alwaysVisible: true,
|
|
78
80
|
}),
|
package/src/utils.test.js
CHANGED
|
@@ -106,6 +106,36 @@ describe('general utilities', () => {
|
|
|
106
106
|
expect(result.hasMatches).toBe(true);
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
+
it('returns no parent blocks when all are excluded or content is empty', () => {
|
|
110
|
+
expect(
|
|
111
|
+
getFilteredBlocks(
|
|
112
|
+
{
|
|
113
|
+
blocks: {
|
|
114
|
+
excluded: {
|
|
115
|
+
'@type': 'group',
|
|
116
|
+
blocks: { child: { '@type': 'map' } },
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
blocks_layout: { items: ['excluded', 'stale'] },
|
|
120
|
+
},
|
|
121
|
+
'group',
|
|
122
|
+
'map',
|
|
123
|
+
),
|
|
124
|
+
).toEqual({
|
|
125
|
+
blocks: {},
|
|
126
|
+
blocks_layout: { items: [] },
|
|
127
|
+
keptKeys: [],
|
|
128
|
+
hasMatches: false,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(getFilteredBlocks({}, 'group', 'map')).toEqual({
|
|
132
|
+
blocks: {},
|
|
133
|
+
blocks_layout: { items: [] },
|
|
134
|
+
keptKeys: [],
|
|
135
|
+
hasMatches: false,
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
109
139
|
it('extracts plan links and normalizes common values', () => {
|
|
110
140
|
expect(extractPlanNameAndURL()).toEqual({ name: '', url: '' });
|
|
111
141
|
expect(
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
width: 100%;
|
|
130
130
|
align-items: center;
|
|
131
131
|
justify-content: space-between;
|
|
132
|
-
padding: 0.65em 0.
|
|
132
|
+
padding: 0.65em 0.7em;
|
|
133
133
|
border: 0;
|
|
134
134
|
background: transparent;
|
|
135
135
|
color: inherit;
|
|
@@ -879,6 +879,7 @@ body.searchlib-page .searchapp-navigatorCatalogueSearch {
|
|
|
879
879
|
padding: 0 0.45rem;
|
|
880
880
|
font-weight: 500;
|
|
881
881
|
font-size: 12px;
|
|
882
|
+
cursor: default;
|
|
882
883
|
|
|
883
884
|
&.sector,
|
|
884
885
|
&.more {
|