diff --git a/src/components/theme/View/TabsView.jsx b/src/components/theme/View/TabsView.jsx
new file mode 100644
index 00000000..881ddaa7
--- /dev/null
+++ b/src/components/theme/View/TabsView.jsx
@@ -0,0 +1,171 @@
+/**
+ * Document view component.
+ * @module components/theme/View/DefaultView
+ */
+
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Helmet } from '@plone/volto/helpers';
+import { compose } from 'redux';
+import { defineMessages, injectIntl } from 'react-intl';
+
+import { map } from 'lodash';
+import { connect } from 'react-redux';
+import { Link } from 'react-router-dom';
+
+import { blocks } from '~/config';
+import {
+ getBlocksFieldname,
+ getBlocksLayoutFieldname,
+ hasBlocksData,
+} from '@plone/volto/helpers';
+import { flattenToAppURL } from '@plone/volto/helpers';
+
+const messages = defineMessages({
+ unknownBlock: {
+ id: 'Unknown Block',
+ defaultMessage: 'Unknown Block {block}',
+ },
+});
+
+class DefaultView extends Component {
+ constructor(props) {
+ super(props);
+ // this.renderTabs = this.renderTabs.bind(this);
+ this.state = {
+ tabs: null,
+ };
+ }
+
+ static defaultProps = {
+ parent: null,
+ };
+ static propTypes = {
+ tabs: PropTypes.array,
+ content: PropTypes.shape({
+ title: PropTypes.string,
+ description: PropTypes.string,
+ text: PropTypes.shape({
+ data: PropTypes.string,
+ }),
+ }).isRequired,
+ localNavigation: PropTypes.any,
+ };
+
+ // componentWillReceiveProps(nextProps) {
+ // console.log('herere', nextProps.parent, this.props.parent);
+ // if (nextProps.parent && nextProps.parent.id !== this.props.parent?.id) {
+
+ // const pathArr = nextProps.location.pathname.split('/');
+ // pathArr.length = 4;
+ // const path = pathArr.join('/');
+ // const tabsItems = nextProps.parent.items.map(i => {
+ // return {
+ // url: `${path}/${i.id}`,
+ // title: i.title,
+ // '@type': i['@type'],
+ // };
+ // });
+ // this.props.setFolderTabs(tabsItems);
+ // }
+ // }
+
+ computeFolderTabs = siblings => {
+ const tabsItems = siblings.items.map(i => {
+ return {
+ url: flattenToAppURL(i.url),
+ title: i.name,
+ };
+ });
+ return tabsItems;
+ };
+
+ render() {
+ const content = this.props.content;
+ const intl = this.props.intl;
+ const blocksFieldname = getBlocksFieldname(content);
+ const blocksLayoutFieldname = getBlocksLayoutFieldname(content);
+ const tabs = this.computeFolderTabs(content['@components'].siblings);
+
+ // const currentUrl = this.props.content?.['@id'];
+ // const shouldRenderRoutes =
+ // typeof currentUrl !== 'undefined' &&
+ // samePath(currentUrl, this.props.pathname)
+ // ? true
+ // : false;
+ //
+ // if (shouldRenderRoutes === false)
+ // return (
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // );
+
+ return (
+ hasBlocksData(content) && (
+
+ {tabs && tabs.length ? (
+
+ ) : (
+ ''
+ )}
+
+ {map(content[blocksLayoutFieldname].items, block => {
+ const Block =
+ blocks.blocksConfig[
+ (content[blocksFieldname]?.[block]?.['@type'])
+ ]?.['view'] || null;
+ return Block !== null ? (
+
+ ) : (
+
+ {intl.formatMessage(messages.unknownBlock, {
+ block: content[blocksFieldname]?.[block]?.['@type'],
+ })}
+
+ );
+ })}
+
+ )
+ );
+ }
+}
+
+export default compose(
+ injectIntl,
+ connect((state, props) => ({
+ pathname: props.location.pathname,
+ content:
+ state.prefetch?.[state.router.location.pathname] || state.content.data,
+ })),
+)(DefaultView);
\ No newline at end of file
diff --git a/src/config.js b/src/config.js
index ace9f9a6..b3550387 100644
--- a/src/config.js
+++ b/src/config.js
@@ -3,29 +3,30 @@ import * as voltoConfig from '@plone/volto/config';
import {
applyConfig as addonsConfig,
installFolderListing,
- // installCustomAddonGroup,
installTableau,
} from 'volto-addons/config';
import { applyConfig as ckeditorConfig } from 'volto-ckeditor/config';
import { applyConfig as dataBlocksConfig } from 'volto-datablocks/config';
import { applyConfig as blocksConfig } from 'volto-blocks/config';
import { applyConfig as mosaicConfig } from 'volto-mosaic/config';
-// import { applyConfig as plotlyConfig } from 'volto-plotlycharts/config';
+import { applyConfig as plotlyConfig } from 'volto-plotlycharts/config';
// import { applyConfig as installEPRTRFrontend } from './localconfig';
import { applyConfig as installSidebar } from 'volto-sidebar/config';
+// import { applyConfig as installEPRTRFrontend } from './localconfig';
+import installEPRTR from './localconfig';
+
const config = [
- // installCustomAddonGroup,
addonsConfig,
- // installSidebar,
- // installFolderListing,
- // installTableau,
- // plotlyConfig,
+ installSidebar,
+ installFolderListing,
+ installTableau,
+ plotlyConfig,
// ckeditorConfig,
// mosaicConfig,
- // blocksConfig,
- // dataBlocksConfig,
- // installEPRTRFrontend,
+ blocksConfig,
+ dataBlocksConfig,
+ installEPRTR,
].reduce((acc, apply) => apply(acc), voltoConfig);
// config.settings.contentExpand=[breadcrumbs,actions,workflow]
diff --git a/src/customizations/volto/components/manage/BlockChooser/BlockChooser.jsx b/src/customizations/volto/components/manage/BlockChooser/BlockChooser.jsx
new file mode 100644
index 00000000..4f3edcf0
--- /dev/null
+++ b/src/customizations/volto/components/manage/BlockChooser/BlockChooser.jsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { filter, map, groupBy } from 'lodash';
+import { Accordion, Button } from 'semantic-ui-react';
+import { injectIntl } from 'react-intl';
+import { Icon } from '@plone/volto/components';
+import AnimateHeight from 'react-animate-height';
+import { blocks } from '~/config';
+
+import upSVG from '@plone/volto/icons/up-key.svg';
+import downSVG from '@plone/volto/icons/down-key.svg';
+
+const BlockChooser = ({ currentBlock, onMutateBlock, intl }) => {
+ const mostUsedBlocks = filter(blocks.blocksConfig, item => item.mostUsed);
+ const groupedBlocks = groupBy(blocks.blocksConfig, item => item.group);
+ const blocksAvailable = { mostUsed: mostUsedBlocks, ...groupedBlocks };
+ const [activeIndex, setActiveIndex] = React.useState(0);
+
+ function handleClick(e, titleProps) {
+ const { index } = titleProps;
+ const newIndex = activeIndex === index ? -1 : index;
+
+ setActiveIndex(newIndex);
+ }
+
+ return (
+
+
+ {map(blocks.groupBlocksOrder, (groupName, index) => (
+
+
+ {intl.formatMessage({
+ id: groupName.id,
+ defaultMessage: groupName.title,
+ })}
+
+ {activeIndex === 0 ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {map(
+ filter(
+ blocksAvailable[groupName.id],
+ block => !block.restricted,
+ ),
+ block => (
+
+
+
+ ),
+ )}
+
+
+
+ ))}
+
+
+ );
+};
+
+BlockChooser.propTypes = {
+ currentBlock: PropTypes.string.isRequired,
+ onMutateBlock: PropTypes.func.isRequired,
+};
+
+export default injectIntl(BlockChooser);
\ No newline at end of file
diff --git a/src/customizations/volto/components/manage/Widgets/FileWidget.jsx b/src/customizations/volto/components/manage/Widgets/FileWidget.jsx
new file mode 100644
index 00000000..0e5ed55b
--- /dev/null
+++ b/src/customizations/volto/components/manage/Widgets/FileWidget.jsx
@@ -0,0 +1,132 @@
+/**
+ * FileWidget component.
+ * @module components/manage/Widgets/FileWidget
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Form, Grid, Input, Label, Button } from 'semantic-ui-react';
+import { map } from 'lodash';
+import { readAsDataURL } from 'promise-file-reader';
+
+import deleteSVG from '@plone/volto/icons/delete.svg';
+import { Icon } from '@plone/volto/components';
+
+/**
+ * FileWidget component class.
+ * @function FileWidget
+ * @returns {string} Markup of the component.
+ */
+const FileWidget = ({
+ id,
+ title,
+ required,
+ description,
+ error,
+ value,
+ onChange,
+ fieldSet,
+}) => {
+ const fileInput = React.useRef(null);
+ return ''
+ return (
+ 0}
+ className={description ? 'help' : ''}
+ id={`${fieldSet || 'field'}-${id}`}
+ >
+
+
+
+
+
+
+
+
+ {
+ const file = target.files[0];
+ readAsDataURL(file).then(data => {
+ const fields = data.match(/^data:(.*);(.*),(.*)$/);
+ onChange(id, {
+ data: fields[3],
+ encoding: fields[2],
+ 'content-type': fields[1],
+ filename: file.name,
+ });
+ });
+ }}
+ />
+
+ {value && value.filename}
+ {value && (
+
+ )}
+
+ {map(error, message => (
+
+ ))}
+
+
+ {description && (
+
+
+ {description}
+
+
+ )}
+
+
+ );
+};
+
+/**
+ * Property types.
+ * @property {Object} propTypes Property types.
+ * @static
+ */
+FileWidget.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.shape({
+ '@type': PropTypes.string,
+ title: PropTypes.string,
+ }),
+ onChange: PropTypes.func.isRequired,
+};
+
+/**
+ * Default properties.
+ * @property {Object} defaultProps Default properties.
+ * @static
+ */
+FileWidget.defaultProps = {
+ description: null,
+ required: false,
+ error: [],
+ value: null,
+};
+
+export default FileWidget;
\ No newline at end of file
diff --git a/src/localconfig.js b/src/localconfig.js
new file mode 100644
index 00000000..5d299e7a
--- /dev/null
+++ b/src/localconfig.js
@@ -0,0 +1,26 @@
+
+import TabsView from '~/components/theme/View/TabsView';
+
+const applyConfig = config => {
+console.log('config', config)
+ config.views = {
+ ...config.views,
+ layoutViews: {
+ ...config.views.layoutViews,
+ tabs_view: TabsView,
+ },
+ };
+
+
+ // config.blocks.blocksConfig.collection_block = {
+ // id: 'collection_block',
+ // title: 'Collection Listing',
+ // view: CollectionBlockView,
+ // edit: CollectionBlockEdit,
+ // icon: chartIcon,
+ // group: 'custom_addons',
+ // };
+ return config;
+}
+
+export default applyConfig
\ No newline at end of file