fix - keep autoPopulate:false options on edit

This commit is contained in:
Alexandre BODIN 2020-01-08 11:40:49 +01:00 committed by Adam Patai
commit c5cef7dcbb
29 changed files with 1016 additions and 339 deletions

View File

@ -36,7 +36,6 @@ function EditViewButton(props) {
: `${category}/${componentSlug}`;
const handleClick = () => {
// TODO
emitEvent('willEditEditLayout');
props.push(`${baseUrl}/${suffixUrl}`);
};

View File

@ -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') {

View File

@ -15,8 +15,10 @@ import Td from '../Td';
function ComponentList({
customRowComponent,
component,
dzName,
mainTypeName,
isFromDynamicZone,
isNestedInDZComponent,
firstLoopComponentName,
firstLoopComponentUid,
}) {
@ -32,6 +34,7 @@ function ComponentList({
<Td colSpan={12} isChildOfDynamicZone={isFromDynamicZone}>
<List
customRowComponent={customRowComponent}
dzName={dzName}
items={convertAttrObjToArray(attributes)}
targetUid={component}
mainTypeName={mainTypeName}
@ -39,6 +42,7 @@ function ComponentList({
firstLoopComponentUid={firstLoopComponentUid || component}
editTarget="components"
isFromDynamicZone={isFromDynamicZone}
isNestedInDZComponent={isNestedInDZComponent}
isSub
secondLoopComponentName={
firstLoopComponentName ? componentName : null
@ -53,15 +57,19 @@ function ComponentList({
ComponentList.defaultProps = {
component: null,
customRowComponent: null,
dzName: null,
isFromDynamicZone: false,
isNestedInDZComponent: false,
};
ComponentList.propTypes = {
component: PropTypes.string,
customRowComponent: PropTypes.func,
dzName: PropTypes.string,
firstLoopComponentName: PropTypes.string,
firstLoopComponentUid: PropTypes.string,
isFromDynamicZone: PropTypes.bool,
isNestedInDZComponent: PropTypes.bool,
mainTypeName: PropTypes.string.isRequired,
targetUid: PropTypes.string.isRequired,
};

View File

@ -85,6 +85,7 @@ function DynamicZoneList({
<ComponentList
{...props}
isFromDynamicZone
dzName={name}
mainTypeName={mainTypeName}
targetUid={targetUid}
key={component}

View File

@ -6,6 +6,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { get } from 'lodash';
import { useGlobalContext } from 'strapi-helper-plugin';
import { Plus } from '@buffetjs/icons';
@ -26,34 +27,125 @@ function List({
mainTypeName,
editTarget,
isFromDynamicZone,
isNestedInDZComponent,
isMain,
firstLoopComponentName,
firstLoopComponentUid,
secondLoopComponentName,
secondLoopComponentUid,
isSub,
dzName,
}) {
const { formatMessage } = useGlobalContext();
const { isInDevelopmentMode } = useDataManager();
const { isInDevelopmentMode, modifiedData } = useDataManager();
const { openModalAddField } = useListView();
const onClickAddField = () => {
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({
<React.Fragment key={item.name}>
<CustomRow
{...item}
dzName={dzName}
isNestedInDZComponent={isNestedInDZComponent}
targetUid={targetUid}
// NEW props
mainTypeName={mainTypeName}
editTarget={editTarget}
firstLoopComponentName={firstLoopComponentName}
@ -103,8 +196,8 @@ function List({
{...item}
customRowComponent={customRowComponent}
targetUid={targetUid}
// NEW PROPS
dzName={dzName}
isNestedInDZComponent={isFromDynamicZone}
mainTypeName={mainTypeName}
editTarget={editTarget}
firstLoopComponentName={firstLoopComponentName}
@ -147,9 +240,11 @@ List.defaultProps = {
addComponentToDZ: () => {},
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,

View File

@ -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,

View File

@ -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 (
<ComponentInfosWrapper>
&nbsp; ({upperFirst(currentComponentCategory)}
&nbsp;&nbsp;
<UpperFirst content={currentComponentFriendlyName} />)
&nbsp; (<UpperFirst content={category} /> &nbsp;&nbsp;
<UpperFirst content={name} />)
</ComponentInfosWrapper>
);
};
ComponentInfos.propTypes = {
uid: PropTypes.string.isRequired,
category: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
};
export default ComponentInfos;

View File

@ -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 (
<Wrapper isOpen={dropdownOpen} toggle={toggle} style={{ margin: 'auto 0' }}>
<Toggle>...</Toggle>
<Menu style={{ top: '8px' }}>
{headers.map((header, index) => {
if (!shouldDisplaySecondHeader && index === 1) {
return null;
}
return (
<Item key={index}>
<Icon type={header.icon.name} />
<span>
<UpperFirst content={header.label} />
</span>
</Item>
);
})}
</Menu>
</Wrapper>
);
};
DropdownInfos.defaultProps = {
headers: [],
shouldDisplaySecondHeader: false,
};
DropdownInfos.propTypes = {
headers: PropTypes.array,
shouldDisplaySecondHeader: PropTypes.bool,
};
export default DropdownInfos;

View File

@ -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 = (
<>
<span>
<UpperFirst content={category} />
</span>
<IconWrapper>
<FontAwesomeIcon icon="chevron-right" />
</IconWrapper>
{subCategory && (
<>
<span>
<UpperFirst content={subCategory} />
</span>
<ComponentInfos uid={subTargetUid} />
<IconWrapper>
<FontAwesomeIcon icon="chevron-right" />
</IconWrapper>
</>
)}
</>
);
return (
<>
{category && content}
<span>
<UpperFirst content={name} />
</span>
{shouldDisplayComponentCatInfos && <ComponentInfos uid={targetUid} />}
</>
);
};
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;

View File

@ -0,0 +1,13 @@
import React from 'react';
import { AttributeIcon } from '@buffetjs/core';
import PropTypes from 'prop-types';
const Icon = ({ type }) => (
<AttributeIcon type={type} style={{ margin: 'auto 20px auto 0' }} />
);
Icon.propTypes = {
type: PropTypes.string.isRequired,
};
export default Icon;

View File

@ -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;

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
import { DropdownMenu } from 'reactstrap';
const Menu = styled(DropdownMenu)`
top: 8px;
`;
export default Menu;

View File

@ -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;

View File

@ -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;

View File

@ -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 (
<section>
<HeaderModalTitle style={{ textTransform: 'none' }}>
{shouldDisplayComponentCatInfos ? (
{headerId && (
<>
<Icon type={get(headers, [0, 'icon', 'name'], '')} />
<FormattedMessage
id={headerId}
values={{ name: get(headers, [0, 'label'], '') }}
/>
</>
)}
{!headerId &&
headers.map((header, index) => {
const iconName = get(header, ['icon', 'name'], '');
const iconType = iconName === null ? '' : iconName;
const icon = get(header, ['icon', 'isCustom'], false) ? (
<ComponentIcon isSelected>
<FontAwesomeIcon icon={currentComponentIcon} />
<FontAwesomeIcon icon={iconType} />
</ComponentIcon>
) : (
<AttributeIcon
type={iconName}
style={{ margin: 'auto 20px auto 0' }}
/>
)}
{headerId && (
<FormattedMessage id={`${pluginId}.${headerId}`} values={{ name }} />
)}
{!headerId && (
<Header
category={category}
name={name}
target={target}
targetUid={targetUid}
subCategory={subCategory}
subTargetUid={subTargetUid}
<Icon type={iconType} />
);
if (shouldDisplayDropDown && index === 1) {
return (
<Fragment key={index}>
<IconWrapper>
<FontAwesomeIcon icon="chevron-right" />
</IconWrapper>
<DropdownInfos
headers={[headers[1], headers[2]]}
shouldDisplaySecondHeader={headers.length > 4}
/>
</Fragment>
);
}
if (shouldDisplayDropDown && index === 2 && headers.length > 4) {
return null;
}
if (index === 0) {
return (
<Fragment key={index}>
{icon}
<span>
<UpperFirst content={get(header, ['label'], '')} />
</span>
</Fragment>
);
}
return (
<Fragment key={index}>
<IconWrapper>
<FontAwesomeIcon icon="chevron-right" />
</IconWrapper>
<span>
<UpperFirst content={get(header, ['label'], '')} />
</span>
{header.info.category && (
<ComponentInfos
category={header.info.category}
name={header.info.name}
/>
)}
</Fragment>
);
})}
</HeaderModalTitle>
</section>
);
};
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;

View File

@ -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;

View File

@ -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'],
''
);
// Remove the last header when editing
if (state.actionType === 'edit') {
headers.pop();
}
return `modalType=chooseAttribute&forTarget=${
state.forTarget
}&targetUid=${searchUid}&headerDisplayName=${state.headerDisplayName ||
modifiedData.name}`;
};
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')}
>
<HeaderModal>
<ModalHeader
name={state.headerDisplayName}
category={state.headerDisplayCategory}
headerId={headerId}
iconType={iconType || 'contentType'}
subCategory={state.headerDisplaySubCategory}
subTargetUid={state.subTargetUid}
target={state.forTarget}
targetUid={state.targetUid}
/>
<ModalHeader headerId={state.headerId} headers={headers} />
<section>
<HeaderModalTitle>
<FormattedMessage
@ -1160,7 +1192,7 @@ const FormModal = () => {
return (
<RelationForm
key="relation"
mainBoxHeader={state.headerDisplayName}
mainBoxHeader={get(headers, [0, 'label'], '')}
modifiedData={modifiedData}
naturePickerType={state.forTarget}
onChange={handleChange}

View File

@ -0,0 +1,37 @@
import { set } from 'lodash';
const ALLOWED_KEYS = [
'header_label',
'header_icon_name',
'header_icon_isCustom',
'header_info_category',
'header_info_name',
];
const createHeadersArray = obj => {
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;

View File

@ -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;

View File

@ -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 };

View File

@ -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);
});
});

View File

@ -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);
});
});

View File

@ -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();

View File

@ -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 (
<ListViewContext.Provider
value={{ openModalAddField: handleClickOpenModalAddField }}
value={{ openModalAddField: handleClickAddField }}
>
<Wrapper>
<BackHeader onClick={goBack} />

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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)) {

View File

@ -85,6 +85,7 @@ const formatAttribute = (key, attribute, { model }) => {
undefined
),
unique: attribute.unique ? true : false,
autoPopulate: attribute.autoPopulate === false ? false : undefined,
};
}
};