@eeacms/volto-cca-policy 1.0.7 → 1.0.8

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 CHANGED
@@ -4,6 +4,16 @@ 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.8](https://github.com/eea/volto-cca-policy/compare/1.0.7...1.0.8) - 17 August 2026
8
+
9
+ #### :house: Internal changes
10
+
11
+ - style: Automated code fix [eea-jenkins - [`c06e6eb`](https://github.com/eea/volto-cca-policy/commit/c06e6ebc41cbe2bb80a9c8472d57fd361fe09dab)]
12
+
13
+ #### :hammer_and_wrench: Others
14
+
15
+ - Refs #307245 - Add test for visualizations. [GhitaB - [`15d7a0b`](https://github.com/eea/volto-cca-policy/commit/15d7a0bc514e6ac09bbec19303e42ceb120647dc)]
16
+ - Refs #307245 - Allow indicators to support multiple visualizations. [GhitaB - [`b7a0b7f`](https://github.com/eea/volto-cca-policy/commit/b7a0b7fe9db40a9d9a1847eb71a95a8f2245dd5e)]
7
17
  ### [1.0.7](https://github.com/eea/volto-cca-policy/compare/1.0.6...1.0.7) - 14 August 2026
8
18
 
9
19
  #### :rocket: Dependency updates
@@ -233,8 +243,39 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
233
243
  #### :hammer_and_wrench: Others
234
244
 
235
245
  - test: pin Chromium version 149 to work with Cypress [valentinab25 - [`659ec82`](https://github.com/eea/volto-cca-policy/commit/659ec823dd71fe592a3a7accda22effbe1fb07bc)]
236
- ## [1.0.0](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.17...1.0.0) - 12 June 2026
246
+ ## [1.0.0](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.18...1.0.0) - 12 June 2026
247
+
248
+ ### [1.0.0-alpha.18](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.17...1.0.0-alpha.18) - 13 August 2026
249
+
250
+ #### :rocket: Dependency updates
251
+
252
+ - Release @eeacms/volto-globalsearch@4.1.1 [EEA Jenkins - [`f34f23c`](https://github.com/eea/volto-cca-policy/commit/f34f23c587f32930acd4316d43f2f64fd9338764)]
253
+ - Release @eeacms/volto-globalsearch@4.1.0 [EEA Jenkins - [`5d7ddd2`](https://github.com/eea/volto-cca-policy/commit/5d7ddd2cf7a371007a569d185690d655c2c4b2d2)]
254
+
255
+ #### :bug: Bug Fixes
256
+
257
+ - fix: update import [kreafox - [`5e98924`](https://github.com/eea/volto-cca-policy/commit/5e9892488dd84e2e280d29905f4471af4f5403be)]
258
+ - fix: imports in GovernanceTab [kreafox - [`c1eb09f`](https://github.com/eea/volto-cca-policy/commit/c1eb09fd59e730fa15c71fd73f625f9811fd98fa)]
259
+ - fix: improve geochars parsing, and enhance capitalizeFirstLetter function [kreafox - [`370deb6`](https://github.com/eea/volto-cca-policy/commit/370deb6395872c4229c0747077f845f8d8375336)]
237
260
 
261
+ #### :nail_care: Enhancements
262
+
263
+ - refactor: remove unused export of euCountryNamesEnergy from helpers [kreafox - [`5c40276`](https://github.com/eea/volto-cca-policy/commit/5c40276f491e4b3a24de8ebe29e8fdc0d0d2fe57)]
264
+ - refactor: change exported components to default exports in ImageWidget, countryMap, and queryUtils [kreafox - [`43ce27c`](https://github.com/eea/volto-cca-policy/commit/43ce27c9af8f036e34d5ccefe185fa138fa6f823)]
265
+ - refactor: replace clientOnly HOC with withClientOnly and reorganize helper imports [kreafox - [`5e326f3`](https://github.com/eea/volto-cca-policy/commit/5e326f378af2ba784e7f8b4499a28500a04031b5)]
266
+ - refactor: reorganize content sections, views, and widgets [kreafox - [`4ff70ec`](https://github.com/eea/volto-cca-policy/commit/4ff70ec1a763071ace8292eeac6d2f0d692580cb)]
267
+ - refactor: shared content view components into reusable theme modules [kreafox - [`e0f1906`](https://github.com/eea/volto-cca-policy/commit/e0f190606acc8ab74dfad147f751451d1e8f38eb)]
268
+
269
+ #### :house: Internal changes
270
+
271
+ - style: Automated code fix [eea-jenkins - [`c06e6eb`](https://github.com/eea/volto-cca-policy/commit/c06e6ebc41cbe2bb80a9c8472d57fd361fe09dab)]
272
+
273
+ #### :hammer_and_wrench: Others
274
+
275
+ - Refs #307245 - Allow indicators to support multiple visualizations. [GhitaB - [`b7a0b7f`](https://github.com/eea/volto-cca-policy/commit/b7a0b7fe9db40a9d9a1847eb71a95a8f2245dd5e)]
276
+ - test: increase coverage for ImageWidget [kreafox - [`5fd74bf`](https://github.com/eea/volto-cca-policy/commit/5fd74bfe00db49e4977a64871de3144a7247415d)]
277
+ - core: update locales [kreafox - [`f1ba2dd`](https://github.com/eea/volto-cca-policy/commit/f1ba2dd01269d42da4cdeb948951b65857a05e3d)]
278
+ - core: update locales [kreafox - [`122817e`](https://github.com/eea/volto-cca-policy/commit/122817ea9f6f0084fe8cb697ccfaffb8a9fe833d)]
238
279
  ### [1.0.0-alpha.17](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.16...1.0.0-alpha.17) - 4 August 2026
239
280
 
240
281
  #### :rocket: New Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
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",
@@ -0,0 +1,151 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Button, Checkbox, Form, Input, TextArea } from 'semantic-ui-react';
4
+ import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
5
+
6
+ import './visualizations.less';
7
+
8
+ const emptyVisualization = {
9
+ title: '',
10
+ embed_code: '',
11
+ height: '',
12
+ full_width: false,
13
+ };
14
+
15
+ const normalizeVisualizations = (value) =>
16
+ Array.isArray(value)
17
+ ? value.map((item) => ({ ...emptyVisualization, ...(item || {}) }))
18
+ : [];
19
+
20
+ const VisualizationsWidget = (props) => {
21
+ const { id, value, onChange, isDisabled } = props;
22
+ const visualizations = normalizeVisualizations(value);
23
+
24
+ const updateVisualizations = (nextValue) => {
25
+ onChange(id, nextValue);
26
+ };
27
+
28
+ const updateItem = (index, field, fieldValue) => {
29
+ updateVisualizations(
30
+ visualizations.map((item, itemIndex) =>
31
+ itemIndex === index ? { ...item, [field]: fieldValue } : item,
32
+ ),
33
+ );
34
+ };
35
+
36
+ const addItem = () => {
37
+ updateVisualizations([...visualizations, { ...emptyVisualization }]);
38
+ };
39
+
40
+ const deleteItem = (index) => {
41
+ updateVisualizations(
42
+ visualizations.filter((_, itemIndex) => itemIndex !== index),
43
+ );
44
+ };
45
+
46
+ return (
47
+ <FormFieldWrapper {...props}>
48
+ <div className="visualizations-widget">
49
+ {visualizations.map((item, index) => (
50
+ <div
51
+ className="visualizations-widget-item"
52
+ key={`visualization-${index}`}
53
+ >
54
+ <div className="visualizations-widget-item-header">
55
+ <h4>Visualization {index + 1}</h4>
56
+ <Button
57
+ type="button"
58
+ basic
59
+ compact
60
+ negative
61
+ disabled={isDisabled}
62
+ onClick={() => deleteItem(index)}
63
+ >
64
+ Delete
65
+ </Button>
66
+ </div>
67
+
68
+ <Form.Field>
69
+ <label htmlFor={`${id}-${index}-title`}>Title</label>
70
+ <Input
71
+ id={`${id}-${index}-title`}
72
+ value={item.title || ''}
73
+ disabled={isDisabled}
74
+ onChange={(event) =>
75
+ updateItem(index, 'title', event.target.value)
76
+ }
77
+ />
78
+ </Form.Field>
79
+
80
+ <Form.Field>
81
+ <label htmlFor={`${id}-${index}-embed-code`}>
82
+ Embed code or URL
83
+ </label>
84
+ <TextArea
85
+ id={`${id}-${index}-embed-code`}
86
+ value={item.embed_code || ''}
87
+ disabled={isDisabled}
88
+ rows={5}
89
+ onChange={(event) =>
90
+ updateItem(index, 'embed_code', event.target.value)
91
+ }
92
+ />
93
+ </Form.Field>
94
+
95
+ <Form.Group widths="equal">
96
+ <Form.Field className="visualizations-widget-height">
97
+ <label htmlFor={`${id}-${index}-height`}>Height</label>
98
+ <Input
99
+ id={`${id}-${index}-height`}
100
+ value={item.height || ''}
101
+ disabled={isDisabled}
102
+ placeholder="800"
103
+ onChange={(event) =>
104
+ updateItem(index, 'height', event.target.value)
105
+ }
106
+ />
107
+ </Form.Field>
108
+
109
+ <Form.Field className="visualizations-widget-layout">
110
+ <label>Layout</label>
111
+ <Checkbox
112
+ label="Full width"
113
+ checked={!!item.full_width}
114
+ disabled={isDisabled}
115
+ onChange={(_, data) =>
116
+ updateItem(index, 'full_width', data.checked)
117
+ }
118
+ />
119
+ </Form.Field>
120
+ </Form.Group>
121
+ </div>
122
+ ))}
123
+
124
+ <Button
125
+ type="button"
126
+ basic
127
+ compact
128
+ primary
129
+ disabled={isDisabled}
130
+ onClick={addItem}
131
+ >
132
+ Add visualization
133
+ </Button>
134
+ </div>
135
+ </FormFieldWrapper>
136
+ );
137
+ };
138
+
139
+ VisualizationsWidget.propTypes = {
140
+ id: PropTypes.string.isRequired,
141
+ value: PropTypes.arrayOf(PropTypes.object),
142
+ onChange: PropTypes.func.isRequired,
143
+ isDisabled: PropTypes.bool,
144
+ };
145
+
146
+ VisualizationsWidget.defaultProps = {
147
+ value: [],
148
+ isDisabled: false,
149
+ };
150
+
151
+ export default VisualizationsWidget;
@@ -0,0 +1,60 @@
1
+ .visualizations-widget {
2
+ max-width: 760px;
3
+
4
+ .visualizations-widget-item {
5
+ padding: 1.25rem;
6
+ border: 1px solid #d8d8d8;
7
+ margin-bottom: 1rem;
8
+ background: #fff;
9
+ }
10
+
11
+ .visualizations-widget-item-header {
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: space-between;
15
+ padding-bottom: 0.75rem;
16
+ border-bottom: 1px solid #e6e6e6;
17
+ margin-bottom: 1rem;
18
+ gap: 1rem;
19
+
20
+ h4 {
21
+ margin: 0;
22
+ color: #1f405c;
23
+ font-size: 1rem;
24
+ }
25
+ }
26
+
27
+ .field {
28
+ margin-bottom: 1rem;
29
+
30
+ > label {
31
+ display: block;
32
+ margin-bottom: 0.35rem;
33
+ color: #1f405c;
34
+ font-weight: 700;
35
+ }
36
+ }
37
+
38
+ .ui.input,
39
+ textarea {
40
+ width: 100%;
41
+ }
42
+
43
+ textarea {
44
+ min-height: 8rem;
45
+ resize: vertical;
46
+ }
47
+
48
+ .fields {
49
+ align-items: flex-end;
50
+ margin-bottom: 0;
51
+ }
52
+
53
+ .visualizations-widget-height {
54
+ max-width: 180px;
55
+ }
56
+
57
+ .visualizations-widget-layout {
58
+ padding-bottom: 0.55rem;
59
+ }
60
+ }
@@ -32,12 +32,16 @@ import {
32
32
 
33
33
  const SHARE_EEA = ['https://cmshare.eea.eu', 'shareit.eea.europa.eu'];
34
34
 
35
- const MaybeFlourishVisualization = ({ content }) => {
36
- const { map_graphs } = content;
35
+ const getVisualizationEmbedCode = (visualization) =>
36
+ visualization?.embed_code || visualization?.map_graphs || '';
37
37
 
38
+ const MaybeFlourishVisualization = ({ visualization }) => {
39
+ const embedCode = getVisualizationEmbedCode(visualization);
38
40
  // https://helpcenter.flourish.studio/hc/en-us/articles/8761537208463-How-to-embed-Flourish-charts-in-your-CMS
39
- const flourishPath = getDataSrcFromEmbedCode(map_graphs);
41
+ const flourishPath = getDataSrcFromEmbedCode(embedCode);
40
42
  const flourishUrl = buildFlourishUrl(flourishPath);
43
+ const height = visualization?.height || '980';
44
+ const title = visualization?.title || 'Interactive or visual content';
41
45
 
42
46
  return !!flourishPath ? (
43
47
  <PrivacyProtection
@@ -47,10 +51,10 @@ const MaybeFlourishVisualization = ({ content }) => {
47
51
  }}
48
52
  >
49
53
  <iframe
50
- height="980"
54
+ height={height}
51
55
  width="100%"
52
56
  src={flourishUrl}
53
- title="Interactive or visual content"
57
+ title={title}
54
58
  className="flourish-embed-iframe"
55
59
  sandbox="allow-same-origin allow-forms allow-scripts allow-downloads allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"
56
60
  ></iframe>
@@ -73,10 +77,11 @@ function getFirstIframeSrc(htmlString) {
73
77
  }
74
78
  }
75
79
 
76
- const MaybeIframeVisualization = ({ content }) => {
77
- const { map_graphs, map_graphs_height } = content;
78
- const url = getFirstIframeSrc(map_graphs || '');
79
- const height = map_graphs_height || 800;
80
+ const MaybeIframeVisualization = ({ visualization }) => {
81
+ const embedCode = getVisualizationEmbedCode(visualization);
82
+ const url = getFirstIframeSrc(embedCode);
83
+ const height = visualization?.height || 800;
84
+ const title = visualization?.title || 'Interactive or visual content';
80
85
  const [isClient, setIsClient] = React.useState();
81
86
 
82
87
  React.useEffect(() => setIsClient(true), []);
@@ -94,7 +99,7 @@ const MaybeIframeVisualization = ({ content }) => {
94
99
  height={height}
95
100
  width="100%"
96
101
  src={url}
97
- title="Interactive or visual content"
102
+ title={title}
98
103
  className="flourish-embed-iframe"
99
104
  sandbox="allow-same-origin allow-forms allow-scripts allow-downloads allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"
100
105
  ></iframe>
@@ -102,6 +107,43 @@ const MaybeIframeVisualization = ({ content }) => {
102
107
  );
103
108
  };
104
109
 
110
+ const Visualization = ({ visualization }) => (
111
+ <>
112
+ {visualization?.title && <h2>{visualization.title}</h2>}
113
+ <MaybeFlourishVisualization visualization={visualization} />
114
+ <MaybeIframeVisualization visualization={visualization} />
115
+ </>
116
+ );
117
+
118
+ const Visualizations = ({ visualizations }) => (
119
+ <>
120
+ {visualizations.map((visualization, index) => (
121
+ <Visualization
122
+ key={`visualization-${index}`}
123
+ visualization={visualization}
124
+ />
125
+ ))}
126
+ </>
127
+ );
128
+
129
+ const getVisualizations = (content) => {
130
+ const visualizations = Array.isArray(content?.visualizations)
131
+ ? content.visualizations.filter((item) => item?.embed_code)
132
+ : [];
133
+
134
+ return content?.map_graphs
135
+ ? [
136
+ ...visualizations,
137
+ {
138
+ title: '',
139
+ embed_code: content.map_graphs,
140
+ height: content.map_graphs_height,
141
+ full_width: content.map_graphs_full_width,
142
+ },
143
+ ]
144
+ : visualizations;
145
+ };
146
+
105
147
  const BottomInfo = (props) => {
106
148
  const { content } = props;
107
149
  const { organisational_websites, organisational_contact_information } =
@@ -157,9 +199,14 @@ const DatabaseItemView = (props) => {
157
199
  } = content;
158
200
  const item_title = acronym ? title + ' (' + acronym + ')' : title;
159
201
  const subtitle = CONTENT_TYPE_LABELS[type] ?? '';
160
- const hasVisualization = !!content?.map_graphs?.length;
161
- const isFullWidthVisualization =
162
- hasVisualization && content?.map_graphs_full_width;
202
+ const visualizations = getVisualizations(content);
203
+ const columnVisualizations = visualizations.filter(
204
+ (visualization) => !visualization.full_width,
205
+ );
206
+ const fullWidthVisualizations = visualizations.filter(
207
+ (visualization) => visualization.full_width,
208
+ );
209
+ const hasFullWidthVisualizations = !!fullWidthVisualizations.length;
163
210
 
164
211
  const is_cmshare_video = SHARE_EEA.some((domain) =>
165
212
  content?.embed_url?.includes(domain),
@@ -252,14 +299,11 @@ const DatabaseItemView = (props) => {
252
299
  </>
253
300
  )}
254
301
 
255
- {hasVisualization && !isFullWidthVisualization && (
256
- <>
257
- <MaybeFlourishVisualization {...props} />
258
- <MaybeIframeVisualization {...props} />
259
- </>
302
+ {!!columnVisualizations.length && (
303
+ <Visualizations visualizations={columnVisualizations} />
260
304
  )}
261
305
 
262
- {!isFullWidthVisualization && <BottomInfo {...props} />}
306
+ {!hasFullWidthVisualizations && <BottomInfo {...props} />}
263
307
  </Grid.Column>
264
308
 
265
309
  <Grid.Column
@@ -273,12 +317,11 @@ const DatabaseItemView = (props) => {
273
317
  </Grid.Column>
274
318
  </Grid.Row>
275
319
 
276
- {isFullWidthVisualization && (
320
+ {hasFullWidthVisualizations && (
277
321
  <>
278
322
  <Grid.Row>
279
323
  <Grid.Column mobile={12} tablet={12} computer={12}>
280
- <MaybeFlourishVisualization {...props} />
281
- <MaybeIframeVisualization {...props} />
324
+ <Visualizations visualizations={fullWidthVisualizations} />
282
325
  </Grid.Column>
283
326
  </Grid.Row>
284
327
  <Grid.Row>
@@ -17,6 +17,58 @@ config.blocks = {
17
17
 
18
18
  const mockStore = configureStore();
19
19
 
20
+ const baseContent = {
21
+ title: 'My DatabaseItemView',
22
+ long_description: {
23
+ 'content-type': null,
24
+ data: '<p>Nam commodo suscipit quam. Praesent egestas neque eu enim. Quisque rutrum.</p>',
25
+ encoding: 'utf-8',
26
+ },
27
+ publication_date: '2022-06-24',
28
+ geochars:
29
+ '{\r\n "geoElements":{"element":"GLOBAL",\r\n "macrotrans":null,"biotrans":null,"countries":[],\r\n "subnational":[],"city":""}}',
30
+ keywords: ['keyword 1', 'keyword 2'],
31
+ websites: ['https://example.org/'],
32
+ contributions: [
33
+ {
34
+ title: 'Contributor 1',
35
+ url: '/contributor-1',
36
+ },
37
+ {
38
+ title: 'Contributor 2',
39
+ url: '/contributor-2',
40
+ },
41
+ ],
42
+ };
43
+
44
+ const visualizationEmbedCode =
45
+ '<div class="flourish-embed" data-src="visualisation/12345"></div>';
46
+
47
+ const renderDatabaseItemView = (content = baseContent) => {
48
+ const store = mockStore({
49
+ userSession: { token: '1234' },
50
+ intl: {
51
+ locale: 'en',
52
+ messages: {},
53
+ },
54
+ });
55
+
56
+ return renderer.create(
57
+ <Provider store={store}>
58
+ <MemoryRouter>
59
+ <DatabaseItemView content={content} />
60
+ </MemoryRouter>
61
+ </Provider>,
62
+ );
63
+ };
64
+
65
+ const findColumnByClassName = (component, className) =>
66
+ component.root.findAll(
67
+ (node) =>
68
+ typeof node.props.className === 'string' &&
69
+ node.props.className.includes(className),
70
+ )[0];
71
+
20
72
  jest.mock('semantic-ui-react', () => ({
21
73
  ...jest.requireActual('semantic-ui-react'),
22
74
  }));
@@ -29,46 +81,54 @@ jest.mock('@eeacms/volto-embed', () => {
29
81
 
30
82
  describe('DatabaseItemView', () => {
31
83
  it('should render the component', () => {
32
- const content = {
33
- title: 'My DatabaseItemView',
34
- long_description: {
35
- 'content-type': null,
36
- data: '<p>Nam commodo suscipit quam. Praesent egestas neque eu enim. Quisque rutrum.</p>',
37
- encoding: 'utf-8',
38
- },
39
- publication_date: '2022-06-24',
40
- geochars:
41
- '{\r\n "geoElements":{"element":"GLOBAL",\r\n "macrotrans":null,"biotrans":null,"countries":[],\r\n "subnational":[],"city":""}}',
42
- keywords: ['keyword 1', 'keyword 2'],
43
- websites: ['https://example.org/'],
44
- contributions: [
45
- {
46
- title: 'Contributor 1',
47
- url: '/contributor-1',
48
- },
49
- {
50
- title: 'Contributor 2',
51
- url: '/contributor-2',
52
- },
53
- ],
54
- };
55
-
56
- const store = mockStore({
57
- userSession: { token: '1234' },
58
- intl: {
59
- locale: 'en',
60
- messages: {},
61
- },
84
+ const component = renderDatabaseItemView();
85
+ const json = component.toJSON();
86
+ expect(json).toMatchSnapshot();
87
+ });
88
+
89
+ it('renders the visualizations field in the left column by default', () => {
90
+ const component = renderDatabaseItemView({
91
+ ...baseContent,
92
+ map_graphs: visualizationEmbedCode,
62
93
  });
94
+ const colLeft = findColumnByClassName(component, 'col-left');
95
+ const fullWidthColumns = component.root.findAll(
96
+ (node) => node.props.computer === 12,
97
+ );
63
98
 
64
- const component = renderer.create(
65
- <Provider store={store}>
66
- <MemoryRouter>
67
- <DatabaseItemView content={content} />
68
- </MemoryRouter>
69
- </Provider>,
99
+ expect(colLeft.findAllByType('iframe')).toHaveLength(1);
100
+ expect(component.root.findByType('iframe').props.src).toBe(
101
+ 'https://flo.uri.sh/visualisation/12345/embed',
70
102
  );
71
- const json = component.toJSON();
72
- expect(json).toMatchSnapshot();
103
+ expect(fullWidthColumns).toHaveLength(0);
104
+ });
105
+
106
+ it('renders the visualizations field full width when enabled', () => {
107
+ const component = renderDatabaseItemView({
108
+ ...baseContent,
109
+ map_graphs: visualizationEmbedCode,
110
+ map_graphs_full_width: true,
111
+ });
112
+ const colLeft = findColumnByClassName(component, 'col-left');
113
+ const fullWidthColumn = component.root.findAll(
114
+ (node) => node.props.computer === 12,
115
+ )[0];
116
+
117
+ expect(colLeft.findAllByType('iframe')).toHaveLength(0);
118
+ expect(fullWidthColumn.findAllByType('iframe')).toHaveLength(1);
119
+ });
120
+
121
+ it('does not render a visualization when the visualizations field is empty', () => {
122
+ const component = renderDatabaseItemView({
123
+ ...baseContent,
124
+ map_graphs: '',
125
+ map_graphs_full_width: true,
126
+ });
127
+
128
+ expect(component.root.findAllByType('iframe')).toHaveLength(0);
129
+ const fullWidthColumns = component.root.findAll(
130
+ (node) => node.props.computer === 12,
131
+ );
132
+ expect(fullWidthColumns).toHaveLength(0);
73
133
  });
74
134
  });
package/src/index.js CHANGED
@@ -48,6 +48,7 @@ import {
48
48
 
49
49
  import GeocharsWidget from './components/manage/Widgets/GeocharsWidget';
50
50
  import PromotionalImageWidget from './components/manage/Widgets/PromotionalImageWidget';
51
+ import VisualizationsWidget from './components/manage/Widgets/VisualizationsWidget';
51
52
  import HealthHorizontalCardItem from './components/Search/Result/HealthHorizontalCardItem';
52
53
  import ClusterHorizontalCardItem from './components/Search/Result/ClusterHorizontalCardItem';
53
54
  import NavigatorCatalogueCardItem from './components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem';
@@ -443,6 +444,7 @@ const applyConfig = (config) => {
443
444
  config.widgets.id.geochars = GeocharsWidget;
444
445
  config.widgets.id.geolocation = GeolocationWidget;
445
446
  config.widgets.id.promotional_image = PromotionalImageWidget;
447
+ config.widgets.id.visualizations = VisualizationsWidget;
446
448
  config.widgets.id.image = ImageWidget;
447
449
 
448
450
  if (config.widgets.views?.widget) {