@eeacms/volto-tableau 7.0.4 → 7.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 +29 -18
- package/jest.setup.js +29 -2
- package/locales/de/LC_MESSAGES/volto.po +55 -0
- package/locales/en/LC_MESSAGES/volto.po +55 -0
- package/locales/it/LC_MESSAGES/volto.po +55 -0
- package/locales/ro/LC_MESSAGES/volto.po +55 -0
- package/locales/volto.pot +56 -1
- package/package.json +1 -1
- package/src/Blocks/EmbedTableauVisualization/Edit.jsx +1 -0
- package/src/Blocks/EmbedTableauVisualization/View.jsx +134 -35
- package/src/Blocks/EmbedTableauVisualization/__snapshots__/Edit.test.jsx.snap +90 -2
- package/src/Blocks/EmbedTableauVisualization/schema.js +44 -1
- package/src/Tableau/Tableau.jsx +113 -29
- package/src/Tableau/helpers.js +124 -1
- package/src/Views/VisualizationView.jsx +31 -19
- package/src/Widgets/CreatableSelectWidget.jsx +300 -0
- package/src/Widgets/VisualizationViewWidget.jsx +34 -18
- package/src/Widgets/VisualizationViewWidget.test.jsx +1 -0
- package/src/Widgets/VisualizationWidget.jsx +113 -29
- package/src/Widgets/VisualizationWidget.test.jsx +1 -1
- package/src/Widgets/index.js +2 -1
- package/src/Widgets/schema.js +314 -41
- package/src/index.js +6 -1
|
@@ -1,30 +1,44 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { flattenToAppURL } from '@plone/volto/helpers';
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { withRouter } from 'react-router';
|
|
4
3
|
import { connect } from 'react-redux';
|
|
5
4
|
import { compose } from 'redux';
|
|
5
|
+
import { isFunction } from 'lodash';
|
|
6
|
+
import { Message } from 'semantic-ui-react';
|
|
7
|
+
import { flattenToAppURL } from '@plone/volto/helpers';
|
|
6
8
|
import { getContent } from '@plone/volto/actions';
|
|
7
9
|
import PrivacyProtection from '@eeacms/volto-embed/PrivacyProtection/PrivacyProtection';
|
|
8
|
-
import { pickMetadata } from '@eeacms/volto-embed/helpers';
|
|
9
10
|
import Tableau from '@eeacms/volto-tableau/Tableau/Tableau';
|
|
11
|
+
import {
|
|
12
|
+
getQuery,
|
|
13
|
+
getTableauVisualization,
|
|
14
|
+
getParameters,
|
|
15
|
+
getFilters,
|
|
16
|
+
} from '@eeacms/volto-tableau/Tableau/helpers';
|
|
17
|
+
|
|
18
|
+
const timer = {};
|
|
10
19
|
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
? props.tableauContent?.tableau_visualization
|
|
17
|
-
: props.content?.tableau_visualization) ||
|
|
18
|
-
props.data.tableau_visualization ||
|
|
19
|
-
{};
|
|
20
|
-
return {
|
|
21
|
-
...pickMetadata(content),
|
|
22
|
-
...tableau_visualization,
|
|
23
|
-
};
|
|
20
|
+
function debounce(func, wait = 500, id) {
|
|
21
|
+
if (!isFunction(func)) return;
|
|
22
|
+
const name = id || func.name || 'generic';
|
|
23
|
+
if (timer[name]) clearTimeout(timer[name]);
|
|
24
|
+
timer[name] = setTimeout(func, wait);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const View = (props) => {
|
|
27
|
-
const {
|
|
28
|
+
const {
|
|
29
|
+
isBlock,
|
|
30
|
+
id,
|
|
31
|
+
location,
|
|
32
|
+
mode,
|
|
33
|
+
data,
|
|
34
|
+
getContent,
|
|
35
|
+
useVisibilitySensor,
|
|
36
|
+
data_query,
|
|
37
|
+
discodata_query,
|
|
38
|
+
tableau_vis_url,
|
|
39
|
+
content,
|
|
40
|
+
tableauContent,
|
|
41
|
+
} = props;
|
|
28
42
|
const {
|
|
29
43
|
with_notes = true,
|
|
30
44
|
with_sources = true,
|
|
@@ -35,21 +49,96 @@ const View = (props) => {
|
|
|
35
49
|
tableau_height,
|
|
36
50
|
} = data;
|
|
37
51
|
|
|
38
|
-
const
|
|
52
|
+
const [tableauVisualization, setTableauVisualization] = useState(() =>
|
|
53
|
+
getTableauVisualization({
|
|
54
|
+
isBlock,
|
|
55
|
+
data,
|
|
56
|
+
content,
|
|
57
|
+
tableauContent,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
const [query, setQuery] = useState(() => {
|
|
61
|
+
return getQuery({ data_query, location, tableau_vis_url, discodata_query });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const [extraParameters, setExtraParameters] = useState(() =>
|
|
65
|
+
getParameters({ tableauVisualization, query, data }),
|
|
66
|
+
);
|
|
67
|
+
const [extraFilters, setExtraFilters] = useState(() =>
|
|
68
|
+
getFilters({ tableauVisualization, query, data }),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Update tableau visualization
|
|
73
|
+
*/
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
setTableauVisualization(
|
|
76
|
+
getTableauVisualization({
|
|
77
|
+
isBlock,
|
|
78
|
+
data,
|
|
79
|
+
content,
|
|
80
|
+
tableauContent,
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
}, [isBlock, data, content, tableauContent]);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Update query
|
|
87
|
+
*/
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
setQuery(
|
|
90
|
+
getQuery({ data_query, location, tableau_vis_url, discodata_query }),
|
|
91
|
+
);
|
|
92
|
+
}, [tableau_vis_url, data_query, discodata_query, location]);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Update extra parameters
|
|
96
|
+
*/
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
debounce(
|
|
99
|
+
() => {
|
|
100
|
+
setExtraParameters(
|
|
101
|
+
getParameters({
|
|
102
|
+
tableauVisualization,
|
|
103
|
+
query,
|
|
104
|
+
data,
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
},
|
|
108
|
+
500,
|
|
109
|
+
'setExtraParameters',
|
|
110
|
+
);
|
|
111
|
+
}, [tableauVisualization, query, data]);
|
|
39
112
|
|
|
40
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Update extra filters
|
|
115
|
+
*/
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
debounce(
|
|
118
|
+
() => {
|
|
119
|
+
setExtraFilters(
|
|
120
|
+
getFilters({
|
|
121
|
+
tableauVisualization,
|
|
122
|
+
query,
|
|
123
|
+
data,
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
},
|
|
127
|
+
500,
|
|
128
|
+
'setExtraFilters',
|
|
129
|
+
);
|
|
130
|
+
}, [tableauVisualization, query, data]);
|
|
41
131
|
|
|
42
132
|
useEffect(() => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
) {
|
|
133
|
+
/**
|
|
134
|
+
* If we are in edit mode, we need to fetch the content of the
|
|
135
|
+
* tableau visualization
|
|
136
|
+
*/
|
|
137
|
+
const tableauVisId = flattenToAppURL(tableauVisualization['@id'] || '');
|
|
138
|
+
if (isBlock && tableau_vis_url && tableau_vis_url !== tableauVisId) {
|
|
50
139
|
getContent(tableau_vis_url, null, id);
|
|
51
140
|
}
|
|
52
|
-
}, [id, isBlock, getContent, mode, tableau_vis_url,
|
|
141
|
+
}, [id, isBlock, getContent, mode, tableau_vis_url, tableauVisualization]);
|
|
53
142
|
|
|
54
143
|
if (props.mode === 'edit' && !tableau_vis_url) {
|
|
55
144
|
return <Message>Please select a tableau from block editor.</Message>;
|
|
@@ -59,14 +148,14 @@ const View = (props) => {
|
|
|
59
148
|
<div className="embed-tableau">
|
|
60
149
|
<PrivacyProtection
|
|
61
150
|
{...props}
|
|
62
|
-
data={{ ...data, url:
|
|
151
|
+
data={{ ...data, url: tableauVisualization?.url }}
|
|
63
152
|
useVisibilitySensor={useVisibilitySensor}
|
|
64
153
|
>
|
|
65
154
|
<Tableau
|
|
66
155
|
data={{
|
|
67
|
-
...
|
|
156
|
+
...tableauVisualization,
|
|
68
157
|
tableau_height:
|
|
69
|
-
tableau_height ||
|
|
158
|
+
tableau_height || tableauVisualization.tableau_height,
|
|
70
159
|
with_notes,
|
|
71
160
|
with_sources,
|
|
72
161
|
with_more_info,
|
|
@@ -75,6 +164,8 @@ const View = (props) => {
|
|
|
75
164
|
with_enlarge,
|
|
76
165
|
tableau_vis_url,
|
|
77
166
|
}}
|
|
167
|
+
extraParameters={extraParameters}
|
|
168
|
+
extraFilters={extraFilters}
|
|
78
169
|
/>
|
|
79
170
|
</PrivacyProtection>
|
|
80
171
|
</div>
|
|
@@ -82,11 +173,19 @@ const View = (props) => {
|
|
|
82
173
|
};
|
|
83
174
|
|
|
84
175
|
export default compose(
|
|
176
|
+
withRouter,
|
|
85
177
|
connect(
|
|
86
|
-
(state, props) =>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
178
|
+
(state, props) => {
|
|
179
|
+
const tableau_vis_url = flattenToAppURL(props.data.tableau_vis_url || '');
|
|
180
|
+
const pathname = flattenToAppURL(state.content.data['@id']);
|
|
181
|
+
return {
|
|
182
|
+
tableauContent: state.content?.subrequests?.[props.id]?.data,
|
|
183
|
+
discodata_query: state.discodata_query,
|
|
184
|
+
data_query: state.connected_data_parameters.byContextPath[pathname],
|
|
185
|
+
isBlock: !!props.data?.['@type'],
|
|
186
|
+
tableau_vis_url,
|
|
187
|
+
};
|
|
188
|
+
},
|
|
90
189
|
{
|
|
91
190
|
getContent,
|
|
92
191
|
},
|
|
@@ -50,12 +50,31 @@ Array [
|
|
|
50
50
|
className="ui segment form attached"
|
|
51
51
|
>
|
|
52
52
|
<div
|
|
53
|
-
className="mocked-
|
|
53
|
+
className="mocked-default-widget"
|
|
54
54
|
id="mocked-field-tableau_vis_url"
|
|
55
55
|
>
|
|
56
56
|
Tableau visualization
|
|
57
57
|
-
|
|
58
|
-
|
|
58
|
+
<div>
|
|
59
|
+
<p>
|
|
60
|
+
When using context query parameters please use the corresponding field name from the Tableau service.
|
|
61
|
+
</p>
|
|
62
|
+
<p>
|
|
63
|
+
NOTE: The embeded tableau dashboard must have the parameters defined in the
|
|
64
|
+
|
|
65
|
+
<span
|
|
66
|
+
style={
|
|
67
|
+
Object {
|
|
68
|
+
"color": "rgb(15, 130, 204)",
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
>
|
|
72
|
+
'Dynamic parameters'
|
|
73
|
+
</span>
|
|
74
|
+
|
|
75
|
+
list so that the context query parameters can take effect.
|
|
76
|
+
</p>
|
|
77
|
+
</div>
|
|
59
78
|
</div>
|
|
60
79
|
<div
|
|
61
80
|
className="mocked-default-widget"
|
|
@@ -181,6 +200,75 @@ Array [
|
|
|
181
200
|
</div>
|
|
182
201
|
</div>
|
|
183
202
|
</div>
|
|
203
|
+
<div
|
|
204
|
+
className="accordion ui fluid styled form"
|
|
205
|
+
>
|
|
206
|
+
<div
|
|
207
|
+
id="blockform-fieldset-options"
|
|
208
|
+
>
|
|
209
|
+
<div
|
|
210
|
+
className="title"
|
|
211
|
+
onClick={[Function]}
|
|
212
|
+
>
|
|
213
|
+
Parameters
|
|
214
|
+
<svg
|
|
215
|
+
className="icon"
|
|
216
|
+
dangerouslySetInnerHTML={
|
|
217
|
+
Object {
|
|
218
|
+
"__html": undefined,
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
onClick={null}
|
|
222
|
+
style={
|
|
223
|
+
Object {
|
|
224
|
+
"fill": "currentColor",
|
|
225
|
+
"height": "20px",
|
|
226
|
+
"width": "auto",
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
viewBox=""
|
|
230
|
+
xmlns=""
|
|
231
|
+
/>
|
|
232
|
+
</div>
|
|
233
|
+
<div
|
|
234
|
+
className="content"
|
|
235
|
+
>
|
|
236
|
+
<div
|
|
237
|
+
aria-hidden={true}
|
|
238
|
+
className="rah-static rah-static--height-zero"
|
|
239
|
+
style={
|
|
240
|
+
Object {
|
|
241
|
+
"height": 0,
|
|
242
|
+
"overflow": "hidden",
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
>
|
|
246
|
+
<div
|
|
247
|
+
style={
|
|
248
|
+
Object {
|
|
249
|
+
"WebkitTransition": "opacity 500ms ease 0ms",
|
|
250
|
+
"opacity": 0,
|
|
251
|
+
"transition": "opacity 500ms ease 0ms",
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
>
|
|
255
|
+
<div
|
|
256
|
+
className="ui segment attached"
|
|
257
|
+
>
|
|
258
|
+
<div
|
|
259
|
+
className="mocked-default-widget"
|
|
260
|
+
id="mocked-field-staticParameters"
|
|
261
|
+
>
|
|
262
|
+
Static parameters
|
|
263
|
+
-
|
|
264
|
+
Set a list of static parameters.
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
184
272
|
<div
|
|
185
273
|
className="accordion ui fluid styled form"
|
|
186
274
|
>
|
|
@@ -53,6 +53,22 @@ const getProtectionSchema = () => ({
|
|
|
53
53
|
required: [],
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
+
const staticParameters = {
|
|
57
|
+
title: 'Parameter',
|
|
58
|
+
fieldsets: [{ id: 'default', title: 'Default', fields: ['field', 'value'] }],
|
|
59
|
+
properties: {
|
|
60
|
+
field: {
|
|
61
|
+
title: 'Tableau fieldname',
|
|
62
|
+
type: 'text',
|
|
63
|
+
},
|
|
64
|
+
value: {
|
|
65
|
+
title: 'Value',
|
|
66
|
+
type: 'text',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
required: [],
|
|
70
|
+
};
|
|
71
|
+
|
|
56
72
|
export default (props) => {
|
|
57
73
|
return {
|
|
58
74
|
title: 'Embed Dashboard (Tableau)',
|
|
@@ -74,6 +90,11 @@ export default (props) => {
|
|
|
74
90
|
'with_enlarge',
|
|
75
91
|
],
|
|
76
92
|
},
|
|
93
|
+
{
|
|
94
|
+
id: 'options',
|
|
95
|
+
title: 'Parameters',
|
|
96
|
+
fields: ['staticParameters'],
|
|
97
|
+
},
|
|
77
98
|
{
|
|
78
99
|
id: 'privacy',
|
|
79
100
|
title: 'Privacy',
|
|
@@ -83,7 +104,23 @@ export default (props) => {
|
|
|
83
104
|
properties: {
|
|
84
105
|
tableau_vis_url: {
|
|
85
106
|
title: 'Tableau visualization',
|
|
86
|
-
widget: '
|
|
107
|
+
widget: 'internal_url',
|
|
108
|
+
description: (
|
|
109
|
+
<div>
|
|
110
|
+
<p>
|
|
111
|
+
When using context query parameters please use the corresponding
|
|
112
|
+
field name from the Tableau service.
|
|
113
|
+
</p>
|
|
114
|
+
<p>
|
|
115
|
+
NOTE: The embeded tableau dashboard must have the parameters
|
|
116
|
+
defined in the{' '}
|
|
117
|
+
<span style={{ color: 'rgb(15, 130, 204)' }}>
|
|
118
|
+
'Dynamic parameters'
|
|
119
|
+
</span>{' '}
|
|
120
|
+
list so that the context query parameters can take effect.
|
|
121
|
+
</p>
|
|
122
|
+
</div>
|
|
123
|
+
),
|
|
87
124
|
},
|
|
88
125
|
with_notes: {
|
|
89
126
|
title: 'Show note',
|
|
@@ -134,6 +171,12 @@ export default (props) => {
|
|
|
134
171
|
widget: 'object',
|
|
135
172
|
schema: getProtectionSchema(),
|
|
136
173
|
},
|
|
174
|
+
staticParameters: {
|
|
175
|
+
title: 'Static parameters',
|
|
176
|
+
widget: 'object_list',
|
|
177
|
+
schema: staticParameters,
|
|
178
|
+
description: 'Set a list of static parameters.',
|
|
179
|
+
},
|
|
137
180
|
},
|
|
138
181
|
|
|
139
182
|
required: ['tableau_vis_url'],
|
package/src/Tableau/Tableau.jsx
CHANGED
|
@@ -9,7 +9,22 @@ import React, {
|
|
|
9
9
|
} from 'react';
|
|
10
10
|
import { connect } from 'react-redux';
|
|
11
11
|
import { toast } from 'react-toastify';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isEqual,
|
|
14
|
+
isUndefined,
|
|
15
|
+
isNaN,
|
|
16
|
+
isNumber,
|
|
17
|
+
forOwn,
|
|
18
|
+
find,
|
|
19
|
+
includes,
|
|
20
|
+
isArray,
|
|
21
|
+
isString,
|
|
22
|
+
isInteger,
|
|
23
|
+
isBoolean,
|
|
24
|
+
toString,
|
|
25
|
+
toInteger,
|
|
26
|
+
toNumber,
|
|
27
|
+
} from 'lodash';
|
|
13
28
|
import cx from 'classnames';
|
|
14
29
|
import { Button } from 'semantic-ui-react';
|
|
15
30
|
import { Toast, Icon } from '@plone/volto/components';
|
|
@@ -48,7 +63,9 @@ const TableauDebug = ({ mode, data, vizState, url, version, clearData }) => {
|
|
|
48
63
|
return (
|
|
49
64
|
<div className="tableau-debug">
|
|
50
65
|
{!url && !vizState.error && <p className="tableau-error">URL required</p>}
|
|
51
|
-
{vizState.error &&
|
|
66
|
+
{isString(vizState.error) && (
|
|
67
|
+
<p className="tableau-error">{vizState.error}</p>
|
|
68
|
+
)}
|
|
52
69
|
{vizState.loaded && url && (
|
|
53
70
|
<h3 className="tableau-version">
|
|
54
71
|
Tableau <span className="version">{version}</span>
|
|
@@ -93,6 +110,7 @@ const Tableau = forwardRef((props, ref) => {
|
|
|
93
110
|
data = {},
|
|
94
111
|
breakpoints = {},
|
|
95
112
|
extraFilters = {},
|
|
113
|
+
extraParameters = {},
|
|
96
114
|
extraOptions = {},
|
|
97
115
|
mode = 'view',
|
|
98
116
|
screen = {},
|
|
@@ -244,10 +262,10 @@ const Tableau = forwardRef((props, ref) => {
|
|
|
244
262
|
hideToolbar,
|
|
245
263
|
toolbarPosition,
|
|
246
264
|
device: !!breakpointUrl ? device : 'desktop',
|
|
265
|
+
...extraOptions,
|
|
247
266
|
...data.filters,
|
|
248
|
-
...data.parameters,
|
|
249
267
|
...extraFilters,
|
|
250
|
-
...
|
|
268
|
+
...extraParameters,
|
|
251
269
|
onFirstInteractive: () => {
|
|
252
270
|
onVizStateUpdate(true, true, null);
|
|
253
271
|
setInitiateViz(false);
|
|
@@ -296,32 +314,11 @@ const Tableau = forwardRef((props, ref) => {
|
|
|
296
314
|
},
|
|
297
315
|
});
|
|
298
316
|
} catch (e) {
|
|
299
|
-
onVizStateUpdate(false, false, e
|
|
317
|
+
onVizStateUpdate(false, false, e?.get_message?.() || e);
|
|
300
318
|
setInitiateViz(false);
|
|
301
319
|
}
|
|
302
320
|
};
|
|
303
321
|
|
|
304
|
-
const addExtraFilters = (extraFilters) => {
|
|
305
|
-
const worksheets =
|
|
306
|
-
viz.current.getWorkbook().getActiveSheet().getWorksheets() || [];
|
|
307
|
-
|
|
308
|
-
worksheets.forEach((worksheet) => {
|
|
309
|
-
if (worksheet.getSheetType() === tableau.DashboardObjectType.WORKSHEET) {
|
|
310
|
-
Object.keys(extraFilters).forEach((filter) => {
|
|
311
|
-
if (!extraFilters[filter]) {
|
|
312
|
-
worksheet.clearFilterAsync(filter);
|
|
313
|
-
} else {
|
|
314
|
-
worksheet.applyFilterAsync(
|
|
315
|
-
filter,
|
|
316
|
-
extraFilters[filter],
|
|
317
|
-
tableau.FilterUpdateType.REPLACE,
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
};
|
|
324
|
-
|
|
325
322
|
const updateScale = () => {
|
|
326
323
|
const iframe = vizEl.current.querySelector('iframe');
|
|
327
324
|
const { sheetSize = {} } = viz.current.getVizSize() || {};
|
|
@@ -358,12 +355,99 @@ const Tableau = forwardRef((props, ref) => {
|
|
|
358
355
|
/* eslint-disable-next-line */
|
|
359
356
|
}, [loaded, loading, initiateViz]);
|
|
360
357
|
|
|
358
|
+
/**
|
|
359
|
+
* TODO: make this work
|
|
360
|
+
*/
|
|
361
|
+
// useEffect(() => {
|
|
362
|
+
// async function addExtraFilters() {
|
|
363
|
+
// if (vizState.current.loaded && viz.current) {
|
|
364
|
+
// const dashboard = viz.current.getWorkbook().getActiveSheet();
|
|
365
|
+
// const tableauFilters = await dashboard.getFiltersAsync();
|
|
366
|
+
|
|
367
|
+
// forOwn(extraFilters, (value, fieldName) => {
|
|
368
|
+
// const tableauFilter = find(
|
|
369
|
+
// tableauFilters,
|
|
370
|
+
// (f) => f.getFieldName() === fieldName,
|
|
371
|
+
// );
|
|
372
|
+
// if (!tableauFilter) return;
|
|
373
|
+
// if (!value) {
|
|
374
|
+
// tableauFilter.getWorksheet().clearFilterAsync(fieldName);
|
|
375
|
+
// return;
|
|
376
|
+
// }
|
|
377
|
+
// const filterType = tableauFilter.getFilterType();
|
|
378
|
+
// if (filterType === 'categorical') {
|
|
379
|
+
// if (!isArray(value)) {
|
|
380
|
+
// value = [value];
|
|
381
|
+
// }
|
|
382
|
+
// dashboard.applyFilterAsync(
|
|
383
|
+
// fieldName,
|
|
384
|
+
// value,
|
|
385
|
+
// tableau.FilterUpdateType.REPLACE,
|
|
386
|
+
// );
|
|
387
|
+
// }
|
|
388
|
+
// /**
|
|
389
|
+
// * TODO: handle other filter types
|
|
390
|
+
// */
|
|
391
|
+
// });
|
|
392
|
+
// }
|
|
393
|
+
// }
|
|
394
|
+
// addExtraFilters();
|
|
395
|
+
// /* eslint-disable-next-line */
|
|
396
|
+
// }, [loaded, JSON.stringify(extraFilters)]);
|
|
397
|
+
|
|
361
398
|
useEffect(() => {
|
|
362
|
-
|
|
363
|
-
|
|
399
|
+
async function addExtraParameters() {
|
|
400
|
+
if (vizState.current.loaded && viz.current) {
|
|
401
|
+
const workbook = viz.current.getWorkbook();
|
|
402
|
+
const tableauParameters = await workbook.getParametersAsync();
|
|
403
|
+
forOwn(extraParameters, (value, fieldName) => {
|
|
404
|
+
const tableauParameter = find(
|
|
405
|
+
tableauParameters,
|
|
406
|
+
(p) => p.getName() === fieldName,
|
|
407
|
+
);
|
|
408
|
+
if (!tableauParameter || !value) return;
|
|
409
|
+
const allowableValuesType = tableauParameter.getAllowableValuesType();
|
|
410
|
+
const dataType = tableauParameter.getDataType();
|
|
411
|
+
if (includes(['all', 'list'], allowableValuesType)) {
|
|
412
|
+
const values = tableauParameter
|
|
413
|
+
.getAllowableValues()
|
|
414
|
+
?.map((v) => v.value);
|
|
415
|
+
if (!isArray(value)) {
|
|
416
|
+
value = [value];
|
|
417
|
+
}
|
|
418
|
+
value = value
|
|
419
|
+
.filter((v) => includes(values, v))
|
|
420
|
+
.map((v) => {
|
|
421
|
+
if (dataType === 'string' && !isString(v)) {
|
|
422
|
+
return toString(v);
|
|
423
|
+
}
|
|
424
|
+
if (dataType === 'integer' && !isInteger(v)) {
|
|
425
|
+
return toInteger(v);
|
|
426
|
+
}
|
|
427
|
+
if (dataType === 'float' && !isNumber(v)) {
|
|
428
|
+
return toNumber(v);
|
|
429
|
+
}
|
|
430
|
+
if (dataType === 'boolean' && !isBoolean(v)) {
|
|
431
|
+
return !!v;
|
|
432
|
+
}
|
|
433
|
+
return v;
|
|
434
|
+
});
|
|
435
|
+
if (value.length) {
|
|
436
|
+
workbook.changeParameterValueAsync(fieldName, value);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (allowableValuesType === 'range' && value) {
|
|
440
|
+
/**
|
|
441
|
+
* TODO: handle range parameters
|
|
442
|
+
*/
|
|
443
|
+
workbook.changeParameterValueAsync(fieldName, value);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
}
|
|
364
447
|
}
|
|
448
|
+
addExtraParameters();
|
|
365
449
|
/* eslint-disable-next-line */
|
|
366
|
-
}, [JSON.stringify(
|
|
450
|
+
}, [loaded, JSON.stringify(extraParameters)]);
|
|
367
451
|
|
|
368
452
|
useEffect(() => {
|
|
369
453
|
if (vizState.current.loaded && viz.current && autoScale) {
|