@eeacms/volto-cca-policy 1.0.27 → 1.0.29

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +157 -1
  2. package/locales/bg/LC_MESSAGES/volto.po +10 -0
  3. package/locales/cs/LC_MESSAGES/volto.po +10 -0
  4. package/locales/da/LC_MESSAGES/volto.po +10 -0
  5. package/locales/de/LC_MESSAGES/volto.po +10 -0
  6. package/locales/el/LC_MESSAGES/volto.po +10 -0
  7. package/locales/en/LC_MESSAGES/volto.po +10 -0
  8. package/locales/es/LC_MESSAGES/volto.po +10 -0
  9. package/locales/et/LC_MESSAGES/volto.po +10 -0
  10. package/locales/fi/LC_MESSAGES/volto.po +10 -0
  11. package/locales/fr/LC_MESSAGES/volto.po +10 -0
  12. package/locales/ga/LC_MESSAGES/volto.po +10 -0
  13. package/locales/hr/LC_MESSAGES/volto.po +10 -0
  14. package/locales/hu/LC_MESSAGES/volto.po +10 -0
  15. package/locales/is/LC_MESSAGES/volto.po +10 -0
  16. package/locales/it/LC_MESSAGES/volto.po +10 -0
  17. package/locales/lt/LC_MESSAGES/volto.po +10 -0
  18. package/locales/lv/LC_MESSAGES/volto.po +10 -0
  19. package/locales/mt/LC_MESSAGES/volto.po +10 -0
  20. package/locales/nl/LC_MESSAGES/volto.po +10 -0
  21. package/locales/nn/LC_MESSAGES/volto.po +10 -0
  22. package/locales/pl/LC_MESSAGES/volto.po +10 -0
  23. package/locales/pt/LC_MESSAGES/volto.po +10 -0
  24. package/locales/ro/LC_MESSAGES/volto.po +10 -0
  25. package/locales/sk/LC_MESSAGES/volto.po +10 -0
  26. package/locales/sl/LC_MESSAGES/volto.po +10 -0
  27. package/locales/sv/LC_MESSAGES/volto.po +10 -0
  28. package/locales/tr/LC_MESSAGES/volto.po +10 -0
  29. package/locales/volto.pot +11 -1
  30. package/package.json +1 -1
  31. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueContentView.jsx +26 -1
  32. package/src/components/Search/NavigatorCatalogue/NavigatorGeographicCoverageFacet.jsx +252 -0
  33. package/src/components/Search/NavigatorCatalogue/NavigatorGeographicCoverageFacet.test.jsx +122 -0
  34. package/src/index.js +5 -0
  35. package/src/search/navigator_catalogue/facets.js +30 -1
  36. package/theme/globals/navigator.less +59 -0
@@ -1738,7 +1738,17 @@ msgstr ""
1738
1738
  msgid "{count, plural, =0 {No tools available} one {# tool available} other {# tools available}}"
1739
1739
  msgstr ""
1740
1740
 
1741
+ #. Default: "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1742
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1743
+ msgid "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1744
+ msgstr ""
1745
+
1741
1746
  #. Default: "{count, plural, one {tool matches} other {tools match}}"
1742
1747
  #: components/Search/NavigatorGuide/NavigatorGuideContentView
1743
1748
  msgid "{count, plural, one {tool matches} other {tools match}}"
1744
1749
  msgstr ""
1750
+
1751
+ #. Default: "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1752
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1753
+ msgid "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1754
+ msgstr ""
@@ -1738,7 +1738,17 @@ msgstr ""
1738
1738
  msgid "{count, plural, =0 {No tools available} one {# tool available} other {# tools available}}"
1739
1739
  msgstr ""
1740
1740
 
1741
+ #. Default: "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1742
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1743
+ msgid "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1744
+ msgstr ""
1745
+
1741
1746
  #. Default: "{count, plural, one {tool matches} other {tools match}}"
1742
1747
  #: components/Search/NavigatorGuide/NavigatorGuideContentView
1743
1748
  msgid "{count, plural, one {tool matches} other {tools match}}"
1744
1749
  msgstr ""
1750
+
1751
+ #. Default: "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1752
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1753
+ msgid "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1754
+ msgstr ""
@@ -1738,7 +1738,17 @@ msgstr ""
1738
1738
  msgid "{count, plural, =0 {No tools available} one {# tool available} other {# tools available}}"
1739
1739
  msgstr ""
1740
1740
 
1741
+ #. Default: "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1742
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1743
+ msgid "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1744
+ msgstr ""
1745
+
1741
1746
  #. Default: "{count, plural, one {tool matches} other {tools match}}"
1742
1747
  #: components/Search/NavigatorGuide/NavigatorGuideContentView
1743
1748
  msgid "{count, plural, one {tool matches} other {tools match}}"
1744
1749
  msgstr ""
1750
+
1751
+ #. Default: "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1752
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1753
+ msgid "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1754
+ msgstr ""
@@ -1738,7 +1738,17 @@ msgstr ""
1738
1738
  msgid "{count, plural, =0 {No tools available} one {# tool available} other {# tools available}}"
1739
1739
  msgstr ""
1740
1740
 
1741
+ #. Default: "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1742
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1743
+ msgid "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1744
+ msgstr ""
1745
+
1741
1746
  #. Default: "{count, plural, one {tool matches} other {tools match}}"
1742
1747
  #: components/Search/NavigatorGuide/NavigatorGuideContentView
1743
1748
  msgid "{count, plural, one {tool matches} other {tools match}}"
1744
1749
  msgstr ""
1750
+
1751
+ #. Default: "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1752
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1753
+ msgid "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1754
+ msgstr ""
@@ -1738,7 +1738,17 @@ msgstr ""
1738
1738
  msgid "{count, plural, =0 {No tools available} one {# tool available} other {# tools available}}"
1739
1739
  msgstr ""
1740
1740
 
1741
+ #. Default: "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1742
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1743
+ msgid "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1744
+ msgstr ""
1745
+
1741
1746
  #. Default: "{count, plural, one {tool matches} other {tools match}}"
1742
1747
  #: components/Search/NavigatorGuide/NavigatorGuideContentView
1743
1748
  msgid "{count, plural, one {tool matches} other {tools match}}"
1744
1749
  msgstr ""
1750
+
1751
+ #. Default: "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1752
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1753
+ msgid "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1754
+ msgstr ""
package/locales/volto.pot CHANGED
@@ -1,7 +1,7 @@
1
1
  msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Plone\n"
4
- "POT-Creation-Date: 2026-09-17T11:25:27.854Z\n"
4
+ "POT-Creation-Date: 2026-09-22T11:58:59.754Z\n"
5
5
  "Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
6
6
  "Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
7
7
  "Content-Type: text/plain; charset=utf-8\n"
@@ -1740,7 +1740,17 @@ msgstr ""
1740
1740
  msgid "{count, plural, =0 {No tools available} one {# tool available} other {# tools available}}"
1741
1741
  msgstr ""
1742
1742
 
1743
+ #. Default: "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1744
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1745
+ msgid "{count, plural, one {tool in the catalogue} other {tools in the catalogue}}"
1746
+ msgstr ""
1747
+
1743
1748
  #. Default: "{count, plural, one {tool matches} other {tools match}}"
1744
1749
  #: components/Search/NavigatorGuide/NavigatorGuideContentView
1745
1750
  msgid "{count, plural, one {tool matches} other {tools match}}"
1746
1751
  msgstr ""
1752
+
1753
+ #. Default: "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1754
+ #: components/Search/NavigatorCatalogue/NavigatorCatalogueContentView
1755
+ msgid "{count, plural, one {tool matches} other {tools match}} \"{searchTerm}\""
1756
+ msgstr ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "1.0.27",
3
+ "version": "1.0.29",
4
4
  "description": "@eeacms/volto-cca-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -55,6 +55,16 @@ const messages = defineMessages({
55
55
  id: 'Active filters are always shown in edit mode',
56
56
  defaultMessage: 'Active filters are always shown in edit mode',
57
57
  },
58
+ toolsCount: {
59
+ id: '{count, plural, one {tool in the catalogue} other {tools in the catalogue}}',
60
+ defaultMessage:
61
+ '{count, plural, one {tool in the catalogue} other {tools in the catalogue}}',
62
+ },
63
+ toolsMatchSearch: {
64
+ id: '{count, plural, one {tool matches} other {tools match}} "{searchTerm}"',
65
+ defaultMessage:
66
+ '{count, plural, one {tool matches} other {tools match}} "{searchTerm}"',
67
+ },
58
68
  });
59
69
 
60
70
  const NavigatorCatalogueContentView = (props) => {
@@ -90,7 +100,7 @@ const NavigatorCatalogueContentView = (props) => {
90
100
  const layoutMode =
91
101
  activeNavigatorViewId === 'listing' ? 'fixed' : 'fullwidth';
92
102
 
93
- const { wasSearched } = searchContext;
103
+ const { searchTerm, totalResults, wasSearched } = searchContext;
94
104
 
95
105
  const loadingAtom = loadingFamily(appConfig.appName);
96
106
  const isLoading = useAtomValue(loadingAtom);
@@ -117,6 +127,21 @@ const NavigatorCatalogueContentView = (props) => {
117
127
  {showClusters && <SectionTabs />}
118
128
 
119
129
  <div className={`results-layout ${layoutMode}`}>
130
+ {children.length > 0 && (
131
+ <div className="navigator-catalogue-result-count">
132
+ <span className="navigator-catalogue-result-count-value">
133
+ {totalResults || 0}
134
+ </span>{' '}
135
+ {intl.formatMessage(
136
+ searchTerm ? messages.toolsMatchSearch : messages.toolsCount,
137
+ {
138
+ count: totalResults || 0,
139
+ searchTerm,
140
+ },
141
+ )}
142
+ </div>
143
+ )}
144
+
120
145
  <div className="navigator-catalogue-above-results">
121
146
  <Menu pointing secondary className="navigator-view-tabs">
122
147
  {navigatorResultViews.map((view) => (
@@ -0,0 +1,252 @@
1
+ import React from 'react';
2
+ import { Button, Card, Icon } from 'semantic-ui-react';
3
+ import { defineMessages, useIntl } from 'react-intl';
4
+ import { Term } from '@eeacms/search/components';
5
+ import { useSearchContext } from '@eeacms/search/lib/hocs';
6
+ import { markSelectedFacetValuesFromFilters } from '@eeacms/search/lib/search/helpers';
7
+
8
+ export const CHARACTERISATION_FIELD = 'cca_geographic_characterisation.keyword';
9
+ export const TRANSNATIONAL_REGION_FIELD =
10
+ 'cca_geographic_transnational_region.keyword';
11
+ export const COUNTRIES_FIELD = 'cca_geographic_countries.keyword';
12
+
13
+ const messages = defineMessages({
14
+ transnationalRegions: {
15
+ id: 'Macro-Transnational region',
16
+ defaultMessage: 'Macro-Transnational region',
17
+ },
18
+ countries: { id: 'Countries', defaultMessage: 'Countries' },
19
+ noOptionsAvailable: {
20
+ id: 'No options available',
21
+ defaultMessage: 'No options available',
22
+ },
23
+ });
24
+
25
+ const valueAsText = (value) =>
26
+ value && typeof value === 'object' && value.name
27
+ ? value.name
28
+ : String(value ?? '');
29
+
30
+ export const getFacetOptions = (facets, filters, field) => {
31
+ const facetValue = facets?.[field];
32
+ const facet = Array.isArray(facetValue) ? facetValue[0] : facetValue;
33
+
34
+ return facet?.data
35
+ ? markSelectedFacetValuesFromFilters(facet, filters || [], field, 'any')
36
+ .data
37
+ : [];
38
+ };
39
+
40
+ const FacetOption = ({ field, option, onChange }) => {
41
+ const intl = useIntl();
42
+ const value = valueAsText(option.value);
43
+ const inputId = `navigator-geographic-${field}-${value}`.replace(
44
+ /[^a-zA-Z0-9_-]/g,
45
+ '-',
46
+ );
47
+
48
+ return (
49
+ <label htmlFor={inputId} className="sui-multi-checkbox-facet__option-label">
50
+ <span className="sui-multi-checkbox-facet__option-input-wrapper">
51
+ <input
52
+ id={inputId}
53
+ type="checkbox"
54
+ aria-label={value}
55
+ className="sui-multi-checkbox-facet__checkbox"
56
+ checked={Boolean(option.selected)}
57
+ onChange={() => onChange(option)}
58
+ />
59
+ <span className="checkmark" />
60
+ <span className="sui-multi-checkbox-facet__input-text">
61
+ <Term
62
+ term={intl.formatMessage({
63
+ id: value || 'no-id',
64
+ defaultMessage: value,
65
+ })}
66
+ field={field}
67
+ />
68
+ </span>
69
+ </span>
70
+ <span className="sui-multi-checkbox-facet__option-count">
71
+ ({Number(option.count || 0).toLocaleString('en')})
72
+ </span>
73
+ </label>
74
+ );
75
+ };
76
+
77
+ const ExpandableFacetGroup = ({
78
+ field,
79
+ id,
80
+ label,
81
+ options,
82
+ emptyMessage,
83
+ onChange,
84
+ }) => {
85
+ const hasSelection = options.some(({ selected }) => selected);
86
+ const [isOpen, setIsOpen] = React.useState(hasSelection);
87
+
88
+ React.useEffect(() => {
89
+ if (hasSelection) setIsOpen(true);
90
+ }, [hasSelection]);
91
+
92
+ return (
93
+ <div className="navigator-geographic-facet-group">
94
+ <button
95
+ type="button"
96
+ className={`navigator-geographic-facet-group-toggle${
97
+ isOpen ? ' active' : ''
98
+ }`}
99
+ aria-expanded={isOpen}
100
+ aria-controls={id}
101
+ onClick={() => setIsOpen((current) => !current)}
102
+ >
103
+ <span>{label}</span>
104
+ <Icon name={isOpen ? 'chevron up' : 'chevron down'} />
105
+ </button>
106
+ {isOpen &&
107
+ (options.length > 0 ? (
108
+ <div id={id} className="sui-multi-checkbox-facet">
109
+ {options.map((option) => (
110
+ <FacetOption
111
+ key={valueAsText(option.value)}
112
+ field={field}
113
+ option={option}
114
+ onChange={onChange}
115
+ />
116
+ ))}
117
+ </div>
118
+ ) : (
119
+ <div id={id} className="navigator-geographic-facet-empty">
120
+ {emptyMessage}.
121
+ </div>
122
+ ))}
123
+ </div>
124
+ );
125
+ };
126
+
127
+ const NavigatorActiveFilters = ({ filters, onRemove }) => {
128
+ const intl = useIntl();
129
+ const geographicFields = [
130
+ CHARACTERISATION_FIELD,
131
+ TRANSNATIONAL_REGION_FIELD,
132
+ COUNTRIES_FIELD,
133
+ ];
134
+ const activeFilters = filters.filter(
135
+ ({ field, values }) =>
136
+ geographicFields.includes(field) && values?.length > 0,
137
+ );
138
+
139
+ if (!activeFilters.length) return null;
140
+
141
+ return (
142
+ <div className="active-filters">
143
+ <h5>Active filters:</h5>
144
+ <div className="facets-wrapper">
145
+ {activeFilters.flatMap(({ field, values, type }) =>
146
+ values.map((value, index) => (
147
+ <Card key={`${field}-${index}`} className="term active-term">
148
+ <Card.Content>
149
+ <Card.Header className="card-header">
150
+ <Term
151
+ term={intl.formatMessage({
152
+ id: value,
153
+ defaultMessage: value,
154
+ })}
155
+ field={field}
156
+ />
157
+ <Button
158
+ className="clear-filters"
159
+ onClick={() => onRemove(field, value, type)}
160
+ onKeyDown={(event) => {
161
+ if (event.key === 'Enter') {
162
+ onRemove(field, value, type);
163
+ }
164
+ }}
165
+ >
166
+ <Icon name="close" role="button" />
167
+ </Button>
168
+ </Card.Header>
169
+ </Card.Content>
170
+ </Card>
171
+ )),
172
+ )}
173
+ </div>
174
+ <Button
175
+ size="mini"
176
+ className="clear-btn"
177
+ content="Clear all"
178
+ onClick={() =>
179
+ activeFilters.forEach(({ field, values, type }) =>
180
+ values.forEach((value) => onRemove(field, value, type)),
181
+ )
182
+ }
183
+ />
184
+ </div>
185
+ );
186
+ };
187
+
188
+ const NavigatorGeographicCoverageFacet = ({
189
+ className = '',
190
+ onRemove,
191
+ onSelect,
192
+ options = [],
193
+ }) => {
194
+ const intl = useIntl();
195
+ const { addFilter, facets, filters = [], removeFilter } = useSearchContext();
196
+ const transnationalOptions = getFacetOptions(
197
+ facets,
198
+ filters,
199
+ TRANSNATIONAL_REGION_FIELD,
200
+ );
201
+ const countryOptions = getFacetOptions(facets, filters, COUNTRIES_FIELD);
202
+
203
+ const updateChildFilter = (field, option) =>
204
+ option.selected
205
+ ? removeFilter(field, option.value, 'any')
206
+ : addFilter(field, option.value, 'any');
207
+
208
+ return (
209
+ <fieldset
210
+ className={`sui-facet searchlib-multiterm-facet navigator-geographic-facet ${className}`}
211
+ >
212
+ <div className="sui-multi-checkbox-facet navigator-geographic-facet-direct-options">
213
+ {options.map((option) => (
214
+ <FacetOption
215
+ key={valueAsText(option.value)}
216
+ field={CHARACTERISATION_FIELD}
217
+ option={option}
218
+ onChange={(selectedOption) =>
219
+ selectedOption.selected
220
+ ? onRemove(selectedOption.value)
221
+ : onSelect(selectedOption.value)
222
+ }
223
+ />
224
+ ))}
225
+ </div>
226
+ <ExpandableFacetGroup
227
+ field={TRANSNATIONAL_REGION_FIELD}
228
+ id="navigator-geographic-transnational-regions"
229
+ label={intl.formatMessage(messages.transnationalRegions)}
230
+ emptyMessage={intl.formatMessage(messages.noOptionsAvailable)}
231
+ options={transnationalOptions}
232
+ onChange={(option) =>
233
+ updateChildFilter(TRANSNATIONAL_REGION_FIELD, option)
234
+ }
235
+ />
236
+ <ExpandableFacetGroup
237
+ field={COUNTRIES_FIELD}
238
+ id="navigator-geographic-countries"
239
+ label={intl.formatMessage(messages.countries)}
240
+ emptyMessage={intl.formatMessage(messages.noOptionsAvailable)}
241
+ options={countryOptions}
242
+ onChange={(option) => updateChildFilter(COUNTRIES_FIELD, option)}
243
+ />
244
+ <NavigatorActiveFilters
245
+ filters={filters}
246
+ onRemove={(field, value, type) => removeFilter(field, value, type)}
247
+ />
248
+ </fieldset>
249
+ );
250
+ };
251
+
252
+ export default NavigatorGeographicCoverageFacet;
@@ -0,0 +1,122 @@
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 { useSearchContext } from '@eeacms/search/lib/hocs';
6
+ import NavigatorGeographicCoverageFacet, {
7
+ COUNTRIES_FIELD,
8
+ TRANSNATIONAL_REGION_FIELD,
9
+ } from './NavigatorGeographicCoverageFacet';
10
+
11
+ jest.mock('@eeacms/search/components', () => ({
12
+ Term: ({ term }) => <>{term}</>,
13
+ }));
14
+ jest.mock('@eeacms/search/lib/hocs', () => ({
15
+ useSearchContext: jest.fn(),
16
+ }));
17
+
18
+ const renderFacet = ({
19
+ filters = [],
20
+ onRemove = jest.fn(),
21
+ onSelect = jest.fn(),
22
+ } = {}) => {
23
+ const addFilter = jest.fn();
24
+ const removeFilter = jest.fn();
25
+
26
+ useSearchContext.mockReturnValue({
27
+ addFilter,
28
+ removeFilter,
29
+ filters,
30
+ facets: {
31
+ [TRANSNATIONAL_REGION_FIELD]: [
32
+ {
33
+ data: [
34
+ { value: 'Alpine Space', count: 3 },
35
+ { value: 'Outermost regions', count: 2 },
36
+ ],
37
+ },
38
+ ],
39
+ [COUNTRIES_FIELD]: [
40
+ {
41
+ data: [
42
+ { value: 'Germany', count: 4 },
43
+ { value: 'Spain', count: 2 },
44
+ ],
45
+ },
46
+ ],
47
+ },
48
+ });
49
+
50
+ render(
51
+ <IntlProvider locale="en">
52
+ <NavigatorGeographicCoverageFacet
53
+ onRemove={onRemove}
54
+ onSelect={onSelect}
55
+ options={[
56
+ { value: 'Global', count: 5, selected: false },
57
+ { value: 'Europe', count: 8, selected: false },
58
+ {
59
+ value: 'Macro-Transnational region',
60
+ count: 4,
61
+ selected: false,
62
+ },
63
+ { value: 'Countries', count: 6, selected: false },
64
+ ]}
65
+ />
66
+ </IntlProvider>,
67
+ );
68
+
69
+ return { addFilter, onRemove, onSelect, removeFilter };
70
+ };
71
+
72
+ describe('NavigatorGeographicCoverageFacet', () => {
73
+ beforeEach(() => {
74
+ jest.clearAllMocks();
75
+ });
76
+
77
+ it('shows Globe and Europe as direct options and filters by the raw value', () => {
78
+ const { onSelect } = renderFacet();
79
+
80
+ expect(screen.getByText('Global')).toBeInTheDocument();
81
+ expect(screen.getByText('Europe')).toBeInTheDocument();
82
+
83
+ fireEvent.click(screen.getByLabelText('Global'));
84
+
85
+ expect(onSelect).toHaveBeenCalledWith('Global');
86
+ });
87
+
88
+ it('expands and filters Macro-Transnational region values', () => {
89
+ const { addFilter } = renderFacet();
90
+
91
+ fireEvent.click(
92
+ screen.getByRole('button', { name: 'Macro-Transnational region' }),
93
+ );
94
+ fireEvent.click(screen.getByLabelText('Outermost regions'));
95
+
96
+ expect(addFilter).toHaveBeenCalledWith(
97
+ TRANSNATIONAL_REGION_FIELD,
98
+ 'Outermost regions',
99
+ 'any',
100
+ );
101
+ });
102
+
103
+ it('opens Countries when it contains an active selection and removes it', () => {
104
+ const { removeFilter } = renderFacet({
105
+ filters: [
106
+ {
107
+ field: COUNTRIES_FIELD,
108
+ values: ['Germany'],
109
+ type: 'any',
110
+ },
111
+ ],
112
+ });
113
+
114
+ fireEvent.click(screen.getByLabelText('Germany'));
115
+
116
+ expect(removeFilter).toHaveBeenCalledWith(
117
+ COUNTRIES_FIELD,
118
+ 'Germany',
119
+ 'any',
120
+ );
121
+ });
122
+ });
package/src/index.js CHANGED
@@ -54,6 +54,7 @@ import ClusterHorizontalCardItem from './components/Search/Result/ClusterHorizon
54
54
  import NavigatorCatalogueCardItem from './components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem';
55
55
  import NavigatorCatalogueMapView from './components/Search/NavigatorCatalogue/NavigatorCatalogueMapView';
56
56
  import NavigatorCatalogueContentView from './components/Search/NavigatorCatalogue/NavigatorCatalogueContentView';
57
+ import NavigatorGeographicCoverageFacet from './components/Search/NavigatorCatalogue/NavigatorGeographicCoverageFacet';
57
58
  import NavigatorGuideLayout from './components/Search/NavigatorGuide/NavigatorGuideLayout';
58
59
  import NavigatorGuideContentView from './components/Search/NavigatorGuide/NavigatorGuideContentView';
59
60
 
@@ -434,6 +435,10 @@ const applyConfig = (config) => {
434
435
  config.settings.searchlib.resolve.NavigatorCatalogueContentView = {
435
436
  component: NavigatorCatalogueContentView,
436
437
  };
438
+ config.settings.searchlib.resolve.NavigatorGeographicCoverageFacet = {
439
+ ...config.settings.searchlib.resolve.MultiTermFacet,
440
+ component: NavigatorGeographicCoverageFacet,
441
+ };
437
442
  config.settings.searchlib.resolve.NavigatorGuideLayout = {
438
443
  component: NavigatorGuideLayout,
439
444
  };
@@ -7,6 +7,14 @@ import {
7
7
  } from './../common';
8
8
 
9
9
  const messages = defineMessages({
10
+ geographicCoverage: {
11
+ id: 'Geographic coverage',
12
+ defaultMessage: 'Geographic coverage',
13
+ },
14
+ macroTransnationalRegion: {
15
+ id: 'Macro-Transnational region',
16
+ defaultMessage: 'Macro-Transnational region',
17
+ },
10
18
  climateHazards: {
11
19
  id: 'Climate hazards',
12
20
  defaultMessage: 'Climate hazards',
@@ -59,7 +67,28 @@ const facets = [
59
67
  label: messages.implementationLevel,
60
68
  alwaysVisible: false,
61
69
  }),
62
- geographic_countries,
70
+ multiTermFacet({
71
+ field: 'cca_geographic_characterisation.keyword',
72
+ factory: 'NavigatorGeographicCoverageFacet',
73
+ isFilterable: false,
74
+ isMulti: true,
75
+ label: messages.geographicCoverage,
76
+ hideActiveFilters: true,
77
+ alwaysVisible: true,
78
+ }),
79
+ multiTermFacet({
80
+ field: 'cca_geographic_transnational_region.keyword',
81
+ isFilterable: false,
82
+ isFilter: true,
83
+ isMulti: true,
84
+ label: messages.macroTransnationalRegion,
85
+ showInFacetsList: true,
86
+ }),
87
+ {
88
+ ...geographic_countries,
89
+ isFilter: true,
90
+ showInFacetsList: true,
91
+ },
63
92
  multiTermFacet({
64
93
  field: 'cca_adaptation_support_cycle_step.keyword',
65
94
  isFilterable: false,
@@ -107,6 +107,65 @@
107
107
  }
108
108
  }
109
109
 
110
+ .navigator-catalogue-result-count {
111
+ margin-bottom: 1em;
112
+ font-weight: 700;
113
+ font-size: 1.5rem;
114
+
115
+ .navigator-catalogue-result-count-value {
116
+ color: @primaryColor;
117
+ }
118
+ }
119
+
120
+ .navigator-geographic-facet {
121
+ min-width: 18rem;
122
+
123
+ .navigator-geographic-facet-group {
124
+ border-top: 1px solid @navigatorBorderColor;
125
+ }
126
+
127
+ .navigator-geographic-facet-group-toggle {
128
+ display: flex;
129
+ width: 100%;
130
+ align-items: center;
131
+ justify-content: space-between;
132
+ padding: 0.65em 0.5em;
133
+ border: 0;
134
+ background: transparent;
135
+ color: inherit;
136
+ cursor: pointer;
137
+ font-family: inherit;
138
+ font-size: 14px;
139
+ font-weight: 500;
140
+ text-align: left;
141
+
142
+ &.active {
143
+ background: @navigatorCriteriaBackgroundColor;
144
+ }
145
+
146
+ i.icon {
147
+ width: auto;
148
+ height: auto;
149
+ margin: 0 0 0 1rem;
150
+ }
151
+ }
152
+
153
+ #navigator-geographic-countries {
154
+ column-count: 2;
155
+ column-gap: 1rem;
156
+ }
157
+
158
+ .sui-multi-checkbox-facet
159
+ .sui-multi-checkbox-facet__option-label:first-child {
160
+ margin-top: 0;
161
+ }
162
+ }
163
+
164
+ .navigator-geographic-facet-empty {
165
+ padding: 0.8em 0.5em;
166
+ font-size: 14px;
167
+ }
168
+
110
169
  .catalogue-compare-panel {
111
170
  position: fixed;
112
171
  z-index: 1000;