import { ComponentProps, useState, useRef } from 'react'; import './styles/basic/main.css'; import './styles/quanta/main.css'; // import type { ActionsResponse } from '@plone/types'; import { VisuallyHidden } from 'react-aria'; import { TooltipTrigger, useDragAndDrop, type Selection, DialogTrigger, MenuTrigger, } from 'react-aria-components'; import { useIntl } from 'react-intl'; import { useMediaQuery } from 'usehooks-ts'; import { // AddIcon, Breadcrumbs, CollectionIcon, Container, MoreoptionsIcon, PasteIcon, QuantaTextField, Tooltip, } from '@plone/components'; import Toast from '@plone/volto/components/manage/Toast/Toast'; import type { Toast as ToastType } from 'react-toastify'; import { Button } from '../Button'; import { Table } from '../Table/Table'; import { ContentsCell } from './ContentsCell'; import { TableIndexesPopover } from './TableIndexesPopover'; import { RearrangePopover } from './RearrangePopover'; import { ContentsActions } from './ContentsActions'; // import { AddContentPopover } from './AddContentPopover'; import type { ArrayElement, Brain } from '../../types'; interface ContentsProps { // pathname: string; breadcrumbs: ComponentProps['items']; // objectActions: ActionsResponse['object']; title: string; // loading: boolean; canPaste: boolean; textFilter: string; onChangeTextFilter: (value: string) => void; items: Brain[]; selected: Selection; setSelected: (value: Selection) => void; indexes: { order: (keyof Brain)[]; values: { [index: string]: { type: string; label: string; selected: boolean; sort_on?: string; }; }; selectedCount: number; }; onSelectIndex: (index: string) => void; sortItems: (index: string) => void; upload: () => Promise; rename: () => Promise; workflow: () => Promise; tags: () => Promise; properties: () => Promise; cut: (value?: string) => Promise; copy: (value?: string) => Promise; paste: () => Promise; deleteItem: (value?: string) => Promise; orderItem: (id: string, delta: number) => Promise; moveToTop: (index: number) => Promise; moveToBottom: (index: number) => Promise; // addableTypes: ComponentProps['addableTypes']; toast: ToastType; } /** * A table showing the contents of an object. * * It has a toolbar for interactions with the items and a searchbar for filtering. * Items can be sorted by drag and drop. */ export function Contents({ // pathname, breadcrumbs = [], // objectActions, title, // loading, canPaste, textFilter, onChangeTextFilter, items, selected, setSelected, indexes: baseIndexes, onSelectIndex, sortItems, upload, rename, workflow, tags, properties, cut, copy, paste, deleteItem, orderItem, moveToTop, moveToBottom, // addableTypes, toast, }: ContentsProps) { const intl = useIntl(); const isMobileScreenSize = useMediaQuery('(max-width: 768px)'); const [isMoreColumnsOpen, setIsMoreColumnsOpen] = useState(false); const triggerRefMoreColumns = useRef(null); // const folderContentsActions = objectActions.find( // (action) => action.id === 'folderContents', // ); // if (!folderContentsActions) { // // TODO current volto returns the Unauthorized component here // // it would be best if the permissions check was done at a higher level // // and this remained null // return null; // } // TODO "id" is a reserved key for table rows, so we cannot add the "ID" column at this time const excluded_indexes = ['id']; const indexes = { ...baseIndexes, order: baseIndexes.order.filter( (index) => !excluded_indexes.includes(index), ), values: Object.fromEntries( Object.entries(baseIndexes.values).filter( ([key]) => !excluded_indexes.includes(key), ), ), }; const columns = [ { id: 'title', name: intl.formatMessage({ id: 'Title' }), isRowHeader: true, }, ...(!isMobileScreenSize ? indexes.order .filter((index) => indexes.values[index].selected) .map((index) => ({ id: index, name: intl.formatMessage({ id: indexes.values[index].label }), })) : []), { id: '_actions', name: !isMobileScreenSize ? ( {intl.formatMessage({ id: 'contentsNextSelectColumnsToDisplay', })} ) : canPaste ? ( {intl.formatMessage({ id: 'Paste' })} ) : null, }, ] as const; const rows = items.map((item, itemIndex) => columns.reduce['rows']>>( (cells, column) => ({ ...cells, [column.id]: ( moveToBottom(itemIndex)} onMoveToTop={() => moveToTop(itemIndex)} onCut={() => cut(item['@id'])} onCopy={() => copy(item['@id'])} onDelete={() => deleteItem(item['@id'])} /> ), }), { id: item['@id'], // Automatic textValue generation does not work // because the title column is a ReactNode and not a string textValue: item.title, }, ), ); const { dragAndDropHooks } = useDragAndDrop({ isDisabled: isMobileScreenSize || selected === 'all' || selected.size > 1, getItems: (keys) => [...keys].map((key) => ({ 'text/plain': key.toString(), })), onReorder(e) { if (e.keys.size !== 1) { toast.error( , ); return; } const target = [...e.keys][0]; if (target === e.target.key) return; const item = items.find((item) => item['@id'] === target); if (!item) return; const initialPosition = rows.findIndex((row) => row.id === item['@id']); if (initialPosition === -1) return; const finalPosition = rows.findIndex((row) => row.id === e.target.key); let delta = finalPosition - initialPosition; if (delta > 0 && e.target.dropPosition === 'before') delta -= 1; if (delta < 0 && e.target.dropPosition === 'after') delta += 1; if (delta !== 0) { orderItem(item.id, delta); } }, }); return (

{title}

{!isMobileScreenSize && ( )} {intl.formatMessage( { id: 'contentsNextNumberOfItems' }, { count: items.length }, )} {/* Add content */}
{intl.formatMessage({ id: 'Rearrange items by…' })} } // onRowSelection={onRowSelection} // resizableColumns={true} /> ); }