From a4f0bdecc8de0a57ca010d6a4ad69a973dcf3a0a Mon Sep 17 00:00:00 2001 From: HichamELBSI Date: Tue, 1 Dec 2020 12:20:35 +0100 Subject: [PATCH 1/3] Add x-to-many relation preview tooltip Signed-off-by: HichamELBSI --- .../api/address/models/Address.settings.json | 4 +- .../src/components/CustomTable/Row/Cell.js | 37 ++++----- .../src/components/CustomTable/Row/index.js | 13 ++- .../RelationPreviewTooltip.js | 81 +++++++++++++++++++ .../components/RelationPreviewList/index.js | 61 +++++++++++--- .../RelationPreviewList/mockData.js | 56 +++++++++++++ .../admin/src/components/Tooltip/index.js | 20 +++++ .../package.json | 1 + yarn.lock | 10 ++- 9 files changed, 245 insertions(+), 38 deletions(-) create mode 100644 packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js create mode 100644 packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js create mode 100644 packages/strapi-plugin-content-manager/admin/src/components/Tooltip/index.js diff --git a/examples/getstarted/api/address/models/Address.settings.json b/examples/getstarted/api/address/models/Address.settings.json index 8aae91bc97..dfc50b3aeb 100755 --- a/examples/getstarted/api/address/models/Address.settings.json +++ b/examples/getstarted/api/address/models/Address.settings.json @@ -6,7 +6,7 @@ "description": "" }, "options": { - "draftAndPublish": true, + "draftAndPublish": false, "increments": true, "timestamps": [ "created_at", @@ -19,8 +19,8 @@ "type": "string" }, "categories": { - "via": "addresses", "collection": "category", + "via": "addresses", "dominant": true }, "cover": { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js index 70d5d70816..b8c36033e0 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js @@ -5,33 +5,34 @@ import RelationPreviewList from '../../RelationPreviewList'; import Truncate from '../../Truncate'; import Truncated from '../../Truncated'; -const RowCell = ({ metadatas, type, value, relationType }) => { - if (type === 'media') { - return ; +const Cell = ({ options }) => { + if (options.type === 'media') { + return ; } - if (type === 'relation') { - return ; + if (options.type === 'relation') { + return ; } return ( - {value} + {options.value} ); }; -RowCell.defaultProps = { - type: null, - value: null, - relationType: null, +Cell.propTypes = { + options: PropTypes.shape({ + cellId: PropTypes.string.isRequired, + metadatas: PropTypes.shape({ + mainField: PropTypes.string, + }).isRequired, + name: PropTypes.string.isRequired, + relationType: PropTypes.string, + rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, + type: PropTypes.string, + value: PropTypes.any, + }).isRequired, }; -RowCell.propTypes = { - metadatas: PropTypes.object.isRequired, - relationType: PropTypes.string, - type: PropTypes.string, - value: PropTypes.any, -}; - -export default memo(RowCell); +export default memo(Cell); diff --git a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/index.js b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/index.js index c3ededce9c..eba03944d3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/index.js @@ -70,10 +70,15 @@ function Row({ canCreate, canDelete, canUpdate, isBulkable, row, headers, goTo } cellFormatter(row) ) : ( )} diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js new file mode 100644 index 0000000000..e3a5f04dc9 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js @@ -0,0 +1,81 @@ +import React, { useState, useEffect, useCallback, useRef, useLayoutEffect } from 'react'; +import { Text, Padded } from '@buffetjs/core'; +import { LoadingIndicator } from 'strapi-helper-plugin'; +import PropTypes from 'prop-types'; + +import getRequestUrl from '../../utils/getRequestUrl'; +import getMockData from './mockData'; +import { useListView } from '../../hooks'; +import Tooltip from '../Tooltip'; + +const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { + const [isLoading, setIsLoading] = useState(true); + const [relationData, setRelationData] = useState([]); + const { slug } = useListView(); + const tooltipRef = useRef(); + + const fetchRelationData = useCallback(async () => { + const requestURL = getRequestUrl(`collection-types/${slug}/${rowId}/${name}`); + try { + // TODO : Wait for the API + // const { data } = await request(requestURL, { + // method: 'GET', + // }); + + console.log(requestURL); + setRelationData(getMockData(mainField)); + setIsLoading(false); + } catch (err) { + console.error({ err }); + setIsLoading(false); + } + }, [mainField, name, rowId, slug]); + + useEffect(() => { + // temp : Should remove the setTimeout and fetch the data + const timeout = setTimeout(() => { + fetchRelationData(); + }, 1000); + + return () => clearTimeout(timeout); + }, [fetchRelationData]); + + // Used to update the position after the loader + useLayoutEffect(() => { + if (!isLoading && tooltipRef.current) { + tooltipRef.current.updatePosition(); + } + }, [isLoading]); + + return ( + +
+ {isLoading ? ( + + + + ) : ( + <> + {relationData.map(item => ( + + + {item[mainField]} + + + ))} + {relationData.length > 10 && [...]} + + )} +
+
+ ); +}; + +RelationPreviewTooltip.propTypes = { + tooltipId: PropTypes.string.isRequired, + mainField: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, +}; + +export default RelationPreviewTooltip; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js index 693a101ea4..545609f009 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js @@ -1,15 +1,28 @@ -import React from 'react'; +import React, { memo, useState, useMemo } from 'react'; import PropTypes from 'prop-types'; import { Flex, Padded, Count } from '@buffetjs/core'; import { useIntl } from 'react-intl'; + import { getTrad } from '../../utils'; import Truncate from '../Truncate'; import Truncated from '../Truncated'; import CountWrapper from './CountWrapper'; +import RelationPreviewTooltip from './RelationPreviewTooltip'; -const RelationPreviewList = ({ metadatas: { mainField }, relationType, value }) => { +const RelationPreviewList = ({ + options: { + metadatas: { mainField }, + relationType, + value, + rowId, + cellId, + name, + }, +}) => { const { formatMessage } = useIntl(); + const [tooltipIsDisplayed, setDisplayTooltip] = useState(false); const isSingle = ['oneWay', 'oneToOne', 'manyToOne'].includes(relationType); + const tooltipId = useMemo(() => `${rowId}-${cellId}`, [rowId, cellId]); if (isSingle) { return ( @@ -21,9 +34,20 @@ const RelationPreviewList = ({ metadatas: { mainField }, relationType, value }) const size = value ? value.length : 0; + const handleTooltipToggle = () => { + setDisplayTooltip(prev => !prev); + }; + return ( - - + + @@ -36,20 +60,31 @@ const RelationPreviewList = ({ metadatas: { mainField }, relationType, value }) })} + {size > 0 && tooltipIsDisplayed && ( + + )} ); }; -RelationPreviewList.defaultProps = { - value: null, -}; - RelationPreviewList.propTypes = { - metadatas: PropTypes.shape({ - mainField: PropTypes.string.isRequired, + options: PropTypes.shape({ + cellId: PropTypes.string.isRequired, + metadatas: PropTypes.shape({ + mainField: PropTypes.string, + }).isRequired, + name: PropTypes.string.isRequired, + relationType: PropTypes.string, + rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, + type: PropTypes.string, + value: PropTypes.any, }).isRequired, - relationType: PropTypes.string.isRequired, - value: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), }; -export default RelationPreviewList; +export default memo(RelationPreviewList); diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js new file mode 100644 index 0000000000..53a5c0af1a --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js @@ -0,0 +1,56 @@ +export default mainField => [ + { + id: 1, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 2, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 3, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 4, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 5, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 6, + [mainField]: 'Aliquip dolor ullamco eu', + }, + { + id: 7, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 8, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 9, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 10, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, + { + id: 11, + [mainField]: + 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', + }, +]; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Tooltip/index.js b/packages/strapi-plugin-content-manager/admin/src/components/Tooltip/index.js new file mode 100644 index 0000000000..91637bc938 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/Tooltip/index.js @@ -0,0 +1,20 @@ +import ReactTooltip from 'react-tooltip'; +import styled from 'styled-components'; + +// Add !important to customize CSS is recommended by react-tooltip in the official readme +const Tooltip = styled(ReactTooltip).attrs(({ theme }) => ({ + // Pre set the tooltip static props. + place: 'bottom', + effect: 'solid', + delayShow: 500, + arrowColor: 'transparent', + backgroundColor: theme.main.colors.greyDark, +}))` + padding: 0.5rem 0.7rem !important; + opacity: 1 !important; + border-radius: ${({ theme }) => theme.main.sizes.borderRadius} !important; + max-width: 400px; + max-height: 400px; +`; + +export default Tooltip; diff --git a/packages/strapi-plugin-content-manager/package.json b/packages/strapi-plugin-content-manager/package.json index 01f146df5f..6c8a30199f 100644 --- a/packages/strapi-plugin-content-manager/package.json +++ b/packages/strapi-plugin-content-manager/package.json @@ -40,6 +40,7 @@ "react-redux": "^7.0.2", "react-router": "^5.0.0", "react-router-dom": "^5.0.0", + "react-tooltip": "4.2.11", "reactstrap": "8.4.1", "redux": "^4.0.1", "redux-immutable": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index a57a48b68d..0c26ae179b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15578,6 +15578,14 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.9.0: react-is "^16.8.6" scheduler "^0.19.1" +react-tooltip@4.2.11: + version "4.2.11" + resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.11.tgz#244d4d1833c583160c4e6c95a8a89e0fb320e18a" + integrity sha512-exREte3mK/qbeuQpFbEL3ImdF5/TSAb+x/T7pkVfKmgVcfQLZKHSgLN+Msv7ZOHxaWNJwuCrSsCAy/iTGoPigg== + dependencies: + prop-types "^15.7.2" + uuid "^7.0.3" + react-transition-group@4.4.1, react-transition-group@^4.3.0: version "4.4.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" @@ -19198,7 +19206,7 @@ uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.1: +uuid@^7.0.1, uuid@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== From d8e71a27712b9cd527dacbbf1c6e6ddd37e502ca Mon Sep 17 00:00:00 2001 From: HichamELBSI Date: Thu, 3 Dec 2020 13:04:55 +0100 Subject: [PATCH 2/3] Fix relations queryInfos Signed-off-by: HichamELBSI --- .../components/CustomTable/Headers/Header.js | 4 +- .../src/components/CustomTable/Row/Cell.js | 2 +- .../src/components/FilterPicker/index.js | 9 +- .../RelationPreviewTooltip.js | 34 +++-- .../components/RelationPreviewList/index.js | 4 +- .../admin/src/containers/ListView/Filter.js | 5 +- .../admin/src/containers/ListView/index.js | 2 - .../admin/src/containers/ListView/reducer.js | 3 +- .../utils/formatLayouts.js | 124 +++++++++++++----- .../utils/tests/formatLayouts.test.js | 101 +++++++++++++- .../admin/src/utils/formatFiltersToQuery.js | 4 +- .../admin/src/utils/formatLayoutToApi.js | 23 +++- .../admin/src/utils/getMainFieldType.js | 9 -- .../admin/src/utils/index.js | 1 - .../utils/tests/formatFiltersToQuery.test.js | 8 +- .../src/utils/tests/formatLayoutToApi.test.js | 25 ++++ .../src/utils/tests/getMainFieldType.test.js | 28 ---- 17 files changed, 278 insertions(+), 108 deletions(-) delete mode 100644 packages/strapi-plugin-content-manager/admin/src/utils/getMainFieldType.js delete mode 100644 packages/strapi-plugin-content-manager/admin/src/utils/tests/getMainFieldType.test.js diff --git a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Headers/Header.js b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Headers/Header.js index 1fc5a6656c..293656820e 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Headers/Header.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Headers/Header.js @@ -12,7 +12,7 @@ const Header = ({ fieldSchema: { type }, metadatas: { label, sortable, mainField let sortField = name; if (type === 'relation') { - sortField = `${name}.${mainField}`; + sortField = `${name}.${mainField.name}`; } const handleClick = () => { @@ -50,7 +50,7 @@ Header.propTypes = { metadatas: PropTypes.shape({ label: PropTypes.string.isRequired, sortable: PropTypes.bool.isRequired, - mainField: PropTypes.string, + mainField: PropTypes.object, }).isRequired, name: PropTypes.string.isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js index b8c36033e0..fb70955fd6 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row/Cell.js @@ -25,7 +25,7 @@ Cell.propTypes = { options: PropTypes.shape({ cellId: PropTypes.string.isRequired, metadatas: PropTypes.shape({ - mainField: PropTypes.string, + mainField: PropTypes.object, }).isRequired, name: PropTypes.string.isRequired, relationType: PropTypes.string, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js index 5eea17569d..ba9a1d5ff9 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js @@ -13,7 +13,7 @@ import { } from 'strapi-helper-plugin'; import pluginId from '../../pluginId'; -import { formatFiltersToQuery, getTrad, getMainFieldType } from '../../utils'; +import { formatFiltersToQuery, getTrad } from '../../utils'; import Container from '../Container'; import FilterPickerOption from '../FilterPickerOption'; import { Flex, Span, Wrapper } from './components'; @@ -24,7 +24,6 @@ const NOT_ALLOWED_FILTERS = ['json', 'component', 'media', 'richtext', 'dynamicz function FilterPicker({ contentType, - editRelations, filters, isOpen, metadatas, @@ -192,12 +191,12 @@ function FilterPicker({ const attributeType = get(contentType, ['attributes', filter.name, 'type'], ''); if (attributeType === 'relation') { - return getMainFieldType(editRelations, filter.name); + return get(metadatas, [filter.name, 'list', 'mainField', 'schema', 'type'], 'string'); } return attributeType; }, - [contentType, editRelations] + [contentType, metadatas] ); return ( @@ -241,13 +240,11 @@ function FilterPicker({ } FilterPicker.defaultProps = { - editRelations: [], name: '', }; FilterPicker.propTypes = { contentType: PropTypes.object.isRequired, - editRelations: PropTypes.array, filters: PropTypes.array.isRequired, isOpen: PropTypes.bool.isRequired, metadatas: PropTypes.object.isRequired, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js index e3a5f04dc9..2354100d5b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js @@ -1,35 +1,37 @@ import React, { useState, useEffect, useCallback, useRef, useLayoutEffect } from 'react'; import { Text, Padded } from '@buffetjs/core'; -import { LoadingIndicator } from 'strapi-helper-plugin'; +import { LoadingIndicator, request } from 'strapi-helper-plugin'; import PropTypes from 'prop-types'; import getRequestUrl from '../../utils/getRequestUrl'; import getMockData from './mockData'; -import { useListView } from '../../hooks'; import Tooltip from '../Tooltip'; const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { const [isLoading, setIsLoading] = useState(true); const [relationData, setRelationData] = useState([]); - const { slug } = useListView(); const tooltipRef = useRef(); + const abortController = new AbortController(); + const { endPoint } = mainField.queryInfos; + const { signal } = abortController; const fetchRelationData = useCallback(async () => { - const requestURL = getRequestUrl(`collection-types/${slug}/${rowId}/${name}`); + const requestURL = getRequestUrl(`${endPoint}/${rowId}/${name}`); try { // TODO : Wait for the API - // const { data } = await request(requestURL, { - // method: 'GET', - // }); + const { data } = await request(requestURL, { + method: 'GET', + signal, + }); - console.log(requestURL); + console.log(data); setRelationData(getMockData(mainField)); setIsLoading(false); } catch (err) { console.error({ err }); setIsLoading(false); } - }, [mainField, name, rowId, slug]); + }, [endPoint, mainField, name, rowId, signal]); useEffect(() => { // temp : Should remove the setTimeout and fetch the data @@ -37,7 +39,11 @@ const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { fetchRelationData(); }, 1000); - return () => clearTimeout(timeout); + return () => { + clearTimeout(timeout); + abortController.abort(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [fetchRelationData]); // Used to update the position after the loader @@ -59,7 +65,7 @@ const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { {relationData.map(item => ( - {item[mainField]} + {item[mainField.name]} ))} @@ -73,7 +79,11 @@ const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { RelationPreviewTooltip.propTypes = { tooltipId: PropTypes.string.isRequired, - mainField: PropTypes.string.isRequired, + mainField: PropTypes.shape({ + name: PropTypes.string.isRequired, + schema: PropTypes.object.isRequired, + queryInfos: PropTypes.object.isRequired, + }).isRequired, name: PropTypes.string.isRequired, rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js index 545609f009..c835aacd61 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/index.js @@ -27,7 +27,7 @@ const RelationPreviewList = ({ if (isSingle) { return ( - {value ? value[mainField] : '-'} + {value ? value[mainField.name] : '-'} ); } @@ -77,7 +77,7 @@ RelationPreviewList.propTypes = { options: PropTypes.shape({ cellId: PropTypes.string.isRequired, metadatas: PropTypes.shape({ - mainField: PropTypes.string, + mainField: PropTypes.object.isRequired, }).isRequired, name: PropTypes.string.isRequired, relationType: PropTypes.string, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/Filter.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/Filter.js index a56b8b3732..53fa1c52be 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/Filter.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/Filter.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { get, toString } from 'lodash'; import moment from 'moment'; import { FilterButton } from 'strapi-helper-plugin'; -import { dateFormats, formatFiltersToQuery, getMainFieldType } from '../../utils'; +import { dateFormats, formatFiltersToQuery } from '../../utils'; function Filter({ contentType, @@ -20,8 +20,7 @@ function Filter({ let type = attributeType; if (attributeType === 'relation') { - const editRelations = get(contentType, ['layouts', 'editRelations'], []); - type = getMainFieldType(editRelations, name); + type = get(contentType, ['metadatas', name, 'list', 'mainField', 'schema', 'type'], 'string'); } let displayedValue = toString(value); diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js index 3d4e95ddff..f7d0db673f 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js @@ -86,7 +86,6 @@ function ListView({ contentType: { attributes, metadatas, - layouts: { editRelations }, settings: { defaultSortBy, defaultSortOrder, @@ -380,7 +379,6 @@ function ListView({ filters={filters} isOpen={isFilterPickerOpen} metadatas={metadatas} - editRelations={editRelations} name={label} toggleFilterPickerState={toggleFilterPickerState} setQuery={setQuery} diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js index eaac04d6e4..bd043f846a 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js @@ -91,7 +91,7 @@ const listViewReducer = (state = initialState, action) => let metas = metadatas[name].list; if (attributes[name].type === 'relation') { - const mainField = metadatas[name].edit.mainField; + const { mainField } = metadatas[name].list; metas = { ...metas, mainField }; } @@ -107,6 +107,7 @@ const listViewReducer = (state = initialState, action) => header => header.name !== name ); } + break; } case ON_DELETE_DATA_SUCCEEDED: { diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js index 4babf0c1ab..954686e6a1 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js @@ -3,23 +3,19 @@ import { mergeMetasWithSchema } from '../../../utils'; import pluginId from '../../../pluginId'; // editRelations is an array of strings... -const formatEditRelationsLayoutWithMetas = (obj, models) => { - const formatted = obj.layouts.editRelations.reduce((acc, current) => { - const fieldSchema = get(obj, ['attributes', current], {}); - const metadatas = get(obj, ['metadatas', current, 'edit'], {}); +const formatEditRelationsLayoutWithMetas = (contentTypeConfiguration, models) => { + const formatted = contentTypeConfiguration.layouts.editRelations.reduce((acc, current) => { + const fieldSchema = get(contentTypeConfiguration, ['attributes', current], {}); + const metadatas = get(contentTypeConfiguration, ['metadatas', current, 'edit'], {}); const size = 6; - const mainField = get(obj, ['metadatas', current, 'edit', 'mainField'], 'id'); - const targetModelUid = get(obj, ['attributes', current, 'targetModel'], ''); - const relationModel = models.find(model => model.uid === targetModelUid); - const mainFieldSchema = get(relationModel, ['attributes', mainField], {}); - const queryInfos = generateRelationQueryInfos(obj, current, models); + const queryInfos = generateRelationQueryInfos(contentTypeConfiguration, current, models); acc.push({ name: current, size, fieldSchema, - metadatas: { ...metadatas, mainFieldSchema }, + metadatas, queryInfos, }); @@ -34,11 +30,13 @@ const formatLayouts = (initialData, models) => { const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, null, models); const ctUid = data.contentType.uid; const formattedEditRelationsLayout = formatEditRelationsLayoutWithMetas(data.contentType, models); - const formattedListLayout = formatListLayoutWithMetas(data.contentType); + const formattedListLayout = formatListLayoutWithMetas(data.contentType, models); + const formattedMetadatasLayout = formatMetadatasRelations(data.contentType, models); set(data, ['contentType', 'layouts', 'edit'], formattedCTEditLayout); set(data, ['contentType', 'layouts', 'editRelations'], formattedEditRelationsLayout); set(data, ['contentType', 'layouts', 'list'], formattedListLayout); + set(data, ['contentType', 'metadatas'], formattedMetadatasLayout); Object.keys(data.components).forEach(compoUID => { const formattedCompoEditLayout = formatLayoutWithMetas( @@ -53,21 +51,48 @@ const formatLayouts = (initialData, models) => { return data; }; -const formatLayoutWithMetas = (obj, ctUid, models) => { - const formatted = obj.layouts.edit.reduce((acc, current) => { +const formatMetadatasRelations = (contentTypeConfiguration, models) => { + const formattedRelationsMetadatas = contentTypeConfiguration.layouts.editRelations.reduce( + (acc, current) => { + const currentMetadatas = get(contentTypeConfiguration, ['metadatas', current], {}); + + return { + ...acc, + [current]: { + ...currentMetadatas, + list: { + ...currentMetadatas.list, + mainField: getMainField(current, contentTypeConfiguration, models), + }, + }, + }; + }, + {} + ); + + return { ...contentTypeConfiguration.metadatas, ...formattedRelationsMetadatas }; +}; + +const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => { + const formatted = contentTypeConfiguration.layouts.edit.reduce((acc, current) => { const row = current.map(attribute => { - const fieldSchema = get(obj, ['attributes', attribute.name], {}); + const fieldSchema = get(contentTypeConfiguration, ['attributes', attribute.name], {}); const data = { ...attribute, fieldSchema, - metadatas: get(obj, ['metadatas', attribute.name, 'edit'], {}), + metadatas: get(contentTypeConfiguration, ['metadatas', attribute.name, 'edit'], {}), }; if (fieldSchema.type === 'relation') { const queryInfos = ctUid - ? generateRelationQueryInfosForComponents(obj, attribute.name, ctUid, models) - : generateRelationQueryInfos(obj, attribute.name, models); + ? generateRelationQueryInfosForComponents( + contentTypeConfiguration, + attribute.name, + ctUid, + models + ) + : generateRelationQueryInfos(contentTypeConfiguration, attribute.name, models); set(data, 'queryInfos', queryInfos); } @@ -83,17 +108,17 @@ const formatLayoutWithMetas = (obj, ctUid, models) => { return formatted; }; -const formatListLayoutWithMetas = obj => { - const formatted = obj.layouts.list.reduce((acc, current) => { - const fieldSchema = get(obj, ['attributes', current], {}); - let metadatas = get(obj, ['metadatas', current, 'list'], {}); +const formatListLayoutWithMetas = contentTypeConfiguration => { + const formatted = contentTypeConfiguration.layouts.list.reduce((acc, current) => { + const fieldSchema = get(contentTypeConfiguration, ['attributes', current], {}); + let metadatas = get(contentTypeConfiguration, ['metadatas', current, 'list'], {}); const type = fieldSchema.type; if (type === 'relation') { metadatas = { ...metadatas, - mainField: get(obj, ['metadatas', current, 'edit', 'mainField'], 'id'), + mainField: get(contentTypeConfiguration, ['metadatas', current, 'edit', 'mainField'], 'id'), }; } @@ -105,11 +130,15 @@ const formatListLayoutWithMetas = obj => { return formatted; }; -const generateRelationQueryInfos = (obj, fieldName, models) => { - const uid = obj.uid; +const generateRelationQueryInfos = (contentTypeConfiguration, fieldName, models) => { + const uid = contentTypeConfiguration.uid; const endPoint = `/${pluginId}/relations/${uid}/${fieldName}`; - const mainField = get(obj, ['metadatas', fieldName, 'edit', 'mainField'], ''); - const targetModel = get(obj, ['attributes', fieldName, 'targetModel'], ''); + const mainField = get( + contentTypeConfiguration, + ['metadatas', fieldName, 'edit', 'mainField'], + '' + ); + const targetModel = get(contentTypeConfiguration, ['attributes', fieldName, 'targetModel'], ''); const shouldDisplayRelationLink = getDisplayedModels(models).indexOf(targetModel) !== -1; const queryInfos = { @@ -122,17 +151,26 @@ const generateRelationQueryInfos = (obj, fieldName, models) => { return queryInfos; }; -const generateRelationQueryInfosForComponents = (obj, fieldName, ctUid, models) => { +const generateRelationQueryInfosForComponents = ( + contentTypeConfiguration, + fieldName, + ctUid, + models +) => { const endPoint = `/${pluginId}/relations/${ctUid}/${fieldName}`; - const mainField = get(obj, ['metadatas', fieldName, 'edit', 'mainField'], ''); - const targetModel = get(obj, ['attributes', fieldName, 'targetModel'], ''); + const mainField = get( + contentTypeConfiguration, + ['metadatas', fieldName, 'edit', 'mainField'], + '' + ); + const targetModel = get(contentTypeConfiguration, ['attributes', fieldName, 'targetModel'], ''); const shouldDisplayRelationLink = getDisplayedModels(models).indexOf(targetModel) !== -1; const queryInfos = { endPoint, containsKey: `${mainField}_contains`, defaultParams: { - _component: obj.uid, + _component: contentTypeConfiguration.uid, }, shouldDisplayRelationLink, }; @@ -143,12 +181,38 @@ const generateRelationQueryInfosForComponents = (obj, fieldName, ctUid, models) const getDisplayedModels = models => models.filter(model => model.isDisplayed).map(({ uid }) => uid); +const getMainField = (relationField, contentTypeConfiguration, models) => { + const mainField = get( + contentTypeConfiguration, + ['metadatas', relationField, 'edit', 'mainField'], + 'id' + ); + const targetModelUid = get( + contentTypeConfiguration, + ['attributes', relationField, 'targetModel'], + '' + ); + const relationModel = models.find(model => model.uid === targetModelUid); + const mainFieldSchema = get(relationModel, ['attributes', mainField], {}); + + return { + name: mainField, + schema: mainFieldSchema, + queryInfos: { + endPoint: `collection-types/${contentTypeConfiguration.uid}`, + defaultParams: {}, + }, + }; +}; + export default formatLayouts; export { formatEditRelationsLayoutWithMetas, formatLayoutWithMetas, formatListLayoutWithMetas, + formatMetadatasRelations, generateRelationQueryInfos, generateRelationQueryInfosForComponents, + getMainField, getDisplayedModels, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js index 568909f0f4..361be547af 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js @@ -2,8 +2,10 @@ import formatLayouts, { formatEditRelationsLayoutWithMetas, formatLayoutWithMetas, formatListLayoutWithMetas, + formatMetadatasRelations, generateRelationQueryInfos, generateRelationQueryInfosForComponents, + getMainField, getDisplayedModels, } from '../formatLayouts'; @@ -49,9 +51,6 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils ', () => { }, metadatas: { mainField: 'name', - mainFieldSchema: { - type: 'string', - }, }, queryInfos: { endPoint: '/content-manager/relations/application::address.address/categories', @@ -513,6 +512,64 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils ', () => { }); }); + describe('formatMetadatasRelations', () => { + it('should format metadatas correctly', () => { + const contentTypeConfiguration = { + uid: 'address', + metadatas: { + categories: { + list: { + ok: true, + }, + edit: { + ok: false, + mainField: 'name', + }, + }, + }, + attributes: { + categories: { + targetModel: 'category', + }, + }, + layouts: { + editRelations: ['categories'], + }, + }; + const models = [ + { + uid: 'category', + attributes: { + name: { + type: 'string', + }, + }, + }, + ]; + const actual = formatMetadatasRelations(contentTypeConfiguration, models); + const expected = { + categories: { + list: { + ok: true, + mainField: { + name: 'name', + schema: { + type: 'string', + }, + queryInfos: { defaultParams: {}, endPoint: 'collection-types/address' }, + }, + }, + edit: { + ok: false, + mainField: 'name', + }, + }, + }; + + expect(actual).toEqual(expected); + }); + }); + describe('generateRelationQueryInfos', () => { it('should return an object with the correct keys', () => { expect(generateRelationQueryInfos(addressSchema, 'categories', simpleModels)).toEqual({ @@ -556,4 +613,42 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils ', () => { expect(getDisplayedModels(models)[0]).toEqual('testtest'); }); }); + + describe('getMainField', () => { + it('should return the main field object correctly', () => { + const relationField = 'categories'; + const contentTypeConfiguration = { + uid: 'address', + metadatas: { + categories: { + edit: { + mainField: 'name', + }, + }, + }, + attributes: { + categories: { + targetModel: 'category', + }, + }, + }; + const models = [ + { + uid: 'category', + attributes: { + name: { + type: 'string', + }, + }, + }, + ]; + const actual = getMainField(relationField, contentTypeConfiguration, models); + const expected = { + name: 'name', + queryInfos: { defaultParams: {}, endPoint: 'collection-types/address' }, + schema: { type: 'string' }, + }; + expect(actual).toEqual(expected); + }); + }); }); diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersToQuery.js b/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersToQuery.js index 442b5aa5fd..d64ab966a2 100644 --- a/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersToQuery.js +++ b/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersToQuery.js @@ -1,10 +1,10 @@ import { get } from 'lodash'; const formatFilterName = (name, metadatas) => { - const mainField = get(metadatas, [name, 'edit', 'mainField'], null); + const mainField = get(metadatas, [name, 'list', 'mainField', 'name'], null); if (mainField) { - return `${name}.${metadatas[name].edit.mainField}`; + return `${name}.${mainField}`; } return name; diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/formatLayoutToApi.js b/packages/strapi-plugin-content-manager/admin/src/utils/formatLayoutToApi.js index dd5179e6e3..66f6b199f7 100644 --- a/packages/strapi-plugin-content-manager/admin/src/utils/formatLayoutToApi.js +++ b/packages/strapi-plugin-content-manager/admin/src/utils/formatLayoutToApi.js @@ -1,4 +1,6 @@ -const formatLayoutToApi = ({ layouts, ...rest }) => { +import { omit, get } from 'lodash'; + +const formatLayoutToApi = ({ layouts, metadatas, ...rest }) => { const list = layouts.list.map(obj => { if (obj.name) { return obj.name; @@ -7,6 +9,19 @@ const formatLayoutToApi = ({ layouts, ...rest }) => { return obj; }); const editRelations = layouts.editRelations.map(({ name }) => name); + + const formattedRelationsMetadatas = editRelations.reduce((acc, current) => { + const currentMetadatas = get(metadatas, [current], {}); + + return { + ...acc, + [current]: { + ...currentMetadatas, + list: omit(currentMetadatas.list, ['mainField']), + }, + }; + }, {}); + const edit = layouts.edit.map(row => row.map(({ name, size }) => ({ name, @@ -14,7 +29,11 @@ const formatLayoutToApi = ({ layouts, ...rest }) => { })) ); - return { ...rest, layouts: { edit, editRelations, list } }; + return { + ...rest, + layouts: { edit, editRelations, list }, + metadatas: { ...metadatas, ...formattedRelationsMetadatas }, + }; }; export default formatLayoutToApi; diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/getMainFieldType.js b/packages/strapi-plugin-content-manager/admin/src/utils/getMainFieldType.js deleted file mode 100644 index 4f71e32e2f..0000000000 --- a/packages/strapi-plugin-content-manager/admin/src/utils/getMainFieldType.js +++ /dev/null @@ -1,9 +0,0 @@ -import { get } from 'lodash'; - -const getMainFieldType = (editRelations, relationName) => { - const relationSchema = editRelations.find(relation => relation.name === relationName); - - return get(relationSchema, ['metadatas', 'mainFieldSchema', 'type'], null); -}; - -export default getMainFieldType; diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/index.js b/packages/strapi-plugin-content-manager/admin/src/utils/index.js index 8e7040e825..0bc1067acd 100644 --- a/packages/strapi-plugin-content-manager/admin/src/utils/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/utils/index.js @@ -8,7 +8,6 @@ export { default as formatLayoutToApi } from './formatLayoutToApi'; export { default as generatePermissionsObject } from './generatePermissionsObject'; export { default as getFieldName } from './getFieldName'; export { default as getInjectedComponents } from './getComponents'; -export { default as getMainFieldType } from './getMainFieldType'; export { default as getMaxTempKey } from './getMaxTempKey'; export { default as getRequestUrl } from './getRequestUrl'; export { default as getTrad } from './getTrad'; diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatFiltersToQuery.test.js b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatFiltersToQuery.test.js index 6090ded717..b0e8cbba69 100644 --- a/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatFiltersToQuery.test.js +++ b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatFiltersToQuery.test.js @@ -5,13 +5,13 @@ describe('CONTENT MANAGER | utils', () => { it('should return the filters query', () => { const metadatas = { categories: { - edit: { - mainField: 'name', + list: { + mainField: { name: 'name' }, }, }, like: { - edit: { - mainField: 'numbers', + list: { + mainField: { name: 'numbers' }, }, }, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatLayoutToApi.test.js b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatLayoutToApi.test.js index 98c96d0ce2..397d558ec1 100644 --- a/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatLayoutToApi.test.js +++ b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatLayoutToApi.test.js @@ -20,4 +20,29 @@ describe('CONTENT MANAGER | utils | formatLayoutToApi', () => { expect(formatLayoutToApi({ layouts }).layouts.list).toEqual(['test']); }); + + it('should remove the mainField in the metadatas relations list', () => { + const layouts = { + list: ['test'], + edit: [], + editRelations: [{ name: 'categories' }], + }; + const metadatas = { + categories: { + list: { + mainField: { + name: 'name', + schema: { + type: 'string', + }, + }, + data: 1, + }, + }, + }; + + expect( + formatLayoutToApi({ layouts, metadatas }).metadatas.categories.list.mainField + ).toBeUndefined(); + }); }); diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/tests/getMainFieldType.test.js b/packages/strapi-plugin-content-manager/admin/src/utils/tests/getMainFieldType.test.js deleted file mode 100644 index 1a3f36274c..0000000000 --- a/packages/strapi-plugin-content-manager/admin/src/utils/tests/getMainFieldType.test.js +++ /dev/null @@ -1,28 +0,0 @@ -import getMainFieldType from '../getMainFieldType'; - -describe('CONTENT MANAGER | UTILS | getMainFieldType', () => { - const editRelationsSchemas = [ - { - name: 'categories', - metadatas: { - mainFieldSchema: { - type: 'string', - }, - }, - }, - { - name: 'likes', - metadatas: { - mainFieldSchema: { - type: 'number', - }, - }, - }, - ]; - it('should return null if the relation schema does not exist', () => { - expect(getMainFieldType(editRelationsSchemas, 'address')).toEqual(null); - }); - it('should return the main field type', () => { - expect(getMainFieldType(editRelationsSchemas, 'categories')).toEqual('string'); - }); -}); From 21488a7a91940ecacddd3ec987450f6e26d4a321 Mon Sep 17 00:00:00 2001 From: HichamELBSI Date: Mon, 7 Dec 2020 13:53:31 +0100 Subject: [PATCH 3/3] Remove mockData and call API Signed-off-by: HichamELBSI --- .../RelationPreviewTooltip.js | 23 +++++--- .../RelationPreviewList/mockData.js | 56 ------------------- .../utils/formatLayouts.js | 4 +- .../utils/tests/formatLayouts.test.js | 42 +++++++++++++- 4 files changed, 56 insertions(+), 69 deletions(-) delete mode 100644 packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js index eac9ade86e..5db20917c1 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/RelationPreviewTooltip.js @@ -4,8 +4,8 @@ import { LoadingIndicator, request } from 'strapi-helper-plugin'; import PropTypes from 'prop-types'; import getRequestUrl from '../../utils/getRequestUrl'; -import getMockData from './mockData'; import Tooltip from '../Tooltip'; +import getDisplayedValue from '../CustomTable/Row/utils/getDisplayedValue'; const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { const [isLoading, setIsLoading] = useState(true); @@ -17,30 +17,28 @@ const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { async signal => { const requestURL = getRequestUrl(`${endPoint}/${rowId}/${name}`); try { - // TODO : Wait for the API - const { data } = await request(requestURL, { + const { results } = await request(requestURL, { method: 'GET', signal, }); - console.log(data); - setRelationData(getMockData(mainField)); + setRelationData(results); setIsLoading(false); } catch (err) { console.error({ err }); setIsLoading(false); } }, - [endPoint, mainField, name, rowId] + [endPoint, name, rowId] ); useEffect(() => { const abortController = new AbortController(); const { signal } = abortController; - // temp : Should remove the setTimeout and fetch the data + const timeout = setTimeout(() => { fetchRelationData(signal); - }, 1000); + }, 500); return () => { clearTimeout(timeout); @@ -48,6 +46,13 @@ const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { }; }, [fetchRelationData]); + const getValueToDisplay = useCallback( + item => { + return getDisplayedValue(mainField.schema.type, item[mainField.name], mainField.name); + }, + [mainField] + ); + // Used to update the position after the loader useLayoutEffect(() => { if (!isLoading && tooltipRef.current) { @@ -67,7 +72,7 @@ const RelationPreviewTooltip = ({ tooltipId, rowId, mainField, name }) => { {relationData.map(item => ( - {item[mainField.name]} + {getValueToDisplay(item)} ))} diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js deleted file mode 100644 index 53a5c0af1a..0000000000 --- a/packages/strapi-plugin-content-manager/admin/src/components/RelationPreviewList/mockData.js +++ /dev/null @@ -1,56 +0,0 @@ -export default mainField => [ - { - id: 1, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 2, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 3, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 4, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 5, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 6, - [mainField]: 'Aliquip dolor ullamco eu', - }, - { - id: 7, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 8, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 9, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 10, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, - { - id: 11, - [mainField]: - 'Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui. Aliquip dolor ullamco eu proident tempor duis dolor elit aliqua excepteur veniam proident occaecat qui.', - }, -]; diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js index 954686e6a1..83ab2e1c9e 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js @@ -108,7 +108,7 @@ const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => { return formatted; }; -const formatListLayoutWithMetas = contentTypeConfiguration => { +const formatListLayoutWithMetas = (contentTypeConfiguration, models) => { const formatted = contentTypeConfiguration.layouts.list.reduce((acc, current) => { const fieldSchema = get(contentTypeConfiguration, ['attributes', current], {}); let metadatas = get(contentTypeConfiguration, ['metadatas', current, 'list'], {}); @@ -118,7 +118,7 @@ const formatListLayoutWithMetas = contentTypeConfiguration => { if (type === 'relation') { metadatas = { ...metadatas, - mainField: get(contentTypeConfiguration, ['metadatas', current, 'edit', 'mainField'], 'id'), + mainField: getMainField(current, contentTypeConfiguration, models), }; } diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js index 361be547af..4ff2be4ec3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js @@ -487,16 +487,29 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils ', () => { describe('formatListLayoutWithMetas', () => { it('should format the list layout correctly', () => { const data = { + uid: 'address', layouts: { - list: ['test'], + list: ['test', 'categories'], }, metadatas: { test: { list: { ok: true }, }, + categories: { + list: { + ok: true, + }, + edit: { + mainField: 'name', + }, + }, }, attributes: { test: { type: 'string' }, + categories: { + type: 'relation', + targetModel: 'category', + }, }, }; const expected = [ @@ -506,9 +519,34 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils ', () => { metadatas: { ok: true }, fieldSchema: { type: 'string' }, }, + { + name: 'categories', + key: '__categories_key__', + metadatas: { + ok: true, + mainField: { + name: 'name', + schema: { + type: 'string', + }, + queryInfos: { defaultParams: {}, endPoint: 'collection-types/address' }, + }, + }, + fieldSchema: { type: 'relation', targetModel: 'category' }, + }, + ]; + const models = [ + { + uid: 'category', + attributes: { + name: { + type: 'string', + }, + }, + }, ]; - expect(formatListLayoutWithMetas(data)).toEqual(expected); + expect(formatListLayoutWithMetas(data, models)).toEqual(expected); }); });