@eeacms/volto-cca-policy 1.0.7 → 1.0.9

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,18 @@ 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.9](https://github.com/eea/volto-cca-policy/compare/1.0.8...1.0.9) - 18 August 2026
8
+
9
+ ### [1.0.8](https://github.com/eea/volto-cca-policy/compare/1.0.7...1.0.8) - 17 August 2026
10
+
11
+ #### :house: Internal changes
12
+
13
+ - style: Automated code fix [eea-jenkins - [`c06e6eb`](https://github.com/eea/volto-cca-policy/commit/c06e6ebc41cbe2bb80a9c8472d57fd361fe09dab)]
14
+
15
+ #### :hammer_and_wrench: Others
16
+
17
+ - Refs #307245 - Add test for visualizations. [GhitaB - [`15d7a0b`](https://github.com/eea/volto-cca-policy/commit/15d7a0bc514e6ac09bbec19303e42ceb120647dc)]
18
+ - Refs #307245 - Allow indicators to support multiple visualizations. [GhitaB - [`b7a0b7f`](https://github.com/eea/volto-cca-policy/commit/b7a0b7fe9db40a9d9a1847eb71a95a8f2245dd5e)]
7
19
  ### [1.0.7](https://github.com/eea/volto-cca-policy/compare/1.0.6...1.0.7) - 14 August 2026
8
20
 
9
21
  #### :rocket: Dependency updates
@@ -233,8 +245,43 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
233
245
  #### :hammer_and_wrench: Others
234
246
 
235
247
  - 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
248
+ ## [1.0.0](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.20...1.0.0) - 12 June 2026
249
+
250
+ ### [1.0.0-alpha.20](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.19...1.0.0-alpha.20) - 18 August 2026
251
+
252
+ ### [1.0.0-alpha.19](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.18...1.0.0-alpha.19) - 18 August 2026
253
+
254
+ ### [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
255
+
256
+ #### :rocket: Dependency updates
257
+
258
+ - Release @eeacms/volto-globalsearch@4.1.1 [EEA Jenkins - [`f34f23c`](https://github.com/eea/volto-cca-policy/commit/f34f23c587f32930acd4316d43f2f64fd9338764)]
259
+ - Release @eeacms/volto-globalsearch@4.1.0 [EEA Jenkins - [`5d7ddd2`](https://github.com/eea/volto-cca-policy/commit/5d7ddd2cf7a371007a569d185690d655c2c4b2d2)]
260
+
261
+ #### :bug: Bug Fixes
262
+
263
+ - fix: update import [kreafox - [`5e98924`](https://github.com/eea/volto-cca-policy/commit/5e9892488dd84e2e280d29905f4471af4f5403be)]
264
+ - fix: imports in GovernanceTab [kreafox - [`c1eb09f`](https://github.com/eea/volto-cca-policy/commit/c1eb09fd59e730fa15c71fd73f625f9811fd98fa)]
265
+ - fix: improve geochars parsing, and enhance capitalizeFirstLetter function [kreafox - [`370deb6`](https://github.com/eea/volto-cca-policy/commit/370deb6395872c4229c0747077f845f8d8375336)]
266
+
267
+ #### :nail_care: Enhancements
268
+
269
+ - refactor: remove unused export of euCountryNamesEnergy from helpers [kreafox - [`5c40276`](https://github.com/eea/volto-cca-policy/commit/5c40276f491e4b3a24de8ebe29e8fdc0d0d2fe57)]
270
+ - refactor: change exported components to default exports in ImageWidget, countryMap, and queryUtils [kreafox - [`43ce27c`](https://github.com/eea/volto-cca-policy/commit/43ce27c9af8f036e34d5ccefe185fa138fa6f823)]
271
+ - refactor: replace clientOnly HOC with withClientOnly and reorganize helper imports [kreafox - [`5e326f3`](https://github.com/eea/volto-cca-policy/commit/5e326f378af2ba784e7f8b4499a28500a04031b5)]
272
+ - refactor: reorganize content sections, views, and widgets [kreafox - [`4ff70ec`](https://github.com/eea/volto-cca-policy/commit/4ff70ec1a763071ace8292eeac6d2f0d692580cb)]
273
+ - refactor: shared content view components into reusable theme modules [kreafox - [`e0f1906`](https://github.com/eea/volto-cca-policy/commit/e0f190606acc8ab74dfad147f751451d1e8f38eb)]
274
+
275
+ #### :house: Internal changes
237
276
 
277
+ - style: Automated code fix [eea-jenkins - [`c06e6eb`](https://github.com/eea/volto-cca-policy/commit/c06e6ebc41cbe2bb80a9c8472d57fd361fe09dab)]
278
+
279
+ #### :hammer_and_wrench: Others
280
+
281
+ - Refs #307245 - Allow indicators to support multiple visualizations. [GhitaB - [`b7a0b7f`](https://github.com/eea/volto-cca-policy/commit/b7a0b7fe9db40a9d9a1847eb71a95a8f2245dd5e)]
282
+ - test: increase coverage for ImageWidget [kreafox - [`5fd74bf`](https://github.com/eea/volto-cca-policy/commit/5fd74bfe00db49e4977a64871de3144a7247415d)]
283
+ - core: update locales [kreafox - [`f1ba2dd`](https://github.com/eea/volto-cca-policy/commit/f1ba2dd01269d42da4cdeb948951b65857a05e3d)]
284
+ - core: update locales [kreafox - [`122817e`](https://github.com/eea/volto-cca-policy/commit/122817ea9f6f0084fe8cb697ccfaffb8a9fe833d)]
238
285
  ### [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
286
 
240
287
  #### :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.9",
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,13 @@ 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;
37
-
35
+ const MaybeFlourishVisualization = ({ visualization }) => {
36
+ const embedCode = visualization?.embed_code || '';
38
37
  // https://helpcenter.flourish.studio/hc/en-us/articles/8761537208463-How-to-embed-Flourish-charts-in-your-CMS
39
- const flourishPath = getDataSrcFromEmbedCode(map_graphs);
38
+ const flourishPath = getDataSrcFromEmbedCode(embedCode);
40
39
  const flourishUrl = buildFlourishUrl(flourishPath);
40
+ const height = visualization?.height || '980';
41
+ const title = visualization?.title || 'Interactive or visual content';
41
42
 
42
43
  return !!flourishPath ? (
43
44
  <PrivacyProtection
@@ -47,10 +48,10 @@ const MaybeFlourishVisualization = ({ content }) => {
47
48
  }}
48
49
  >
49
50
  <iframe
50
- height="980"
51
+ height={height}
51
52
  width="100%"
52
53
  src={flourishUrl}
53
- title="Interactive or visual content"
54
+ title={title}
54
55
  className="flourish-embed-iframe"
55
56
  sandbox="allow-same-origin allow-forms allow-scripts allow-downloads allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"
56
57
  ></iframe>
@@ -73,10 +74,11 @@ function getFirstIframeSrc(htmlString) {
73
74
  }
74
75
  }
75
76
 
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;
77
+ const MaybeIframeVisualization = ({ visualization }) => {
78
+ const embedCode = visualization?.embed_code || '';
79
+ const url = getFirstIframeSrc(embedCode);
80
+ const height = visualization?.height || 800;
81
+ const title = visualization?.title || 'Interactive or visual content';
80
82
  const [isClient, setIsClient] = React.useState();
81
83
 
82
84
  React.useEffect(() => setIsClient(true), []);
@@ -94,7 +96,7 @@ const MaybeIframeVisualization = ({ content }) => {
94
96
  height={height}
95
97
  width="100%"
96
98
  src={url}
97
- title="Interactive or visual content"
99
+ title={title}
98
100
  className="flourish-embed-iframe"
99
101
  sandbox="allow-same-origin allow-forms allow-scripts allow-downloads allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"
100
102
  ></iframe>
@@ -102,6 +104,31 @@ const MaybeIframeVisualization = ({ content }) => {
102
104
  );
103
105
  };
104
106
 
107
+ const Visualization = ({ visualization }) => (
108
+ <>
109
+ {visualization?.title && <h2>{visualization.title}</h2>}
110
+ <MaybeFlourishVisualization visualization={visualization} />
111
+ <MaybeIframeVisualization visualization={visualization} />
112
+ </>
113
+ );
114
+
115
+ const Visualizations = ({ visualizations }) => (
116
+ <>
117
+ {visualizations.map((visualization, index) => (
118
+ <Visualization
119
+ key={`visualization-${index}`}
120
+ visualization={visualization}
121
+ />
122
+ ))}
123
+ </>
124
+ );
125
+
126
+ const getVisualizations = (content) => {
127
+ return Array.isArray(content?.visualizations)
128
+ ? content.visualizations.filter((item) => item?.embed_code)
129
+ : [];
130
+ };
131
+
105
132
  const BottomInfo = (props) => {
106
133
  const { content } = props;
107
134
  const { organisational_websites, organisational_contact_information } =
@@ -157,9 +184,14 @@ const DatabaseItemView = (props) => {
157
184
  } = content;
158
185
  const item_title = acronym ? title + ' (' + acronym + ')' : title;
159
186
  const subtitle = CONTENT_TYPE_LABELS[type] ?? '';
160
- const hasVisualization = !!content?.map_graphs?.length;
161
- const isFullWidthVisualization =
162
- hasVisualization && content?.map_graphs_full_width;
187
+ const visualizations = getVisualizations(content);
188
+ const columnVisualizations = visualizations.filter(
189
+ (visualization) => !visualization.full_width,
190
+ );
191
+ const fullWidthVisualizations = visualizations.filter(
192
+ (visualization) => visualization.full_width,
193
+ );
194
+ const hasFullWidthVisualizations = !!fullWidthVisualizations.length;
163
195
 
164
196
  const is_cmshare_video = SHARE_EEA.some((domain) =>
165
197
  content?.embed_url?.includes(domain),
@@ -252,14 +284,11 @@ const DatabaseItemView = (props) => {
252
284
  </>
253
285
  )}
254
286
 
255
- {hasVisualization && !isFullWidthVisualization && (
256
- <>
257
- <MaybeFlourishVisualization {...props} />
258
- <MaybeIframeVisualization {...props} />
259
- </>
287
+ {!!columnVisualizations.length && (
288
+ <Visualizations visualizations={columnVisualizations} />
260
289
  )}
261
290
 
262
- {!isFullWidthVisualization && <BottomInfo {...props} />}
291
+ {!hasFullWidthVisualizations && <BottomInfo {...props} />}
263
292
  </Grid.Column>
264
293
 
265
294
  <Grid.Column
@@ -273,12 +302,11 @@ const DatabaseItemView = (props) => {
273
302
  </Grid.Column>
274
303
  </Grid.Row>
275
304
 
276
- {isFullWidthVisualization && (
305
+ {hasFullWidthVisualizations && (
277
306
  <>
278
307
  <Grid.Row>
279
308
  <Grid.Column mobile={12} tablet={12} computer={12}>
280
- <MaybeFlourishVisualization {...props} />
281
- <MaybeIframeVisualization {...props} />
309
+ <Visualizations visualizations={fullWidthVisualizations} />
282
310
  </Grid.Column>
283
311
  </Grid.Row>
284
312
  <Grid.Row>
@@ -17,6 +17,66 @@ 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 getVisualization = (overrides = {}) => ({
48
+ title: '',
49
+ embed_code: visualizationEmbedCode,
50
+ height: '',
51
+ full_width: false,
52
+ ...overrides,
53
+ });
54
+
55
+ const renderDatabaseItemView = (content = baseContent) => {
56
+ const store = mockStore({
57
+ userSession: { token: '1234' },
58
+ intl: {
59
+ locale: 'en',
60
+ messages: {},
61
+ },
62
+ });
63
+
64
+ return renderer.create(
65
+ <Provider store={store}>
66
+ <MemoryRouter>
67
+ <DatabaseItemView content={content} />
68
+ </MemoryRouter>
69
+ </Provider>,
70
+ );
71
+ };
72
+
73
+ const findColumnByClassName = (component, className) =>
74
+ component.root.findAll(
75
+ (node) =>
76
+ typeof node.props.className === 'string' &&
77
+ node.props.className.includes(className),
78
+ )[0];
79
+
20
80
  jest.mock('semantic-ui-react', () => ({
21
81
  ...jest.requireActual('semantic-ui-react'),
22
82
  }));
@@ -29,46 +89,52 @@ jest.mock('@eeacms/volto-embed', () => {
29
89
 
30
90
  describe('DatabaseItemView', () => {
31
91
  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
- },
92
+ const component = renderDatabaseItemView();
93
+ const json = component.toJSON();
94
+ expect(json).toMatchSnapshot();
95
+ });
96
+
97
+ it('renders the visualizations field in the left column by default', () => {
98
+ const component = renderDatabaseItemView({
99
+ ...baseContent,
100
+ visualizations: [getVisualization()],
62
101
  });
102
+ const colLeft = findColumnByClassName(component, 'col-left');
103
+ const fullWidthColumns = component.root.findAll(
104
+ (node) => node.props.computer === 12,
105
+ );
63
106
 
64
- const component = renderer.create(
65
- <Provider store={store}>
66
- <MemoryRouter>
67
- <DatabaseItemView content={content} />
68
- </MemoryRouter>
69
- </Provider>,
107
+ expect(colLeft.findAllByType('iframe')).toHaveLength(1);
108
+ expect(component.root.findByType('iframe').props.src).toBe(
109
+ 'https://flo.uri.sh/visualisation/12345/embed',
70
110
  );
71
- const json = component.toJSON();
72
- expect(json).toMatchSnapshot();
111
+ expect(fullWidthColumns).toHaveLength(0);
112
+ });
113
+
114
+ it('renders the visualizations field full width when enabled', () => {
115
+ const component = renderDatabaseItemView({
116
+ ...baseContent,
117
+ visualizations: [getVisualization({ full_width: true })],
118
+ });
119
+ const colLeft = findColumnByClassName(component, 'col-left');
120
+ const fullWidthColumn = component.root.findAll(
121
+ (node) => node.props.computer === 12,
122
+ )[0];
123
+
124
+ expect(colLeft.findAllByType('iframe')).toHaveLength(0);
125
+ expect(fullWidthColumn.findAllByType('iframe')).toHaveLength(1);
126
+ });
127
+
128
+ it('does not render a visualization when the visualizations field is empty', () => {
129
+ const component = renderDatabaseItemView({
130
+ ...baseContent,
131
+ visualizations: [],
132
+ });
133
+
134
+ expect(component.root.findAllByType('iframe')).toHaveLength(0);
135
+ const fullWidthColumns = component.root.findAll(
136
+ (node) => node.props.computer === 12,
137
+ );
138
+ expect(fullWidthColumns).toHaveLength(0);
73
139
  });
74
140
  });
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) {