Fix navigation between relations

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2020-09-09 11:08:08 +02:00 committed by Pierre Noël
parent 92a43a8152
commit e10452c245
7 changed files with 74 additions and 39 deletions

View File

@ -1,9 +1,8 @@
import React, { memo, useEffect, useMemo } from 'react'; import React, { memo, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useDrag, useDrop } from 'react-dnd'; import { useDrag, useDrop } from 'react-dnd';
import { getEmptyImage } from 'react-dnd-html5-backend'; import { getEmptyImage } from 'react-dnd-html5-backend';
import { has } from 'lodash'; import { has } from 'lodash';
import { useGlobalContext } from 'strapi-helper-plugin';
import pluginId from '../../pluginId'; import pluginId from '../../pluginId';
import ItemTypes from '../../utils/ItemTypes'; import ItemTypes from '../../utils/ItemTypes';
@ -13,6 +12,7 @@ import Relation from './Relation';
function ListItem({ function ListItem({
data, data,
displayNavigationLink,
findRelation, findRelation,
isDisabled, isDisabled,
mainField, mainField,
@ -20,16 +20,7 @@ function ListItem({
onRemove, onRemove,
targetModel, targetModel,
}) { }) {
const { settingsBaseURL } = useGlobalContext(); const to = `/plugins/${pluginId}/collectionType/${targetModel}/${data.id}`;
const to = useMemo(() => {
const isAdminUserModel = targetModel === 'strapi::user';
if (isAdminUserModel) {
return `${settingsBaseURL}/users/${data.id}`;
}
return `/plugins/${pluginId}/collectionType/${targetModel}/${data.id}`;
}, [targetModel, data.id, settingsBaseURL]);
const hasDraftAndPublish = has(data, 'published_at'); const hasDraftAndPublish = has(data, 'published_at');
@ -74,6 +65,7 @@ function ListItem({
style={{ opacity }} style={{ opacity }}
> >
<Relation <Relation
displayNavigationLink={displayNavigationLink}
hasDraftAndPublish={hasDraftAndPublish} hasDraftAndPublish={hasDraftAndPublish}
mainField={mainField} mainField={mainField}
onRemove={onRemove} onRemove={onRemove}
@ -94,6 +86,7 @@ ListItem.defaultProps = {
ListItem.propTypes = { ListItem.propTypes = {
data: PropTypes.object.isRequired, data: PropTypes.object.isRequired,
displayNavigationLink: PropTypes.bool.isRequired,
findRelation: PropTypes.func, findRelation: PropTypes.func,
isDisabled: PropTypes.bool.isRequired, isDisabled: PropTypes.bool.isRequired,
mainField: PropTypes.string.isRequired, mainField: PropTypes.string.isRequired,

View File

@ -1,5 +1,5 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/click-events-have-key-events */
import React, { memo } from 'react'; import React, { memo, useMemo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
@ -13,6 +13,7 @@ import { Span } from './components';
const Relation = ({ const Relation = ({
data, data,
displayNavigationLink,
hasDraftAndPublish, hasDraftAndPublish,
isDisabled, isDisabled,
isDragging, isDragging,
@ -21,7 +22,17 @@ const Relation = ({
to, to,
}) => { }) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const cursor = isDisabled ? 'not-allowed' : 'pointer'; const cursor = useMemo(() => {
if (isDisabled) {
return 'not-allowed';
}
if (!displayNavigationLink) {
return 'default';
}
return 'pointer';
}, [displayNavigationLink, isDisabled]);
const { pathname } = useLocation(); const { pathname } = useLocation();
const isDraft = isEmpty(data.published_at); const isDraft = isEmpty(data.published_at);
const titleLabelID = isDraft const titleLabelID = isDraft
@ -31,7 +42,7 @@ const Relation = ({
? formatMessage({ id: getTrad(titleLabelID) }) ? formatMessage({ id: getTrad(titleLabelID) })
: formatMessage({ id: getTrad('containers.Edit.clickToJump') }); : formatMessage({ id: getTrad('containers.Edit.clickToJump') });
if (isDragging) { if (isDragging || !displayNavigationLink) {
title = ''; title = '';
} }
@ -46,9 +57,13 @@ const Relation = ({
<RelationDPState isDraft={isDraft} /> <RelationDPState isDraft={isDraft} />
</div> </div>
)} )}
<Link to={{ pathname: to, state: { from: pathname } }} title={title}> {displayNavigationLink ? (
<Span>{data[mainField]}</Span> <Link to={{ pathname: to, state: { from: pathname } }} title={title}>
</Link> <Span>{data[mainField]}&nbsp;</Span>
</Link>
) : (
<Span>{data[mainField]}&nbsp;</Span>
)}
</div> </div>
<div style={{ cursor }}> <div style={{ cursor }}>
<img src={IconRemove} alt="Remove Icon" onClick={onRemove} /> <img src={IconRemove} alt="Remove Icon" onClick={onRemove} />
@ -65,6 +80,7 @@ Relation.defaultProps = {
Relation.propTypes = { Relation.propTypes = {
data: PropTypes.object.isRequired, data: PropTypes.object.isRequired,
displayNavigationLink: PropTypes.bool.isRequired,
hasDraftAndPublish: PropTypes.bool.isRequired, hasDraftAndPublish: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired, isDisabled: PropTypes.bool.isRequired,
isDragging: PropTypes.bool, isDragging: PropTypes.bool,

View File

@ -10,6 +10,7 @@ import ListItem from './ListItem';
function SelectMany({ function SelectMany({
addRelation, addRelation,
components, components,
displayNavigationLink,
mainField, mainField,
name, name,
isDisabled, isDisabled,
@ -95,6 +96,7 @@ function SelectMany({
<ListItem <ListItem
key={data.id} key={data.id}
data={data} data={data}
displayNavigationLink={displayNavigationLink}
isDisabled={isDisabled} isDisabled={isDisabled}
findRelation={findRelation} findRelation={findRelation}
mainField={mainField} mainField={mainField}
@ -124,7 +126,7 @@ SelectMany.defaultProps = {
SelectMany.propTypes = { SelectMany.propTypes = {
addRelation: PropTypes.func.isRequired, addRelation: PropTypes.func.isRequired,
components: PropTypes.object, components: PropTypes.object,
displayNavigationLink: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired, isDisabled: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired,
mainField: PropTypes.string.isRequired, mainField: PropTypes.string.isRequired,

View File

@ -37,7 +37,7 @@ const Option = props => {
/> />
<TextGrow ellipsis as="div" fontWeight={fontWeight}> <TextGrow ellipsis as="div" fontWeight={fontWeight}>
{props.label} {props.label}&nbsp;
</TextGrow> </TextGrow>
</Flex> </Flex>
</Component> </Component>
@ -53,8 +53,12 @@ const Option = props => {
); );
}; };
Option.defaultProps = {
label: '',
};
Option.propTypes = { Option.propTypes = {
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
isFocused: PropTypes.bool.isRequired, isFocused: PropTypes.bool.isRequired,
selectProps: PropTypes.shape({ selectProps: PropTypes.shape({
hasDraftAndPublish: PropTypes.bool, hasDraftAndPublish: PropTypes.bool,

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
import { cloneDeep, findIndex, get, isArray, isEmpty, set } from 'lodash'; import { cloneDeep, findIndex, get, isArray, isEmpty, set } from 'lodash';
import { request, useGlobalContext } from 'strapi-helper-plugin'; import { request } from 'strapi-helper-plugin';
import { Flex, Text, Padded } from '@buffetjs/core'; import { Flex, Text, Padded } from '@buffetjs/core';
import pluginId from '../../pluginId'; import pluginId from '../../pluginId';
import useDataManager from '../../hooks/useDataManager'; import useDataManager from '../../hooks/useDataManager';
@ -22,6 +22,7 @@ import { connect, select, styles } from './utils';
function SelectWrapper({ function SelectWrapper({
componentUid, componentUid,
description, description,
displayNavigationLink,
editable, editable,
label, label,
isCreatingEntry, isCreatingEntry,
@ -34,8 +35,6 @@ function SelectWrapper({
targetModel, targetModel,
placeholder, placeholder,
}) { }) {
const { settingsBaseURL } = useGlobalContext();
// Disable the input in case of a polymorphic relation // Disable the input in case of a polymorphic relation
const isMorph = relationType.toLowerCase().includes('morph'); const isMorph = relationType.toLowerCase().includes('morph');
const { addRelation, modifiedData, moveRelation, onChange, onRemoveRelation } = useDataManager(); const { addRelation, modifiedData, moveRelation, onChange, onRemoveRelation } = useDataManager();
@ -187,28 +186,26 @@ function SelectWrapper({
relationType relationType
); );
const to = useMemo(() => { const to = `/plugins/${pluginId}/collectionType/${targetModel}/${value ? value.id : null}`;
const isAdminUserModel = targetModel === 'strapi::user';
if (isAdminUserModel) { const link = useMemo(() => {
return `${settingsBaseURL}/users/${value ? value.id : null}`; if (!value) {
return null;
} }
return `/plugins/${pluginId}/collectionType/${targetModel}/${value ? value.id : null}`; if (!displayNavigationLink) {
}, [targetModel, value, settingsBaseURL]); return null;
}
const link = return (
value === null ||
value === undefined ||
['plugins::users-permissions.role', 'plugins::users-permissions.permission'].includes(
targetModel
) ? null : (
<Link to={{ pathname: to, state: { from: pathname } }}> <Link to={{ pathname: to, state: { from: pathname } }}>
<FormattedMessage id="content-manager.containers.Edit.seeDetails"> <FormattedMessage id="content-manager.containers.Edit.seeDetails">
{msg => <A color="mediumBlue">{msg}</A>} {msg => <A color="mediumBlue">{msg}</A>}
</FormattedMessage> </FormattedMessage>
</Link> </Link>
); );
}, [displayNavigationLink, pathname, to, value]);
const Component = isSingle ? SelectOne : SelectMany; const Component = isSingle ? SelectOne : SelectMany;
const associationsLength = isArray(value) ? value.length : 0; const associationsLength = isArray(value) ? value.length : 0;
@ -258,6 +255,7 @@ function SelectWrapper({
addRelation({ target: { name, value } }); addRelation({ target: { name, value } });
}} }}
components={{ ClearIndicator, DropdownIndicator, IndicatorSeparator, Option }} components={{ ClearIndicator, DropdownIndicator, IndicatorSeparator, Option }}
displayNavigationLink={displayNavigationLink}
id={name} id={name}
isDisabled={isDisabled} isDisabled={isDisabled}
isLoading={isLoading} isLoading={isLoading}
@ -303,6 +301,7 @@ SelectWrapper.defaultProps = {
SelectWrapper.propTypes = { SelectWrapper.propTypes = {
componentUid: PropTypes.string, componentUid: PropTypes.string,
displayNavigationLink: PropTypes.bool.isRequired,
editable: PropTypes.bool, editable: PropTypes.bool,
description: PropTypes.string, description: PropTypes.string,
label: PropTypes.string, label: PropTypes.string,

View File

@ -1,7 +1,9 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { get } from 'lodash';
import useDataManager from '../../../hooks/useDataManager'; import useDataManager from '../../../hooks/useDataManager';
import useEditView from '../../../hooks/useEditView';
function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name }) { function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name, targetModel }) {
const { const {
isCreatingEntry, isCreatingEntry,
createActionAllowedFields, createActionAllowedFields,
@ -9,6 +11,13 @@ function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name })
slug, slug,
updateActionAllowedFields, updateActionAllowedFields,
} = useDataManager(); } = useDataManager();
const { models } = useEditView();
const displayNavigationLink = useMemo(() => {
const targetModelSchema = models.find(obj => obj.uid === targetModel);
return get(targetModelSchema, 'isDisplayed', false);
}, [targetModel, models]);
const isFieldAllowed = useMemo(() => { const isFieldAllowed = useMemo(() => {
if (isUserAllowedToEditField === true) { if (isUserAllowedToEditField === true) {
@ -37,6 +46,7 @@ function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name })
}, [isCreatingEntry, isUserAllowedToReadField, name, readActionAllowedFields]); }, [isCreatingEntry, isUserAllowedToReadField, name, readActionAllowedFields]);
return { return {
displayNavigationLink,
isCreatingEntry, isCreatingEntry,
isFieldAllowed, isFieldAllowed,
isFieldReadable, isFieldReadable,

View File

@ -27,10 +27,19 @@ import InformationCard from './InformationCard';
/* eslint-disable react/no-array-index-key */ /* eslint-disable react/no-array-index-key */
const EditView = ({ components, currentEnvironment, deleteLayout, layouts, plugins, slug }) => { const EditView = ({
components,
currentEnvironment,
deleteLayout,
layouts,
models,
plugins,
slug,
}) => {
const formatLayoutRef = useRef(); const formatLayoutRef = useRef();
formatLayoutRef.current = createAttributesLayout; formatLayoutRef.current = createAttributesLayout;
const { goBack } = useHistory(); const { goBack } = useHistory();
// Retrieve the search and the pathname // Retrieve the search and the pathname
const { pathname } = useLocation(); const { pathname } = useLocation();
const { const {
@ -117,9 +126,10 @@ const EditView = ({ components, currentEnvironment, deleteLayout, layouts, plugi
allowedActions={allowedActions} allowedActions={allowedActions}
allLayoutData={allLayoutData} allLayoutData={allLayoutData}
components={components} components={components}
layout={currentContentTypeLayoutData}
isDraggingComponent={isDraggingComponent} isDraggingComponent={isDraggingComponent}
isSingleType={isSingleType} isSingleType={isSingleType}
layout={currentContentTypeLayoutData}
models={models}
setIsDraggingComponent={() => { setIsDraggingComponent={() => {
dispatch({ dispatch({
type: 'SET_IS_DRAGGING_COMPONENT', type: 'SET_IS_DRAGGING_COMPONENT',
@ -286,6 +296,7 @@ EditView.propTypes = {
deleteLayout: PropTypes.func.isRequired, deleteLayout: PropTypes.func.isRequired,
emitEvent: PropTypes.func, emitEvent: PropTypes.func,
layouts: PropTypes.object.isRequired, layouts: PropTypes.object.isRequired,
models: PropTypes.array.isRequired,
plugins: PropTypes.object, plugins: PropTypes.object,
slug: PropTypes.string.isRequired, slug: PropTypes.string.isRequired,
}; };