mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 10:55:37 +00:00
Add relation dnd
Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
parent
9bd2011f61
commit
6e77d7699e
@ -55,6 +55,7 @@ const CustomDragLayer = () => {
|
||||
<div style={layerStyles}>
|
||||
<div style={getItemStyles(initialOffset, currentOffset, mouseOffset)} className="col-md-2">
|
||||
{itemType === ItemTypes.FIELD && <CardPreview labelField={item.labelField} />}
|
||||
{itemType === ItemTypes.EDIT_RELATION && <CardPreview labelField={item.labelField} />}
|
||||
{itemType === ItemTypes.COMPONENT && (
|
||||
<RepeatableComponentPreview displayedValue={item.displayedValue} />
|
||||
)}
|
||||
|
||||
@ -11,14 +11,14 @@ import { Flex } from '@strapi/design-system/Flex';
|
||||
import { VisuallyHidden } from '@strapi/design-system/VisuallyHidden';
|
||||
import { SimpleMenu, MenuItem } from '@strapi/design-system/SimpleMenu';
|
||||
import Plus from '@strapi/icons/Plus';
|
||||
import { getTrad } from '../../../utils';
|
||||
import { getTrad, ItemTypes } from '../../../utils';
|
||||
import { useLayoutDnd } from '../../../hooks';
|
||||
import FieldButton from './FieldButton';
|
||||
import LinkToCTB from './LinkToCTB';
|
||||
|
||||
const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField, onAddField }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { setEditFieldToSelect, attributes, modifiedData } = useLayoutDnd();
|
||||
const { setEditFieldToSelect, attributes, modifiedData, onMoveField } = useLayoutDnd();
|
||||
|
||||
return (
|
||||
<Stack size={4}>
|
||||
@ -32,15 +32,14 @@ const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField,
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
{/* Since the drag n drop will not be available, this text will be hidden for the moment */}
|
||||
{/* <Box>
|
||||
<Box>
|
||||
<Typography variant="pi" textColor="neutral600">
|
||||
{formatMessage({
|
||||
id: 'containers.SettingPage.editSettings.description',
|
||||
defaultMessage: 'Drag & drop the fields to build the layout',
|
||||
})}
|
||||
</Typography>
|
||||
</Box> */}
|
||||
</Box>
|
||||
</div>
|
||||
<LinkToCTB />
|
||||
</Flex>
|
||||
@ -63,6 +62,10 @@ const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField,
|
||||
onEditField={() => setEditFieldToSelect(rowItem.name)}
|
||||
onDeleteField={() => onRemoveField(row.rowId, index)}
|
||||
attribute={attribute}
|
||||
itemType={ItemTypes.EDIT_RELATION}
|
||||
index={index}
|
||||
name={rowItem.name}
|
||||
onMoveField={onMoveField}
|
||||
>
|
||||
{attributeLabel || rowItem.name}
|
||||
</FieldButton>
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import React from 'react';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDrop, useDrag } from 'react-dnd';
|
||||
import { getEmptyImage } from 'react-dnd-html5-backend';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Box } from '@strapi/design-system/Box';
|
||||
import { Flex } from '@strapi/design-system/Flex';
|
||||
import { IconButton } from '@strapi/design-system/IconButton';
|
||||
@ -8,10 +11,9 @@ import { Typography } from '@strapi/design-system/Typography';
|
||||
import Drag from '@strapi/icons/Drag';
|
||||
import Pencil from '@strapi/icons/Pencil';
|
||||
import Trash from '@strapi/icons/Trash';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { getTrad } from '../../../utils';
|
||||
import ComponentFieldList from './ComponentFieldList';
|
||||
import DynamicZoneList from './DynamicZoneList';
|
||||
import getTrad from '../../../utils/getTrad';
|
||||
|
||||
const CustomIconButton = styled(IconButton)`
|
||||
background-color: transparent;
|
||||
@ -27,10 +29,63 @@ const CustomDragIcon = styled(Drag)`
|
||||
}
|
||||
`;
|
||||
const CustomFlex = styled(Flex)`
|
||||
opacity: ${({ isDragging }) => (isDragging ? 0 : 1)};
|
||||
`;
|
||||
const DragButton = styled(Flex)`
|
||||
cursor: all-scroll;
|
||||
border-right: 1px solid ${({ theme }) => theme.colors.neutral200};
|
||||
`;
|
||||
|
||||
const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
|
||||
const FieldButton = ({
|
||||
attribute,
|
||||
onEditField,
|
||||
onDeleteField,
|
||||
children,
|
||||
index,
|
||||
itemType,
|
||||
name,
|
||||
onMoveField,
|
||||
}) => {
|
||||
const dragButtonRef = useRef();
|
||||
|
||||
const [, drop] = useDrop({
|
||||
accept: itemType,
|
||||
hover(item) {
|
||||
if (!dragButtonRef.current) {
|
||||
return;
|
||||
}
|
||||
const dragIndex = item.index;
|
||||
const hoverIndex = index;
|
||||
|
||||
// Don't replace items with themselves
|
||||
if (dragIndex === hoverIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(hoverIndex);
|
||||
|
||||
onMoveField(dragIndex, hoverIndex);
|
||||
|
||||
item.index = hoverIndex;
|
||||
},
|
||||
});
|
||||
|
||||
const [{ isDragging }, drag, dragPreview] = useDrag({
|
||||
type: itemType,
|
||||
item: () => {
|
||||
return { index, labelField: children, name };
|
||||
},
|
||||
collect: monitor => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
dragPreview(getEmptyImage(), { captureDraggingState: true });
|
||||
}, [dragPreview]);
|
||||
|
||||
drag(drop(dragButtonRef));
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
const getHeight = () => {
|
||||
const higherFields = ['json', 'text', 'file', 'media', 'component', 'richtext', 'dynamiczone'];
|
||||
@ -43,17 +98,28 @@ const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex
|
||||
<CustomFlex
|
||||
width="100%"
|
||||
borderColor="neutral150"
|
||||
hasRadius
|
||||
background="neutral100"
|
||||
minHeight={getHeight()}
|
||||
alignItems="stretch"
|
||||
isDragging={isDragging}
|
||||
>
|
||||
<CustomFlex alignItems="center" paddingLeft={3} paddingRight={3}>
|
||||
<DragButton
|
||||
as="button"
|
||||
type="button"
|
||||
ref={dragButtonRef}
|
||||
onClick={e => e.stopPropagation()}
|
||||
alignItems="center"
|
||||
paddingLeft={3}
|
||||
paddingRight={3}
|
||||
// Disable the keyboard navigation since the drag n drop isn't accessible with the keyboard for the moment
|
||||
tabIndex={-1}
|
||||
>
|
||||
<CustomDragIcon />
|
||||
</CustomFlex>
|
||||
</DragButton>
|
||||
<Box overflow="hidden" width="100%">
|
||||
<Flex paddingLeft={3} alignItems="baseline" justifyContent="space-between">
|
||||
<Box>
|
||||
@ -96,7 +162,7 @@ const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
|
||||
)}
|
||||
{attribute?.type === 'dynamiczone' && <DynamicZoneList components={attribute.components} />}
|
||||
</Box>
|
||||
</Flex>
|
||||
</CustomFlex>
|
||||
);
|
||||
};
|
||||
|
||||
@ -113,6 +179,10 @@ FieldButton.propTypes = {
|
||||
onEditField: PropTypes.func.isRequired,
|
||||
onDeleteField: PropTypes.func.isRequired,
|
||||
children: PropTypes.string.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
itemType: PropTypes.string.isRequired,
|
||||
onMoveField: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default FieldButton;
|
||||
|
||||
@ -8,9 +8,9 @@ import { Typography } from '@strapi/design-system/Typography';
|
||||
import { Stack } from '@strapi/design-system/Stack';
|
||||
import { SimpleMenu, MenuItem } from '@strapi/design-system/SimpleMenu';
|
||||
import Plus from '@strapi/icons/Plus';
|
||||
import { getTrad } from '../../../utils';
|
||||
import FieldButton from './FieldButton';
|
||||
import { getTrad, ItemTypes } from '../../../utils';
|
||||
import { useLayoutDnd } from '../../../hooks';
|
||||
import FieldButton from './FieldButton';
|
||||
|
||||
const RelationalFields = ({
|
||||
relationsLayout,
|
||||
@ -19,7 +19,7 @@ const RelationalFields = ({
|
||||
onAddField,
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { setEditFieldToSelect, modifiedData } = useLayoutDnd();
|
||||
const { setEditFieldToSelect, modifiedData, onMoveRelation } = useLayoutDnd();
|
||||
|
||||
return (
|
||||
<Stack size={4}>
|
||||
@ -56,6 +56,10 @@ const RelationalFields = ({
|
||||
onEditField={() => setEditFieldToSelect(relationName)}
|
||||
onDeleteField={() => onRemoveField(index)}
|
||||
key={relationName}
|
||||
index={index}
|
||||
name={relationName}
|
||||
onMoveField={onMoveRelation}
|
||||
itemType={ItemTypes.EDIT_RELATION}
|
||||
>
|
||||
{relationLabel || relationName}
|
||||
</FieldButton>
|
||||
|
||||
@ -151,6 +151,22 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
|
||||
submitMutation.mutate(body);
|
||||
};
|
||||
|
||||
const handleMoveRelation = (fromIndex, toIndex) => {
|
||||
dispatch({
|
||||
type: 'MOVE_RELATION',
|
||||
fromIndex,
|
||||
toIndex,
|
||||
});
|
||||
};
|
||||
|
||||
const handleMoveField = (fromIndex, toIndex) => {
|
||||
dispatch({
|
||||
type: 'MOVE_FIELD',
|
||||
fromIndex,
|
||||
toIndex,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<LayoutDndProvider
|
||||
isContentTypeView={isContentTypeView}
|
||||
@ -160,6 +176,8 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
|
||||
componentLayouts={componentLayouts}
|
||||
selectedField={metaToEdit}
|
||||
fieldForm={metaForm}
|
||||
onMoveRelation={handleMoveRelation}
|
||||
onMoveField={handleMoveField}
|
||||
setEditFieldToSelect={name => {
|
||||
dispatch({
|
||||
type: 'SET_FIELD_TO_EDIT',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user