diff --git a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js
index 52f1c5e588..95a7155838 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js
@@ -36,7 +36,6 @@ function EditViewButton(props) {
: `${category}/${componentSlug}`;
const handleClick = () => {
- // TODO
emitEvent('willEditEditLayout');
props.push(`${baseUrl}/${suffixUrl}`);
};
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeOption/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeOption/index.js
index 6819788e1a..9efae86ff7 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeOption/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeOption/index.js
@@ -44,7 +44,24 @@ const AttributeOption = forwardRef(({ tabIndex, type }, ref) => {
const handleClick = () => {
const forTarget = query.get('forTarget');
const targetUid = query.get('targetUid');
- const headerDisplayName = query.get('headerDisplayName');
+ const header_label_1 = query.get('header_label_1');
+ const header_info_category_1 = query.get('header_info_category_1');
+ const header_info_name_1 = query.get('header_info_name_1');
+ const header_label_2 = query.get('header_label_2');
+ const header_icon_name_2 = query.get('header_icon_name_2');
+ const header_icon_isCustom_2 = query.get('header_icon_isCustom_2');
+ const header_info_category_2 = query.get('header_info_category_2');
+ const header_info_name_2 = query.get('header_info_name_2');
+ const header_label_3 = query.get('header_label_3');
+ const header_icon_name_3 = query.get('header_icon_name_3');
+ const header_icon_isCustom_3 = query.get('header_icon_isCustom_3');
+ const header_info_category_3 = query.get('header_info_category_3');
+ const header_info_name_3 = query.get('header_info_name_3');
+ const header_label_4 = query.get('header_label_4');
+ const header_icon_name_4 = query.get('header_icon_name_4');
+ const header_icon_isCustom_4 = query.get('header_icon_isCustom_4');
+ const header_info_category_4 = query.get('header_info_category_4');
+ const header_info_name_4 = query.get('header_info_name_4');
const search = makeSearch({
modalType: 'attribute',
@@ -53,11 +70,28 @@ const AttributeOption = forwardRef(({ tabIndex, type }, ref) => {
forTarget,
targetUid,
attributeType: type,
- headerDisplayName,
step: type === 'component' ? '1' : null,
- headerDisplayCategory: query.get('headerDisplayCategory'),
- headerDisplaySubCategory: query.get('headerDisplaySubCategory'),
- subTargetUid: query.get('subTargetUid'),
+
+ header_label_1,
+ header_info_name_1,
+ header_info_category_1,
+ header_label_2,
+ header_icon_name_2,
+ header_icon_isCustom_2,
+ header_info_name_2,
+ header_info_category_2,
+ header_label_3,
+ header_icon_name_3,
+ header_icon_isCustom_3,
+ header_info_name_3,
+ header_info_category_3,
+ header_label_4,
+ header_icon_name_4,
+ header_icon_isCustom_4,
+ header_info_name_4,
+ header_info_category_4,
+ header_icon_isCustom_1: false,
+ header_icon_name_1: type,
});
if (forTarget === 'contentType') {
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentList/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentList/index.js
index 9c9380412e..9ffdedae3c 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentList/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentList/index.js
@@ -15,8 +15,10 @@ import Td from '../Td';
function ComponentList({
customRowComponent,
component,
+ dzName,
mainTypeName,
isFromDynamicZone,
+ isNestedInDZComponent,
firstLoopComponentName,
firstLoopComponentUid,
}) {
@@ -32,6 +34,7 @@ function ComponentList({
{
- let headerDisplayName = mainTypeName;
+ const firstComponentIcon = get(
+ modifiedData,
+ ['components', firstLoopComponentUid, 'schema', 'icon'],
+ ''
+ );
+ const firstComponentCategory = get(
+ modifiedData,
+ ['components', firstLoopComponentUid, 'category'],
+ null
+ );
+ const firstComponentFriendlyName = get(
+ modifiedData,
+ ['components', firstLoopComponentUid, 'schema', 'name'],
+ null
+ );
+ const secondComponentCategory = get(
+ modifiedData,
+ ['components', secondLoopComponentUid, 'category'],
+ null
+ );
+ const secondComponentFriendlyName = get(
+ modifiedData,
+ ['components', secondLoopComponentUid, 'schema', 'name'],
+ null
+ );
+ const secondComponentIcon = get(
+ modifiedData,
+ ['components', secondLoopComponentUid, 'schema', 'icon'],
+ ''
+ );
+ let firstHeaderObject = {
+ header_label_1: mainTypeName,
+ header_icon_name_1: editTarget,
+ header_icon_isCustom_1: false,
+ header_info_category_1: null,
+ header_info_name_1: null,
+ };
+ let secondHeaderObject = {
+ header_label_2: firstLoopComponentName,
+ header_icon_name_2: 'component',
+ header_icon_isCustom_2: false,
+ header_info_category_2: firstComponentCategory,
+ header_info_name_2: firstComponentFriendlyName,
+ };
+ let thirdHeaderObject = {
+ header_icon_name_3: 'component',
+ header_icon_isCustom_3: false,
+ header_info_category_3: secondComponentCategory,
+ header_info_name_3: secondComponentFriendlyName,
+ };
+ let fourthHeaderObject = {
+ header_icon_name_4: null,
+ header_icon_isCustom_4: false,
+ header_info_category_4: secondComponentCategory,
+ header_info_name_4: secondComponentFriendlyName,
+ };
if (firstLoopComponentName) {
- headerDisplayName = firstLoopComponentName;
+ firstHeaderObject = {
+ ...firstHeaderObject,
+ header_icon_name_1: firstComponentIcon,
+ header_icon_isCustom_1: true,
+ };
}
if (secondLoopComponentUid) {
- headerDisplayName = secondLoopComponentName;
+ firstHeaderObject = {
+ ...firstHeaderObject,
+ header_icon_name_1: secondComponentIcon,
+ header_icon_isCustom_1: true,
+ };
+ thirdHeaderObject = {
+ ...thirdHeaderObject,
+ header_label_3: secondLoopComponentName,
+ };
+ }
+
+ if (isFromDynamicZone || isNestedInDZComponent) {
+ secondHeaderObject = {
+ ...secondHeaderObject,
+ header_label_2: dzName,
+ header_icon_name_2: 'dynamiczone',
+ header_icon_isCustom_2: false,
+ header_info_category_2: null,
+ header_info_name_2: null,
+ };
+ thirdHeaderObject = {
+ ...thirdHeaderObject,
+ header_icon_name_3: isNestedInDZComponent ? 'component' : null,
+ header_label_3: firstLoopComponentName,
+ header_info_category_3: firstComponentCategory,
+ header_info_name_3: firstComponentFriendlyName,
+ };
+ fourthHeaderObject = {
+ ...fourthHeaderObject,
+ header_label_4: secondLoopComponentName,
+ };
}
openModalAddField(
editTarget,
targetUid,
- headerDisplayName,
- firstLoopComponentUid ? mainTypeName : null,
- secondLoopComponentName ? firstLoopComponentName : null,
- secondLoopComponentUid ? firstLoopComponentUid : null
+ firstHeaderObject,
+ secondHeaderObject,
+ thirdHeaderObject,
+ fourthHeaderObject
);
};
@@ -87,8 +179,9 @@ function List({
{},
className: null,
customRowComponent: null,
+ dzName: null,
firstLoopComponentName: null,
firstLoopComponentUid: null,
isFromDynamicZone: false,
+ isNestedInDZComponent: false,
isMain: false,
isSub: false,
items: [],
@@ -162,10 +257,12 @@ List.propTypes = {
addComponentToDZ: PropTypes.func,
className: PropTypes.string,
customRowComponent: PropTypes.func,
+ dzName: PropTypes.string,
editTarget: PropTypes.string.isRequired,
firstLoopComponentName: PropTypes.string,
firstLoopComponentUid: PropTypes.string,
isFromDynamicZone: PropTypes.bool,
+ isNestedInDZComponent: PropTypes.bool,
isMain: PropTypes.bool,
items: PropTypes.instanceOf(Array),
mainTypeName: PropTypes.string.isRequired,
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ListRow/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ListRow/index.js
index 1bdc055780..c0057d0fb3 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/ListRow/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ListRow/index.js
@@ -6,6 +6,7 @@ import { AttributeIcon } from '@buffetjs/core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import pluginId from '../../pluginId';
import useDataManager from '../../hooks/useDataManager';
+import getAttributeDisplayedType from '../../utils/getAttributeDisplayedType';
import getTrad from '../../utils/getTrad';
import Curve from '../../icons/Curve';
import UpperFist from '../UpperFirst';
@@ -14,6 +15,7 @@ import Wrapper from './Wrapper';
function ListRow({
configurable,
name,
+ dzName,
nature,
onClick,
plugin,
@@ -28,12 +30,15 @@ function ListRow({
repeatable,
secondLoopComponentName,
secondLoopComponentUid,
+ isNestedInDZComponent,
}) {
const {
contentTypes,
isInDevelopmentMode,
+ modifiedData,
removeAttribute,
} = useDataManager();
+
const ico = ['integer', 'biginteger', 'float', 'decimal'].includes(type)
? 'number'
: type;
@@ -54,15 +59,120 @@ function ListRow({
const handleClick = () => {
if (configurable !== false) {
+ const firstComponentCategory = get(
+ modifiedData,
+ ['components', firstLoopComponentUid, 'category'],
+ null
+ );
+ const secondComponentCategory = get(
+ modifiedData,
+ ['components', secondLoopComponentUid, 'category'],
+ null
+ );
+
const attrType = nature ? 'relation' : type;
- let headerDisplayName = mainTypeName;
+ const icoType = getAttributeDisplayedType(attrType);
+
+ let firstHeaderObject = {
+ header_label_1: mainTypeName,
+ header_icon_name_1: icoType,
+ header_icon_isCustom_1: false,
+ header_info_category_1: null,
+ header_info_name_1: null,
+ };
+ let secondHeaderObject = {
+ header_label_2: name,
+ header_icon_name_2: null,
+ header_icon_isCustom_2: false,
+ header_info_category_2: null,
+ header_info_name_2: null,
+ };
+ let thirdHeaderObject = {
+ header_icon_name_3: 'component',
+ header_icon_isCustom_3: false,
+ header_info_category_3: null,
+ header_info_name_3: null,
+ };
+ let fourthHeaderObject = {
+ header_icon_name_4: null,
+ header_icon_isCustom_4: false,
+ header_info_category_4: null,
+ header_info_name_4: null,
+ };
+ let fifthHeaderObject = {
+ header_icon_name_5: null,
+ header_icon_isCustom_5: false,
+ header_info_category_5: null,
+ header_info_name_5: null,
+ };
if (firstLoopComponentName) {
- headerDisplayName = firstLoopComponentName;
+ secondHeaderObject = {
+ header_label_2: firstLoopComponentName,
+ header_icon_name_2: 'component',
+ header_icon_isCustom_2: false,
+ header_info_category_2: firstComponentCategory,
+ header_info_name_2: firstLoopComponentName,
+ };
+
+ thirdHeaderObject = {
+ ...thirdHeaderObject,
+ header_label_3: name,
+ header_icon_name_3: null,
+ };
}
if (secondLoopComponentUid) {
- headerDisplayName = secondLoopComponentName;
+ thirdHeaderObject = {
+ ...thirdHeaderObject,
+ header_label_3: secondLoopComponentName,
+ header_icon_name_3: 'component',
+ header_info_category_3: secondComponentCategory,
+ header_info_name_3: secondLoopComponentName,
+ };
+ fourthHeaderObject = {
+ ...fourthHeaderObject,
+ header_label_4: name,
+ header_icon_name_4: null,
+ };
+ }
+
+ if (isFromDynamicZone || isNestedInDZComponent) {
+ secondHeaderObject = {
+ header_label_2: dzName,
+ header_icon_name_2: 'dynamiczone',
+ header_icon_isCustom_2: false,
+ header_info_name_2: null,
+ header_info_category_2: null,
+ };
+ thirdHeaderObject = {
+ header_icon_name_3: 'component',
+ header_label_3: firstLoopComponentName,
+ header_info_name_3: firstComponentCategory,
+ header_info_category_3: firstComponentCategory,
+ };
+
+ if (!isNestedInDZComponent) {
+ fourthHeaderObject = {
+ header_icon_name_4: null,
+ header_icon_isCustom_4: false,
+ header_info_category_4: null,
+ header_label_4: name,
+ };
+ } else {
+ fourthHeaderObject = {
+ header_icon_name_4: 'components',
+ header_icon_isCustom_4: false,
+ header_info_category_4: secondComponentCategory,
+ header_info_name_4: secondLoopComponentName,
+ header_label_4: secondLoopComponentName,
+ };
+
+ fifthHeaderObject = {
+ ...fifthHeaderObject,
+ header_label_5: name,
+ };
+ }
}
onClick(
@@ -74,10 +184,11 @@ function ListRow({
name,
// Type of the attribute
attrType,
- headerDisplayName,
- firstLoopComponentUid ? mainTypeName : null,
- secondLoopComponentName ? firstLoopComponentName : null,
- secondLoopComponentUid ? firstLoopComponentUid : null
+ firstHeaderObject,
+ secondHeaderObject,
+ thirdHeaderObject,
+ fourthHeaderObject,
+ fifthHeaderObject
);
}
};
@@ -171,9 +282,11 @@ function ListRow({
ListRow.defaultProps = {
configurable: true,
+ dzName: null,
firstLoopComponentName: null,
firstLoopComponentUid: null,
isFromDynamicZone: false,
+ isNestedInDZComponent: false,
nature: null,
onClick: () => {},
onClickDelete: () => {},
@@ -188,10 +301,12 @@ ListRow.defaultProps = {
ListRow.propTypes = {
configurable: PropTypes.bool,
+ dzName: PropTypes.string,
editTarget: PropTypes.string.isRequired,
firstLoopComponentName: PropTypes.string,
firstLoopComponentUid: PropTypes.string,
isFromDynamicZone: PropTypes.bool,
+ isNestedInDZComponent: PropTypes.bool,
mainTypeName: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
nature: PropTypes.string,
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/ComponentInfos.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/ComponentInfos.js
index c48c48fe24..6f6cf23877 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/ComponentInfos.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/ComponentInfos.js
@@ -1,33 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { get, upperFirst } from 'lodash';
-import ComponentInfosWrapper from './ComponentInfosWrapper';
-import useDataManager from '../../hooks/useDataManager';
import UpperFirst from '../UpperFirst';
+import ComponentInfosWrapper from './ComponentInfosWrapper';
-const ComponentInfos = ({ uid }) => {
- // We might want to change to initialData...
- // @Aurelsicoko
- const { modifiedData } = useDataManager();
- const currentComponent = get(modifiedData, ['components', uid], {});
- const currentComponentCategory = get(currentComponent, 'category', '');
- const currentComponentFriendlyName = get(
- currentComponent,
- ['schema', 'name'],
- ''
- );
-
+const ComponentInfos = ({ category, name }) => {
return (
- ({upperFirst(currentComponentCategory)}
- —
- )
+ ( —
+ )
);
};
ComponentInfos.propTypes = {
- uid: PropTypes.string.isRequired,
+ category: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
};
export default ComponentInfos;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/DropdownInfos.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/DropdownInfos.js
new file mode 100644
index 0000000000..e6af105937
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/DropdownInfos.js
@@ -0,0 +1,47 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import UpperFirst from '../UpperFirst';
+import Icon from './Icon';
+import Item from './Item';
+import Menu from './Menu';
+import Toggle from './Toggle';
+import Wrapper from './Wrapper';
+
+const DropdownInfos = ({ headers, shouldDisplaySecondHeader }) => {
+ const [dropdownOpen, setDropdownOpen] = useState(false);
+
+ const toggle = () => setDropdownOpen(prevState => !prevState);
+ return (
+
+ ...
+
+
+ );
+};
+
+DropdownInfos.defaultProps = {
+ headers: [],
+ shouldDisplaySecondHeader: false,
+};
+
+DropdownInfos.propTypes = {
+ headers: PropTypes.array,
+ shouldDisplaySecondHeader: PropTypes.bool,
+};
+
+export default DropdownInfos;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Header.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Header.js
deleted file mode 100644
index 0603b5393e..0000000000
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Header.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import UpperFirst from '../UpperFirst';
-import ComponentInfos from './ComponentInfos';
-import IconWrapper from './IconWrapper';
-
-const Header = ({
- category,
- name,
- subCategory,
- target,
- targetUid,
- subTargetUid,
-}) => {
- const shouldDisplayComponentCatInfos = target === 'components';
-
- const content = (
- <>
-
-
-
-
-
-
- {subCategory && (
- <>
-
-
-
-
-
-
-
- >
- )}
- >
- );
-
- return (
- <>
- {category && content}
-
-
-
- {shouldDisplayComponentCatInfos && }
- >
- );
-};
-
-Header.defaultProps = {
- category: null,
- name: null,
- subCategory: null,
- subTargetUid: null,
- target: null,
- targetUid: null,
-};
-
-Header.propTypes = {
- category: PropTypes.string,
- name: PropTypes.string,
- subCategory: PropTypes.string,
- subTargetUid: PropTypes.string,
- target: PropTypes.string,
- targetUid: PropTypes.string,
-};
-
-export default Header;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Icon.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Icon.js
new file mode 100644
index 0000000000..e3b43e8c3a
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Icon.js
@@ -0,0 +1,13 @@
+import React from 'react';
+import { AttributeIcon } from '@buffetjs/core';
+import PropTypes from 'prop-types';
+
+const Icon = ({ type }) => (
+
+);
+
+Icon.propTypes = {
+ type: PropTypes.string.isRequired,
+};
+
+export default Icon;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Item.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Item.js
new file mode 100644
index 0000000000..cc74645fa9
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Item.js
@@ -0,0 +1,19 @@
+import styled from 'styled-components';
+import { DropdownItem } from 'reactstrap';
+
+const Item = styled(DropdownItem)`
+ display: flex;
+ padding-left: 10px;
+ padding-right: 10px;
+ color: #3b3b3b;
+ font-weight: 600;
+ font-size: 14px;
+ &:active,
+ &:focus,
+ &:hover {
+ background-color: transparent;
+ outline: 0;
+ }
+`;
+
+export default Item;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Menu.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Menu.js
new file mode 100644
index 0000000000..798a681a39
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Menu.js
@@ -0,0 +1,8 @@
+import styled from 'styled-components';
+import { DropdownMenu } from 'reactstrap';
+
+const Menu = styled(DropdownMenu)`
+ top: 8px;
+`;
+
+export default Menu;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Toggle.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Toggle.js
new file mode 100644
index 0000000000..a032de0504
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Toggle.js
@@ -0,0 +1,14 @@
+import styled from 'styled-components';
+import { DropdownToggle } from 'reactstrap';
+
+const Toggle = styled(DropdownToggle)`
+ height: 12px;
+ background: transparent;
+ border: 0;
+ margin-top: -14px;
+ color: #3b3b3b;
+ font-weight: 600;
+ font-size: 14px;
+`;
+
+export default Toggle;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Wrapper.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Wrapper.js
new file mode 100644
index 0000000000..26d85e9cef
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/Wrapper.js
@@ -0,0 +1,12 @@
+import styled from 'styled-components';
+import { Dropdown } from 'reactstrap';
+
+const Wrapper = styled(Dropdown)`
+ .dropdown-menu {
+ top: 8px !important;
+ box-shadow: 0 2px 4px #e3e9f3;
+ border: 0;
+ }
+`;
+
+export default Wrapper;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/index.js
index 5014d5b29a..8646d1ea9b 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ModalHeader/index.js
@@ -1,89 +1,103 @@
-import React from 'react';
+import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { HeaderModalTitle } from 'strapi-helper-plugin';
import { get } from 'lodash';
-import { AttributeIcon } from '@buffetjs/core';
import { FormattedMessage } from 'react-intl';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import useDataManager from '../../hooks/useDataManager';
-import pluginId from '../../pluginId';
import ComponentIcon from './ComponentIcon';
-import Header from './Header';
+import ComponentInfos from './ComponentInfos';
+import Icon from './Icon';
+import IconWrapper from './IconWrapper';
+import UpperFirst from '../UpperFirst';
+import DropdownInfos from './DropdownInfos';
-const ModalHeader = ({
- category,
- headerId,
- iconType,
- name,
- target,
- targetUid,
- subCategory,
- subTargetUid,
-}) => {
- const { modifiedData } = useDataManager();
- const currentComponent = get(modifiedData, ['components', targetUid], {});
- const shouldDisplayComponentCatInfos = target === 'components';
- const currentComponentIcon = get(currentComponent, ['schema', 'icon'], '');
-
- let iconName;
-
- if (iconType === 'components') {
- iconName = 'component';
- } else {
- iconName = iconType;
- }
+const ModalHeader = ({ headerId, headers }) => {
+ const shouldDisplayDropDown = headers.length > 3;
return (
- {shouldDisplayComponentCatInfos ? (
-
-
-
- ) : (
-
- )}
{headerId && (
-
- )}
- {!headerId && (
-
+ <>
+
+
+ >
)}
+ {!headerId &&
+ headers.map((header, index) => {
+ const iconName = get(header, ['icon', 'name'], '');
+ const iconType = iconName === null ? '' : iconName;
+ const icon = get(header, ['icon', 'isCustom'], false) ? (
+
+
+
+ ) : (
+
+ );
+
+ if (shouldDisplayDropDown && index === 1) {
+ return (
+
+
+
+
+ 4}
+ />
+
+ );
+ }
+
+ if (shouldDisplayDropDown && index === 2 && headers.length > 4) {
+ return null;
+ }
+
+ if (index === 0) {
+ return (
+
+ {icon}
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ {header.info.category && (
+
+ )}
+
+ );
+ })}
);
};
ModalHeader.defaultProps = {
- category: null,
headerId: '',
- iconType: 'contentType',
- name: '',
- target: null,
- targetUid: null,
- subCategory: null,
- subTargetUid: null,
+ headers: [],
};
ModalHeader.propTypes = {
- category: PropTypes.string,
headerId: PropTypes.string,
- iconType: PropTypes.string,
- name: PropTypes.string,
- target: PropTypes.string,
- targetUid: PropTypes.string,
- subCategory: PropTypes.string,
- subTargetUid: PropTypes.string,
+ headers: PropTypes.array,
};
export default ModalHeader;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js
index 634056bc7e..d1d8ef40ac 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js
@@ -1,5 +1,6 @@
import { fromJS, OrderedMap } from 'immutable';
import { get, has } from 'lodash';
+import retrieveComponentsFromSchema from './utils/retrieveComponentsFromSchema';
import makeUnique from '../../utils/makeUnique';
const initialState = fromJS({
@@ -24,6 +25,47 @@ const getOppositeNature = originalNature => {
}
};
+const addComponentsToState = (state, componentToAddUid, objToUpdate) => {
+ let newObj = objToUpdate;
+ const componentToAdd = state.getIn(['components', componentToAddUid]);
+ const isTemporaryComponent = componentToAdd.get('isTemporary');
+ const componentToAddSchema = componentToAdd.getIn(['schema', 'attributes']);
+ const hasComponentAlreadyBeenAdded =
+ state.getIn(['modifiedData', 'components', componentToAddUid]) !==
+ undefined;
+
+ // created components are already in the modifiedData.components
+ // We don't add them because all modifications will be lost
+ if (isTemporaryComponent || hasComponentAlreadyBeenAdded) {
+ return newObj;
+ }
+
+ // Add the added components to the modifiedData.compontnes
+ newObj = newObj.set(componentToAddUid, componentToAdd);
+ const nestedComponents = retrieveComponentsFromSchema(
+ componentToAddSchema.toJS(),
+ state.get('components').toJS()
+ );
+
+ // We need to add the nested components to the modifiedData.components as well
+ nestedComponents.forEach(componentUid => {
+ const isTemporary =
+ state.getIn(['components', componentUid, 'isTemporary']) || false;
+ const hasNestedComponentAlreadyBeenAdded =
+ state.getIn(['modifiedData', 'components', componentUid]) !== undefined;
+
+ // Same logic here otherwise we will lose the modifications added to the components
+ if (!isTemporary && !hasNestedComponentAlreadyBeenAdded) {
+ newObj = newObj.set(
+ componentUid,
+ state.getIn(['components', componentUid])
+ );
+ }
+ });
+
+ return newObj;
+};
+
const reducer = (state, action) => {
switch (action.type) {
case 'ADD_ATTRIBUTE': {
@@ -86,12 +128,7 @@ const reducer = (state, action) => {
)
.updateIn(['modifiedData', 'components'], existingCompos => {
if (action.shouldAddComponentToData) {
- const componentToAdd = state.getIn(['components', rest.component]);
-
- return existingCompos.update(
- componentToAdd.get('uid'),
- () => componentToAdd
- );
+ return addComponentsToState(state, rest.component, existingCompos);
}
return existingCompos;
@@ -138,15 +175,7 @@ const reducer = (state, action) => {
)
.updateIn(['modifiedData', 'components'], old => {
const componentsSchema = newComponents.reduce((acc, current) => {
- const addedCompoSchema = state.getIn(['components', current]);
- const isTemporaryComponent = addedCompoSchema.get('isTemporary');
-
- // created components are already in the modifiedData.components
- if (isTemporaryComponent) {
- return acc;
- }
-
- return acc.set(current, addedCompoSchema);
+ return addComponentsToState(state, current, acc);
}, old);
return componentsSchema;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js
index f369cb1fd0..3daf815e4d 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js
@@ -31,6 +31,8 @@ import getTrad from '../../utils/getTrad';
import makeSearch from '../../utils/makeSearch';
import getAttributes from './utils/attributes';
import forms from './utils/forms';
+import createHeadersArray from './utils/createHeadersArray';
+import createHeadersObjectFromArray from './utils/createHeadersObjectFromArray';
import { createComponentUid, createUid } from './utils/createUid';
import getModalTitleSubHeader from './utils/getModalTitleSubHeader';
import getNextSearch from './utils/getNextSearch';
@@ -75,18 +77,40 @@ const FormModal = () => {
useEffect(() => {
if (!isEmpty(search)) {
const actionType = query.get('actionType');
- // Return 'null' if there isn't any attributeType search params
+ // Returns 'null' if there isn't any attributeType search params
const attributeName = query.get('attributeName');
const attributeType = query.get('attributeType');
const dynamicZoneTarget = query.get('dynamicZoneTarget');
const forTarget = query.get('forTarget');
- const headerDisplayCategory = query.get('headerDisplayCategory');
- const headerDisplayName = query.get('headerDisplayName');
- const headerDisplaySubCategory = query.get('headerDisplaySubCategory');
const modalType = query.get('modalType');
const targetUid = query.get('targetUid');
const settingType = query.get('settingType');
- const subTargetUid = query.get('subTargetUid');
+ const headerId = query.get('headerId');
+ const header_label_1 = query.get('header_label_1');
+ const header_icon_name_1 = query.get('header_icon_name_1');
+ const header_icon_isCustom_1 = query.get('header_icon_isCustom_1');
+ const header_info_category_1 = query.get('header_info_category_1');
+ const header_info_name_1 = query.get('header_info_name_1');
+ const header_label_2 = query.get('header_label_2');
+ const header_icon_name_2 = query.get('header_icon_name_2');
+ const header_icon_isCustom_2 = query.get('header_icon_isCustom_2');
+ const header_info_category_2 = query.get('header_info_category_2');
+ const header_info_name_2 = query.get('header_info_name_2');
+ const header_label_3 = query.get('header_label_3');
+ const header_icon_name_3 = query.get('header_icon_name_3');
+ const header_icon_isCustom_3 = query.get('header_icon_isCustom_3');
+ const header_info_category_3 = query.get('header_info_category_3');
+ const header_info_name_3 = query.get('header_info_name_3');
+ const header_label_4 = query.get('header_label_4');
+ const header_icon_name_4 = query.get('header_icon_name_4');
+ const header_icon_isCustom_4 = query.get('header_icon_isCustom_4');
+ const header_info_category_4 = query.get('header_info_category_4');
+ const header_info_name_4 = query.get('header_info_name_4');
+ const header_label_5 = query.get('header_label_5');
+ const header_icon_name_5 = query.get('header_icon_name_5');
+ const header_icon_isCustom_5 = query.get('header_icon_isCustom_5');
+ const header_info_category_5 = query.get('header_info_category_5');
+ const header_info_name_5 = query.get('header_info_name_5');
const step = query.get('step');
const pathToSchema =
forTarget === 'contentType' || forTarget === 'component'
@@ -98,16 +122,38 @@ const FormModal = () => {
attributeName,
attributeType,
dynamicZoneTarget,
- headerDisplayName,
- headerDisplayCategory,
- headerDisplaySubCategory,
forTarget,
modalType,
pathToSchema,
settingType,
- subTargetUid,
step,
targetUid,
+ header_label_1,
+ header_icon_name_1,
+ header_icon_isCustom_1,
+ header_info_name_1,
+ header_info_category_1,
+ header_label_2,
+ header_icon_name_2,
+ header_icon_isCustom_2,
+ header_info_name_2,
+ header_info_category_2,
+ header_label_3,
+ header_icon_name_3,
+ header_icon_isCustom_3,
+ header_info_name_3,
+ header_info_category_3,
+ header_label_4,
+ header_icon_name_4,
+ header_icon_isCustom_4,
+ header_info_name_4,
+ header_info_category_4,
+ header_label_5,
+ header_icon_name_5,
+ header_icon_isCustom_5,
+ header_info_name_5,
+ header_info_category_5,
+ headerId,
});
// Reset all the modification when opening the edit category modal
@@ -280,19 +326,7 @@ const FormModal = () => {
const form = get(forms, [state.modalType, 'form', state.settingType], () => ({
items: [],
}));
-
- // TODO improve icon logic
- let iconType = ['component', 'contentType'].includes(state.modalType)
- ? state.modalType
- : state.forTarget;
-
- if (state.modalType === 'addComponentToDynamicZone') {
- iconType = 'dynamiczone';
- }
-
- if (state.modalType === 'editCategory') {
- iconType = 'component';
- }
+ const headers = createHeadersArray(state);
const isCreatingContentType = state.modalType === 'contentType';
const isCreatingComponent = state.modalType === 'component';
@@ -310,14 +344,6 @@ const FormModal = () => {
const isPickingAttribute = state.modalType === 'chooseAttribute';
const uid = createUid(modifiedData.name || '');
- let headerId = isCreating
- ? `modalForm.${state.modalType}.header-create`
- : 'modalForm.header-edit';
-
- if (!['contentType', 'component'].includes(state.modalType)) {
- headerId = null;
- }
-
const checkFormValidity = async () => {
let schema;
const dataToValidate =
@@ -532,6 +558,7 @@ const FormModal = () => {
...rest,
});
};
+
const handleSubmit = async (e, shouldContinue = isCreating) => {
e.preventDefault();
@@ -541,17 +568,21 @@ const FormModal = () => {
const targetUid =
state.forTarget === 'components' ? state.targetUid : uid;
- // TODO REMOVE and use makeSearch
- const createNextSearch = searchUid => {
- if (!shouldContinue) {
- return '';
- }
+ const headerIcon = ['contentType', 'component'].includes(state.forTarget)
+ ? state.forTarget
+ : get(
+ allDataSchema,
+ ['components', state.targetUid, 'schema', 'icon'],
+ ''
+ );
- return `modalType=chooseAttribute&forTarget=${
- state.forTarget
- }&targetUid=${searchUid}&headerDisplayName=${state.headerDisplayName ||
- modifiedData.name}`;
- };
+ // Remove the last header when editing
+ if (state.actionType === 'edit') {
+ headers.pop();
+ }
+
+ const headersObject = createHeadersObjectFromArray(headers);
+ const nextHeaderIndex = headers.length + 1;
if (isCreatingContentType) {
// Create the content type schema
@@ -571,7 +602,9 @@ const FormModal = () => {
modalType: 'chooseAttribute',
forTarget: state.forTarget,
targetUid,
- headerDisplayName: modifiedData.name,
+ header_label_1: modifiedData.name,
+ header_icon_name_1: 'contentType',
+ header_icon_isCustom_1: null,
}),
});
} else if (isCreatingComponent) {
@@ -590,7 +623,9 @@ const FormModal = () => {
modalType: 'chooseAttribute',
forTarget: state.forTarget,
targetUid: componentUid,
- headerDisplayName: modifiedData.name,
+ header_label_1: modifiedData.name,
+ header_icon_name_1: 'contentType',
+ header_icon_isCustom_1: null,
}),
pathname: `/plugins/${pluginId}/component-categories/${category}/${componentUid}`,
});
@@ -604,6 +639,7 @@ const FormModal = () => {
}
} else if (isEditingCategory) {
if (toLower(initialData.name) === toLower(modifiedData.name)) {
+ // Close the modal
push({ search: '' });
return;
@@ -629,20 +665,19 @@ const FormModal = () => {
// Adding a component to a dynamiczone is not the same logic as creating a simple field
// so the search is different
- // For the modal header
- const displayCategory = state.headerDisplayName;
- const displayName = modifiedData.name;
-
const dzSearch = makeNextSearch({
modalType: 'addComponentToDynamicZone',
forTarget: 'contentType',
targetUid: state.targetUid,
- headerDisplayName: displayName,
- headerDisplayCategory: displayCategory,
+
dynamicZoneTarget: modifiedData.name,
settingType: 'base',
step: '1',
actionType: 'create',
+ ...headersObject,
+ header_label_2: modifiedData.name,
+ header_icon_name_2: null,
+ header_icon_isCustom_2: false,
});
const nextSearch = isDynamicZoneAttribute
? dzSearch
@@ -651,11 +686,12 @@ const FormModal = () => {
modalType: 'chooseAttribute',
forTarget: state.forTarget,
targetUid,
- headerDisplayName: state.headerDisplayName,
- headerDisplayCategory: state.headerDisplayCategory,
- // keep the old state
- headerDisplaySubCategory: state.headerDisplaySubCategory,
- subTargetUid: state.subTargetUid,
+ ...headersObject,
+ header_icon_isCustom_1: ![
+ 'contentType',
+ 'component',
+ ].includes(state.forTarget),
+ header_icon_name_1: headerIcon,
},
shouldContinue
);
@@ -680,7 +716,6 @@ const FormModal = () => {
} else {
if (isInFirstComponentStep) {
// Navigate the user to step 2
- // TODO refacto
const nextSearchObj = {
modalType: 'attribute',
actionType: state.actionType,
@@ -688,8 +723,12 @@ const FormModal = () => {
forTarget: state.forTarget,
targetUid: state.targetUid,
attributeType: 'component',
- headerDisplayName: state.headerDisplayName,
step: '2',
+ ...headersObject,
+ header_icon_isCustom_1: !['contentType', 'component'].includes(
+ state.forTarget
+ ),
+ header_icon_name_1: headerIcon,
};
push({
@@ -723,9 +762,18 @@ const FormModal = () => {
// This way we can add fields to the added component (if it wasn't there already)
true
);
+ const nextSearch = {
+ modalType: 'chooseAttribute',
+ forTarget: state.forTarget,
+ targetUid: state.targetUid,
+ ...headersObject,
+ header_icon_isCustom_1: !['contentType', 'component'].includes(
+ state.forTarget
+ ),
+ header_icon_name_1: headerIcon,
+ };
- // TODO change the search so the modal header is kept
- push({ search: shouldContinue ? createNextSearch(targetUid) : '' });
+ push({ search: makeSearch(nextSearch, shouldContinue) });
// We don't need to end the loop here we want the reducer to be reinitialised
}
@@ -736,7 +784,6 @@ const FormModal = () => {
// even though the user didn't set any field
// We need to prevent the component from being created if the user closes the modal at step 2 without any submission
} else if (isCreatingAttribute && isCreatingComponentFromAView) {
- const { headerDisplayCategory } = state;
// Step 1
if (isInFirstComponentStep) {
// Here the search could be refactored since it is the same as the case from above
@@ -749,18 +796,12 @@ const FormModal = () => {
forTarget: state.forTarget,
targetUid: state.targetUid,
attributeType: 'component',
- headerDisplayName: state.headerDisplayName,
step: '2',
+ ...headersObject,
+ header_icon_isCustom_1: false,
+ header_icon_name_1: 'component',
};
- // Modify the searchObj for the modal header
- // This case is happening when creating a nestedComponent after creating a component
- if (headerDisplayCategory) {
- searchObj.headerDisplayCategory = state.headerDisplayCategory;
- searchObj.headerDisplayName = state.headerDisplayName;
- searchObj.targetUid = state.targetUid;
- }
-
emitEvent('willCreateComponentFromAttributesModal');
push({
@@ -812,21 +853,16 @@ const FormModal = () => {
modalType: 'chooseAttribute',
forTarget: 'components',
targetUid: componentUid,
- headerDisplayName: modifiedData.name,
- headerDisplayCategory:
- state.headerDisplayCategory || state.headerDisplayName,
+ ...headersObject,
+ header_icon_isCustom_1: true,
+ header_icon_name_1: componentToCreate.icon,
+ [`header_label_${nextHeaderIndex}`]: modifiedData.name,
+ [`header_icon_name_${nextHeaderIndex}`]: 'component',
+ [`header_icon_isCustom_${nextHeaderIndex}`]: false,
+ [`header_info_category_${nextHeaderIndex}`]: category,
+ [`header_info_name_${nextHeaderIndex}`]: componentToCreate.name,
};
- // Then we inverse the headerDisplayName because it becomes the last one displayed
- // The case is created a component then created a nested one
- if (headerDisplayCategory) {
- // This is allows to modify the modal header
- searchToOpenModalAttributeToAddAttributesToAComponent.headerDisplaySubCategory =
- state.headerDisplayName;
- searchToOpenModalAttributeToAddAttributesToAComponent.subTargetUid =
- state.targetUid;
- }
-
push({
search: makeNextSearch(
searchToOpenModalAttributeToAddAttributesToAComponent,
@@ -869,13 +905,19 @@ const FormModal = () => {
// The Dynamic Zone and the component is created created
// Open the modal to add fields to the created component
- // TODO search for modal header
const searchToOpenAddField = {
modalType: 'chooseAttribute',
forTarget: 'components',
targetUid: componentUid,
- headerDisplayName: modifiedData.componentToCreate.name,
- headerDisplayCategory: state.headerDisplayCategory,
+ ...headersObject,
+ header_icon_isCustom_1: true,
+ header_icon_name_1: modifiedData.componentToCreate.icon,
+ [`header_label_${nextHeaderIndex}`]: modifiedData.name,
+ [`header_icon_name_${nextHeaderIndex}`]: 'component',
+ [`header_icon_isCustom_${nextHeaderIndex}`]: false,
+ [`header_info_category_${nextHeaderIndex}`]: category,
+ [`header_info_name_${nextHeaderIndex}`]: modifiedData
+ .componentToCreate.name,
};
push({ search: makeSearch(searchToOpenAddField, true) });
@@ -901,7 +943,6 @@ const FormModal = () => {
type: 'RESET_PROPS',
});
} catch (err) {
- console.log({ err });
const errors = getYupInnerErrors(err);
dispatch({
@@ -986,16 +1027,7 @@ const FormModal = () => {
withoverflow={toString(state.modalType === 'addComponentToDynamicZone')}
>
-
+
{
return (
{
+ const array = Object.keys(obj).reduce((acc, current) => {
+ const splitted = current.split('_');
+ const currentKeys = splitted.filter((_, i) => i !== splitted.length - 1);
+
+ if (ALLOWED_KEYS.includes(currentKeys.join('_'))) {
+ const currentKeysIndex = parseInt(splitted[splitted.length - 1] - 1, 10);
+ const path = [
+ currentKeysIndex,
+ ...currentKeys.filter(key => key !== 'header'),
+ ];
+
+ let value = obj[current];
+
+ if (current.includes('isCustom')) {
+ value = obj[current] === 'true';
+ }
+
+ set(acc, path, value);
+ }
+
+ return acc;
+ }, []);
+
+ return array.filter(obj => obj.label !== null);
+};
+
+export default createHeadersArray;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/createHeadersObjectFromArray.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/createHeadersObjectFromArray.js
new file mode 100644
index 0000000000..9712d9e0c8
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/createHeadersObjectFromArray.js
@@ -0,0 +1,27 @@
+import { isObject } from 'lodash';
+
+const createHeadersObjectFromArray = array => {
+ return array.reduce((acc, current, index) => {
+ const createHeaderObject = (obj, i, middle = '') =>
+ Object.keys(obj).reduce((acc1, current1) => {
+ if (isObject(obj[current1])) {
+ return {
+ ...acc1,
+ ...createHeaderObject(obj[current1], i, `_${current1}`),
+ };
+ }
+
+ const name = `header${middle}_${current1}_${i}`;
+
+ acc1[name] = obj[current1];
+
+ return acc1;
+ }, {});
+
+ const headerObject = createHeaderObject(current, index + 1);
+
+ return { ...acc, ...headerObject };
+ }, {});
+};
+
+export default createHeadersObjectFromArray;
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticData.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticData.js
index e168a52a9c..a782f34dfd 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticData.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticData.js
@@ -6,15 +6,37 @@ const INITIAL_STATE_DATA = {
attributeType: null,
dynamicZoneTarget: null,
forTarget: null,
- headerDisplayCategory: null,
- headerDisplayName: null,
- headerDisplaySubCategory: null,
modalType: null,
pathToSchema: [],
settingType: null,
step: null,
- subTargetUid: null,
targetUid: null,
+ headerId: null,
+ header_label_1: null,
+ header_icon_name_1: null,
+ header_icon_isCustom_1: null,
+ header_info_category_1: null,
+ header_info_name_1: null,
+ header_label_2: null,
+ header_icon_name_2: null,
+ header_icon_isCustom_2: null,
+ header_info_category_2: null,
+ header_info_name_2: null,
+ header_label_3: null,
+ header_icon_name_3: null,
+ header_icon_isCustom_3: null,
+ header_info_category_3: null,
+ header_info_name_3: null,
+ header_label_4: null,
+ header_icon_name_4: null,
+ header_icon_isCustom_4: null,
+ header_info_category_4: null,
+ header_info_name_4: null,
+ header_label_5: null,
+ header_icon_name_5: null,
+ header_icon_isCustom_5: null,
+ header_info_category_5: null,
+ header_info_name_5: null,
};
export { NAVLINKS, INITIAL_STATE_DATA };
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/tests/createHeadersArray.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/tests/createHeadersArray.test.js
new file mode 100644
index 0000000000..1cbe4a9638
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/tests/createHeadersArray.test.js
@@ -0,0 +1,143 @@
+import createHeadersArray from '../createHeadersArray';
+
+describe('FormModal | utils | createHeadersArray', () => {
+ it('should return an empty array if no header key is set', () => {
+ const data = {
+ actionType: null,
+ attributeName: null,
+ attributeType: null,
+ dynamicZoneTarget: null,
+ forTarget: null,
+ modalType: null,
+ pathToSchema: [],
+ settingType: null,
+ step: null,
+ targetUid: null,
+ headerId: null,
+ header_label_1: null,
+ header_icon_name_1: null,
+ header_icon_isCustom_1: null,
+ header_info_category_1: null,
+ header_info_name_1: null,
+ header_label_2: null,
+ header_icon_name_2: null,
+ header_icon_isCustom_2: null,
+ header_info_category_2: null,
+ header_info_name_2: null,
+ header_label_3: null,
+ header_icon_name_3: null,
+ header_icon_isCustom_3: null,
+ header_info_category_3: null,
+ header_info_name_3: null,
+ };
+
+ expect(createHeadersArray(data)).toEqual([]);
+ });
+
+ it('should return an array containing a header object', () => {
+ const data = {
+ actionType: 'something',
+ attributeName: null,
+ attributeType: null,
+ dynamicZoneTarget: null,
+ forTarget: null,
+
+ modalType: null,
+ pathToSchema: [],
+ settingType: null,
+ step: null,
+ targetUid: null,
+ headerId: null,
+ header_label_1: 'restaurant',
+ header_icon_name_1: 'contentType',
+ header_icon_isCustom_1: 'false',
+ header_info_category_1: null,
+ header_info_name_1: null,
+ header_label_2: null,
+ header_icon_name_2: null,
+ header_icon_isCustom_2: null,
+ header_info_category_2: null,
+ header_info_name_2: null,
+ header_label_3: null,
+ header_icon_name_3: null,
+ header_icon_isCustom_3: null,
+ header_info_category_3: null,
+ header_info_name_3: null,
+ };
+ const expected = [
+ {
+ label: 'restaurant',
+ icon: {
+ name: 'contentType',
+ isCustom: false,
+ },
+ info: {
+ name: null,
+ category: null,
+ },
+ },
+ ];
+
+ expect(createHeadersArray(data)).toEqual(expected);
+ });
+
+ it('should handle multiple headers correctly', () => {
+ const data = {
+ actionType: 'something',
+ attributeName: null,
+ attributeType: null,
+ dynamicZoneTarget: null,
+ forTarget: null,
+
+ modalType: null,
+ pathToSchema: [],
+ settingType: null,
+ step: null,
+
+ targetUid: null,
+ headerId: null,
+ header_label_1: 'restaurant',
+ header_icon_name_1: 'bool',
+ header_icon_isCustom_1: 'true',
+ header_info_category_1: null,
+ header_info_name_1: null,
+ header_label_2: 'closing period',
+ header_icon_name_2: null,
+ header_icon_isCustom_2: null,
+ header_info_category_2: 'default',
+ header_info_name_2: 'closingperiod',
+ header_label_3: null,
+ header_icon_name_3: null,
+ header_icon_isCustom_3: null,
+ header_info_category_3: null,
+ header_info_name_3: null,
+ };
+
+ const expected = [
+ {
+ label: 'restaurant',
+ icon: {
+ name: 'bool',
+ isCustom: true,
+ },
+ info: {
+ name: null,
+ category: null,
+ },
+ },
+ {
+ label: 'closing period',
+ icon: {
+ name: null,
+ isCustom: false,
+ },
+ info: {
+ name: 'closingperiod',
+ category: 'default',
+ },
+ },
+ ];
+
+ expect(createHeadersArray(data)).toEqual(expected);
+ });
+});
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/tests/createHeadersObjectFromArray.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/tests/createHeadersObjectFromArray.test.js
new file mode 100644
index 0000000000..8acf3a881c
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/tests/createHeadersObjectFromArray.test.js
@@ -0,0 +1,45 @@
+import createHeadersObjectFromArray from '../createHeadersObjectFromArray';
+
+describe('FormModal | utils | createHeadersArray', () => {
+ it('should return a header object', () => {
+ const data = [
+ {
+ label: 'test',
+ icon: {
+ name: 'contentType',
+ isCustom: false,
+ },
+ info: {
+ name: null,
+ category: null,
+ },
+ },
+ {
+ label: 'test2',
+ icon: {
+ name: 'book',
+ isCustom: true,
+ },
+ info: {
+ name: 'something',
+ category: 'default',
+ },
+ },
+ ];
+
+ const expected = {
+ header_label_1: 'test',
+ header_icon_name_1: 'contentType',
+ header_icon_isCustom_1: false,
+ header_info_name_1: null,
+ header_info_category_1: null,
+ header_label_2: 'test2',
+ header_icon_name_2: 'book',
+ header_icon_isCustom_2: true,
+ header_info_name_2: 'something',
+ header_info_category_2: 'default',
+ };
+
+ expect(createHeadersObjectFromArray(data)).toEqual(expected);
+ });
+});
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/LeftMenu/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/LeftMenu/index.js
index eb0fd9c3d5..9a8bcc4016 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/LeftMenu/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/LeftMenu/index.js
@@ -43,10 +43,19 @@ function LeftMenu({ wait }) {
actionType: 'edit',
modalType: 'editCategory',
categoryName: data.name,
- headerDisplayName: data.name,
- headerDisplayCategory: formatMessage({
+ header_label_1: formatMessage({
id: getTrad('modalForm.header.categories'),
}),
+ header_icon_name_1: 'component',
+ header_icon_isCustom_1: false,
+ header_info_category_1: null,
+ header_info_name_1: null,
+ header_label_2: data.name,
+ header_icon_name_2: null,
+ header_icon_isCustom_2: false,
+ header_info_category_2: null,
+ header_info_name_2: null,
+
settingType: 'base',
});
@@ -86,7 +95,9 @@ function LeftMenu({ wait }) {
await wait();
push({
- search: `modalType=${type}&actionType=create&settingType=base&forTarget=${type}`,
+ search: `modalType=${type}&actionType=create&settingType=base&forTarget=${type}&headerId=${getTrad(
+ `modalForm.${type}.header-create`
+ )}&header_icon_name_1=${type}&header_icon_isCustom_1=false&header_label_1=null`,
});
} else {
displayNotificationCTNotSaved();
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ListView/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ListView/index.js
index 5c89907d61..1c6072d54d 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ListView/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ListView/index.js
@@ -11,6 +11,7 @@ import {
import { Header } from '@buffetjs/custom';
import ListViewContext from '../../contexts/ListViewContext';
import convertAttrObjToArray from '../../utils/convertAttrObjToArray';
+import getAttributeDisplayedType from '../../utils/getAttributeDisplayedType';
import getTrad from '../../utils/getTrad';
import makeSearch from '../../utils/makeSearch';
import ListRow from '../../components/ListRow';
@@ -71,41 +72,49 @@ const ListView = () => {
const hasModelBeenModified = !isEqual(modifiedData, initialData);
const forTarget = isInContentTypeView ? 'contentType' : 'component';
- const handleClickOpenModalAddField = async (
+ const handleClickAddField = async (
forTarget,
targetUid,
- headerDisplayName,
- headerDisplayCategory = null,
- headerDisplaySubCategory = null,
- subTargetUid = null
+ firstHeaderObj,
+ secondHeaderObj,
+ thirdHeaderObj,
+ fourthHeaderObj
) => {
+ // disable the prompt
+ await wait();
+
const searchObj = {
modalType: 'chooseAttribute',
forTarget,
targetUid,
- headerDisplayName,
- headerDisplayCategory,
- headerDisplaySubCategory,
- subTargetUid,
+ ...firstHeaderObj,
+ ...secondHeaderObj,
+ ...thirdHeaderObj,
+ ...fourthHeaderObj,
};
- // Disable the prompt
- await wait();
-
- push({ search: makeSearch(searchObj, true) });
+ push({ search: makeSearch(searchObj) });
};
const handleClickAddComponentToDZ = async dzName => {
+ const firstHeaderObject = {
+ header_label_1: currentDataName,
+ header_icon_name_1: 'dynamiczone',
+ header_icon_isCustom_1: false,
+ };
+ const secondHeaderObj = {
+ header_label_2: dzName,
+ };
const search = {
modalType: 'addComponentToDynamicZone',
forTarget: 'contentType',
targetUid,
- headerDisplayCategory: currentDataName,
dynamicZoneTarget: dzName,
settingType: 'base',
step: '1',
actionType: 'edit',
- headerDisplayName: dzName,
+ ...firstHeaderObject,
+ ...secondHeaderObj,
};
await wait();
@@ -118,30 +127,13 @@ const ListView = () => {
targetUid,
attributeName,
type,
- headerDisplayName,
- headerDisplayCategory = null,
- headerDisplaySubCategory = null,
- subTargetUid = null
+ firstHeaderObj,
+ secondHeaderObj,
+ thirdHeaderObj,
+ fourthHeaderObj,
+ fifthHeaderObj
) => {
- let attributeType;
-
- switch (type) {
- case 'integer':
- case 'biginteger':
- case 'decimal':
- case 'float':
- attributeType = 'number';
- break;
- case 'string':
- case 'text':
- attributeType = 'text';
- break;
- case '':
- attributeType = 'relation';
- break;
- default:
- attributeType = type;
- }
+ const attributeType = getAttributeDisplayedType(type);
await wait();
@@ -153,11 +145,12 @@ const ListView = () => {
targetUid,
attributeName,
attributeType,
- headerDisplayName,
- headerDisplayCategory,
- headerDisplaySubCategory,
step: type === 'component' ? '2' : null,
- subTargetUid,
+ ...firstHeaderObj,
+ ...secondHeaderObj,
+ ...thirdHeaderObj,
+ ...fourthHeaderObj,
+ ...fifthHeaderObj,
};
await wait();
@@ -181,6 +174,7 @@ const ListView = () => {
const wait = async () => {
togglePrompt(false);
+
return new Promise(resolve => setTimeout(resolve, 100));
};
const label = get(modifiedData, [firstMainDataPath, 'schema', 'name'], '');
@@ -231,7 +225,10 @@ const ListView = () => {
settingType: 'base',
forTarget: firstMainDataPath,
targetUid,
- headerDisplayName: label,
+ header_label_1: label,
+ header_icon_isCustom_1: false,
+ header_icon_name_1: firstMainDataPath,
+ headerId: getTrad('modalForm.header-edit'),
}),
});
},
@@ -258,7 +255,12 @@ const ListView = () => {
color: 'primary',
label: formatMessage({ id: `${pluginId}.button.attributes.add.another` }),
onClick: () => {
- handleClickOpenModalAddField(forTarget, targetUid, currentDataName);
+ const headerDisplayObject = {
+ header_label_1: currentDataName,
+ header_icon_name_1: forTarget,
+ header_icon_isCustom_1: false,
+ };
+ handleClickAddField(forTarget, targetUid, headerDisplayObject);
},
};
const goToCMSettingsPage = () => {
@@ -281,8 +283,6 @@ const ListView = () => {
? [{ ...configureButtonProps }, { ...addButtonProps }]
: [configureButtonProps];
- const handleClickOnTrashIcon = () => {};
-
const CustomRow = props => {
const { name } = props;
@@ -292,7 +292,6 @@ const ListView = () => {
attributeName={name}
name={name}
onClick={handleClickEditField}
- onClickDelete={handleClickOnTrashIcon}
/>
);
};
@@ -307,7 +306,7 @@ const ListView = () => {
return (
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/utils/getAttributeDisplayedType.js b/packages/strapi-plugin-content-type-builder/admin/src/utils/getAttributeDisplayedType.js
new file mode 100644
index 0000000000..cb088b225b
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/utils/getAttributeDisplayedType.js
@@ -0,0 +1,25 @@
+const getAttributeDisplayedType = type => {
+ let displayedType;
+
+ switch (type) {
+ case 'integer':
+ case 'biginteger':
+ case 'decimal':
+ case 'float':
+ displayedType = 'number';
+ break;
+ case 'string':
+ case 'text':
+ displayedType = 'text';
+ break;
+ case '':
+ displayedType = 'relation';
+ break;
+ default:
+ displayedType = type;
+ }
+
+ return displayedType;
+};
+
+export default getAttributeDisplayedType;
diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js b/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js
index e9375af1ed..e4330459dd 100644
--- a/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js
+++ b/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js
@@ -22,6 +22,7 @@ module.exports = (obj, validNatures) => {
.required(),
unique: validators.unique.nullable(),
configurable: yup.boolean().nullable(),
+ autoPopulate: yup.boolean().nullable(),
dominant: yup.boolean().nullable(),
columnName: yup.string().nullable(),
targetAttribute: REVERSE_RELATIONS.includes(obj.nature)
diff --git a/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js b/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js
index e80e1864a8..692975529d 100644
--- a/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js
+++ b/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js
@@ -172,6 +172,10 @@ module.exports = function createComponentBuilder() {
this.unsetRelation(oldAttribute);
}
+ if (Object.keys(oldAttribute).includes('autoPopulate')) {
+ newAttribute.autoPopulate = oldAttribute.autoPopulate;
+ }
+
return this.setRelation({
key,
modelName: contentType.modelName,
diff --git a/packages/strapi-plugin-content-type-builder/services/schema-builder/index.js b/packages/strapi-plugin-content-type-builder/services/schema-builder/index.js
index 12a343e3e8..871c51cea8 100644
--- a/packages/strapi-plugin-content-type-builder/services/schema-builder/index.js
+++ b/packages/strapi-plugin-content-type-builder/services/schema-builder/index.js
@@ -119,12 +119,14 @@ function createSchemaBuilder({ components, contentTypes }) {
targetAttribute,
columnName,
dominant,
+ autoPopulate,
} = attribute;
const attr = {
unique: unique === true ? true : undefined,
columnName: columnName || undefined,
configurable: configurable === false ? false : undefined,
+ autoPopulate: autoPopulate === false ? false : undefined,
};
if (!this.contentTypes.has(target)) {
diff --git a/packages/strapi-plugin-content-type-builder/utils/attributes.js b/packages/strapi-plugin-content-type-builder/utils/attributes.js
index 08459acbab..1a093ef79b 100644
--- a/packages/strapi-plugin-content-type-builder/utils/attributes.js
+++ b/packages/strapi-plugin-content-type-builder/utils/attributes.js
@@ -85,6 +85,7 @@ const formatAttribute = (key, attribute, { model }) => {
undefined
),
unique: attribute.unique ? true : false,
+ autoPopulate: attribute.autoPopulate === false ? false : undefined,
};
}
};
|