@eeacms/volto-embed 10.0.2 → 10.1.0
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 +28 -1
- package/package.json +2 -2
- package/src/Blocks/Maps/schema.js +6 -1
- package/src/EmbedMap/EmbedMap.jsx +8 -4
- package/src/PrivacyProtection/helpers.test.js +34 -0
- package/src/Toolbar/Sources.test.jsx +72 -0
- package/src/Widgets/MapWidget.test.jsx +96 -0
- package/src/Widgets/MapsWidget.jsx +40 -5
- package/src/index.js +5 -0
- package/src/middlewares/preview_image.js +93 -0
- package/src/middlewares/preview_image.test.js +49 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,12 +4,39 @@ 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
|
+
### [10.1.0](https://github.com/eea/volto-embed/compare/10.0.3...10.1.0) - 11 September 2024
|
|
8
|
+
|
|
9
|
+
#### :hammer_and_wrench: Others
|
|
10
|
+
|
|
11
|
+
- Update version [dobri1408 - [`21e7852`](https://github.com/eea/volto-embed/commit/21e7852cfa27bedd7e3670402bf89d7f3b6fdc06)]
|
|
12
|
+
- cleanup preview image loaded [dobri1408 - [`b3e60ff`](https://github.com/eea/volto-embed/commit/b3e60ffedd7e7f7790afbc76e99df4e001e57550)]
|
|
13
|
+
- double check preview [dobri1408 - [`35c6210`](https://github.com/eea/volto-embed/commit/35c621031b4cd25777ac19a2789eac08ffd48176)]
|
|
14
|
+
- tests [dobri1408 - [`70c3620`](https://github.com/eea/volto-embed/commit/70c3620057ffd203105b80ff1c9121a39947c212)]
|
|
15
|
+
- tests [dobri1408 - [`8aa1bfe`](https://github.com/eea/volto-embed/commit/8aa1bfe536968b42cd76abc91b685b28ce485e28)]
|
|
16
|
+
- tests [dobri1408 - [`879f6a7`](https://github.com/eea/volto-embed/commit/879f6a70d329228d974f347cea983621194433a3)]
|
|
17
|
+
- Create preview_image.test.js [dobri1408 - [`fbb7cdb`](https://github.com/eea/volto-embed/commit/fbb7cdb69c1d43a928024d2c83a0dee87faae7af)]
|
|
18
|
+
- Update MapsWidget.jsx [dobri1408 - [`cd46123`](https://github.com/eea/volto-embed/commit/cd46123d39c71d034a2aa9919ad04e7364a08e8d)]
|
|
19
|
+
- Update MapsWidget.jsx [dobri1408 - [`e36c6a9`](https://github.com/eea/volto-embed/commit/e36c6a9c0269622cabf2069d6b8cd082cfbe879b)]
|
|
20
|
+
- preview image middlware [dobri1408 - [`5a0f8e9`](https://github.com/eea/volto-embed/commit/5a0f8e9231d8f5f760dcbd82bbab4a84778d1202)]
|
|
21
|
+
### [10.0.3](https://github.com/eea/volto-embed/compare/10.0.2...10.0.3) - 24 July 2024
|
|
22
|
+
|
|
23
|
+
#### :bug: Bug Fixes
|
|
24
|
+
|
|
25
|
+
- fix: package.json [alin - [`6c29d0d`](https://github.com/eea/volto-embed/commit/6c29d0d3875a95d24b9197db05c187f7c37083a0)]
|
|
26
|
+
|
|
27
|
+
#### :hammer_and_wrench: Others
|
|
28
|
+
|
|
29
|
+
- update [Miu Razvan - [`371e6fc`](https://github.com/eea/volto-embed/commit/371e6fc4a344a995f8be1e2b8fd80325777515c5)]
|
|
30
|
+
- update [Miu Razvan - [`c0536f0`](https://github.com/eea/volto-embed/commit/c0536f00732e3761a71bf5103ee064b5b3c1cc22)]
|
|
31
|
+
- update [Miu Razvan - [`e6c8526`](https://github.com/eea/volto-embed/commit/e6c852685654986be6c8695b4f8888e78adcc0a9)]
|
|
32
|
+
- add useScreenHeight prop [Miu Razvan - [`a261a59`](https://github.com/eea/volto-embed/commit/a261a593892f44845579b2c0aa764e22bbf48e73)]
|
|
33
|
+
- fix tests [Miu Razvan - [`0798660`](https://github.com/eea/volto-embed/commit/0798660ce054a7a60e4c3888cb63ba9c131a42f8)]
|
|
34
|
+
- Set interactiv map height to window innerheight, ref #272831 [Miu Razvan - [`5ac9eb5`](https://github.com/eea/volto-embed/commit/5ac9eb5e66cdc626b33d0bdad5b80994af2d7d79)]
|
|
7
35
|
### [10.0.2](https://github.com/eea/volto-embed/compare/10.0.1...10.0.2) - 7 June 2024
|
|
8
36
|
|
|
9
37
|
#### :bug: Bug Fixes
|
|
10
38
|
|
|
11
39
|
- fix: re-add parseInt with a check for NaN [nileshgulia1 - [`f7dd30c`](https://github.com/eea/volto-embed/commit/f7dd30c47aa2cc31726e49b8eb4cb40aae624941)]
|
|
12
|
-
- fix: remove parseInt [nileshgulia1 - [`0b981b4`](https://github.com/eea/volto-embed/commit/0b981b4035b247ce8bd086ab90fc5dd4a23865c8)]
|
|
13
40
|
|
|
14
41
|
### [10.0.1](https://github.com/eea/volto-embed/compare/10.0.0...10.0.1) - 4 June 2024
|
|
15
42
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eeacms/volto-embed",
|
|
3
|
-
"version": "10.0
|
|
3
|
+
"version": "10.1.0",
|
|
4
4
|
"description": "Embed external content",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"@eeacms/volto-datablocks": "*"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"cypress": "13.1.0",
|
|
27
26
|
"@cypress/code-coverage": "^3.10.0",
|
|
28
27
|
"@plone/scripts": "*",
|
|
29
28
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
|
29
|
+
"cypress": "13.1.0",
|
|
30
30
|
"cypress-fail-fast": "^5.0.1",
|
|
31
31
|
"dotenv": "^16.3.2",
|
|
32
32
|
"husky": "^8.0.3",
|
|
@@ -35,7 +35,7 @@ export const MapsSchema = (props) => {
|
|
|
35
35
|
{
|
|
36
36
|
id: 'default',
|
|
37
37
|
title: 'Default',
|
|
38
|
-
fields: ['url', 'title', 'align', 'height'],
|
|
38
|
+
fields: ['url', 'title', 'align', 'height', 'useScreenHeight'],
|
|
39
39
|
},
|
|
40
40
|
],
|
|
41
41
|
|
|
@@ -63,6 +63,11 @@ export const MapsSchema = (props) => {
|
|
|
63
63
|
),
|
|
64
64
|
description: props.intl.formatMessage(messages.CSSMapHeightDescription),
|
|
65
65
|
},
|
|
66
|
+
useScreenHeight: {
|
|
67
|
+
title: 'Use screen height',
|
|
68
|
+
type: 'boolean',
|
|
69
|
+
default: false,
|
|
70
|
+
},
|
|
66
71
|
},
|
|
67
72
|
required: [],
|
|
68
73
|
};
|
|
@@ -22,12 +22,16 @@ const messages = defineMessages({
|
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
function getHeight(
|
|
25
|
+
function getHeight(data, screen) {
|
|
26
|
+
const { height, useScreenHeight } = data;
|
|
26
27
|
const asNumber = isNumber(Number(height)) && !isNaN(Number(height));
|
|
27
28
|
if (asNumber) {
|
|
28
29
|
return `${height}px`;
|
|
29
30
|
}
|
|
30
|
-
return
|
|
31
|
+
return (
|
|
32
|
+
height ||
|
|
33
|
+
(useScreenHeight && screen?.page?.height ? screen.page.height - 50 : 400)
|
|
34
|
+
);
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
function EmbedMap({ data, intl, id, screen }) {
|
|
@@ -78,7 +82,7 @@ function EmbedMap({ data, intl, id, screen }) {
|
|
|
78
82
|
<PrivacyProtection
|
|
79
83
|
data={data}
|
|
80
84
|
id={id}
|
|
81
|
-
height={getHeight(data
|
|
85
|
+
height={getHeight(data, screen)}
|
|
82
86
|
useVisibilitySensor={data.useVisibilitySensor ?? true}
|
|
83
87
|
>
|
|
84
88
|
<iframe
|
|
@@ -87,7 +91,7 @@ function EmbedMap({ data, intl, id, screen }) {
|
|
|
87
91
|
className="google-map"
|
|
88
92
|
frameBorder="0"
|
|
89
93
|
allowFullScreen
|
|
90
|
-
style={
|
|
94
|
+
style={{ height: getHeight(data, screen) }}
|
|
91
95
|
/>
|
|
92
96
|
</PrivacyProtection>
|
|
93
97
|
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createImageUrl } from './helpers';
|
|
2
|
+
|
|
3
|
+
describe('createImageUrl', () => {
|
|
4
|
+
it('should create a valid image URL from the base64 encoded data', () => {
|
|
5
|
+
// Mock data for the test
|
|
6
|
+
const mockResult = {
|
|
7
|
+
data: 'aGVsbG8gd29ybGQ=', // "hello world" in base64
|
|
8
|
+
'content-type': 'image/png',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Mock the atob function
|
|
12
|
+
jest.spyOn(window, 'atob').mockImplementation(() => 'hello world');
|
|
13
|
+
|
|
14
|
+
// Mock the URL.createObjectURL function
|
|
15
|
+
const mockUrl = 'blob:http://localhost:3000/some-url';
|
|
16
|
+
global.URL.createObjectURL = jest.fn().mockReturnValue(mockUrl);
|
|
17
|
+
|
|
18
|
+
// Call the function
|
|
19
|
+
const imageUrl = createImageUrl(mockResult);
|
|
20
|
+
|
|
21
|
+
// Assertions
|
|
22
|
+
expect(window.atob).toHaveBeenCalledWith(mockResult.data);
|
|
23
|
+
expect(URL.createObjectURL).toHaveBeenCalledWith(expect.any(Blob));
|
|
24
|
+
expect(imageUrl).toBe(mockUrl);
|
|
25
|
+
|
|
26
|
+
// Verify the Blob creation
|
|
27
|
+
const blobArgs = URL.createObjectURL.mock.calls[0][0];
|
|
28
|
+
expect(blobArgs.type).toBe(mockResult['content-type']);
|
|
29
|
+
expect(blobArgs.size).toBe(11); // "hello world" is 11 bytes
|
|
30
|
+
|
|
31
|
+
// Clean up mocks
|
|
32
|
+
jest.restoreAllMocks();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent, screen } from '@testing-library/react';
|
|
3
|
+
import Sources from './Sources';
|
|
4
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
5
|
+
|
|
6
|
+
const mockSources = [
|
|
7
|
+
{
|
|
8
|
+
chart_source: 'Source 1',
|
|
9
|
+
chart_source_link: 'http://example.com/source1',
|
|
10
|
+
organisation: 'Organisation 1',
|
|
11
|
+
title: 'Title 1',
|
|
12
|
+
link: 'http://example.com/link1',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
chart_source: 'Source 2',
|
|
16
|
+
chart_source_link: 'http://example.com/source2',
|
|
17
|
+
organisation: 'Organisation 2',
|
|
18
|
+
title: 'Title 2',
|
|
19
|
+
link: 'http://example.com/link2',
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
describe('Sources', () => {
|
|
24
|
+
it('renders the Sources button', () => {
|
|
25
|
+
render(<Sources sources={mockSources} />);
|
|
26
|
+
expect(screen.getByText('Sources')).toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('opens and closes the popup on click', () => {
|
|
30
|
+
render(<Sources sources={mockSources} />);
|
|
31
|
+
|
|
32
|
+
const triggerButton = screen.getByText('Sources');
|
|
33
|
+
|
|
34
|
+
expect(screen.queryByText('Source 1')).toBeInTheDocument();
|
|
35
|
+
|
|
36
|
+
fireEvent.click(triggerButton);
|
|
37
|
+
expect(screen.getByText('Source 1')).toBeInTheDocument();
|
|
38
|
+
expect(screen.getByText('Source 2')).toBeInTheDocument();
|
|
39
|
+
|
|
40
|
+
fireEvent.click(triggerButton);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('renders sources correctly', () => {
|
|
44
|
+
render(<Sources sources={mockSources} />);
|
|
45
|
+
|
|
46
|
+
const triggerButton = screen.getByText('Sources');
|
|
47
|
+
fireEvent.click(triggerButton);
|
|
48
|
+
|
|
49
|
+
expect(screen.getByText('Source 1')).toBeInTheDocument();
|
|
50
|
+
expect(screen.getByText('Source 2')).toBeInTheDocument();
|
|
51
|
+
|
|
52
|
+
expect(screen.getByText('Source 1').closest('a')).toHaveAttribute(
|
|
53
|
+
'href',
|
|
54
|
+
'http://example.com/source1',
|
|
55
|
+
);
|
|
56
|
+
expect(screen.getByText('Source 2').closest('a')).toHaveAttribute(
|
|
57
|
+
'href',
|
|
58
|
+
'http://example.com/source2',
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('renders a message when there are no sources', () => {
|
|
63
|
+
render(<Sources sources={[]} />);
|
|
64
|
+
|
|
65
|
+
const triggerButton = screen.getByText('Sources');
|
|
66
|
+
fireEvent.click(triggerButton);
|
|
67
|
+
|
|
68
|
+
expect(
|
|
69
|
+
screen.getByText('Data provenance is not set for this visualization.'),
|
|
70
|
+
).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { Provider } from 'react-redux';
|
|
4
|
+
import configureStore from 'redux-mock-store';
|
|
5
|
+
import MapsViewWidget from './MapsViewWidget';
|
|
6
|
+
import EmbedMap from '@eeacms/volto-embed/EmbedMap/EmbedMap';
|
|
7
|
+
import { pickMetadata } from '@eeacms/volto-embed/helpers';
|
|
8
|
+
import '@testing-library/jest-dom/extend-expect'; // Importă jest-dom
|
|
9
|
+
|
|
10
|
+
jest.mock('@eeacms/volto-embed/EmbedMap/EmbedMap', () =>
|
|
11
|
+
jest.fn(() => <div>Mocked EmbedMap</div>),
|
|
12
|
+
);
|
|
13
|
+
jest.mock('@eeacms/volto-embed/helpers', () => ({
|
|
14
|
+
pickMetadata: jest.fn(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
const mockStore = configureStore([]);
|
|
18
|
+
|
|
19
|
+
describe('MapsViewWidget', () => {
|
|
20
|
+
let store;
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
store = mockStore({
|
|
24
|
+
content: {
|
|
25
|
+
data: {
|
|
26
|
+
metadata: {
|
|
27
|
+
title: 'Test Title',
|
|
28
|
+
description: 'Test Description',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should render EmbedMap with the correct data props', () => {
|
|
36
|
+
const mockValue = {
|
|
37
|
+
map_url: 'http://example.com/map',
|
|
38
|
+
};
|
|
39
|
+
const mockId = 'map-widget-1';
|
|
40
|
+
|
|
41
|
+
pickMetadata.mockReturnValue({
|
|
42
|
+
title: 'Test Title',
|
|
43
|
+
description: 'Test Description',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const { getByText } = render(
|
|
47
|
+
<Provider store={store}>
|
|
48
|
+
<MapsViewWidget id={mockId} value={mockValue} />
|
|
49
|
+
</Provider>,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
expect(EmbedMap).toHaveBeenCalledWith(
|
|
53
|
+
{
|
|
54
|
+
data: {
|
|
55
|
+
map_url: 'http://example.com/map',
|
|
56
|
+
title: 'Test Title',
|
|
57
|
+
description: 'Test Description',
|
|
58
|
+
with_share: true,
|
|
59
|
+
},
|
|
60
|
+
id: mockId,
|
|
61
|
+
},
|
|
62
|
+
{},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
expect(getByText('Mocked EmbedMap')).toBeInTheDocument(); // Verifică dacă elementul este în document
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should handle empty value prop correctly', () => {
|
|
69
|
+
const mockId = 'map-widget-2';
|
|
70
|
+
|
|
71
|
+
pickMetadata.mockReturnValue({
|
|
72
|
+
title: 'Test Title',
|
|
73
|
+
description: 'Test Description',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const { getByText } = render(
|
|
77
|
+
<Provider store={store}>
|
|
78
|
+
<MapsViewWidget id={mockId} value={null} />
|
|
79
|
+
</Provider>,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
expect(EmbedMap).toHaveBeenCalledWith(
|
|
83
|
+
{
|
|
84
|
+
data: {
|
|
85
|
+
title: 'Test Title',
|
|
86
|
+
description: 'Test Description',
|
|
87
|
+
with_share: true,
|
|
88
|
+
},
|
|
89
|
+
id: mockId,
|
|
90
|
+
},
|
|
91
|
+
{},
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
expect(getByText('Mocked EmbedMap')).toBeInTheDocument(); // Verifică dacă elementul este în document
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useMemo, useState } from 'react';
|
|
1
|
+
import React, { useMemo, useState, useEffect } from 'react';
|
|
2
2
|
import { useIntl, FormattedMessage, defineMessages } from 'react-intl';
|
|
3
3
|
import { Icon } from '@plone/volto/components';
|
|
4
4
|
import { Button, Modal, Grid, Label, Input, Message } from 'semantic-ui-react';
|
|
@@ -7,6 +7,7 @@ import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
|
|
|
7
7
|
import { addPrivacyProtectionToSchema } from '@eeacms/volto-embed';
|
|
8
8
|
import EmbedMap from '@eeacms/volto-embed/EmbedMap/EmbedMap';
|
|
9
9
|
import { MapsSchema } from '@eeacms/volto-embed/Blocks/Maps/schema';
|
|
10
|
+
import { getBaseUrl } from '@plone/volto/helpers';
|
|
10
11
|
|
|
11
12
|
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
12
13
|
import aheadSVG from '@plone/volto/icons/ahead.svg';
|
|
@@ -19,6 +20,17 @@ const messages = defineMessages({
|
|
|
19
20
|
},
|
|
20
21
|
});
|
|
21
22
|
|
|
23
|
+
function blobToBase64(blob) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const reader = new FileReader();
|
|
26
|
+
reader.onloadend = () => {
|
|
27
|
+
resolve(reader.result);
|
|
28
|
+
};
|
|
29
|
+
reader.onerror = reject;
|
|
30
|
+
reader.readAsDataURL(blob);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
function MapEditorModal({ id, onClose, onChange, ...rest }) {
|
|
23
35
|
const intl = useIntl();
|
|
24
36
|
const [value, setValue] = useState(rest.value || {});
|
|
@@ -189,14 +201,37 @@ function MapEditorModal({ id, onClose, onChange, ...rest }) {
|
|
|
189
201
|
}
|
|
190
202
|
|
|
191
203
|
export default function MapsWidget(props) {
|
|
192
|
-
const { id, title, description, error, value } = props;
|
|
204
|
+
const { id, title, description, error, value, onChange } = props;
|
|
193
205
|
const [mapEditor, setMapEditor] = useState(false);
|
|
194
206
|
|
|
195
|
-
function
|
|
196
|
-
|
|
207
|
+
function onChangeMap(value) {
|
|
208
|
+
onChange(id, value);
|
|
197
209
|
setMapEditor(false);
|
|
198
210
|
}
|
|
199
211
|
|
|
212
|
+
useEffect(() => {
|
|
213
|
+
if (value && value.url && value.preview_url_loaded !== value.url) {
|
|
214
|
+
fetch(
|
|
215
|
+
`${getBaseUrl(
|
|
216
|
+
'',
|
|
217
|
+
)}/cors-proxy/https://screenshot.eea.europa.eu/api/v1/retrieve_image_for_url?url=${encodeURIComponent(
|
|
218
|
+
value.url,
|
|
219
|
+
)}&w=1920&h=1000&waitfor=4000`,
|
|
220
|
+
)
|
|
221
|
+
.then((e) => e.blob())
|
|
222
|
+
.then((myBlob) => {
|
|
223
|
+
blobToBase64(myBlob).then((base64String) => {
|
|
224
|
+
onChange(id, {
|
|
225
|
+
...value,
|
|
226
|
+
preview: base64String,
|
|
227
|
+
preview_url_loaded: value.url,
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
})
|
|
231
|
+
.catch(() => {});
|
|
232
|
+
}
|
|
233
|
+
}, [value, onChange, id]);
|
|
234
|
+
|
|
200
235
|
return (
|
|
201
236
|
<FormFieldWrapper {...props} columns={1}>
|
|
202
237
|
<div className="wrapper">
|
|
@@ -218,7 +253,7 @@ export default function MapsWidget(props) {
|
|
|
218
253
|
<MapEditorModal
|
|
219
254
|
id={id}
|
|
220
255
|
value={value || {}}
|
|
221
|
-
onChange={
|
|
256
|
+
onChange={onChangeMap}
|
|
222
257
|
onClose={() => setMapEditor(false)}
|
|
223
258
|
/>
|
|
224
259
|
)}
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import installBlocks from './Blocks';
|
|
|
2
2
|
import MapView from './Views/MapView';
|
|
3
3
|
import MapsViewWidget from './Widgets/MapsViewWidget';
|
|
4
4
|
import MapsWidget from './Widgets/MapsWidget';
|
|
5
|
+
import { preview_image } from './middlewares/preview_image';
|
|
5
6
|
export {
|
|
6
7
|
PrivacyProtection,
|
|
7
8
|
addPrivacyProtectionToSchema,
|
|
@@ -16,5 +17,9 @@ export default function applyConfig(config) {
|
|
|
16
17
|
...config.settings.allowed_cors_destinations,
|
|
17
18
|
'screenshot.eea.europa.eu',
|
|
18
19
|
];
|
|
20
|
+
config.settings.storeExtenders = [
|
|
21
|
+
...(config.settings.storeExtenders || []),
|
|
22
|
+
preview_image,
|
|
23
|
+
];
|
|
19
24
|
return [installBlocks].reduce((acc, apply) => apply(acc), config);
|
|
20
25
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CREATE_CONTENT,
|
|
3
|
+
UPDATE_CONTENT,
|
|
4
|
+
} from '@plone/volto/constants/ActionTypes';
|
|
5
|
+
|
|
6
|
+
const cleanAction = (action) => {
|
|
7
|
+
if (action?.request?.data?.maps) {
|
|
8
|
+
const mapVisualizationData = {
|
|
9
|
+
...action.request.data.maps,
|
|
10
|
+
};
|
|
11
|
+
if (mapVisualizationData.preview && mapVisualizationData.preview_url_loaded)
|
|
12
|
+
delete mapVisualizationData.preview;
|
|
13
|
+
delete mapVisualizationData.preview_url_loaded;
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
...action,
|
|
17
|
+
request: {
|
|
18
|
+
...action.request,
|
|
19
|
+
data: {
|
|
20
|
+
...action.request.data,
|
|
21
|
+
|
|
22
|
+
maps: mapVisualizationData,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
} else return action;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const preview_image = (middlewares) => [
|
|
30
|
+
(store) => (next) => async (action) => {
|
|
31
|
+
if (![CREATE_CONTENT, UPDATE_CONTENT].includes(action.type)) {
|
|
32
|
+
return next(action);
|
|
33
|
+
}
|
|
34
|
+
const state = store.getState();
|
|
35
|
+
const contentData = state.content.data;
|
|
36
|
+
const lastPreviewImage = Object.keys(action?.request?.data).includes(
|
|
37
|
+
'preview_image',
|
|
38
|
+
)
|
|
39
|
+
? action?.request?.data.preview_image
|
|
40
|
+
: contentData?.preview_image;
|
|
41
|
+
const type = action?.request?.data?.['@type'] || contentData['@type'];
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
!contentData ||
|
|
45
|
+
type !== 'map_interactive' ||
|
|
46
|
+
contentData.preview_image_saved ||
|
|
47
|
+
!action?.request?.data?.maps?.preview
|
|
48
|
+
) {
|
|
49
|
+
return next(cleanAction(action));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (
|
|
53
|
+
lastPreviewImage &&
|
|
54
|
+
lastPreviewImage.filename !==
|
|
55
|
+
'preview_image_generated_map_interactive.png'
|
|
56
|
+
) {
|
|
57
|
+
return next(cleanAction(action));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const previewImage = {
|
|
62
|
+
preview_image: {
|
|
63
|
+
data: action.request.data.maps.preview.split(',')[1],
|
|
64
|
+
encoding: 'base64',
|
|
65
|
+
'content-type': 'image/png',
|
|
66
|
+
filename: 'preview_image_generated_map_interactive.png',
|
|
67
|
+
},
|
|
68
|
+
preview_image_saved: true,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const mapVisualizationData = {
|
|
72
|
+
...action.request.data.maps,
|
|
73
|
+
};
|
|
74
|
+
delete mapVisualizationData.preview;
|
|
75
|
+
delete mapVisualizationData.preview_url_loaded;
|
|
76
|
+
|
|
77
|
+
return next({
|
|
78
|
+
...action,
|
|
79
|
+
request: {
|
|
80
|
+
...action.request,
|
|
81
|
+
data: {
|
|
82
|
+
...action.request.data,
|
|
83
|
+
...previewImage,
|
|
84
|
+
maps: mapVisualizationData,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return next(action);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
...middlewares,
|
|
93
|
+
];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { preview_image } from './preview_image';
|
|
2
|
+
describe('preview_image middleware', () => {
|
|
3
|
+
let store;
|
|
4
|
+
let next;
|
|
5
|
+
let action;
|
|
6
|
+
let middlewares;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
store = {
|
|
10
|
+
getState: jest.fn(() => ({
|
|
11
|
+
content: {
|
|
12
|
+
data: {
|
|
13
|
+
'@type': 'map_interactive',
|
|
14
|
+
preview_image: 'existing_image.png',
|
|
15
|
+
preview_image_saved: false,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
})),
|
|
19
|
+
};
|
|
20
|
+
next = jest.fn();
|
|
21
|
+
middlewares = [];
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('existing image', () => {
|
|
25
|
+
action = { type: 'UPDATE_CONTENT', request: { data: {} } };
|
|
26
|
+
const middleware = preview_image(middlewares)[0]; // Accesăm prima funcție din array
|
|
27
|
+
middleware(store)(next)(action); // Executăm funcția de middleware
|
|
28
|
+
expect(next).toHaveBeenCalledWith(action); // Verificăm că funcția next a fost apelată cu acțiunea originală
|
|
29
|
+
});
|
|
30
|
+
it('redo the image', () => {
|
|
31
|
+
store = {
|
|
32
|
+
getState: jest.fn(() => ({
|
|
33
|
+
content: {
|
|
34
|
+
data: {
|
|
35
|
+
'@type': 'map_interactive',
|
|
36
|
+
preview_image: 'preview_image_generated_map_interactive.png',
|
|
37
|
+
preview_image_saved: false,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
})),
|
|
41
|
+
};
|
|
42
|
+
next = jest.fn();
|
|
43
|
+
middlewares = [];
|
|
44
|
+
action = { type: 'UPDATE_CONTENT', request: { data: {} } };
|
|
45
|
+
const middleware = preview_image(middlewares)[0]; // Accesăm prima funcție din array
|
|
46
|
+
middleware(store)(next)(action); // Executăm funcția de middleware
|
|
47
|
+
expect(next).toHaveBeenCalledWith(action); // Verificăm că funcția next a fost apelată cu acțiunea originală
|
|
48
|
+
});
|
|
49
|
+
});
|