From 1218f46acb2e9cb5f5986b3038a29a45b34e5305 Mon Sep 17 00:00:00 2001 From: Mihai Macaneata Date: Tue, 7 Apr 2020 09:06:41 +0300 Subject: [PATCH] install addons, fix edit --- src/components/theme/View/TabsView.jsx | 171 ++++++++++++++++++ src/config.js | 21 ++- .../manage/BlockChooser/BlockChooser.jsx | 95 ++++++++++ .../components/manage/Widgets/FileWidget.jsx | 132 ++++++++++++++ src/localconfig.js | 26 +++ 5 files changed, 435 insertions(+), 10 deletions(-) create mode 100644 src/components/theme/View/TabsView.jsx create mode 100644 src/customizations/volto/components/manage/BlockChooser/BlockChooser.jsx create mode 100644 src/customizations/volto/components/manage/Widgets/FileWidget.jsx create mode 100644 src/localconfig.js 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