diff --git a/CHANGELOG.md b/CHANGELOG.md index c97eec6..f73a7e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,29 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [0.2.0](https://github.com/eea/volto-forests-theme/compare/0.2.0-beta.0...0.2.0) + +- Develop [`#51`](https://github.com/eea/volto-forests-theme/pull/51) + +#### [0.2.0-beta.0](https://github.com/eea/volto-forests-theme/compare/0.1.37...0.2.0-beta.0) + +> 3 February 2022 + +- adapt to data-blocks v3 [`#52`](https://github.com/eea/volto-forests-theme/pull/52) +- Release 0.2.0-beta.0 [`4c7e23a`](https://github.com/eea/volto-forests-theme/commit/4c7e23a7d710c656ad39260b9d4509cc903c424c) +- Use latest volto-datablocks [`cc5e03b`](https://github.com/eea/volto-forests-theme/commit/cc5e03b45ba8ce1b3e632353bd1f43c4ae62c54e) +- Added DiscodataConnectorBlock [`7502a9e`](https://github.com/eea/volto-forests-theme/commit/7502a9ea2c57aacfdfabf86fbf80c752c856cb6a) +- fix navigationBlock View [`ee0891a`](https://github.com/eea/volto-forests-theme/commit/ee0891addb9e7c78283b2d9b03a36224ac6904b6) +- object list widget [`874c0d7`](https://github.com/eea/volto-forests-theme/commit/874c0d7077b9e36fccf765547e550679c4bfb5bb) +- rafactor navigation block [`e96c48e`](https://github.com/eea/volto-forests-theme/commit/e96c48ed5995b075a2b8a7c0834befd6608763db) +- Updated style [`26d2e5e`](https://github.com/eea/volto-forests-theme/commit/26d2e5ee9cef90533338359e35bc6df1ada7f7eb) +- WIP: adapt to volto-datablocks v3 [`e5d143e`](https://github.com/eea/volto-forests-theme/commit/e5d143e8a76a1d90921b73f7e6f7238b31fd4164) + #### [0.1.37](https://github.com/eea/volto-forests-theme/compare/0.1.36...0.1.37) +> 28 January 2022 + +- Develop [`#51`](https://github.com/eea/volto-forests-theme/pull/51) - nice homepage buttons [`14616da`](https://github.com/eea/volto-forests-theme/commit/14616da40f1d51b24d1fee540b0ea9331569306b) #### [0.1.36](https://github.com/eea/volto-forests-theme/compare/0.1.35...0.1.36) diff --git a/package.json b/package.json index 771822c..f6b79e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-forests-theme", - "version": "0.1.37", + "version": "0.2.0", "description": "@eeacms/volto-forests-theme: Volto add-on", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", @@ -25,7 +25,7 @@ "dependencies": { "@eeacms/volto-plotlycharts": "*", "@eeacms/volto-addons-forest": "*", - "@eeacms/volto-datablocks": "2.0.16", + "@eeacms/volto-datablocks": "*", "@eeacms/volto-matomo": "*", "react-highlight-words": "^0.16.0", "react-image-gallery": "1.2.7", diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/index.js b/src/components/manage/Blocks/DiscodataConnectorBlock/index.js new file mode 100644 index 0000000..d775912 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/index.js @@ -0,0 +1,24 @@ +import worldSVG from '@plone/volto/icons/world.svg'; +import DiscodataConnectorBlockEdit from './v1/Edit'; +import DiscodataConnectorBlockView from './v1/View'; + +// TODO: Move this to volto-forests-theme + +export default (config) => { + config.blocks.blocksConfig.discodata_connector_block = { + id: 'discodata_connector_block', + title: 'Discodata connector block', + icon: worldSVG, + group: 'data_blocks', + view: DiscodataConnectorBlockView, + edit: DiscodataConnectorBlockEdit, + restricted: false, + mostUsed: false, + sidebarTab: 1, + security: { + addPermission: [], + view: [], + }, + }; + return config; +}; diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/styles.css b/src/components/manage/Blocks/DiscodataConnectorBlock/styles.css new file mode 100644 index 0000000..db5c8e9 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/styles.css @@ -0,0 +1,16 @@ +.connected-data-block { + background-color: lightblue; +} + +.block-container .data-content span { + white-space: break-spaces; +} + +#sidebar-properties .accordion .ui.menu { + flex-wrap: wrap; +} + +#sidebar-properties .accordion .ui.menu .active.item { + border: 1px solid #d4d4d5; + border-radius: 0.28rem !important; +} diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/v1/Edit.jsx b/src/components/manage/Blocks/DiscodataConnectorBlock/v1/Edit.jsx new file mode 100644 index 0000000..d0b04df --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/v1/Edit.jsx @@ -0,0 +1,90 @@ +import React, { useState, useEffect } from 'react'; +import { compose } from 'redux'; +import _uniqueId from 'lodash/uniqueId'; +import { v4 as uuid } from 'uuid'; +import View from './View'; +import { SidebarPortal } from '@plone/volto/components'; +import InlineForm from '@plone/volto/components/manage/Form/InlineForm'; +import { connectToMultipleProviders } from '@eeacms/volto-datablocks/hocs'; + +import { getSchema } from './schema'; + +import '../styles.css'; + +const Edit = (props) => { + const [state, setState] = useState({ + id: _uniqueId('block_'), + schema: getSchema(props), + }); + + useEffect(() => { + const newData = { ...props.data }; + if (props.data.data_providers) { + if ( + typeof props.data?.data_providers === 'object' && + props.data?.data_providers?.value + ) { + try { + newData.data_providers = []; + const dataProvidersSchema = JSON.parse( + props.data?.data_providers?.value, + ); + dataProvidersSchema?.fieldsets?.[0]?.fields && + dataProvidersSchema.fieldsets[0].fields.forEach((dataProvider) => { + newData.data_providers.push({ + ...dataProvidersSchema.properties[dataProvider], + '@id': uuid(), + id: dataProvider, + }); + }); + } catch {} + } + } + if (JSON.stringify(newData) !== JSON.stringify(props.data)) { + props.onChangeBlock(props.block, { + ...newData, + }); + } + /* eslint-disable-next-line */ + }, []); + + useEffect(() => { + setState({ + ...state, + schema: getSchema(props), + }); + /* eslint-disable-next-line */ + }, [props.providers_data, props.data.data_providers_new]); + + return ( +
+ + { + props.onChangeBlock(props.block, { + ...(props.data || {}), + [field]: data, + }); + }} + formData={props.data || {}} + block={props.block} + /> + + +
+ ); +}; + +export default compose( + connectToMultipleProviders((props) => ({ + providers: + props.data?.data_providers + ?.map((provider) => ({ + provider_url: provider.path, + title: provider.title, + })) + ?.filter((provider) => provider.provider_url) || [], + })), +)(Edit); diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/v1/View.jsx b/src/components/manage/Blocks/DiscodataConnectorBlock/v1/View.jsx new file mode 100644 index 0000000..bb82ae5 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/v1/View.jsx @@ -0,0 +1,180 @@ +import React, { useState, useEffect } from 'react'; +import { compose } from 'redux'; +import { connectToMultipleProviders } from '@eeacms/volto-datablocks/hocs'; +import { DataConnectedValue } from '@eeacms/volto-datablocks/Utils'; +import { Sources } from '@eeacms/volto-datablocks/Utils'; + +const providerView = (dataProviderKey, dataProvider) => { + return ( +
+ + {dataProvider.hasDiscodataConnector && ( + + )} + {dataProvider.measurmentUnit || ''} + + {' ' + (dataProvider.additionalText || '')} +
+ ); +}; + +const bulletListView = (items) => ( +
+ {items && + Object.entries(items).map(([key, item]) => ( +
+ {item.leftText} + {item.rightText} +
+ ))} +
+); + +const View = (props) => { + const [dataProviders, setDataProviders] = useState({}); + const [parentsDataProviders, setParentsDataProviders] = useState({}); + const { providers_data, providers_metadata } = props; + const bulletList = + props.data?.bullet_list?.value && + JSON.parse(props.data?.bullet_list?.value).properties; + + const updateDataProviders = () => { + let newDataProviders = { ...dataProviders }; + if (props.data.data_providers) { + if ( + typeof props.data.data_providers === 'object' && + props.data.data_providers.value + ) { + newDataProviders = {}; + const dataProvidersSchema = + props.data?.data_providers?.value && + JSON.parse(props.data?.data_providers?.value); + dataProvidersSchema?.fieldsets?.[0]?.fields && + dataProvidersSchema.fieldsets[0].fields.forEach((dataProvider) => { + newDataProviders[dataProvider] = { + ...dataProvidersSchema.properties[dataProvider], + }; + }); + } else if (Array.isArray(props.data.data_providers)) { + newDataProviders = {}; + props.data.data_providers.forEach((provider) => { + newDataProviders[provider.id] = { ...provider }; + }); + } + } + setDataProviders({ ...newDataProviders }); + return newDataProviders; + }; + + const updateParentsDataProviders = () => { + const newParentsDataProviders = {}; + dataProviders && + Object.entries(dataProviders).forEach( + ([dataProviderKey, dataProvider]) => { + if (!dataProvider.hasParent) { + newParentsDataProviders[dataProviderKey] = { ...dataProvider }; + } else if ( + dataProvider.parent && + newParentsDataProviders[dataProvider.parent] + ) { + if (!newParentsDataProviders[dataProvider.parent].children) { + newParentsDataProviders[dataProvider.parent].children = {}; + } + newParentsDataProviders[dataProvider.parent].children[ + dataProviderKey + ] = dataProvider; + } + }, + ); + setParentsDataProviders({ ...newParentsDataProviders }); + return newParentsDataProviders; + }; + + useEffect(() => { + updateDataProviders(); + /* eslint-disable-next-line */ + }, [JSON.stringify(props.data?.data_providers)]); + + useEffect(() => { + updateParentsDataProviders(); + /* eslint-disable-next-line */ + }, [JSON.stringify(dataProviders)]); + + const view = ( +
+
+ {/* {props.data?.block_title ?
{props.data.block_title}
: ''} */} + {parentsDataProviders && + Object.entries(parentsDataProviders).map( + ([dataProviderKey, dataProvider]) => { + if (dataProvider.children) { + return ( +
+ {providerView(dataProviderKey, dataProvider)} + {Object.entries( + dataProvider.children, + ).map(([cildrenKey, children]) => + providerView(cildrenKey, children), + )} +
+ ); + } + return ( +
+ {providerView(dataProviderKey, dataProvider)} +
+ ); + }, + )} + {bulletList && bulletListView(bulletList)} + {props?.data?.chartSources && ( +
+ provider.path) + ?.filter((path) => path)?.[0] + } + /> +
+ )} +
+
+ ); + return view; +}; + +export default compose( + connectToMultipleProviders((props) => ({ + providers: + props.data?.data_providers + ?.map((provider) => ({ + provider_url: provider.path, + title: provider.title, + has_data_query_by_context: provider.has_data_query_by_context, + has_data_query_by_provider: provider.has_data_query_by_provider, + data_query: provider.data_query, + })) + ?.filter((provider) => provider.provider_url) || [], + })), +)(View); diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/v1/schema.js b/src/components/manage/Blocks/DiscodataConnectorBlock/v1/schema.js new file mode 100644 index 0000000..cb983b2 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/v1/schema.js @@ -0,0 +1,254 @@ +import React from 'react'; + +const makeChoices = (keys) => keys && keys.map((k) => [k, k]); + +const getDataProvidersIds = (data_providers = [], child = {}) => { + const ids = data_providers + .map((data_provider) => data_provider.id) + .filter((id) => id && id !== child.id); + return makeChoices(ids); +}; + +const dataProviderSchemaExtender = (schema, child = {}, props) => { + const data_providers = props.data.data_providers || []; + return { + ...schema, + fieldsets: [ + { + ...schema.fieldsets[0], + }, + { + id: 'properties', + title: 'Properties', + fields: ['measurmentUnit', 'additionalText', 'className'], + }, + ...(child.hasDiscodataConnector + ? [ + { + id: 'Discodata connector', + title: 'Discodata connector', + fields: [ + 'path', + 'displayColumn', + 'textTemplate', + 'specifier', + 'data_query', + ], + }, + ] + : []), + ...(child.hasParent + ? [ + { + id: 'parent', + title: 'Parent', + fields: ['parent'], + }, + ] + : []), + ], + properties: { + ...schema.properties, + displayColumn: { + ...schema.properties.displayColumn, + choices: makeChoices( + Object.keys(props.providers_data?.[child.title] || {}), + ), + }, + parent: { + ...schema.properties.parent, + choices: getDataProvidersIds(data_providers, child), + }, + }, + }; +}; + +const dataProviderSchema = { + title: 'Data provider', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: [ + 'title', + 'id', + 'hasDiscodataConnector', + 'hasParent', + 'wrapperClassName', + ], + }, + { + id: 'advanced', + title: 'Advanced', + fields: [ + 'path', + 'displayColumn', + 'textTemplate', + 'specifier', + 'measurmentUnit', + 'additionalText', + 'className', + 'parent', + 'wrapperClassName', + ], + }, + ], + properties: { + title: { + type: 'text', + title: 'Title', + }, + id: { + type: 'text', + title: 'Id', + }, + hasDiscodataConnector: { + type: 'boolean', + title: 'Has discodata connector', + }, + hasParent: { + type: 'boolean', + title: 'Has parent', + }, + path: { + widget: 'object_by_path', + title: 'Discodata connector', + }, + displayColumn: { + type: 'select', + title: 'Display column', + choices: [], + }, + textTemplate: { + title: 'Text template', + widget: 'textarea', + description: 'Add suffix/prefix to text. Use {} for value placeholder', + }, + specifier: { + title: 'Format', + description: ( + <> + See{' '} + + D3 format documentation + + + ), + }, + measurmentUnit: { + type: 'text', + title: 'Measurment unit', + }, + additionalText: { + type: 'text', + title: 'Additional text', + }, + + className: { + type: 'select', + title: 'Class name', + choices: [ + ['data', 'Data'], + ['data-content', 'Data content'], + ], + }, + parent: { + type: 'select', + title: 'Parent', + choices: [], + }, + wrapperClassName: { + type: 'select', + title: 'Wrapper class name', + choices: [ + ['data-wrapper brown', 'Brown wrapper'], + ['data-wrapper green', 'Green wrapper'], + ['data-wrapper blue', 'Blue wrapper'], + ['data-wrapper purple', 'Purple wrapper'], + ], + }, + data_query: { + title: 'Data query', + widget: 'data_query', + }, + }, + required: ['title', 'id'], +}; + +const SourceSchema = { + title: 'Source', + + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['chart_source', 'chart_source_link'], + }, + ], + + properties: { + chart_source: { + type: 'string', + title: 'Source', + }, + chart_source_link: { + type: 'string', + title: 'Link', + }, + }, + + required: ['source'], +}; + +export const getSchema = (props) => ({ + title: 'Discodata connector block', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['block_title'], + }, + { + id: 'advanced', + title: 'Advanced', + fields: ['data_providers'], + }, + { + id: 'sources', + title: 'Sources', + fields: ['chartSources', 'download_button'], + }, + ], + properties: { + block_title: { + title: 'Title', + widget: 'textarea', + }, + download_button: { + title: 'Download button', + type: 'boolean', + defaultValue: true, + }, + chartSources: { + widget: 'object_list', + title: 'Sources', + schema: SourceSchema, + }, + data_providers: { + title: 'Data providers', + widget: 'object_list', + schema: dataProviderSchema, + schemaExtender: (schema, child) => + dataProviderSchemaExtender(schema, child, props), + defaultData: { + hasDiscodataConnector: true, + hasParent: false, + }, + }, + }, + required: [], +}); diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/v2/Edit.jsx b/src/components/manage/Blocks/DiscodataConnectorBlock/v2/Edit.jsx new file mode 100644 index 0000000..70a1926 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/v2/Edit.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { compose } from 'redux'; +import { SidebarPortal } from '@plone/volto/components'; +import InlineForm from '@plone/volto/components/manage/Form/InlineForm'; +import { connectToMultipleProviders } from '@eeacms/volto-datablocks/hocs'; +import getSchema from './schema'; +import View from './View'; + +const Edit = (props) => { + const schema = React.useMemo(() => getSchema(props), [props]); + + return ( + <> + + + + { + props.onChangeBlock(props.block, { + ...props.data, + [id]: value, + }); + }} + formData={props.data} + /> + + + ); +}; + +export default compose( + connectToMultipleProviders((props) => ({ + providers: props.data?.providers, + })), +)(Edit); diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/v2/View.jsx b/src/components/manage/Blocks/DiscodataConnectorBlock/v2/View.jsx new file mode 100644 index 0000000..b0f1d11 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/v2/View.jsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { compose } from 'redux'; +import { connectToMultipleProviders } from '@eeacms/volto-datablocks/hocs'; +import { DataConnectedValue } from '@eeacms/volto-datablocks/Utils'; +import { Sources } from '@eeacms/volto-datablocks/Utils'; + +const ProviderView = ({ provider }) => { + if (!provider) return ''; + return ( +
+ + + +
+ ); +}; + +const View = (props) => { + const { data = {} } = props; + const { providers = [] } = data; + + if (!providers.length) return

Add providers

; + + return ( +
+
+ {providers.map((provider, index) => { + if ((index + 1) % 2 === 0) return ''; + return ( +
+ + +
+ ); + })} + {props.data?.chartSources && providers?.[0]?.url && ( +
+ +
+ )} +
+
+ ); +}; + +export default compose( + connectToMultipleProviders((props) => ({ + providers: props.data.providers, + })), +)(View); diff --git a/src/components/manage/Blocks/DiscodataConnectorBlock/v2/schema.js b/src/components/manage/Blocks/DiscodataConnectorBlock/v2/schema.js new file mode 100644 index 0000000..629743d --- /dev/null +++ b/src/components/manage/Blocks/DiscodataConnectorBlock/v2/schema.js @@ -0,0 +1,204 @@ +import React from 'react'; + +const dataProviderSchemaExtender = (schema = {}, child = {}, props) => { + const title = child.title || child.url; + if (!title || !props.providers_data) return schema; + const provider_data = props.providers_data[title] || {}; + const columns = Array.from( + new Set(Object.keys(provider_data || {})), + ).map((n) => [n, n]); + const rows = + child.column && provider_data[child.column] + ? provider_data[child.column].map((value, index) => [index, value]) + : []; + + return { + ...schema, + properties: { + ...schema.properties, + column: { + title: 'Column', + choices: columns, + }, + row: { + title: 'Row', + choices: rows, + }, + }, + }; +}; + +const dataProviderSchema = { + title: 'Data provider', + fieldsets: [ + { + id: 'default', + title: 'Properties', + fields: [ + 'title', + 'url', + 'column', + 'row', + 'specifier', + 'textTemplate', + 'placeholder', + ], + }, + { + id: 'advanced', + title: 'Advanced', + fields: [ + 'className', + 'wrapperClassName', + 'has_data_query_by_context', + 'has_data_query_by_provider', + 'data_query', + ], + }, + ], + properties: { + title: { + type: 'text', + title: 'Title', + }, + url: { + widget: 'object_by_path', + title: 'Data provider', + }, + column: { + title: 'Column', + choices: [], + }, + row: { + title: 'Row', + default: 0, + choices: [], + }, + specifier: { + title: 'Format specifier', + description: ( + <> + See{' '} + + D3 format documentation + + + ), + }, + textTemplate: { + title: 'Text template', + widget: 'textarea', + description: 'Add suffix/prefix to text. Use {} for value placeholder', + }, + placeholder: { + title: 'Placeholder', + }, + className: { + type: 'select', + title: 'Class name', + choices: [ + ['data', 'Data'], + ['data-content', 'Data content'], + ], + }, + wrapperClassName: { + type: 'select', + title: 'Wrapper class name', + choices: [ + ['data-wrapper brown', 'Brown wrapper'], + ['data-wrapper green', 'Green wrapper'], + ['data-wrapper blue', 'Blue wrapper'], + ['data-wrapper purple', 'Purple wrapper'], + ], + }, + has_data_query_by_context: { + title: 'Has data_query by context', + type: 'boolean', + defaultValue: true, + }, + has_data_query_by_provider: { + title: 'Has data_query by provider', + type: 'boolean', + defaultValue: true, + }, + data_query: { + title: 'Data query', + widget: 'data_query', + }, + }, + required: ['title', 'id'], +}; + +const SourceSchema = { + title: 'Source', + + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['chart_source', 'chart_source_link'], + }, + ], + + properties: { + chart_source: { + type: 'string', + title: 'Source', + }, + chart_source_link: { + type: 'string', + title: 'Link', + }, + }, + + required: ['source'], +}; + +export default (props) => ({ + title: 'Discodata connector block', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['block_title'], + }, + { + id: 'advanced', + title: 'Advanced', + fields: ['providers'], + }, + { + id: 'sources', + title: 'Sources', + fields: ['chartSources', 'download_button'], + }, + ], + properties: { + block_title: { + title: 'Title', + widget: 'textarea', + }, + chartSources: { + widget: 'object_list', + title: 'Sources', + schema: SourceSchema, + }, + download_button: { + title: 'Download button', + type: 'boolean', + defaultValue: true, + }, + providers: { + title: 'Data providers', + widget: 'object_list', + schema: dataProviderSchema, + schemaExtender: (schema, child) => + dataProviderSchemaExtender(schema, child, props), + }, + }, + required: [], +}); diff --git a/src/components/manage/Blocks/NavigationBlock/Edit.jsx b/src/components/manage/Blocks/NavigationBlock/Edit.jsx index c3c69c2..8409b01 100644 --- a/src/components/manage/Blocks/NavigationBlock/Edit.jsx +++ b/src/components/manage/Blocks/NavigationBlock/Edit.jsx @@ -1,92 +1,31 @@ -import React, { useState, useEffect } from 'react'; +import React from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; -import _uniqueId from 'lodash/uniqueId'; -import RenderFields from '@eeacms/volto-datablocks/Utils/RenderFields'; +import { SidebarPortal } from '@plone/volto/components'; +import InlineForm from '@plone/volto/components/manage/Form/InlineForm'; + import View from './View'; -import config from '@plone/volto/registry'; -const getSchema = (props) => { - return { - parent: { - title: 'Parent page', - widget: 'object_by_path', - }, - className: { - title: 'Classname', - type: 'text', - }, - fixedTabs: { - title: 'Fixed navigation', - type: 'boolean', - }, - navFromParent: { - title: 'Show navigation from parent', - type: 'boolean', - }, - pages: { - title: 'Specific pages', - type: 'schema', - fieldSetTitle: 'specific pages', - fieldSetId: 'specific-pages', - fieldSetSchema: { - fieldsets: [ - { - id: 'default', - title: 'Default', - fields: ['title', 'url'], - }, - ], - properties: { - title: { - title: 'Title', - type: 'text', - }, - url: { - title: 'Url', - widget: 'text', - }, - }, - required: ['title', 'url'], - }, - editFieldset: false, - deleteFieldset: false, - }, - }; -}; +import schema from './schema'; const Edit = (props) => { - const [state, setState] = useState({ - schema: getSchema({ ...props, providerUrl: config.settings.providerUrl }), - id: _uniqueId('block_'), - }); - useEffect(() => { - setState({ - ...state, - schema: getSchema({ - ...props, - }), - }); - /* eslint-disable-next-line */ - }, [state.item, props.data.components]); return ( -
- - -
-
+ <> + + + { + props.onChangeBlock(props.block, { + ...props.data, + [id]: value, + }); + }} + formData={props.data} + /> + + ); }; diff --git a/src/components/manage/Blocks/NavigationBlock/View.jsx b/src/components/manage/Blocks/NavigationBlock/View.jsx index 511f994..c8f482a 100644 --- a/src/components/manage/Blocks/NavigationBlock/View.jsx +++ b/src/components/manage/Blocks/NavigationBlock/View.jsx @@ -28,14 +28,12 @@ const View = ({ content, ...props }) => { const isLoggedIn = cookie.load('auth_token'); const parent = - data?.navFromParent?.value && props.properties?.parent + data?.navFromParent && props.properties?.parent ? getBasePath(props.properties?.parent?.['@id']) - : data.parent?.value; + : data.parent; const history = useHistory(); useEffect(() => { - const pagesProperties = data.pages?.value - ? data.pages?.value?.properties || {} - : {}; + const pagesProperties = data.pages ? data.pages?.properties || {} : {}; const newPages = Object.keys(pagesProperties).map((page) => pagesProperties[page]) || []; setPages(newPages); @@ -49,7 +47,7 @@ const View = ({ content, ...props }) => { setIsMobile(false); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.navigation, data.pages?.value]); + }, [props.navigation, data.pages]); const isFixed = props.fixedTabs; @@ -82,9 +80,7 @@ const View = ({ content, ...props }) => { props.navigation?.items?.length || pages.length } - className={ - props.data.className?.value ? props.data.className.value : '' - } + className={props.data.className || ''} > {isMobile ? ( @@ -235,13 +231,13 @@ export default compose( discodata_resources: state.discodata_resources, navItems: state.navigation?.items, flags: state.flags, - fixedTabs: props.data?.fixedTabs?.value, + fixedTabs: props.data?.fixedTabs, navigation: props.properties?.parent ? getNavigationByParent( state.navigation?.items, - props.data?.navFromParent?.value + props.data?.navFromParent ? getBasePath(props.properties?.parent?.['@id']) - : props.data?.parent?.value, + : props.data?.parent, ) : {}, }), diff --git a/src/components/manage/Blocks/NavigationBlock/schema.js b/src/components/manage/Blocks/NavigationBlock/schema.js new file mode 100644 index 0000000..e15dd38 --- /dev/null +++ b/src/components/manage/Blocks/NavigationBlock/schema.js @@ -0,0 +1,56 @@ +const pagesSchema = { + title: 'Specific pages', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['title', 'url'], + }, + ], + properties: { + title: { + title: 'Title', + type: 'text', + }, + url: { + title: 'Url', + widget: 'text', + }, + }, + required: ['title', 'url'], +}; + +export default { + title: 'Navigation block', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['navFromParent', 'className', 'fixedTabs', 'parent', 'pages'], + }, + ], + properties: { + parent: { + title: 'Parent page', + widget: 'object_by_path', + }, + className: { + title: 'Classname', + type: 'text', + }, + fixedTabs: { + title: 'Fixed navigation', + type: 'boolean', + }, + navFromParent: { + title: 'Show navigation from parent', + type: 'boolean', + }, + pages: { + title: 'Pages', + schema: pagesSchema, + widget: 'object_list', + }, + }, + required: [], +}; diff --git a/src/customizations/volto/components/manage/Widgets/ObjectListWidget.jsx b/src/customizations/volto/components/manage/Widgets/ObjectListWidget.jsx deleted file mode 100644 index 1cc7db4..0000000 --- a/src/customizations/volto/components/manage/Widgets/ObjectListWidget.jsx +++ /dev/null @@ -1,200 +0,0 @@ -import React from 'react'; -import { defineMessages, useIntl } from 'react-intl'; -import { Accordion, Button, Segment } from 'semantic-ui-react'; -import { DragDropList, FormFieldWrapper, Icon } from '@plone/volto/components'; -import ObjectWidget from '@plone/volto/components/manage/Widgets/ObjectWidget'; - -import upSVG from '@plone/volto/icons/up-key.svg'; -import downSVG from '@plone/volto/icons/down-key.svg'; -import deleteSVG from '@plone/volto/icons/delete.svg'; -import addSVG from '@plone/volto/icons/add.svg'; -import dragSVG from '@plone/volto/icons/drag.svg'; -import { v4 as uuid } from 'uuid'; - -const messages = defineMessages({ - labelRemoveItem: { - id: 'Remove item', - defaultMessage: 'Remove item', - }, - labelCollapseItem: { - id: 'Collapse item', - defaultMessage: 'Collapse item', - }, - labelShowItem: { - id: 'Show item', - defaultMessage: 'Show item', - }, - emptyObjectList: { - id: 'Empty object list', - defaultMessage: 'Empty object list', - }, -}); - -const ObjectListWidget = (props) => { - const { - block, - fieldSet, - id, - schema, - value = [], - onChange, - schemaExtender, - } = props; - const [activeColumn, setActiveColumn] = React.useState(value.length - 1); - const intl = useIntl(); - - function handleChangeColumn(e, blockProps) { - const { index } = blockProps; - const newIndex = activeColumn === index ? -1 : index; - - setActiveColumn(newIndex); - } - const objectSchema = typeof schema === 'function' ? schema(props) : schema; - - const topLayerShadow = '0 1px 1px rgba(0,0,0,0.15)'; - const secondLayer = ', 0 10px 0 -5px #eee, 0 10px 1px -4px rgba(0,0,0,0.15)'; - const thirdLayer = ', 0 20px 0 -10px #eee, 0 20px 1px -9px rgba(0,0,0,0.15)'; - - return ( -
- -
- -
- {value.length === 0 && ( - - )} -
- 1 ? secondLayer : ''}${ - value.length > 2 ? thirdLayer : '' - }`, - }} - forwardedAriaLabelledBy={`fieldset-${ - fieldSet || 'default' - }-field-label-${id}`} - childList={value.map((o, index) => [o['@id'] || index + 1, o])} - onMoveItem={(result) => { - const { source, destination } = result; - if (!destination) { - return; - } - - const first = value[source.index]; - const second = value[destination.index]; - value[destination.index] = first; - value[source.index] = second; - - onChange(id, value); - return true; - }} - > - {({ child, childId, index, draginfo }) => { - return ( -
- - - - -
- {`${objectSchema.title} #${index + 1}`} -
-
- - {activeColumn === index ? ( - - ) : ( - - )} -
-
- - - { - const newvalue = value.map((v, i) => - i !== index ? v : fv, - ); - onChange(id, newvalue); - }} - /> - - -
-
- ); - }} -
-
- ); -}; -export default ObjectListWidget; diff --git a/src/helpers/index.js b/src/helpers/index.js index db2302d..2114dfd 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -1,41 +1,9 @@ import { getBaseUrl, flattenToAppURL } from '@plone/volto/helpers'; -import { setConnectedDataParameters } from '@eeacms/volto-datablocks/actions'; export function getBasePath(url) { return flattenToAppURL(getBaseUrl(url)); } -export const objectHasData = (obj) => { - return typeof obj === 'object' && obj !== null && Object.keys(obj).length > 0; -}; - -export const getSchemaWithDataQuery = (props) => { - if (!props.schema) return {}; - let schemaWithDataQuery = {}; - Object.keys(props.schema).forEach((element) => { - if (props.schema[element].type === 'data-provider') { - if ( - !objectHasData( - props?.connected_data_parameters?.byProviderPath?.[props.path], - ) && - !objectHasData( - props?.connected_data_parameters?.byContextPath?.[props.path], - ) - ) { - const dataQuery = {}; - dataQuery[element + '_data_query'] = { - defaultformat: 'compactnumber', - type: 'data-query', - }; - schemaWithDataQuery[element] = props.schema[element]; - schemaWithDataQuery = { ...schemaWithDataQuery, ...dataQuery }; - } - } - schemaWithDataQuery[element] = props.schema[element]; - }); - return schemaWithDataQuery; -}; - export function getLocation(href) { var match = href.match( /^(https?:)\/\/(([^:/?#]*)(?::([0-9]+))?)([/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/, @@ -65,40 +33,3 @@ export function samePath(url, path) { const cleanPath = path.replace(/\/$/, ''); return clean === cleanPath; } - -export const updateConnectedDataParameters = (props) => { - props.schema && - Object.keys(props.schema).forEach((element) => { - if (props.schema[element].type === 'data-query') { - if ( - props?.newData?.columns?.[element] && - (props?.newData?.columns?.[element]?.value?.i !== - props?.data?.columns?.[element]?.value?.i || - props?.newData?.columns?.[element]?.value?.v !== - props?.data?.columns?.[element]?.value?.v) - ) { - const path = getBasePath(props.pathname); - const byPath = props?.connected_data_parameters?.byPath; - const connected_data_parameters = - (byPath?.[path]?.override?.length > 0 && - byPath?.[path]?.override?.[`${props.id}_${element}`]) || - null; - if ( - connected_data_parameters === null || - connected_data_parameters?.i !== - props?.newData?.columns?.[element]?.value?.i || - connected_data_parameters?.v?.join(',') !== - props?.newData?.columns?.[element]?.value?.v - ) { - props.dispatch( - setConnectedDataParameters( - path.replace('/edit', ''), - props?.newData?.columns?.[element]?.value, - `${props.id}_${element}`, - ), - ); - } - } - } - }); -}; diff --git a/src/index.js b/src/index.js index 6121174..6100ebe 100644 --- a/src/index.js +++ b/src/index.js @@ -2,8 +2,9 @@ import Forbidden from '@plone/volto/components/theme/Forbidden/Forbidden'; import Unauthorized from '@plone/volto/components/theme/Unauthorized/Unauthorized'; import installAppExtras from '@eeacms/volto-forests-theme/components/theme/AppExtras'; -import { installBlocks } from '@eeacms/volto-plotlycharts'; + import { applyConfig as installFiseFrontend } from './localconfig'; +import installDiscodataConnectorBlock from '@eeacms/volto-forests-theme/components/manage/Blocks/DiscodataConnectorBlock'; import ObjectListInlineWidget from './components/manage/Widgets/ObjectListInlineWidget'; import reducers from '@eeacms/volto-forests-theme/reducers'; @@ -12,10 +13,11 @@ import './slate-styles.css'; export default function applyConfig(config) { // Add here your project's configuration here by modifying `config` accordingly - config = [installBlocks, installAppExtras, installFiseFrontend].reduce( - (acc, apply) => apply(acc), - config, - ); + config = [ + installAppExtras, + installFiseFrontend, + installDiscodataConnectorBlock, + ].reduce((acc, apply) => apply(acc), config); config.settings = { ...config.settings, diff --git a/theme/site/globals/site.overrides b/theme/site/globals/site.overrides index 98c9089..e8b80e0 100644 --- a/theme/site/globals/site.overrides +++ b/theme/site/globals/site.overrides @@ -176,7 +176,7 @@ body.has-toolbar { .sticky-header-nav { - + position: absolute; bottom: -5px; z-index: 4; @@ -190,7 +190,7 @@ body.has-toolbar { .header-navigation-lead { - + .navigation-prev { position: absolute; @@ -1607,6 +1607,14 @@ span.float-right { padding: 1em; margin-bottom: 1em; border-radius: 5px; + + .formatted-value { + span { + color: #000 !important; + font-size: 13px; + font-weight: normal; + } + } } .land-data,