diff --git a/packages/core/admin/admin/src/content-manager/components/DragLayer/index.js b/packages/core/admin/admin/src/content-manager/components/DragLayer/index.js
index d77e66ac21..1923965456 100644
--- a/packages/core/admin/admin/src/content-manager/components/DragLayer/index.js
+++ b/packages/core/admin/admin/src/content-manager/components/DragLayer/index.js
@@ -55,6 +55,7 @@ const CustomDragLayer = () => {
{itemType === ItemTypes.FIELD && }
+ {itemType === ItemTypes.EDIT_RELATION && }
{itemType === ItemTypes.COMPONENT && (
)}
diff --git a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/DisplayedFields.js b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/DisplayedFields.js
index c68ae73695..0cfa51b2a5 100644
--- a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/DisplayedFields.js
+++ b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/DisplayedFields.js
@@ -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 (
@@ -32,15 +32,14 @@ const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField,
})}
- {/* Since the drag n drop will not be available, this text will be hidden for the moment */}
- {/*
+
{formatMessage({
id: 'containers.SettingPage.editSettings.description',
defaultMessage: 'Drag & drop the fields to build the layout',
})}
- */}
+
@@ -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}
diff --git a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/FieldButton.js b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/FieldButton.js
index 1800daeabb..8913dc1499 100644
--- a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/FieldButton.js
+++ b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/FieldButton.js
@@ -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 (
-
-
+ 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}
+ >
-
+
@@ -96,7 +162,7 @@ const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
)}
{attribute?.type === 'dynamiczone' && }
-
+
);
};
@@ -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;
diff --git a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/RelationalFields.js b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/RelationalFields.js
index 639c1aa438..c4f05d1fb3 100644
--- a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/RelationalFields.js
+++ b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/components/RelationalFields.js
@@ -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 (
@@ -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}
diff --git a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/index.js
index 137b2d10d6..04c236083c 100644
--- a/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/index.js
+++ b/packages/core/admin/admin/src/content-manager/pages/EditSettingsView/index.js
@@ -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 (
{
dispatch({
type: 'SET_FIELD_TO_EDIT',