@eeacms/volto-tableau 8.0.5 → 8.0.7

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,11 +4,43 @@ 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
- ### [8.0.5](https://github.com/eea/volto-tableau/compare/8.0.4...8.0.5) - 23 July 2024
7
+ ### [8.0.7](https://github.com/eea/volto-tableau/compare/8.0.6...8.0.7) - 9 September 2024
8
8
 
9
- #### :hammer_and_wrench: Others
9
+ #### :house: Internal changes
10
+
11
+ - style: Automated code fix [eea-jenkins - [`ef00271`](https://github.com/eea/volto-tableau/commit/ef00271928ae63ba0d22485f9343fc304e090b03)]
12
+
13
+ #### :hammer_and_wrench: Others
14
+
15
+ - Update View.test.jsx [dobri1408 - [`984f762`](https://github.com/eea/volto-tableau/commit/984f76249550287ef297526d3962a61fd498a0be)]
16
+ - increase code coverage [dobri1408 - [`4a0b444`](https://github.com/eea/volto-tableau/commit/4a0b4449f244c4deacc4015b0d2373d0baa49e2f)]
17
+ - increase code coverage [dobri1408 - [`0a036f4`](https://github.com/eea/volto-tableau/commit/0a036f4d45401da63e71104cae57f7378a4d3624)]
18
+ - increase code coverage [dobri1408 - [`0438558`](https://github.com/eea/volto-tableau/commit/0438558970650d3a01d74802e622cd9d27ebda81)]
19
+ - double check preview [dobri1408 - [`85e0689`](https://github.com/eea/volto-tableau/commit/85e0689f800064e98937be6f74bfdd9959ccd1da)]
20
+ - double check preview [dobri1408 - [`1671a45`](https://github.com/eea/volto-tableau/commit/1671a45608c765f832b48789721dbe7b06b65ed4)]
21
+ - Update preview_image.js [dobri1408 - [`87925c5`](https://github.com/eea/volto-tableau/commit/87925c5c45d8395c9c5b956ead2a7d988823233a)]
22
+ - double check preview [dobri1408 - [`1579659`](https://github.com/eea/volto-tableau/commit/1579659822d56993dd147a6256013b0e7c12bbb5)]
23
+ - Create preview_image.test.js [dobri1408 - [`c562940`](https://github.com/eea/volto-tableau/commit/c562940a2f0bb7ae34ef98a62d2c95f4fe2506c0)]
24
+ - Update preview_image.js [dobri1408 - [`aa3b15e`](https://github.com/eea/volto-tableau/commit/aa3b15edd95d64c8ca969a8252f7d9371e142a6d)]
25
+ - merge [dobri1408 - [`ba63a8f`](https://github.com/eea/volto-tableau/commit/ba63a8f95349d00e5782ebff31870e96891362ca)]
26
+ - manage redux and action right [dobri1408 - [`85be516`](https://github.com/eea/volto-tableau/commit/85be51613a3789adbebd3a517f6b87f600ed3e92)]
27
+ - Update preview_image.js [dobri1408 - [`bb20a02`](https://github.com/eea/volto-tableau/commit/bb20a0204292ef9f94734b343eea9f2fd3e5a96a)]
28
+ - Update VisualizationWidget.jsx [dobri1408 - [`e5ee11c`](https://github.com/eea/volto-tableau/commit/e5ee11ca4f5ee10a42f28e7087582744628aa144)]
29
+ - Update VisualizationWidget.jsx [dobri1408 - [`f0d3bdf`](https://github.com/eea/volto-tableau/commit/f0d3bdf6edff339a037a64453eea714496c39d92)]
30
+ - fix multiple rerenders [dobri1408 - [`6cc0ef0`](https://github.com/eea/volto-tableau/commit/6cc0ef0b8d1bb7f3a0770666c6e60bb3c28df0d4)]
31
+ - Update VisualizationWidget.jsx [dobri1408 - [`56d94fd`](https://github.com/eea/volto-tableau/commit/56d94fdf9bd26db1512d2ae5ee5f65e743b795b5)]
32
+ - fix eslint [dobri1408 - [`d7d754e`](https://github.com/eea/volto-tableau/commit/d7d754e9d89b60951ac7da27b14db93389832216)]
33
+ - fix eslint [dobri1408 - [`58b50d9`](https://github.com/eea/volto-tableau/commit/58b50d995059eea0cc31a0bb6e8e80b48ace99ea)]
34
+ - middleware to save preview image [dobri1408 - [`4b9d1b3`](https://github.com/eea/volto-tableau/commit/4b9d1b3efc5c1cc04d273ce91ccc0621cb60b324)]
35
+ - Update package.json [dobri1408 - [`12a1c94`](https://github.com/eea/volto-tableau/commit/12a1c9478591ba4729f00a55932858b5ef616ff2)]
36
+ - middleware to save preview image [dobri1408 - [`9fe3dd7`](https://github.com/eea/volto-tableau/commit/9fe3dd795842f40e2f0d91475df04b7b97de922e)]
37
+ ### [8.0.6](https://github.com/eea/volto-tableau/compare/8.0.5...8.0.6) - 25 July 2024
38
+
39
+ #### :hammer_and_wrench: Others
40
+
41
+ - Update Jenkinsfile [Alexandru Ghica - [`d5e7d48`](https://github.com/eea/volto-tableau/commit/d5e7d48a52e494ebf139b14ea06d0cac8cce82f3)]
42
+ ### [8.0.5](https://github.com/eea/volto-tableau/compare/8.0.4...8.0.5) - 23 July 2024
10
43
 
11
- - remove default height value on tableau, ref #272831 [Miu Razvan - [`e3fbe96`](https://github.com/eea/volto-tableau/commit/e3fbe9665bec14204694db1968746fb565a2cdc8)]
12
44
  ### [8.0.4](https://github.com/eea/volto-tableau/compare/8.0.3...8.0.4) - 22 July 2024
13
45
 
14
46
  #### :hammer_and_wrench: Others
package/Jenkinsfile CHANGED
@@ -14,7 +14,7 @@ pipeline {
14
14
  BACKEND_PROFILES = "eea.kitkat:testing"
15
15
  BACKEND_ADDONS = ""
16
16
  VOLTO = "17"
17
- VOLTO16_BREAKING_CHANGES = "no"
17
+ VOLTO16_BREAKING_CHANGES = "yes"
18
18
  IMAGE_NAME = BUILD_TAG.toLowerCase()
19
19
  }
20
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-tableau",
3
- "version": "8.0.5",
3
+ "version": "8.0.7",
4
4
  "description": "@eeacms/volto-tableau: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -0,0 +1,144 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { Provider } from 'react-redux';
4
+ import configureStore from 'redux-mock-store';
5
+ import View from './View';
6
+ import '@testing-library/jest-dom/extend-expect';
7
+ import Tableau from '@eeacms/volto-tableau/Tableau/Tableau';
8
+
9
+ jest.mock('@eeacms/volto-tableau/Tableau/Tableau', () =>
10
+ jest.fn(() => <div>Mocked Tableau</div>),
11
+ );
12
+
13
+ jest.mock('@plone/volto/registry', () => ({
14
+ blocks: {
15
+ blocksConfig: {
16
+ tableau_block: {
17
+ breakpoints: {},
18
+ },
19
+ },
20
+ },
21
+ }));
22
+
23
+ const mockStore = configureStore([]);
24
+
25
+ describe('View component', () => {
26
+ let store;
27
+
28
+ beforeEach(() => {
29
+ store = mockStore({
30
+ router: {
31
+ location: {
32
+ search: '?param1=value1',
33
+ },
34
+ },
35
+ discodata_query: {
36
+ search: {},
37
+ },
38
+ screen: {},
39
+ });
40
+ });
41
+
42
+ it('renders correctly with title and description when loaded', () => {
43
+ const mockProps = {
44
+ block: '1234',
45
+ data: {
46
+ title: 'Test Title',
47
+ description: 'Test Description',
48
+ staticParameters: [],
49
+ urlParameters: [],
50
+ },
51
+ mode: 'view',
52
+ query: {},
53
+ };
54
+
55
+ render(
56
+ <Provider store={store}>
57
+ <View {...mockProps} />
58
+ </Provider>,
59
+ );
60
+
61
+ // Simulăm vizualizarea încărcată
62
+ const tableauBlock = screen.getByText('Mocked Tableau');
63
+ expect(tableauBlock).toBeInTheDocument();
64
+
65
+ // Verificăm titlul și descrierea
66
+ expect(screen.queryByText('Test Title')).not.toBeInTheDocument();
67
+ expect(screen.queryByText('Test Description')).not.toBeInTheDocument();
68
+
69
+ // Aici simulăm setVizState pentru a actualiza starea vizualizării ca fiind "loaded"
70
+ mockProps.setVizState = jest.fn((state) => {
71
+ state.loaded = true;
72
+ });
73
+
74
+ // Re-render după schimbarea stării
75
+ render(
76
+ <Provider store={store}>
77
+ <View {...mockProps} />
78
+ </Provider>,
79
+ );
80
+
81
+ expect(screen.getByText('Test Title')).toBeInTheDocument();
82
+ expect(screen.getByText('Test Description')).toBeInTheDocument();
83
+ });
84
+
85
+ it('sets extraFilters correctly based on query parameters', () => {
86
+ const mockProps = {
87
+ block: '1234',
88
+ data: {
89
+ staticParameters: [],
90
+ urlParameters: [{ field: 'filter1', urlParam: 'param1' }],
91
+ },
92
+ mode: 'view',
93
+ query: { param1: 'value1' },
94
+ };
95
+
96
+ render(
97
+ <Provider store={store}>
98
+ <View {...mockProps} />
99
+ </Provider>,
100
+ );
101
+
102
+ expect(Tableau).toHaveBeenCalledWith(
103
+ expect.objectContaining({
104
+ extraFilters: { filter1: 'value1' },
105
+ }),
106
+ {},
107
+ );
108
+ });
109
+
110
+ it('renders Tableau with correct props', () => {
111
+ const mockProps = {
112
+ block: '1234',
113
+ data: {
114
+ title: 'Test Title',
115
+ description: 'Test Description',
116
+ staticParameters: [{ field: 'static1', value: 'staticValue' }],
117
+ urlParameters: [],
118
+ },
119
+ mode: 'view',
120
+ query: {},
121
+ };
122
+
123
+ render(
124
+ <Provider store={store}>
125
+ <View {...mockProps} />
126
+ </Provider>,
127
+ );
128
+
129
+ expect(Tableau).toHaveBeenCalledWith(
130
+ expect.objectContaining({
131
+ data: expect.objectContaining({
132
+ title: 'Test Title',
133
+ description: 'Test Description',
134
+ with_sources: true,
135
+ with_download: true,
136
+ with_share: true,
137
+ with_enlarge: true,
138
+ }),
139
+ extraOptions: { static1: 'staticValue' },
140
+ }),
141
+ {},
142
+ );
143
+ });
144
+ });
@@ -16,9 +16,21 @@ import {
16
16
  } from '@eeacms/volto-tableau/Tableau/helpers';
17
17
 
18
18
  import '@eeacms/volto-tableau/less/tableau.less';
19
+ import { getBaseUrl } from '@plone/volto/helpers';
20
+
21
+ function blobToBase64(blob) {
22
+ return new Promise((resolve, reject) => {
23
+ const reader = new FileReader();
24
+ reader.onloadend = () => {
25
+ resolve(reader.result);
26
+ };
27
+ reader.onerror = reject;
28
+ reader.readAsDataURL(blob);
29
+ });
30
+ }
19
31
 
20
32
  const VisualizationWidget = (props) => {
21
- const { location, content } = props;
33
+ const { location, content, onChange, id } = props;
22
34
  const ogValue = props.value || {};
23
35
  const inAddForm = props.location.pathname.split('/').pop() === 'add';
24
36
  const viz = React.useRef();
@@ -120,6 +132,29 @@ const VisualizationWidget = (props) => {
120
132
  );
121
133
  }, [vizState, value]);
122
134
 
135
+ React.useEffect(() => {
136
+ if (value && value.url && value.preview_url_loaded !== value.url) {
137
+ fetch(
138
+ `${getBaseUrl(
139
+ '',
140
+ )}/cors-proxy/https://screenshot.eea.europa.eu/api/v1/retrieve_image_for_url?url=${encodeURIComponent(
141
+ value.url,
142
+ )}&w=1920&h=1000&waitfor=4000`,
143
+ )
144
+ .then((e) => e.blob())
145
+ .then((myBlob) => {
146
+ blobToBase64(myBlob).then((base64String) => {
147
+ onChange(id, {
148
+ ...value,
149
+ preview: base64String,
150
+ preview_url_loaded: value.url,
151
+ });
152
+ });
153
+ })
154
+ .catch(() => {});
155
+ }
156
+ }, [value, onChange, id]);
157
+
123
158
  return (
124
159
  <FormFieldWrapper {...props}>
125
160
  <Modal id="tableau-editor-modal" open={open}>
@@ -41,7 +41,9 @@ async function getUrlParametersSchema({ viz, vizState, data }) {
41
41
 
42
42
  async function getStaticParametersSchema({ viz, vizState, data }) {
43
43
  const tableauParameters =
44
- vizState.loaded && viz ? await viz.getWorkbook().getParametersAsync() : [];
44
+ vizState.loaded && viz
45
+ ? (await viz.getWorkbook?.().getParametersAsync?.()) || []
46
+ : [];
45
47
 
46
48
  const currentFields = (data.staticParameters || [])
47
49
  .map((p) => p.field)
@@ -75,7 +77,7 @@ async function getStaticParametersSchema({ viz, vizState, data }) {
75
77
  async function getDynamicFiltersSchema({ viz, vizState, data }) {
76
78
  const tableauFilters =
77
79
  vizState.loaded && viz
78
- ? await viz.getWorkbook().getActiveSheet().getFiltersAsync()
80
+ ? (await viz.getWorkbook?.().getActiveSheet?.().getFiltersAsync?.()) || []
79
81
  : [];
80
82
 
81
83
  const currentFields = (data.staticFilters || [])
@@ -112,7 +114,7 @@ async function getDynamicFiltersSchema({ viz, vizState, data }) {
112
114
  async function getStaticFiltersSchema({ viz, vizState, data }) {
113
115
  const tableauFilters =
114
116
  vizState.loaded && viz
115
- ? await viz.getWorkbook().getActiveSheet().getFiltersAsync()
117
+ ? (await viz.getWorkbook?.().getActiveSheet?.().getFiltersAsync?.()) || []
116
118
  : [];
117
119
 
118
120
  const currentFields = (data.staticFilters || [])
package/src/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  VisualizationViewWidget,
6
6
  CreatableSelectWidget,
7
7
  } from './Widgets';
8
+ import { preview_image } from './middlewares/preview_image';
8
9
 
9
10
  const applyConfig = (config) => {
10
11
  config.settings.allowed_cors_destinations = [
@@ -12,7 +13,10 @@ const applyConfig = (config) => {
12
13
  'public.tableau.com',
13
14
  ];
14
15
 
15
- config.settings.storeExtenders = [...(config.settings.storeExtenders || [])];
16
+ config.settings.storeExtenders = [
17
+ ...(config.settings.storeExtenders || []),
18
+ preview_image,
19
+ ];
16
20
 
17
21
  config.views.contentTypesViews.tableau_visualization = VisualizationView;
18
22
  config.widgets.id.tableau_visualization = VisualizationWidget;
@@ -0,0 +1,108 @@
1
+ import {
2
+ CREATE_CONTENT,
3
+ UPDATE_CONTENT,
4
+ } from '@plone/volto/constants/ActionTypes';
5
+
6
+ export const preview_image = (middlewares) => [
7
+ (store) => (next) => (action) => {
8
+ if (![CREATE_CONTENT, UPDATE_CONTENT].includes(action.type)) {
9
+ return next(action);
10
+ }
11
+ const state = store.getState();
12
+ const contentData = state.content.data;
13
+ const lastPreviewImage = Object.keys(action?.request?.data).includes(
14
+ 'preview_image',
15
+ )
16
+ ? action?.request?.data.preview_image
17
+ : contentData?.preview_image;
18
+ const type = action?.request?.data?.['@type'] || contentData['@type'];
19
+ if (
20
+ !contentData ||
21
+ type !== 'tableau_visualization' ||
22
+ contentData.preview_image_saved ||
23
+ !action?.request?.data?.tableau_visualization?.preview
24
+ ) {
25
+ return next(action);
26
+ }
27
+
28
+ if (
29
+ lastPreviewImage &&
30
+ lastPreviewImage !== 'preview_image_generated_tableau_visualization.png'
31
+ ) {
32
+ if (action?.request?.data?.tableau_visualization) {
33
+ const tableauVisualizationData = {
34
+ ...action.request.data.tableau_visualization,
35
+ };
36
+
37
+ if (
38
+ tableauVisualizationData.preview &&
39
+ tableauVisualizationData.preview_url_loaded
40
+ )
41
+ delete tableauVisualizationData.preview;
42
+ delete tableauVisualizationData.preview_url_loaded;
43
+
44
+ return next({
45
+ ...action,
46
+ request: {
47
+ ...action.request,
48
+ data: {
49
+ ...action.request.data,
50
+
51
+ tableau_visualization: tableauVisualizationData,
52
+ },
53
+ },
54
+ });
55
+ } else return next(action);
56
+ }
57
+
58
+ try {
59
+ const previewImage = {
60
+ preview_image: {
61
+ data: action.request.data.tableau_visualization.preview.split(',')[1],
62
+ encoding: 'base64',
63
+ 'content-type': 'image/png',
64
+ filename: 'preview_image_generated_tableau_visualization.png',
65
+ },
66
+ preview_image_saved: true,
67
+ };
68
+
69
+ const tableauVisualizationData = {
70
+ ...action.request.data.tableau_visualization,
71
+ };
72
+ delete tableauVisualizationData.preview;
73
+ delete tableauVisualizationData.preview_url_loaded;
74
+
75
+ return next({
76
+ ...action,
77
+ request: {
78
+ ...action.request,
79
+ data: {
80
+ ...action.request.data,
81
+ ...previewImage,
82
+ tableau_visualization: tableauVisualizationData,
83
+ },
84
+ },
85
+ });
86
+ } catch (error) {
87
+ if (action.request.data.tableau_visualization.preview) {
88
+ const tableauVisualizationData = {
89
+ ...action.request.data.tableau_visualization,
90
+ };
91
+ delete tableauVisualizationData.preview;
92
+ delete tableauVisualizationData.preview_url_loaded;
93
+
94
+ return next({
95
+ ...action,
96
+ request: {
97
+ ...action.request,
98
+ data: {
99
+ ...action.request.data,
100
+ tableau_visualization: tableauVisualizationData,
101
+ },
102
+ },
103
+ });
104
+ } else return next(action);
105
+ }
106
+ },
107
+ ...middlewares,
108
+ ];
@@ -0,0 +1,30 @@
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': 'tableau_visualization',
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('should pass through if action type is not CREATE_CONTENT or UPDATE_CONTENT', () => {
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
+ });