From 8d220bebefa6ebef0019bfcae7fa973c1bf8dee5 Mon Sep 17 00:00:00 2001 From: Miu Razvan Date: Mon, 8 Nov 2021 12:27:21 +0200 Subject: [PATCH] Customize TableauBlock from volto-tableau --- src/components/index.js | 10 +- .../manage/Blocks/FiltersBlock/schema.js | 2 +- .../manage/Blocks/IndustryDataTable/schema.js | 2 +- .../manage/Blocks/IndustryMap/schema.js | 2 +- src/components/manage/Blocks/List/schema.js | 2 +- .../manage/Blocks/NavigationBlock/schema.js | 2 +- .../manage/Blocks/PollutantIndex/schema.js | 2 +- src/components/manage/Blocks/Select/schema.js | 2 +- .../Blocks/SiteStructureSidebar/schema.js | 2 +- .../manage/Blocks/SiteTableau/schema.js | 2 +- .../manage/Blocks/TableauBlock/Edit.jsx | 32 +++++ .../manage/Blocks/TableauBlock/View.jsx | 109 ++++++++++++++ .../manage/Blocks/TableauBlock/index.js | 28 ++++ .../manage/Blocks/TableauBlock/schema.js | 134 ++++++++++++++++++ 14 files changed, 318 insertions(+), 13 deletions(-) create mode 100644 src/components/manage/Blocks/TableauBlock/Edit.jsx create mode 100644 src/components/manage/Blocks/TableauBlock/View.jsx create mode 100644 src/components/manage/Blocks/TableauBlock/index.js create mode 100644 src/components/manage/Blocks/TableauBlock/schema.js diff --git a/src/components/index.js b/src/components/index.js index 90e3ab9..8dd73b4 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -32,6 +32,7 @@ import installPollutantIndex from './manage/Blocks/PollutantIndex'; /*--- Custom connected blocks ---*/ import installCustomConnectedList from './manage/Blocks/List'; import installCustomConnectedSelect from './manage/Blocks/Select'; +import installCustomTableau from './manage/Blocks/TableauBlock'; /*--- App extras ---*/ import installAppExtras from './theme/AppExtras'; @@ -48,10 +49,11 @@ const installCustomViews = (config) => { }; const installCustomConnectedBlocks = (config) => { - return [installCustomConnectedList, installCustomConnectedSelect].reduce( - (acc, apply) => apply(acc), - config, - ); + return [ + installCustomConnectedList, + installCustomConnectedSelect, + installCustomTableau, + ].reduce((acc, apply) => apply(acc), config); }; const installEprtrSpecificBlocks = (config) => { diff --git a/src/components/manage/Blocks/FiltersBlock/schema.js b/src/components/manage/Blocks/FiltersBlock/schema.js index 68c629b..9bb4bdd 100644 --- a/src/components/manage/Blocks/FiltersBlock/schema.js +++ b/src/components/manage/Blocks/FiltersBlock/schema.js @@ -13,7 +13,7 @@ const providerSchema = { }, url: { title: 'Provider url', - widget: 'object_by_path', + widget: 'url', }, }, required: [], diff --git a/src/components/manage/Blocks/IndustryDataTable/schema.js b/src/components/manage/Blocks/IndustryDataTable/schema.js index ae67982..7a419f6 100644 --- a/src/components/manage/Blocks/IndustryDataTable/schema.js +++ b/src/components/manage/Blocks/IndustryDataTable/schema.js @@ -10,7 +10,7 @@ export default () => ({ properties: { link: { title: 'Site details path', - widget: 'object_by_path', + widget: 'url', }, }, required: [], diff --git a/src/components/manage/Blocks/IndustryMap/schema.js b/src/components/manage/Blocks/IndustryMap/schema.js index 88ce673..58ff5e6 100644 --- a/src/components/manage/Blocks/IndustryMap/schema.js +++ b/src/components/manage/Blocks/IndustryMap/schema.js @@ -13,7 +13,7 @@ const providerSchema = { }, url: { title: 'Provider url', - widget: 'object_by_path', + widget: 'url', }, }, required: [], diff --git a/src/components/manage/Blocks/List/schema.js b/src/components/manage/Blocks/List/schema.js index 7a76604..fcdb192 100644 --- a/src/components/manage/Blocks/List/schema.js +++ b/src/components/manage/Blocks/List/schema.js @@ -44,7 +44,7 @@ const getSchema = (props) => { properties: { url: { title: 'Url', - widget: 'object_by_path', + widget: 'url', }, value: { title: 'Value', diff --git a/src/components/manage/Blocks/NavigationBlock/schema.js b/src/components/manage/Blocks/NavigationBlock/schema.js index 5aabbff..7a1eac1 100644 --- a/src/components/manage/Blocks/NavigationBlock/schema.js +++ b/src/components/manage/Blocks/NavigationBlock/schema.js @@ -31,7 +31,7 @@ export default { properties: { parent: { title: 'Parent', - widget: 'object_by_path', + widget: 'url', }, pages: { title: 'Pages', diff --git a/src/components/manage/Blocks/PollutantIndex/schema.js b/src/components/manage/Blocks/PollutantIndex/schema.js index e5568c8..471fdf6 100644 --- a/src/components/manage/Blocks/PollutantIndex/schema.js +++ b/src/components/manage/Blocks/PollutantIndex/schema.js @@ -13,7 +13,7 @@ const providerSchema = { }, url: { title: 'Provider url', - widget: 'object_by_path', + widget: 'url', }, }, required: [], diff --git a/src/components/manage/Blocks/Select/schema.js b/src/components/manage/Blocks/Select/schema.js index 72a8273..f026c14 100644 --- a/src/components/manage/Blocks/Select/schema.js +++ b/src/components/manage/Blocks/Select/schema.js @@ -44,7 +44,7 @@ const getSchema = (props) => { properties: { url: { title: 'Url', - widget: 'object_by_path', + widget: 'url', }, value: { title: 'Value', diff --git a/src/components/manage/Blocks/SiteStructureSidebar/schema.js b/src/components/manage/Blocks/SiteStructureSidebar/schema.js index cb840f9..f60c52c 100644 --- a/src/components/manage/Blocks/SiteStructureSidebar/schema.js +++ b/src/components/manage/Blocks/SiteStructureSidebar/schema.js @@ -13,7 +13,7 @@ const getSchema = (props) => { properties: { pathname: { title: 'Parent pathname', - widget: 'object_by_path', + widget: 'url', }, pages: { title: 'Pages', diff --git a/src/components/manage/Blocks/SiteTableau/schema.js b/src/components/manage/Blocks/SiteTableau/schema.js index 23102b3..7af8063 100644 --- a/src/components/manage/Blocks/SiteTableau/schema.js +++ b/src/components/manage/Blocks/SiteTableau/schema.js @@ -85,7 +85,7 @@ export default (config, provider_keys = []) => ({ }, provider_url: { title: 'Data provider', - widget: 'object_by_path', + widget: 'url', }, allowedParams: { title: 'Allowed params', diff --git a/src/components/manage/Blocks/TableauBlock/Edit.jsx b/src/components/manage/Blocks/TableauBlock/Edit.jsx new file mode 100644 index 0000000..3170c27 --- /dev/null +++ b/src/components/manage/Blocks/TableauBlock/Edit.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { SidebarPortal } from '@plone/volto/components'; +import InlineForm from '@plone/volto/components/manage/Form/InlineForm'; +import config from '@plone/volto/registry'; +import getSchema from './schema'; +import View from './View'; + +const Edit = (props) => { + const [schema] = React.useState(getSchema(config)); + + return ( + <> + + + + { + props.onChangeBlock(props.block, { + ...props.data, + [id]: value, + }); + }} + formData={props.data} + /> + + + ); +}; + +export default Edit; diff --git a/src/components/manage/Blocks/TableauBlock/View.jsx b/src/components/manage/Blocks/TableauBlock/View.jsx new file mode 100644 index 0000000..97ce788 --- /dev/null +++ b/src/components/manage/Blocks/TableauBlock/View.jsx @@ -0,0 +1,109 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { compose } from 'redux'; +import { withRouter } from 'react-router'; +import Tableau from '@eeacms/volto-tableau/Tableau/View'; +import config from '@plone/volto/registry'; +import { getLatestTableauVersion } from 'tableau-api-js'; +import qs from 'querystring'; +import '@eeacms/volto-tableau/less/tableau.less'; + +const getDevice = (config, width) => { + const breakpoints = config.blocks.blocksConfig.tableau_block.breakpoints; + let device = 'default'; + Object.keys(breakpoints).forEach((breakpoint) => { + if ( + width <= breakpoints[breakpoint][0] && + width >= breakpoints[breakpoint][1] + ) { + device = breakpoint; + } + }); + return device; +}; + +const View = (props) => { + const [error, setError] = React.useState(null); + const [loaded, setLoaded] = React.useState(null); + const [mounted, setMounted] = React.useState(false); + const [extraFilters, setExtraFilters] = React.useState({}); + const { data = {}, query = {}, screen = {} } = props; + const { + breakpointUrls = [], + urlParameters = [], + title = null, + description = null, + autoScale = false, + } = data; + const version = + props.data.version || + config.settings.tableauVersion || + getLatestTableauVersion(); + const device = getDevice(config, screen.page?.width || Infinity); + const breakpointUrl = breakpointUrls.filter( + (breakpoint) => breakpoint.device === device, + )[0]?.url; + const url = breakpointUrl || data.url; + + React.useEffect(() => { + setMounted(true); + /* eslint-disable-next-line */ + }, []); + + React.useEffect(() => { + const newExtraFilters = { ...extraFilters }; + urlParameters.forEach((element) => { + if (element.field && typeof query[element.urlParam] !== 'undefined') { + newExtraFilters[element.field] = query[element.urlParam]; + } else if (newExtraFilters[element.field]) { + delete newExtraFilters[element.field]; + } + }); + setExtraFilters(newExtraFilters); + /* eslint-disable-next-line */ + }, [JSON.stringify(query), JSON.stringify(urlParameters)]); + + return mounted ? ( +
+ {props.mode === 'edit' ? ( +
+

== Tableau {version} ==

+ {!props.data.url ?

URL required

: ''} + {error ?

{error}

: ''} +
+ ) : ( + '' + )} + {loaded && title ?

{title}

: ''} + {loaded && description ? ( +

{description}

+ ) : ( + '' + )} + +
+ ) : ( + '' + ); +}; + +export default compose( + connect((state, props) => ({ + query: { + ...(qs.parse(state.router.location?.search?.replace('?', '')) || {}), + ...(state.query?.search || {}), + }, + screen: state.screen, + })), +)(withRouter(View)); diff --git a/src/components/manage/Blocks/TableauBlock/index.js b/src/components/manage/Blocks/TableauBlock/index.js new file mode 100644 index 0000000..33dcbd0 --- /dev/null +++ b/src/components/manage/Blocks/TableauBlock/index.js @@ -0,0 +1,28 @@ +import sliderSVG from '@plone/volto/icons/slider.svg'; +import TableauEdit from './Edit'; +import TableauView from './View'; + +export default (config) => { + config.blocks.blocksConfig.tableau_block = { + id: 'tableau_block', + title: 'Tableau', + icon: sliderSVG, + group: 'common', + edit: TableauEdit, + view: TableauView, + restricted: false, + mostUsed: false, + sidebarTab: 1, + blocks: {}, + security: { + addPermission: [], + view: [], + }, + breakpoints: { + desktop: [Infinity, 982], + tablet: [981, 768], + mobile: [767, 0], + }, + }; + return config; +}; diff --git a/src/components/manage/Blocks/TableauBlock/schema.js b/src/components/manage/Blocks/TableauBlock/schema.js new file mode 100644 index 0000000..7cce058 --- /dev/null +++ b/src/components/manage/Blocks/TableauBlock/schema.js @@ -0,0 +1,134 @@ +import { tableauVersions, getLatestTableauVersion } from 'tableau-api-js'; + +const urlParametersSchema = { + title: 'Parameter', + fieldsets: [ + { id: 'default', title: 'Default', fields: ['field', 'urlParam'] }, + ], + properties: { + field: { + title: 'Tableau fieldname', + type: 'text', + }, + urlParam: { + title: 'URL param', + type: 'text', + }, + }, + required: [], +}; + +const breakpointUrlSchema = (config) => { + const breakpoints = config.blocks.blocksConfig.tableau_block.breakpoints; + + return { + title: 'URL', + fieldsets: [{ id: 'default', title: 'Default', fields: ['device', 'url'] }], + properties: { + device: { + title: 'Device', + type: 'array', + choices: Object.keys(breakpoints).map((breakpoint) => [ + breakpoint, + breakpoint, + ]), + }, + url: { + title: 'Url', + widget: 'textarea', + }, + }, + required: [], + }; +}; + +export default (config) => ({ + title: 'Tableau', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['version', 'url', 'title', 'description'], + }, + { + id: 'options', + title: 'Options', + fields: [ + 'sheetname', + 'hideTabs', + 'hideToolbar', + 'autoScale', + 'toolbarPosition', + ], + }, + { + id: 'extra_options', + title: 'Extra options', + fields: ['urlParameters', 'breakpointUrls'], + }, + ], + properties: { + version: { + title: 'Version', + type: 'array', + choices: [ + ...tableauVersions.map((version) => [version, `tableau-${version}`]), + ], + default: config.settings.tableauVersion || getLatestTableauVersion(), + }, + url: { + title: 'Url', + widget: 'textarea', + }, + title: { + title: 'Title', + widget: 'textarea', + }, + description: { + title: 'Description', + widget: 'textarea', + }, + sheetname: { + title: 'Sheetname', + type: 'text', + }, + hideTabs: { + title: 'Hide tabs', + type: 'boolean', + default: false, + }, + hideToolbar: { + title: 'Hide toolbar', + type: 'boolean', + default: false, + }, + autoScale: { + title: 'Auto scale', + type: 'boolean', + default: false, + description: 'Scale down tableau according to width', + }, + toolbarPosition: { + title: 'Toolbar position', + type: 'array', + choices: [ + ['Top', 'Top'], + ['Bottom', 'Bottom'], + ], + default: 'Top', + }, + urlParameters: { + title: 'URL parameters', + widget: 'object_list', + schema: urlParametersSchema, + description: 'Set a list of url parameters to filter the tableau', + }, + breakpointUrls: { + title: 'Breakpoint urls', + widget: 'object_list', + schema: breakpointUrlSchema(config), + description: 'Set different vizualization for specific breakpoint', + }, + }, + required: ['version', 'url'], +});