@eeacms/volto-cca-policy 0.2.68 → 0.2.70

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 (25) hide show
  1. package/CHANGELOG.md +38 -8
  2. package/package.json +1 -1
  3. package/src/components/Result/ClusterHorizontalCardItem.jsx +136 -0
  4. package/src/components/manage/Blocks/C3SIndicatorsGlossaryBlock/C3SIndicatorsGlossaryBlockView.test.jsx +34 -0
  5. package/src/components/manage/Blocks/C3SIndicatorsListingBlock/C3SIndicatorsListingBlockView.test.jsx +43 -0
  6. package/src/components/manage/Blocks/CaseStudyExplorer/CaseStudyExplorerEdit.test.jsx +89 -0
  7. package/src/components/manage/Blocks/CaseStudyExplorer/CaseStudyExplorerView.test.jsx +93 -0
  8. package/src/components/manage/Blocks/CaseStudyExplorer/CaseStudyMap.jsx +13 -79
  9. package/src/components/manage/Blocks/CaseStudyExplorer/CaseStudyMap.test.jsx +131 -0
  10. package/src/components/manage/Blocks/CaseStudyExplorer/FeatureDisplay.jsx +5 -1
  11. package/src/components/manage/Blocks/CaseStudyExplorer/FeatureDisplay.test.jsx +59 -0
  12. package/src/components/manage/Blocks/CaseStudyExplorer/FeatureInteraction.jsx +132 -53
  13. package/src/components/manage/Blocks/CaseStudyExplorer/styles.less +4 -0
  14. package/src/components/manage/Blocks/CaseStudyExplorer/useInteractiveStyles.jsx +189 -0
  15. package/src/components/manage/Blocks/MKHMap/InfoOverlay.jsx +20 -8
  16. package/src/components/manage/Blocks/MKHMap/View.jsx +1 -1
  17. package/src/components/theme/ImageGallery/styles.less +1 -1
  18. package/src/components/theme/Views/C3SIndicatorView.jsx +1 -1
  19. package/src/components/theme/Views/CaseStudyView.jsx +2 -6
  20. package/src/helpers/Utils.jsx +25 -33
  21. package/src/index.js +4 -1
  22. package/src/search/config.js +79 -26
  23. package/src/search/facets.js +12 -1
  24. package/src/search/views.js +15 -0
  25. package/src/components/manage/Blocks/CaseStudyExplorer/InfoOverlay.jsx +0 -80
@@ -4,13 +4,25 @@ import { openlayers as ol } from '@eeacms/volto-openlayers-map';
4
4
  import FeatureDisplay from './FeatureDisplay';
5
5
  import { usePrevious } from '@plone/volto/helpers/Utils/usePrevious';
6
6
 
7
- export default function InfoOverlay({ selectedFeature, layerId }) {
7
+ const isCluster = (features) => {
8
+ return features.length > 1 ? true : features[0].values_?.features?.length > 1;
9
+ };
10
+
11
+ export default function InfoOverlay({
12
+ selectedFeature,
13
+ onFeatureSelect,
14
+ layerId,
15
+ hasCusters = false,
16
+ }) {
8
17
  const { map } = useMapContext();
9
18
  const [tooltip, setTooltipRef] = React.useState();
10
19
  const [showTooltip, setShowTooltip] = React.useState();
11
20
 
12
21
  const prevLayerId = usePrevious(layerId);
13
22
 
23
+ const [isClient, setIsClient] = React.useState(false);
24
+ React.useEffect(() => setIsClient(true), []);
25
+
14
26
  React.useEffect(() => {
15
27
  if (prevLayerId && layerId !== prevLayerId) {
16
28
  setShowTooltip(false);
@@ -23,7 +35,7 @@ export default function InfoOverlay({ selectedFeature, layerId }) {
23
35
  const overlay = new ol.Overlay({
24
36
  element: document.getElementById('popup-overlay'),
25
37
  positioning: 'bottom-center',
26
- offset: [0, -10],
38
+ offset: [10, -10],
27
39
  stopEvent: false,
28
40
  });
29
41
  map.addOverlay(overlay);
@@ -33,11 +45,14 @@ export default function InfoOverlay({ selectedFeature, layerId }) {
33
45
  const { pixel, target } = evt;
34
46
  const features = target.getFeaturesAtPixel(pixel);
35
47
 
36
- if (features.length) {
48
+ if (features.length && (hasCusters ? !isCluster(features) : true)) {
37
49
  overlay.setPosition(coordinate);
38
50
  setShowTooltip(true);
39
51
  } else {
52
+ // handle a click in an overlay popup
53
+ if (evt.originalEvent.target.tagName === 'A') return;
40
54
  setShowTooltip(false);
55
+ onFeatureSelect(null);
41
56
  }
42
57
  }
43
58
 
@@ -47,10 +62,7 @@ export default function InfoOverlay({ selectedFeature, layerId }) {
47
62
  map.un('click', handler);
48
63
  map.removeOverlay(overlay);
49
64
  };
50
- }, [map, tooltip]); //
51
-
52
- const [isClient, setIsClient] = React.useState(false);
53
- React.useEffect(() => setIsClient(true), []);
65
+ }, [map, tooltip, onFeatureSelect, hasCusters]);
54
66
 
55
67
  return isClient ? (
56
68
  <div
@@ -62,7 +74,7 @@ export default function InfoOverlay({ selectedFeature, layerId }) {
62
74
  }}
63
75
  ref={setTooltipRef}
64
76
  >
65
- <FeatureDisplay feature={selectedFeature} />
77
+ {selectedFeature ? <FeatureDisplay feature={selectedFeature} /> : null}
66
78
  </div>
67
79
  ) : null;
68
80
  }
@@ -11,7 +11,7 @@ import { openlayers as ol } from '@eeacms/volto-openlayers-map';
11
11
 
12
12
  import * as layers from './layers';
13
13
  import FeatureInteraction from './FeatureInteraction';
14
- import InfoOverlay from '@eeacms/volto-cca-policy/components/manage/Blocks/CaseStudyExplorer/InfoOverlay';
14
+ import InfoOverlay from './InfoOverlay';
15
15
 
16
16
  import './styles.less';
17
17
 
@@ -9,7 +9,7 @@
9
9
  bottom: 0em;
10
10
  left: 0em;
11
11
  padding: 10px;
12
- background: rgba(0, 0, 0, 0.5); /* optional: semi-transparent background */
12
+ // background: rgba(0, 0, 0, 0.5); /* optional: semi-transparent background */
13
13
  color: white; /* text color */
14
14
  font-size: 14px; /* adjust font size as needed */
15
15
  text-align: left; /* optional: center the text */
@@ -71,7 +71,7 @@ const createIframe = (
71
71
  if (typeof ecde_identifier !== 'undefined' && ecde_identifier) {
72
72
  return (
73
73
  // '<iframe src="http://ecde-dev.copernicus-climate.eu/apps/ecde/?disabled=true&theme=eea&indicator=' +
74
- '<iframe src="https://apps.copernicus-climate.eu/ecde/?disabled=true&theme=eea&indicator=' +
74
+ '<iframe src="https://apps.copernicus-climate.eu/c3s-apps/ecde/?disabled=true&theme=eea&indicator=' +
75
75
  ecde_identifier +
76
76
  '" style="width: 100%; border: 0; height: min(800px, 80vh);"/>'
77
77
  );
@@ -278,6 +278,7 @@ const SectionsMenu = ({ sections, title }) => {
278
278
 
279
279
  const SectionContent = ({ sectionData, content }) => {
280
280
  const intl = useIntl();
281
+ const sectionDataTitle = sectionData.contentTitle || sectionData.title;
281
282
 
282
283
  const adaptationOptionsLinks = () => {
283
284
  let list = [];
@@ -288,17 +289,12 @@ const SectionContent = ({ sectionData, content }) => {
288
289
  };
289
290
 
290
291
  const section = content[sectionData.field];
291
-
292
292
  for (var key in section) {
293
293
  if (section[key] === '') {
294
294
  section[key] = '<p>-</p>';
295
295
  }
296
296
  }
297
297
 
298
- const sectionDataTitle =
299
- sectionData.contentTitle !== undefined
300
- ? sectionData.contentTitle
301
- : sectionData.title;
302
298
  return (
303
299
  <div id={sectionID(sectionData.title)} className="section">
304
300
  <h5 className="section-title">
@@ -324,6 +320,7 @@ const SectionContent = ({ sectionData, content }) => {
324
320
  };
325
321
 
326
322
  function CaseStudyView(props) {
323
+ const intl = useIntl();
327
324
  const { content } = props;
328
325
  const { long_description, updating_notes } = content;
329
326
 
@@ -345,7 +342,6 @@ function CaseStudyView(props) {
345
342
  (data) => data.group === group && hasValue(data.field),
346
343
  );
347
344
  };
348
- const intl = useIntl();
349
345
 
350
346
  return (
351
347
  <div className="db-item-view case-study-view">
@@ -71,7 +71,7 @@ export const ExternalLink = (props) => {
71
71
  };
72
72
 
73
73
  export const LinksList = (props) => {
74
- let { title, value, withText, isInternal } = props;
74
+ let { value, withText, isInternal } = props;
75
75
 
76
76
  if (isInternal === undefined) {
77
77
  isInternal = false;
@@ -79,33 +79,27 @@ export const LinksList = (props) => {
79
79
 
80
80
  if (withText === true) {
81
81
  return (
82
- <>
83
- <h5 id="websites">{title}</h5>
84
- <List>
85
- {value.map((linkItem, index) => (
86
- <ListItem key={index}>
87
- {isInternal ? (
88
- <UniversalLink href={linkItem[0]}>{linkItem[1]}</UniversalLink>
89
- ) : (
90
- <ExternalLink url={linkItem[0]} text={linkItem[1]} />
91
- )}
92
- </ListItem>
93
- ))}
94
- </List>
95
- </>
82
+ <List>
83
+ {value.map((linkItem, index) => (
84
+ <ListItem key={index}>
85
+ {isInternal ? (
86
+ <UniversalLink href={linkItem[0]}>{linkItem[1]}</UniversalLink>
87
+ ) : (
88
+ <ExternalLink url={linkItem[0]} text={linkItem[1]} />
89
+ )}
90
+ </ListItem>
91
+ ))}
92
+ </List>
96
93
  );
97
94
  } else {
98
95
  return (
99
- <>
100
- <h5 id="websites">{title}</h5>
101
- <List>
102
- {value.map((url, index) => (
103
- <ListItem key={index}>
104
- <ExternalLink url={url} text={url} />
105
- </ListItem>
106
- ))}
107
- </List>
108
- </>
96
+ <List>
97
+ {value.map((url, index) => (
98
+ <ListItem key={index}>
99
+ <ExternalLink url={url} text={url} />
100
+ </ListItem>
101
+ ))}
102
+ </List>
109
103
  );
110
104
  }
111
105
  };
@@ -155,14 +149,14 @@ export const ReferenceInfo = (props) => {
155
149
  defaultMessage="Reference information"
156
150
  />
157
151
  </h2>
158
-
159
152
  {websites?.length > 0 && (
160
- <LinksList
161
- title={<FormattedMessage id="Websites:" defaultMessage="Websites:" />}
162
- value={websites}
163
- />
153
+ <>
154
+ <h5 id="websites">
155
+ <FormattedMessage id="Websites:" defaultMessage="Websites:" />
156
+ </h5>
157
+ <LinksList value={websites} />
158
+ </>
164
159
  )}
165
-
166
160
  {type !== ACE_PROJECT && type !== ORGANISATION && (
167
161
  <>
168
162
  {source && source?.data.length > 0 && (
@@ -173,7 +167,6 @@ export const ReferenceInfo = (props) => {
173
167
  )}
174
168
  </>
175
169
  )}
176
-
177
170
  {(contributor_list?.length > 0 || other_contributor?.length > 0) && (
178
171
  <>
179
172
  <h5>
@@ -190,7 +183,6 @@ export const ReferenceInfo = (props) => {
190
183
  {other_contributor}
191
184
  </>
192
185
  )}
193
-
194
186
  {contributions && contributions.length > 0 && (
195
187
  <>
196
188
  <h5>
package/src/index.js CHANGED
@@ -22,6 +22,7 @@ import GeocharsWidget from './components/theme/Widgets/GeocharsWidget';
22
22
  import GeolocationWidget from './components/theme/Widgets/GeolocationWidget';
23
23
  import MigrationButtons from './components/MigrationButtons';
24
24
  import HealthHorizontalCardItem from './components/Result/HealthHorizontalCardItem';
25
+ import ClusterHorizontalCardItem from './components/Result/ClusterHorizontalCardItem';
25
26
 
26
27
  import { langRedirection } from './store/middleware';
27
28
 
@@ -339,7 +340,9 @@ const applyConfig = (config) => {
339
340
  config.settings.searchlib.resolve.HealthHorizontalCardItem = {
340
341
  component: HealthHorizontalCardItem,
341
342
  };
342
-
343
+ config.settings.searchlib.resolve.ClusterHorizontalCardItem = {
344
+ component: ClusterHorizontalCardItem,
345
+ };
343
346
  // Custom widgets
344
347
  config.widgets.id.geochars = GeocharsWidget;
345
348
  config.widgets.id.geolocation = GeolocationWidget;
@@ -1,27 +1,65 @@
1
1
  import { mergeConfig } from '@eeacms/search';
2
- import { build_runtime_mappings } from '@eeacms/volto-globalsearch/utils';
3
2
  import { getClientProxyAddress } from './utils';
4
3
  import vocabs from './vocabulary';
5
4
 
6
5
  import facets from './facets';
6
+ import views from './views';
7
7
 
8
8
  const ccaConfig = {
9
9
  title: 'ClimateAdapt Main',
10
+ ...views,
10
11
  };
11
12
 
12
13
  export const clusters = {
13
14
  name: 'op_cluster',
14
- field: 'objectProvides',
15
+ // field: 'objectProvides',
15
16
  clusters: [
16
- // {
17
- // name: 'Type1',
18
- // icon: { name: 'bullhorn' },
19
- // values: ['Video', 'Guidance'],
20
- // defaultResultView: 'horizontalCard',
21
- // },
22
- ],
17
+ {
18
+ name: 'Climate-ADAPT',
19
+ icon: { name: 'file text' },
20
+ values: ['climate'],
21
+ },
22
+ {
23
+ name: 'Health Observatory',
24
+ icon: { name: 'compass' },
25
+ values: ['observatory'],
26
+ },
27
+ {
28
+ name: 'Mission Portal',
29
+ icon: { name: 'compass' },
30
+ values: ['mission'],
31
+ },
32
+ ].map((cluster) => ({
33
+ ...cluster,
34
+ defaultResultView: 'ClusterHorizontalCardItem',
35
+ })),
36
+ };
37
+
38
+ // console.log('clusters default', clusters, build_runtime_mappings(clusters));
39
+ // console.log(
40
+ // 'clusters mission',
41
+ // clusters_mission,
42
+ // build_runtime_mappings(clusters_mission),
43
+ // );
44
+
45
+ const cca_build_runtime_mappings = {};
46
+ cca_build_runtime_mappings['op_cluster'] = {
47
+ type: 'keyword',
48
+ script: {
49
+ source:
50
+ // "emit('_all_'); if (doc['cca_include_in_search_observatory'][0]) {emit('Health Observatory')} if (doc['cca_include_in_mission.keyword'][0].toString() == 'true') {emit('Mission Portal')} else {emit('Climate-ADAPT')}",
51
+ // "emit('_all_'); if (doc['cca_include_in_search_observatory'][0]) {emit('Health Observatory')} if (doc['cca_include_in_mission.keyword'][0].toString() == 'true' or (doc['id.keyword'].length==1 and doc['id.keyword'][0].toString().indexOf('https://climate-adapt.eea.europa.eu/en/mission')==0)) {emit('Mission Portal')} else {emit('Climate adapt')}",
52
+ // "def objectProvides = ['Adaptation option','Case study','Guidance','Video','Indicator','Information portal','Organisation','Publication reference','Research and knowledge project','Video','Tool'];def vals = doc['objectProvides'];for (defVal in objectProvides) {for (objVal in vals) {if (objVal.contains(defVal)) {emit('Climate-ADAPT')}}}emit('_all_');if (doc['cca_include_in_search_observatory'][0]) {emit('Health Observatory')} if (doc['cca_include_in_mission.keyword'][0].toString() == 'true') {emit('Mission Portal')} else {if (doc['id.keyword'].length==1) { if(doc['id.keyword'][0].toString().contains('climate-adapt.eea.europa.eu/en/mission')) {emit('Mission Portal')}}}",
53
+ "def objectProvides = ['Adaptation option','Case study','Guidance','Video','Indicator','Information portal','Organisation','Publication reference','Research and knowledge project','Video','Tool'];def vals = doc['objectProvides'];for (defVal in objectProvides) {for (objVal in vals) {if (objVal.contains(defVal)) {emit('Climate-ADAPT')}}}emit('_all_');if (doc['cca_include_in_search_observatory'][0]) {for (defVal in objectProvides) {for (objVal in vals) {if (objVal.contains(defVal)){emit('Health Observatory')}}}} if (doc['cca_include_in_mission.keyword'][0].toString() == 'true') {emit('Mission Portal')} else {if (doc['id.keyword'].length==1) { if(doc['id.keyword'][0].toString().contains('climate-adapt.eea.europa.eu/en/mission')) {emit('Mission Portal')}}}",
54
+ },
23
55
  };
24
56
 
57
+ // const mapping = {};
58
+ // mapping[settings.name] = {
59
+ // type: 'keyword',
60
+ // script: { source: source },
61
+ // };
62
+
25
63
  export default function installMainSearch(config) {
26
64
  const envConfig = ccaConfig;
27
65
 
@@ -30,41 +68,56 @@ export default function installMainSearch(config) {
30
68
  envConfig.app_name = pjson.name;
31
69
  envConfig.app_version = pjson.version;
32
70
 
71
+ // console.log('config.searchui.ccaSearch clusers', clusters);
72
+ // debugger;
33
73
  config.searchui.ccaSearch = {
34
74
  ...mergeConfig(envConfig, config.searchui.globalsearchbase),
35
75
  elastic_index: '_es/globalsearch',
36
76
  index_name: 'data_searchui',
37
77
  host: process.env.RAZZLE_ES_PROXY_ADDR || 'http://localhost:3000',
38
- runtime_mappings: build_runtime_mappings(clusters),
78
+ runtime_mappings: cca_build_runtime_mappings,
39
79
  ...vocabs,
40
80
  };
41
81
 
42
82
  const { ccaSearch } = config.searchui;
43
83
 
84
+ ccaSearch.contentSectionsParams = {
85
+ enable: true,
86
+ sectionFacetsField: 'op_cluster',
87
+ sections: clusters.clusters,
88
+ clusterMapping: Object.assign(
89
+ {},
90
+ ...clusters.clusters.map(({ name, values }) =>
91
+ Object.assign({}, ...values.map((v) => ({ [v]: name }))),
92
+ ),
93
+ ),
94
+ };
95
+
44
96
  ccaSearch.permanentFilters.push({
45
97
  term: {
46
98
  cluster_name: 'cca',
47
99
  },
48
100
  });
49
101
 
50
- ccaSearch.permanentFilters.push({
51
- terms: {
52
- objectProvides: [
53
- 'Adaptation option',
54
- 'Case study',
55
- 'Guidance',
56
- 'Video',
57
- 'Indicator',
58
- 'Information portal',
59
- 'Organisation',
60
- 'Publication reference',
61
- 'Research and knowledge project',
62
- 'Tool',
63
- ],
64
- },
65
- });
102
+ // ccaSearch.permanentFilters.push({
103
+ // terms: {
104
+ // objectProvides: [
105
+ // 'Adaptation option',
106
+ // 'Case study',
107
+ // 'Guidance',
108
+ // 'Video',
109
+ // 'Indicator',
110
+ // 'Information portal',
111
+ // 'Organisation',
112
+ // 'Publication reference',
113
+ // 'Research and knowledge project',
114
+ // 'Tool',
115
+ // ],
116
+ // },
117
+ // });
66
118
 
67
119
  ccaSearch.facets = facets;
120
+ // console.log('ccaSearch.facets', ccaSearch.facets);
68
121
 
69
122
  ccaSearch.initialView.tilesLandingPageParams.sections = [
70
123
  {
@@ -18,7 +18,17 @@ const adaptation_sectors = {
18
18
  showAllOptions: true,
19
19
  alwaysVisible: true,
20
20
  };
21
-
21
+ const op_cluster = {
22
+ field: 'op_cluster',
23
+ factory: 'MultiTermFacet',
24
+ isFilterable: true,
25
+ isMulti: true,
26
+ label: 'Section',
27
+ show: 10000,
28
+ showInFacetsList: false,
29
+ ignoreNLPWhenActive: true,
30
+ blacklist: ['Others', 'Publications'],
31
+ };
22
32
  // const clusters = {
23
33
  // field: 'op_cluster',
24
34
  // factory: 'MultiTermFacet',
@@ -113,6 +123,7 @@ const origin_websites = {
113
123
  const facets = [
114
124
  adaptation_sectors,
115
125
  // clusters,
126
+ op_cluster,
116
127
  objectProvides,
117
128
  issued_date,
118
129
  climate_impacts,
@@ -0,0 +1,15 @@
1
+ export default {
2
+ resultViews: [
3
+ {
4
+ id: 'ClusterHorizontalCardItem',
5
+ title: 'Cluster Climate catalogue items',
6
+ icon: 'bars',
7
+ render: null,
8
+ isDefault: true,
9
+ factories: {
10
+ view: 'HorizontalCard.Group',
11
+ item: 'ClusterHorizontalCardItem',
12
+ },
13
+ },
14
+ ],
15
+ };
@@ -1,80 +0,0 @@
1
- import React from 'react';
2
- import { useMapContext } from '@eeacms/volto-openlayers-map/api';
3
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
4
- import FeatureDisplay from './FeatureDisplay';
5
- import { usePrevious } from '@plone/volto/helpers/Utils/usePrevious';
6
-
7
- const isCluster = (features) => {
8
- return features.length > 1 ? true : features[0].values_?.features?.length > 1;
9
- };
10
-
11
- export default function InfoOverlay({
12
- selectedFeature,
13
- onFeatureSelect,
14
- layerId,
15
- hasCusters = false,
16
- }) {
17
- const { map } = useMapContext();
18
- const [tooltip, setTooltipRef] = React.useState();
19
- const [showTooltip, setShowTooltip] = React.useState();
20
-
21
- const prevLayerId = usePrevious(layerId);
22
-
23
- const [isClient, setIsClient] = React.useState(false);
24
- React.useEffect(() => setIsClient(true), []);
25
-
26
- React.useEffect(() => {
27
- if (prevLayerId && layerId !== prevLayerId) {
28
- setShowTooltip(false);
29
- }
30
- }, [layerId, prevLayerId]);
31
-
32
- React.useEffect(() => {
33
- if (!(map && tooltip)) return;
34
-
35
- const overlay = new ol.Overlay({
36
- element: document.getElementById('popup-overlay'),
37
- positioning: 'bottom-center',
38
- offset: [10, -10],
39
- stopEvent: false,
40
- });
41
- map.addOverlay(overlay);
42
-
43
- function handler(evt) {
44
- const coordinate = evt.coordinate;
45
- const { pixel, target } = evt;
46
- const features = target.getFeaturesAtPixel(pixel);
47
-
48
- if (features.length && (hasCusters ? !isCluster(features) : true)) {
49
- overlay.setPosition(coordinate);
50
- setShowTooltip(true);
51
- } else {
52
- // handle a click in an overlay popup
53
- if (evt.originalEvent.target.tagName === 'A') return;
54
- setShowTooltip(false);
55
- onFeatureSelect(null);
56
- }
57
- }
58
-
59
- map.on('click', handler);
60
-
61
- return () => {
62
- map.un('click', handler);
63
- map.removeOverlay(overlay);
64
- };
65
- }, [map, tooltip, onFeatureSelect, hasCusters]);
66
-
67
- return isClient ? (
68
- <div
69
- id="popup-overlay"
70
- style={{
71
- position: 'absolute',
72
- zIndex: 1,
73
- visibility: showTooltip ? 'visible' : 'hidden',
74
- }}
75
- ref={setTooltipRef}
76
- >
77
- {selectedFeature ? <FeatureDisplay feature={selectedFeature} /> : null}
78
- </div>
79
- ) : null;
80
- }