mirror of
https://github.com/strapi/strapi.git
synced 2025-12-16 17:53:53 +00:00
Fix navigation between relations
Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
parent
92a43a8152
commit
e10452c245
@ -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,
|
||||||
|
|||||||
@ -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]} </Span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<Span>{data[mainField]} </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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -37,7 +37,7 @@ const Option = props => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TextGrow ellipsis as="div" fontWeight={fontWeight}>
|
<TextGrow ellipsis as="div" fontWeight={fontWeight}>
|
||||||
{props.label}
|
{props.label}
|
||||||
</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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user