diff --git a/src/customizations/volto/components/manage/Contents/Contents.jsx b/src/customizations/volto/components/manage/Contents/Contents.jsx new file mode 100644 index 00000000..fb07fb12 --- /dev/null +++ b/src/customizations/volto/components/manage/Contents/Contents.jsx @@ -0,0 +1,1893 @@ +/** + * Contents component. + * @module components/manage/Contents/Contents + */ + +/** !!!IMPORTANTE!!! + * CUSTOMIZATION -> FILE DA RIMUOVERE QUANDO AGGIORNIAMO A VOLTO16 + * - added getContent action from '@plone/volto/actions', + * getContent refetching content to sync the current object in the toolbar + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { compose } from 'redux'; +import { Portal } from 'react-portal'; +import { Link } from 'react-router-dom'; +import { + Button, + Confirm, + Container, + Dropdown, + Menu, + Input, + Segment, + Table, + Popup, + Loader, + Dimmer, +} from 'semantic-ui-react'; +import { + concat, + filter, + find, + indexOf, + keys, + map, + mapValues, + pull, +} from 'lodash'; +import move from 'lodash-move'; +import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; +import { asyncConnect } from '@plone/volto/helpers'; + +import { + searchContent, + cut, + copy, + copyContent, + deleteContent, + listActions, + moveContent, + orderContent, + sortContent, + updateColumnsContent, + getContent, +} from '@plone/volto/actions'; +import Indexes, { defaultIndexes } from '@plone/volto/constants/Indexes'; +import { + ContentsBreadcrumbs, + ContentsIndexHeader, + ContentsItem, + ContentsRenameModal, + ContentsUploadModal, + ContentsWorkflowModal, + ContentsTagsModal, + ContentsPropertiesModal, + Pagination, + Toolbar, + Toast, + Icon, + Unauthorized, +} from '@plone/volto/components'; + +import { Helmet, getBaseUrl } from '@plone/volto/helpers'; +import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable'; + +import backSVG from '@plone/volto/icons/back.svg'; +import cutSVG from '@plone/volto/icons/cut.svg'; +import deleteSVG from '@plone/volto/icons/delete.svg'; +import copySVG from '@plone/volto/icons/copy.svg'; +import tagSVG from '@plone/volto/icons/tag.svg'; +import renameSVG from '@plone/volto/icons/rename.svg'; +import semaphoreSVG from '@plone/volto/icons/semaphore.svg'; +import uploadSVG from '@plone/volto/icons/upload.svg'; +import propertiesSVG from '@plone/volto/icons/properties.svg'; +import pasteSVG from '@plone/volto/icons/paste.svg'; +import zoomSVG from '@plone/volto/icons/zoom.svg'; +import checkboxUncheckedSVG from '@plone/volto/icons/checkbox-unchecked.svg'; +import checkboxCheckedSVG from '@plone/volto/icons/checkbox-checked.svg'; +import checkboxIndeterminateSVG from '@plone/volto/icons/checkbox-indeterminate.svg'; +import configurationSVG from '@plone/volto/icons/configuration-app.svg'; +import sortDownSVG from '@plone/volto/icons/sort-down.svg'; +import sortUpSVG from '@plone/volto/icons/sort-up.svg'; +import downKeySVG from '@plone/volto/icons/down-key.svg'; +import moreSVG from '@plone/volto/icons/more.svg'; + +const messages = defineMessages({ + back: { + id: 'Back', + defaultMessage: 'Back', + }, + contents: { + id: 'Contents', + defaultMessage: 'Contents', + }, + copy: { + id: 'Copy', + defaultMessage: 'Copy', + }, + cut: { + id: 'Cut', + defaultMessage: 'Cut', + }, + error: { + id: "You can't paste this content here", + defaultMessage: "You can't paste this content here", + }, + delete: { + id: 'Delete', + defaultMessage: 'Delete', + }, + deleteConfirm: { + id: 'Do you really want to delete the following items?', + defaultMessage: 'Do you really want to delete the following items?', + }, + deleteError: { + id: 'The item could not be deleted.', + defaultMessage: 'The item could not be deleted.', + }, + loading: { + id: 'loading', + defaultMessage: 'Loading', + }, + home: { + id: 'Home', + defaultMessage: 'Home', + }, + filter: { + id: 'Filter…', + defaultMessage: 'Filter…', + }, + messageCopied: { + id: 'Item(s) copied.', + defaultMessage: 'Item(s) copied.', + }, + messageCut: { + id: 'Item(s) cut.', + defaultMessage: 'Item(s) cut.', + }, + messageUpdate: { + id: 'Item(s) has been updated.', + defaultMessage: 'Item(s) has been updated.', + }, + messageReorder: { + id: 'Item succesfully moved.', + defaultMessage: 'Item succesfully moved.', + }, + messagePasted: { + id: 'Item(s) pasted.', + defaultMessage: 'Item(s) pasted.', + }, + messageWorkflowUpdate: { + id: 'Item(s) state has been updated.', + defaultMessage: 'Item(s) state has been updated.', + }, + paste: { + id: 'Paste', + defaultMessage: 'Paste', + }, + properties: { + id: 'Properties', + defaultMessage: 'Properties', + }, + rearrangeBy: { + id: 'Rearrange items by…', + defaultMessage: 'Rearrange items by…', + }, + rename: { + id: 'Rename', + defaultMessage: 'Rename', + }, + select: { + id: 'Select…', + defaultMessage: 'Select…', + }, + selected: { + id: '{count} selected', + defaultMessage: '{count} selected', + }, + selectColumns: { + id: 'Select columns to show', + defaultMessage: 'Select columns to show', + }, + sort: { + id: 'sort', + defaultMessage: 'sort', + }, + state: { + id: 'State', + defaultMessage: 'State', + }, + tags: { + id: 'Tags', + defaultMessage: 'Tags', + }, + upload: { + id: 'Upload', + defaultMessage: 'Upload', + }, + success: { + id: 'Success', + defaultMessage: 'Success', + }, + publicationDate: { + id: 'Publication date', + defaultMessage: 'Publication date', + }, + createdOn: { + id: 'Created on', + defaultMessage: 'Created on', + }, + expirationDate: { + id: 'Expiration date', + defaultMessage: 'Expiration date', + }, + id: { + id: 'ID', + defaultMessage: 'ID', + }, + uid: { + id: 'UID', + defaultMessage: 'UID', + }, + reviewState: { + id: 'Review state', + defaultMessage: 'Review state', + }, + folder: { + id: 'Folder', + defaultMessage: 'Folder', + }, + excludedFromNavigation: { + id: 'Excluded from navigation', + defaultMessage: 'Excluded from navigation', + }, + objectSize: { + id: 'Object Size', + defaultMessage: 'Object Size', + }, + lastCommentedDate: { + id: 'Last comment date', + defaultMessage: 'Last comment date', + }, + totalComments: { + id: 'Total comments', + defaultMessage: 'Total comments', + }, + creator: { + id: 'Creator', + defaultMessage: 'Creator', + }, + endDate: { + id: 'End Date', + defaultMessage: 'End Date', + }, + startDate: { + id: 'Start Date', + defaultMessage: 'Start Date', + }, + all: { + id: 'All', + defaultMessage: 'All', + }, +}); + +/** + * Contents class. + * @class Contents + * @extends Component + */ +class Contents extends Component { + /** + * Property types. + * @property {Object} propTypes Property types. + * @static + */ + static propTypes = { + action: PropTypes.string, + source: PropTypes.arrayOf(PropTypes.string), + searchContent: PropTypes.func.isRequired, + cut: PropTypes.func.isRequired, + copy: PropTypes.func.isRequired, + copyContent: PropTypes.func.isRequired, + deleteContent: PropTypes.func.isRequired, + moveContent: PropTypes.func.isRequired, + orderContent: PropTypes.func.isRequired, + sortContent: PropTypes.func.isRequired, + updateColumnsContent: PropTypes.func.isRequired, + clipboardRequest: PropTypes.shape({ + loading: PropTypes.bool, + loaded: PropTypes.bool, + }).isRequired, + deleteRequest: PropTypes.shape({ + loading: PropTypes.bool, + loaded: PropTypes.bool, + }).isRequired, + updateRequest: PropTypes.shape({ + loading: PropTypes.bool, + loaded: PropTypes.bool, + }).isRequired, + searchRequest: PropTypes.shape({ + loading: PropTypes.bool, + loaded: PropTypes.bool, + }).isRequired, + items: PropTypes.arrayOf( + PropTypes.shape({ + '@id': PropTypes.string, + '@type': PropTypes.string, + title: PropTypes.string, + description: PropTypes.string, + }), + ), + breadcrumbs: PropTypes.arrayOf( + PropTypes.shape({ + title: PropTypes.string, + url: PropTypes.string, + }), + ).isRequired, + total: PropTypes.number.isRequired, + pathname: PropTypes.string.isRequired, + }; + + /** + * Default properties. + * @property {Object} defaultProps Default properties. + * @static + */ + static defaultProps = { + items: [], + action: null, + source: null, + index: { + order: keys(Indexes), + values: mapValues(Indexes, (value, key) => ({ + ...value, + selected: indexOf(defaultIndexes, key) !== -1, + })), + selectedCount: defaultIndexes.length + 1, + }, + }; + + /** + * Constructor + * @method constructor + * @param {Object} props Component properties + * @constructs ContentsComponent + */ + constructor(props) { + super(props); + this.onDeselect = this.onDeselect.bind(this); + this.onSelect = this.onSelect.bind(this); + this.onSelectAll = this.onSelectAll.bind(this); + this.onSelectIndex = this.onSelectIndex.bind(this); + this.onSelectNone = this.onSelectNone.bind(this); + this.onDeleteOk = this.onDeleteOk.bind(this); + this.onDeleteCancel = this.onDeleteCancel.bind(this); + this.onUploadOk = this.onUploadOk.bind(this); + this.onUploadCancel = this.onUploadCancel.bind(this); + this.onRenameOk = this.onRenameOk.bind(this); + this.onRenameCancel = this.onRenameCancel.bind(this); + this.onTagsOk = this.onTagsOk.bind(this); + this.onTagsCancel = this.onTagsCancel.bind(this); + this.onPropertiesOk = this.onPropertiesOk.bind(this); + this.onPropertiesCancel = this.onPropertiesCancel.bind(this); + this.onWorkflowOk = this.onWorkflowOk.bind(this); + this.onWorkflowCancel = this.onWorkflowCancel.bind(this); + this.onChangeFilter = this.onChangeFilter.bind(this); + this.onChangePage = this.onChangePage.bind(this); + this.onChangePageSize = this.onChangePageSize.bind(this); + this.onOrderIndex = this.onOrderIndex.bind(this); + this.onOrderItem = this.onOrderItem.bind(this); + this.onSortItems = this.onSortItems.bind(this); + this.onMoveToTop = this.onMoveToTop.bind(this); + this.onChangeSelected = this.onChangeSelected.bind(this); + this.onMoveToBottom = this.onMoveToBottom.bind(this); + this.cut = this.cut.bind(this); + this.copy = this.copy.bind(this); + this.delete = this.delete.bind(this); + this.upload = this.upload.bind(this); + this.rename = this.rename.bind(this); + this.tags = this.tags.bind(this); + this.properties = this.properties.bind(this); + this.workflow = this.workflow.bind(this); + this.paste = this.paste.bind(this); + this.fetchContents = this.fetchContents.bind(this); + this.orderTimeout = null; + this.state = { + selected: [], + showDelete: false, + showUpload: false, + showRename: false, + showTags: false, + showProperties: false, + showWorkflow: false, + itemsToDelete: [], + items: this.props.items, + filter: '', + currentPage: 0, + pageSize: 50, + index: this.props.index || { + order: keys(Indexes), + values: mapValues(Indexes, (value, key) => ({ + ...value, + selected: indexOf(defaultIndexes, key) !== -1, + })), + selectedCount: defaultIndexes.length + 1, + }, + sort_on: this.props.sort?.on || 'getObjPositionInParent', + sort_order: this.props.sort?.order || 'ascending', + isClient: false, + }; + this.filterTimeout = null; + } + + /** + * Component did mount + * @method componentDidMount + * @returns {undefined} + */ + componentDidMount() { + this.fetchContents(); + this.setState({ isClient: true }); + } + + /** + * Component will receive props + * @method componentWillReceiveProps + * @param {Object} nextProps Next properties + * @returns {undefined} + */ + UNSAFE_componentWillReceiveProps(nextProps) { + if ( + (this.props.clipboardRequest.loading && + nextProps.clipboardRequest.loaded) || + (this.props.deleteRequest.loading && nextProps.deleteRequest.loaded) || + (this.props.updateRequest.loading && nextProps.updateRequest.loaded) + ) { + this.fetchContents(nextProps.pathname); + } + if (this.props.updateRequest.loading && nextProps.updateRequest.loaded) { + this.props.toastify.toast.success( + , + ); + } + if (this.props.pathname !== nextProps.pathname) { + // Refetching content to sync the current object in the toolbar + this.props.getContent(getBaseUrl(nextProps.pathname)); + this.setState( + { + currentPage: 0, + }, + () => this.fetchContents(nextProps.pathname), + ); + } + if (this.props.searchRequest.loading && nextProps.searchRequest.loaded) { + this.setState({ + items: nextProps.items, + }); + } + if ( + this.props.clipboardRequest.loading && + nextProps.clipboardRequest.error + ) { + this.props.toastify.toast.error( + , + ); + } + + if ( + this.props.clipboardRequest.loading && + nextProps.clipboardRequest.loaded + ) { + this.props.toastify.toast.success( + , + ); + } + + if (this.props.deleteRequest.loading && nextProps.deleteRequest.error) { + this.props.toastify.toast.error( + , + ); + } + + if (this.props.orderRequest.loading && nextProps.orderRequest.loaded) { + this.props.toastify.toast.success( + , + ); + } + } + + /** + * On deselect handler + * @method onDeselect + * @param {object} event Event object + * @param {string} value Value + * @returns {undefined} + */ + onDeselect(event, { value }) { + this.setState({ + selected: pull(this.state.selected, value), + }); + } + + /** + * On select handler + * @method onSelect + * @param {object} event Event object + * @returns {undefined} + */ + onSelect(event, id) { + if (indexOf(this.state.selected, id) === -1) { + this.setState({ + selected: concat(this.state.selected, id), + }); + } else { + this.setState({ + selected: pull(this.state.selected, id), + }); + } + } + + /** + * On select all handler + * @method onSelectAll + * @returns {undefined} + */ + onSelectAll() { + this.setState({ + selected: map(this.state.items, (item) => item['@id']), + }); + } + + /** + * On select none handler + * @method onSelectNone + * @returns {undefined} + */ + onSelectNone() { + this.setState({ + selected: [], + }); + } + + /** + * On select index + * @method onSelectIndex + * @param {object} event Event object. + * @param {string} value Index value. + * @returns {undefined} + */ + onSelectIndex(event, { value }) { + let newIndex = { + ...this.state.index, + selectedCount: + this.state.index.selectedCount + + (this.state.index.values[value].selected ? -1 : 1), + values: mapValues(this.state.index.values, (indexValue, indexKey) => ({ + ...indexValue, + selected: + indexKey === value ? !indexValue.selected : indexValue.selected, + })), + }; + this.setState({ + index: newIndex, + }); + this.props.updateColumnsContent(getBaseUrl(this.props.pathname), newIndex); + } + + /** + * On change filter + * @method onChangeFilter + * @param {object} event Event object. + * @param {string} value Filter value. + * @returns {undefined} + */ + onChangeFilter(event, { value }) { + const self = this; + clearTimeout(self.filterTimeout); + this.setState( + { + filter: value, + }, + () => { + self.filterTimeout = setTimeout(() => { + self.fetchContents(); + }, 200); + }, + ); + } + + /** + * On change selected values (Filter) + * @method onChangeSelected + * @param {object} event Event object. + * @param {string} value Filter value. + * @returns {undefined} + */ + onChangeSelected(event, { value }) { + event.stopPropagation(); + const { items, selected } = this.state; + + const filteredItems = filter(selected, (selectedItem) => + find(items, (item) => item['@id'] === selectedItem) + .title.toLowerCase() + .includes(value.toLowerCase()), + ); + + this.setState({ + filteredItems, + }); + } + + /** + * On change page + * @method onChangePage + * @param {object} event Event object. + * @param {string} value Page value. + * @returns {undefined} + */ + onChangePage(event, { value }) { + this.setState( + { + currentPage: value, + }, + () => this.fetchContents(), + ); + } + + /** + * On change page size + * @method onChangePageSize + * @param {object} event Event object. + * @param {string} value Page size value. + * @returns {undefined} + */ + onChangePageSize(event, { value }) { + this.setState( + { + pageSize: value, + currentPage: 0, + }, + () => this.fetchContents(), + ); + } + + /** + * On order index + * @method onOrderIndex + * @param {number} index Index + * @param {number} delta Delta + * @returns {undefined} + */ + onOrderIndex(index, delta) { + this.setState({ + index: { + ...this.state.index, + order: move(this.state.index.order, index, index + delta), + }, + }); + this.props.updateColumnsContent( + getBaseUrl(this.props.pathname), + this.state.index, + ); + } + + /** + * On order item + * @method onOrderItem + * @param {string} id Item id + * @param {number} itemIndex Item index + * @param {number} delta Delta + * @returns {undefined} + */ + onOrderItem(id, itemIndex, delta, backend) { + if (backend) { + this.props.orderContent( + getBaseUrl(this.props.pathname), + id.replace(/^.*\//, ''), + delta, + ); + } else { + this.setState({ + items: move(this.state.items, itemIndex, itemIndex + delta), + }); + } + } + + /** + * On sort items + * @method onSortItems + * @param {object} event Event object + * @param {string} value Item index + * @returns {undefined} + */ + onSortItems(event, { value }) { + const values = value.split('|'); + this.setState({ + sort_on: values[0], + sort_order: values[1], + }); + this.props.sortContent( + getBaseUrl(this.props.pathname), + values[0], + values[1], + ); + } + + /** + * On move to top + * @method onMoveToTop + * @param {object} event Event object + * @param {string} value Item index + * @returns {undefined} + */ + onMoveToTop(event, { value }) { + const id = this.state.items[value]['@id']; + value = this.state.currentPage * this.state.pageSize + value; + this.props.orderContent( + getBaseUrl(this.props.pathname), + id.replace(/^.*\//, ''), + -value, + ); + this.setState( + { + currentPage: 0, + }, + () => this.fetchContents(), + ); + } + + /** + * On move to bottom + * @method onMoveToBottom + * @param {object} event Event object + * @param {string} value Item index + * @returns {undefined} + */ + onMoveToBottom(event, { value }) { + this.onOrderItem( + this.state.items[value]['@id'], + value, + this.state.items.length - 1 - value, + false, + ); + this.onOrderItem( + this.state.items[value]['@id'], + value, + this.state.items.length - 1 - value, + true, + ); + } + + /** + * On delete ok + * @method onDeleteOk + * @returns {undefined} + */ + onDeleteOk() { + this.props.deleteContent(this.state.itemsToDelete); + this.setState({ + showDelete: false, + itemsToDelete: [], + selected: [], + }); + } + + /** + * On delete cancel + * @method onDeleteCancel + * @returns {undefined} + */ + onDeleteCancel() { + this.setState({ + showDelete: false, + itemsToDelete: [], + }); + } + + /** + * On upload ok + * @method onUploadOk + * @returns {undefined} + */ + onUploadOk() { + this.fetchContents(); + this.setState({ + showUpload: false, + }); + } + + /** + * On upload cancel + * @method onUploadCancel + * @returns {undefined} + */ + onUploadCancel() { + this.setState({ + showUpload: false, + }); + } + + /** + * On rename ok + * @method onRenameOk + * @returns {undefined} + */ + onRenameOk() { + this.setState({ + showRename: false, + selected: [], + }); + } + + /** + * On rename cancel + * @method onRenameCancel + * @returns {undefined} + */ + onRenameCancel() { + this.setState({ + showRename: false, + }); + } + + /** + * On tags ok + * @method onTagsOk + * @returns {undefined} + */ + onTagsOk() { + this.setState({ + showTags: false, + selected: [], + }); + } + + /** + * On tags cancel + * @method onTagsCancel + * @returns {undefined} + */ + onTagsCancel() { + this.setState({ + showTags: false, + }); + } + + /** + * On properties ok + * @method onPropertiesOk + * @returns {undefined} + */ + onPropertiesOk() { + this.setState({ + showProperties: false, + selected: [], + }); + } + + /** + * On properties cancel + * @method onPropertiesCancel + * @returns {undefined} + */ + onPropertiesCancel() { + this.setState({ + showProperties: false, + }); + } + + /** + * On workflow ok + * @method onWorkflowOk + * @returns {undefined} + */ + onWorkflowOk() { + this.fetchContents(); + this.setState({ + showWorkflow: false, + selected: [], + }); + this.props.toastify.toast.success( + , + ); + } + + /** + * On workflow cancel + * @method onWorkflowCancel + * @returns {undefined} + */ + onWorkflowCancel() { + this.setState({ + showWorkflow: false, + }); + } + + /** + * Get field by id + * @method getFieldById + * @param {string} id Id of object + * @param {string} field Field of object + * @returns {string} Field of object + */ + getFieldById(id, field) { + const item = find(this.state.items, { '@id': id }); + return item ? item[field] : ''; + } + + /** + * Fetch contents handler + * @method fetchContents + * @param {string} pathname Pathname to fetch contents. + * @returns {undefined} + */ + fetchContents(pathname) { + if (this.state.pageSize === this.props.intl.formatMessage(messages.all)) { + //'All' + this.props.searchContent(getBaseUrl(pathname || this.props.pathname), { + 'path.depth': 1, + sort_on: this.state.sort_on, + sort_order: this.state.sort_order, + metadata_fields: '_all', + b_size: 100000000, + ...(this.state.filter && { SearchableText: `${this.state.filter}*` }), + }); + } else { + this.props.searchContent(getBaseUrl(pathname || this.props.pathname), { + 'path.depth': 1, + sort_on: this.state.sort_on, + sort_order: this.state.sort_order, + metadata_fields: '_all', + ...(this.state.filter && { SearchableText: `${this.state.filter}*` }), + b_size: this.state.pageSize, + b_start: this.state.currentPage * this.state.pageSize, + }); + } + } + + /** + * Cut handler + * @method cut + * @param {Object} event Event object. + * @param {string} value Value of the event. + * @returns {undefined} + */ + cut(event, { value }) { + this.props.cut(value ? [value] : this.state.selected); + this.onSelectNone(); + this.props.toastify.toast.success( + , + ); + } + + /** + * Copy handler + * @method copy + * @param {Object} event Event object. + * @param {string} value Value of the event. + * @returns {undefined} + */ + copy(event, { value }) { + this.props.copy(value ? [value] : this.state.selected); + this.onSelectNone(); + this.props.toastify.toast.success( + , + ); + } + + /** + * Delete handler + * @method delete + * @param {Object} event Event object. + * @param {string} value Value of the event. + * @returns {undefined} + */ + delete(event, { value }) { + this.setState({ + showDelete: true, + itemsToDelete: value ? [value] : this.state.selected, + }); + } + + /** + * Upload handler + * @method upload + * @returns {undefined} + */ + upload() { + this.setState({ + showUpload: true, + }); + } + + /** + * Rename handler + * @method rename + * @returns {undefined} + */ + rename() { + this.setState({ + showRename: true, + }); + } + + /** + * Tags handler + * @method tags + * @returns {undefined} + */ + tags() { + this.setState({ + showTags: true, + }); + } + + /** + * Properties handler + * @method properties + * @returns {undefined} + */ + properties() { + this.setState({ + showProperties: true, + }); + } + + /** + * Workflow handler + * @method workflow + * @returns {undefined} + */ + workflow() { + this.setState({ + showWorkflow: true, + }); + } + + /** + * Paste handler + * @method paste + * @returns {undefined} + */ + paste() { + if (this.props.action === 'copy') { + this.props.copyContent( + this.props.source, + getBaseUrl(this.props.pathname), + ); + } + if (this.props.action === 'cut') { + this.props.moveContent( + this.props.source, + getBaseUrl(this.props.pathname), + ); + } + } + + /** + * Render method. + * @method render + * @returns {string} Markup for the component. + */ + render() { + const selected = this.state.selected.length > 0; + const filteredItems = this.state.filteredItems || this.state.selected; + const path = getBaseUrl(this.props.pathname); + const folderContentsAction = find(this.props.objectActions, { + id: 'folderContents', + }); + + const loading = + (this.props.clipboardRequest?.loading && + !this.props.clipboardRequest?.error) || + (this.props.deleteRequest?.loading && !this.props.deleteRequest?.error) || + (this.props.updateRequest?.loading && !this.props.updateRequest?.error) || + (this.props.orderRequest?.loading && !this.props.orderRequest?.error) || + (this.props.searchRequest?.loading && !this.props.searchRequest?.error); + + return this.props.token && this.props.objectActions?.length > 0 ? ( + <> + {folderContentsAction ? ( + + + + + {this.props.intl.formatMessage(messages.loading)} + + + + +
+
+ +
    + {map(this.state.itemsToDelete, (item) => ( +
  • + {this.getFieldById(item, 'title')} +
  • + ))} +
+
+ } + onCancel={this.onDeleteCancel} + onConfirm={this.onDeleteOk} + size="mini" + /> + + ({ + url: item, + title: this.getFieldById(item, 'title'), + id: this.getFieldById(item, 'id'), + }))} + /> + ({ + url: item, + subjects: this.getFieldById(item, 'Subject'), + }))} + /> + + {this.state.showWorkflow && ( + + )} +
+ + + + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.upload, + )} + size="mini" + /> + + + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.rename, + )} + size="mini" + /> + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.state, + )} + size="mini" + /> + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.tags, + )} + size="mini" + /> + + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.properties, + )} + size="mini" + /> + + + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.cut, + )} + size="mini" + /> + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.copy, + )} + size="mini" + /> + + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.paste, + )} + size="mini" + /> + + + + + } + position="top center" + content={this.props.intl.formatMessage( + messages.delete, + )} + size="mini" + /> + + +
+ + +
+
+ +
+ + + + } + className="right floating selectIndex" + > + + + + {map( + filter( + this.state.index.order, + (index) => index !== 'sortable_title', + ), + (index) => ( + + {this.state.index.values[index].selected ? ( + + ) : ( + + )} + + {' '} + {this.props.intl.formatMessage({ + id: this.state.index.values[index] + .label, + defaultMessage: this.state.index.values[ + index + ].label, + })} + + + ), + )} + + + + +
+ + + + + + } + > + + + {map( + [ + 'id', + 'sortable_title', + 'EffectiveDate', + 'CreationDate', + 'ModificationDate', + 'portal_type', + ], + (index) => ( + + + + + + {' '} + + + + {' '} + + + + + ), + )} + + + + + 0 + ? '#007eb1' + : '#826a6a' + } + size="24px" + /> + } + icon={null} + > + + + + {' '} + + + + {' '} + + + + + } + iconPosition="left" + className="search" + placeholder={this.props.intl.formatMessage( + messages.filter, + )} + onChange={this.onChangeSelected} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + }} + /> + + {map(filteredItems, (item) => ( + + {' '} + {this.getFieldById(item, 'title')} + + ))} + + + + + + + + {map( + this.state.index.order, + (index, order) => + this.state.index.values[index].selected && ( + + ), + )} + + + + + + + {this.state.items.map((item, order) => ( + ({ + id: index, + type: this.state.index.values[index].type, + })), + (index) => + this.state.index.values[index.id].selected, + )} + onCut={this.cut} + onCopy={this.copy} + onDelete={this.delete} + onOrderItem={this.onOrderItem} + onMoveToTop={this.onMoveToTop} + onMoveToBottom={this.onMoveToBottom} + /> + ))} + +
+
+ +
+ +
+
+
+ + + {this.state.isClient && ( + + + + + } + /> + + )} +
+
+ ) : ( + + )} + + ) : ( + + ); + } +} + +const DragDropConnector = (props) => { + const { DragDropContext } = props.reactDnd; + const HTML5Backend = props.reactDndHtml5Backend.default; + + const DndConnectedContents = React.useMemo( + () => DragDropContext(HTML5Backend)(Contents), + [DragDropContext, HTML5Backend], + ); + + return ; +}; + +export const __test__ = compose( + injectIntl, + injectLazyLibs(['toastify', 'reactDnd']), + connect( + (store, props) => { + return { + token: store.userSession.token, + items: store.search.items, + sort: store.content.update.sort, + index: store.content.updatecolumns.idx, + breadcrumbs: store.breadcrumbs.items, + total: store.search.total, + searchRequest: { + loading: store.search.loading, + loaded: store.search.loaded, + }, + pathname: props.location.pathname, + action: store.clipboard.action, + source: store.clipboard.source, + clipboardRequest: store.clipboard.request, + deleteRequest: store.content.delete, + updateRequest: store.content.update, + objectActions: store.actions.actions.object, + orderRequest: store.content.order, + }; + }, + { + searchContent, + cut, + copy, + copyContent, + deleteContent, + listActions, + moveContent, + orderContent, + sortContent, + updateColumnsContent, + getContent, + }, + ), +)(Contents); + +export default compose( + injectIntl, + connect( + (store, props) => { + return { + token: store.userSession.token, + items: store.search.items, + sort: store.content.update.sort, + index: store.content.updatecolumns.idx, + breadcrumbs: store.breadcrumbs.items, + total: store.search.total, + searchRequest: { + loading: store.search.loading, + loaded: store.search.loaded, + }, + pathname: props.location.pathname, + action: store.clipboard.action, + source: store.clipboard.source, + clipboardRequest: store.clipboard.request, + deleteRequest: store.content.delete, + updateRequest: store.content.update, + objectActions: store.actions.actions.object, + orderRequest: store.content.order, + }; + }, + { + searchContent, + cut, + copy, + copyContent, + deleteContent, + listActions, + moveContent, + orderContent, + sortContent, + updateColumnsContent, + getContent, + }, + ), + asyncConnect([ + { + key: 'actions', + // Dispatch async/await to make the operation syncronous, otherwise it returns + // before the promise is resolved + promise: async ({ location, store: { dispatch } }) => + await dispatch(listActions(getBaseUrl(location.pathname))), + }, + ]), + injectLazyLibs(['toastify', 'reactDnd', 'reactDndHtml5Backend']), +)(DragDropConnector); diff --git a/src/routes.js b/src/routes.js index bd4304b4..65a8239d 100644 --- a/src/routes.js +++ b/src/routes.js @@ -3,7 +3,7 @@ * @module routes */ -import { App, Search } from '@plone/volto/components'; +import { App, Search, Contents } from '@plone/volto/components'; import { defaultRoutes, multilingualRoutes } from '@plone/volto/routes'; import config from '@plone/volto/registry'; @@ -13,6 +13,11 @@ export const italiaRoutes = [ path: '/**/search', component: Search, }, + // TO DO: DA RIMUOVERE QUANDO AGGIORNIAMO A VOLTO16 + { + path: ['/contents', '/**/contents'], + component: Contents, + }, ]; /**