From eef9fdb463d97f5c4595c5b643c340d77a1b36e1 Mon Sep 17 00:00:00 2001
From: Josh <37798644+joshuaellis@users.noreply.github.com>
Date: Mon, 7 Nov 2022 10:52:14 +0000
Subject: [PATCH] feat: add visual re-ordering with mouse
---
.../EditViewDataManagerProvider/reducer.js | 4 -
.../components/RelationInput/RelationInput.js | 162 ++++++++++++------
.../RelationInput/components/RelationItem.js | 82 ++++-----
.../RelationInputDataManager.js | 14 +-
.../__test__/useModifiedDataSelector.test.js | 13 --
.../hooks/useModifiedDataSelector.js | 20 ---
6 files changed, 159 insertions(+), 136 deletions(-)
delete mode 100644 packages/core/admin/admin/src/content-manager/hooks/__test__/useModifiedDataSelector.test.js
delete mode 100644 packages/core/admin/admin/src/content-manager/hooks/useModifiedDataSelector.js
diff --git a/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js b/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js
index 57e2c2d3df..d8e58893f2 100644
--- a/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js
+++ b/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js
@@ -187,13 +187,9 @@ const reducer = (state, action) =>
const newRelations = [...modifiedDataRelations];
- console.log(oldIndex, newIndex);
-
newRelations.splice(oldIndex, 1);
newRelations.splice(newIndex, 0, currentItem);
- console.log(newRelations);
-
set(draftState, path, newRelations);
break;
diff --git a/packages/core/admin/admin/src/content-manager/components/RelationInput/RelationInput.js b/packages/core/admin/admin/src/content-manager/components/RelationInput/RelationInput.js
index d968709b72..84483c9825 100644
--- a/packages/core/admin/admin/src/content-manager/components/RelationInput/RelationInput.js
+++ b/packages/core/admin/admin/src/content-manager/components/RelationInput/RelationInput.js
@@ -293,64 +293,19 @@ const RelationInput = ({
outerRef={outerListRef}
itemCount={totalNumberOfRelations}
itemSize={RELATION_ITEM_HEIGHT + RELATION_GUTTER}
- itemData={relations}
- itemKey={(index, listData) => `${listData[index].id}-${listData[index].name}`}
+ itemData={{
+ disabled,
+ labelDisconnectRelation,
+ onRelationDisconnect,
+ publicationStateTranslations,
+ relations,
+ totalNumberOfRelations,
+ updatePositionOfRelation: handleUpdatePositionOfRelation,
+ }}
+ itemKey={(index, { relations: relationsItems }) => relationsItems[index].id}
innerElementType="ol"
>
- {({ data, index, style }) => {
- const { publicationState, href, mainField, id } = data[index];
- const statusColor = publicationState === 'draft' ? 'secondary' : 'success';
- const canDrag = totalNumberOfRelations > 1;
-
- return (
- onRelationDisconnect(data[index])}
- aria-label={labelDisconnectRelation}
- >
-
-
- }
- style={{
- ...style,
- bottom: style.bottom + RELATION_GUTTER,
- height: style.height - RELATION_GUTTER,
- }}
- >
-
-
- {href ? (
-
- {mainField ?? id}
-
- ) : (
-
- {mainField ?? id}
-
- )}
-
-
-
- {publicationState && (
-
-
- {publicationStateTranslations[publicationState]}
-
-
- )}
-
- );
- }}
+ {ListItem}
{(description || error) && (
@@ -434,4 +389,99 @@ RelationInput.propTypes = {
relations: RelationsResult,
};
+/**
+ * This is in a seperate component to enforce passing all the props the component requires to react-window
+ * to ensure drag & drop correctly works.
+ */
+const ListItem = ({ data, index, style }) => {
+ const {
+ disabled,
+ labelDisconnectRelation,
+ onRelationDisconnect,
+ publicationStateTranslations,
+ relations,
+ totalNumberOfRelations,
+ updatePositionOfRelation,
+ } = data;
+ const { publicationState, href, mainField, id } = relations[index];
+ const statusColor = publicationState === 'draft' ? 'secondary' : 'success';
+ const canDrag = totalNumberOfRelations > 1;
+
+ return (
+ onRelationDisconnect(data[index])}
+ aria-label={labelDisconnectRelation}
+ >
+
+
+ }
+ style={{
+ ...style,
+ bottom: style.bottom + RELATION_GUTTER,
+ height: style.height - RELATION_GUTTER,
+ }}
+ >
+
+
+ {href ? (
+
+ {mainField ?? id}
+
+ ) : (
+
+ {mainField ?? id}
+
+ )}
+
+
+
+ {publicationState && (
+
+
+ {publicationStateTranslations[publicationState]}
+
+
+ )}
+
+ );
+};
+
+ListItem.defaultProps = {
+ data: {},
+};
+
+ListItem.propTypes = {
+ data: PropTypes.shape({
+ disabled: PropTypes.bool.isRequired,
+ labelDisconnectRelation: PropTypes.string.isRequired,
+ onRelationDisconnect: PropTypes.func.isRequired,
+ publicationStateTranslations: PropTypes.shape({
+ draft: PropTypes.string.isRequired,
+ published: PropTypes.string.isRequired,
+ }).isRequired,
+ relations: PropTypes.arrayOf(
+ PropTypes.shape({
+ href: PropTypes.string,
+ id: PropTypes.number.isRequired,
+ publicationState: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ mainField: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ })
+ ),
+ totalNumberOfRelations: PropTypes.number.isRequired,
+ updatePositionOfRelation: PropTypes.func.isRequired,
+ }),
+ index: PropTypes.number.isRequired,
+ style: PropTypes.object.isRequired,
+};
+
export default RelationInput;
diff --git a/packages/core/admin/admin/src/content-manager/components/RelationInput/components/RelationItem.js b/packages/core/admin/admin/src/content-manager/components/RelationInput/components/RelationItem.js
index 0b7427b80b..ef8761886d 100644
--- a/packages/core/admin/admin/src/content-manager/components/RelationInput/components/RelationItem.js
+++ b/packages/core/admin/admin/src/content-manager/components/RelationInput/components/RelationItem.js
@@ -51,22 +51,11 @@ export const RelationItem = ({
return;
}
- // Determine rectangle on screen
const hoverBoundingRect = relationRef.current.getBoundingClientRect();
-
- // Get vertical middle
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
-
- // Determine mouse position
const clientOffset = monitor.getClientOffset();
-
- // Get pixels to the top
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
- // Only perform the move when the mouse has crossed half of the items height
- // When dragging downwards, only move when the cursor is below 50%
- // When dragging upwards, only move when the cursor is above 50%
-
// Dragging downwards
if (dragIndex < currentIndex && hoverClientY < hoverMiddleY) {
return;
@@ -84,42 +73,57 @@ export const RelationItem = ({
},
});
- const [{ isDragging }, dragRef] = useDrag(() => ({
+ const [{ isDragging }, dragRef, dragPreviewRef] = useDrag({
type: RELATION_ITEM_DRAG_TYPE,
- item: { index },
+ item: { index, id },
canDrag,
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
- }));
+ });
- const composedRefs = composeRefs(relationRef, dropRef, dragRef);
-
- const opacity = isDragging ? 0 : 1;
+ const composedRefs = composeRefs(relationRef, dragRef);
return (
-
-
- {/* TODO: swap this out for using children when DS is updated */}
- {canDrag ? } /> : null}
- {children}
- {endAction && {endAction}}
-
+
+ {isDragging ? (
+
+ ) : (
+
+ {/* TODO: swap this out for using children when DS is updated */}
+ {canDrag ? (
+ } />
+ ) : null}
+ {children}
+ {endAction && {endAction}}
+
+ )}
);
};
diff --git a/packages/core/admin/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js b/packages/core/admin/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js
index a176019a91..0788e9c643 100644
--- a/packages/core/admin/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js
+++ b/packages/core/admin/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js
@@ -10,7 +10,6 @@ import { useCMEditViewDataManager, NotAllowedInput } from '@strapi/helper-plugin
import { RelationInput } from '../RelationInput';
import { useRelation } from '../../hooks/useRelation';
-import { useModifiedDataSelector } from '../../hooks/useModifiedDataSelector';
import { getTrad } from '../../utils';
@@ -38,10 +37,17 @@ export const RelationInputDataManager = ({
targetModel,
}) => {
const { formatMessage } = useIntl();
- const { connectRelation, disconnectRelation, loadRelation, slug, initialData, reorderRelation } =
- useCMEditViewDataManager();
+ const {
+ connectRelation,
+ disconnectRelation,
+ loadRelation,
+ slug,
+ initialData,
+ modifiedData,
+ reorderRelation,
+ } = useCMEditViewDataManager();
- const relationsFromModifiedData = useModifiedDataSelector(name, []);
+ const relationsFromModifiedData = get(modifiedData, name);
const currentLastPage = Math.ceil(relationsFromModifiedData.length / RELATIONS_TO_DISPLAY);
diff --git a/packages/core/admin/admin/src/content-manager/hooks/__test__/useModifiedDataSelector.test.js b/packages/core/admin/admin/src/content-manager/hooks/__test__/useModifiedDataSelector.test.js
deleted file mode 100644
index d9c0db242c..0000000000
--- a/packages/core/admin/admin/src/content-manager/hooks/__test__/useModifiedDataSelector.test.js
+++ /dev/null
@@ -1,13 +0,0 @@
-describe('useModifiedDataSelector', () => {
- it.todo('should not re render when the same primitive value is returned from the modifiedData');
-
- it.todo('should not re render when the same object value is returned from the modifiedData');
-
- it.todo('should not re render when the same array value is returned from the modifiedData');
-
- it.todo('should re render when a different primitive value is returned from the modifiedData');
-
- it.todo('should re render when a different object value is returned from the modifiedData');
-
- it.todo('should re render when a different array value is returned from the modifiedData');
-});
diff --git a/packages/core/admin/admin/src/content-manager/hooks/useModifiedDataSelector.js b/packages/core/admin/admin/src/content-manager/hooks/useModifiedDataSelector.js
deleted file mode 100644
index 004a4f621b..0000000000
--- a/packages/core/admin/admin/src/content-manager/hooks/useModifiedDataSelector.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { useEffect, useState } from 'react';
-import get from 'lodash/get';
-import isEqual from 'react-fast-compare';
-import { useCMEditViewDataManager } from '@strapi/helper-plugin';
-
-export const useModifiedDataSelector = (path, defaultValue) => {
- const { modifiedData } = useCMEditViewDataManager();
-
- const [value, setValue] = useState(get(modifiedData, path, defaultValue));
-
- useEffect(() => {
- const newValue = get(modifiedData, path, defaultValue);
-
- if (!isEqual(newValue, value)) {
- setValue(newValue);
- }
- }, [modifiedData, path, defaultValue, value]);
-
- return value;
-};