Add dnd relation state

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2020-09-01 11:49:34 +02:00 committed by Pierre Noël
parent bb4cea6019
commit d3082807d1
10 changed files with 94 additions and 19 deletions

View File

@ -19,8 +19,8 @@
"type": "string"
},
"categories": {
"via": "addresses",
"collection": "category",
"via": "addresses",
"dominant": true
},
"cover": {
@ -46,6 +46,10 @@
"city": {
"type": "string",
"required": true
},
"likes": {
"collection": "like",
"via": "address"
}
}
}

View File

@ -16,8 +16,8 @@
"type": "string"
},
"addresses": {
"collection": "address",
"via": "categories"
"via": "categories",
"collection": "address"
}
}
}

View File

@ -1,4 +1,5 @@
{
"kind": "collectionType",
"collectionName": "likes",
"info": {
"name": "like",
@ -18,6 +19,10 @@
"review": {
"model": "review",
"via": "likes"
},
"address": {
"via": "likes",
"model": "address"
}
}
}

View File

@ -66,7 +66,13 @@ const CustomDragLayer = () => {
case ItemTypes.RELATION:
return (
<Li>
<RelationItem data={item.data} mainField={item.mainField} isDisabled={false} />
<RelationItem
data={item.data}
mainField={item.mainField}
isDisabled={false}
isDragging
hasDraftAndPublish={item.hasDraftAndPublish}
/>
</Li>
);
case ItemTypes.EDIT_FIELD:

View File

@ -0,0 +1,21 @@
import styled from 'styled-components';
const RelationDPState = styled.div`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:before {
content: '';
display: flex;
width: 6px;
height: 6px;
margin-bottom: 1px;
margin-left: 10px;
border-radius: 50%;
background-color: ${({ theme, isDraft }) =>
isDraft ? theme.main.colors.mediumBlue : theme.main.colors.green};
}
`;
export default RelationDPState;

View File

@ -12,6 +12,7 @@ import Relation from './Relation';
function ListItem({
data,
findRelation,
hasDraftAndPublish,
isDisabled,
mainField,
moveRelation,
@ -27,6 +28,7 @@ function ListItem({
id: data.id,
originalIndex,
data,
hasDraftAndPublish,
mainField,
},
collect: monitor => ({
@ -60,6 +62,7 @@ function ListItem({
style={{ opacity }}
>
<Relation
hasDraftAndPublish={hasDraftAndPublish}
mainField={mainField}
onRemove={onRemove}
data={data}
@ -80,6 +83,7 @@ ListItem.defaultProps = {
ListItem.propTypes = {
data: PropTypes.object.isRequired,
findRelation: PropTypes.func,
hasDraftAndPublish: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired,
mainField: PropTypes.string.isRequired,
moveRelation: PropTypes.func,

View File

@ -2,30 +2,53 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import { Link, useLocation } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import pluginId from '../../pluginId';
import { isEmpty } from 'lodash';
import { useIntl } from 'react-intl';
import { getTrad } from '../../utils';
import IconRemove from '../../assets/images/icon_remove.svg';
import RelationDPState from '../RelationDPState';
import { Span } from './components';
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
const Relation = ({ data, isDisabled, mainField, onRemove, to }) => {
const Relation = ({
data,
hasDraftAndPublish,
isDisabled,
isDragging,
mainField,
onRemove,
to,
}) => {
const { formatMessage } = useIntl();
const cursor = isDisabled ? 'not-allowed' : 'pointer';
const { pathname } = useLocation();
const isDraft = isEmpty(data.published_at);
const titleLabelID = isDraft
? 'components.Select.draft-info-title'
: 'components.Select.publish-info-title';
let title = hasDraftAndPublish
? formatMessage({ id: getTrad(titleLabelID) })
: formatMessage({ id: getTrad('containers.Edit.clickToJump') });
if (isDragging) {
title = '';
}
return (
<>
<div style={{ cursor }}>
<div style={{ cursor }} title={title}>
<div className="dragHandle">
<span />
</div>
<FormattedMessage id={`${pluginId}.containers.Edit.clickToJump`}>
{title => (
<Link to={{ pathname: to, state: { from: pathname } }} title={title}>
<Span>{data[mainField]}</Span>
</Link>
)}
</FormattedMessage>
{hasDraftAndPublish && (
<div>
<RelationDPState isDraft={isDraft} />
</div>
)}
<Link to={{ pathname: to, state: { from: pathname } }} title={title}>
<Span>{data[mainField]}</Span>
</Link>
</div>
<div style={{ cursor }}>
<img src={IconRemove} alt="Remove Icon" onClick={onRemove} />
@ -35,13 +58,16 @@ const Relation = ({ data, isDisabled, mainField, onRemove, to }) => {
};
Relation.defaultProps = {
isDragging: false,
onRemove: () => {},
to: '',
};
Relation.propTypes = {
data: PropTypes.object.isRequired,
hasDraftAndPublish: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired,
isDragging: PropTypes.bool,
mainField: PropTypes.string.isRequired,
onRemove: PropTypes.func,
to: PropTypes.string,

View File

@ -2,10 +2,8 @@ import React, { memo, useCallback } from 'react';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import { useDrop } from 'react-dnd';
import Select, { createFilter } from 'react-select';
import ItemTypes from '../../utils/ItemTypes';
import { ListShadow, ListWrapper } from './components';
import ListItem from './ListItem';
@ -13,6 +11,7 @@ function SelectMany({
addRelation,
mainField,
name,
hasDraftAndPublish,
isDisabled,
isLoading,
move,
@ -95,6 +94,7 @@ function SelectMany({
<ListItem
key={data.id}
data={data}
hasDraftAndPublish={hasDraftAndPublish}
isDisabled={isDisabled}
findRelation={findRelation}
mainField={mainField}
@ -122,11 +122,12 @@ SelectMany.defaultProps = {
SelectMany.propTypes = {
addRelation: PropTypes.func.isRequired,
hasDraftAndPublish: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired,
mainField: PropTypes.string.isRequired,
move: PropTypes.func,
name: PropTypes.string.isRequired,
isLoading: PropTypes.bool.isRequired,
onInputChange: PropTypes.func.isRequired,
onMenuClose: PropTypes.func.isRequired,
onMenuScrollToBottom: PropTypes.func.isRequired,

View File

@ -3,7 +3,7 @@ import React, { useState, useEffect, useMemo, useRef, memo } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Link, useLocation } from 'react-router-dom';
import { cloneDeep, findIndex, get, isArray, isEmpty, set } from 'lodash';
import { cloneDeep, findIndex, get, isArray, isEmpty, set, has } from 'lodash';
import { request } from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
import useDataManager from '../../hooks/useDataManager';
@ -34,6 +34,7 @@ function SelectWrapper({
const isMorph = relationType.toLowerCase().includes('morph');
const { addRelation, modifiedData, moveRelation, onChange, onRemoveRelation } = useDataManager();
const { isDraggingComponent } = useEditView();
const [hasDraftAndPublish, setHasDraftAndPublish] = useState(false);
// This is needed for making requests when used in a component
const fieldName = useMemo(() => {
@ -102,6 +103,10 @@ function SelectWrapper({
signal,
});
if (data.some(value => has(value, 'published_at'))) {
setHasDraftAndPublish(true);
}
const formattedData = data.map(obj => {
return { value: obj, label: obj[mainField] };
});
@ -240,6 +245,7 @@ function SelectWrapper({
addRelation={value => {
addRelation({ target: { name, value } });
}}
hasDraftAndPublish={hasDraftAndPublish}
id={name}
isDisabled={isDisabled}
isLoading={isLoading}

View File

@ -20,6 +20,8 @@
"components.FiltersPickWrapper.hide": "Hide",
"components.LimitSelect.itemsPerPage": "Items per page",
"components.NotAllowedInput.text": "No permissions to see this field",
"components.Select.draft-info-title": "State: Draft",
"components.Select.publish-info-title": "State: Published",
"components.Search.placeholder": "Search for an entry...",
"components.SettingsViewWrapper.pluginHeader.description.edit-settings": "Customize how the edit view will look like.",
"components.SettingsViewWrapper.pluginHeader.description.list-settings": "Define the settings of the list view.",