diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/Add.js b/packages/strapi-plugin-content-manager/admin/src/components/AddDropdown/components.js similarity index 57% rename from packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/Add.js rename to packages/strapi-plugin-content-manager/admin/src/components/AddDropdown/components.js index 72dd1dac4d..ba32f109c3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/Add.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/AddDropdown/components.js @@ -1,13 +1,4 @@ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; -import PropTypes from 'prop-types'; import styled, { css } from 'styled-components'; -import { - ButtonDropdown, - DropdownToggle, - DropdownMenu, - DropdownItem, -} from 'reactstrap'; const Wrapper = styled.div` margin-left: 29px; @@ -17,10 +8,10 @@ const Wrapper = styled.div` justify-content: space-between; background: #ffffff; color: #333740; - border: 1px solid #e3e9f3; border-radius: 2px; + border: solid 1px #006ced; + > button { - position: relative; cursor: pointer; padding-left: 10px !important; line-height: 30px; @@ -40,21 +31,22 @@ const Wrapper = styled.div` color: #333740; } > p { + position: relative; height: 100%; - margin-left: 20px; + text-align: center; margin-bottom: 0; margin-top: -1px; color: #007eff !important; font-size: 13px !important; - } - &:before { - position: absolute; - top: 0px; - bottom: 0; - content: '\f067'; - font-family: FontAwesome; - font-size: 10px; - color: #007eff; + > span { + &:before { + margin-right: 10px; + content: '\f067'; + font-family: FontAwesome; + font-size: 10px; + color: #007eff; + } + } } } > div { @@ -114,49 +106,4 @@ const Wrapper = styled.div` }} `; -function Add({ data, onClick }) { - const [state, setState] = React.useState(false); - - return ( - - { - if (data.length > 0) { - setState(prevState => !prevState); - } - }} - > - - - {msg =>

{msg}

} -
-
- - {data.map(item => ( - { - onClick(item); - }} - > - {item} - - ))} - -
-
- ); -} - -Add.defaultProps = { - data: [], - onClick: () => {}, -}; - -Add.propTypes = { - data: PropTypes.array, - onClick: PropTypes.func, -}; - -export default Add; +export { Wrapper }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/AddDropdown/index.js b/packages/strapi-plugin-content-manager/admin/src/components/AddDropdown/index.js new file mode 100644 index 0000000000..df26f90f9b --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/AddDropdown/index.js @@ -0,0 +1,68 @@ +import React, { memo, useState } from 'react'; +import { FormattedMessage } from 'react-intl'; +import PropTypes from 'prop-types'; + +import { + ButtonDropdown, + DropdownToggle, + DropdownMenu, + DropdownItem, +} from 'reactstrap'; + +import { Wrapper } from './components'; + +function Add({ data, onClick, pStyle, style }) { + const [state, setState] = useState(false); + + return ( + + { + if (data.length > 0) { + setState(prevState => !prevState); + } + }} + > + + + {msg => ( +

+ + {msg} +

+ )} +
+
+ + {data.map(item => ( + { + onClick(item); + }} + > + {item} + + ))} + +
+
+ ); +} + +Add.defaultProps = { + data: [], + onClick: () => {}, + pStyle: {}, + style: {}, +}; + +Add.propTypes = { + data: PropTypes.array, + onClick: PropTypes.func, + pStyle: PropTypes.object, + style: PropTypes.object, +}; + +export default memo(Add); diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/components.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/components.js index 527a444f15..a06901e8c3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/components.js @@ -40,7 +40,7 @@ const NameWrapper = styled.div` position: relative; height: 30px; width: 100%; - margin-bottom: 10px; + display: flex; padding-left: 10px; justify-content: space-between; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/index.js index 1bcc5a222e..96cba44295 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldItem/index.js @@ -13,6 +13,7 @@ const FieldItem = forwardRef( isDragging, isEditing, name, + onClickRemove, showLeftCarret, showRightCarret, size, @@ -58,6 +59,7 @@ const FieldItem = forwardRef( {!isHidden && ( @@ -76,6 +78,7 @@ const FieldItem = forwardRef( FieldItem.defaultProps = { isDragging: false, isEditing: false, + onClickRemove: () => {}, showLeftCarret: false, showRightCarret: false, type: 'string', @@ -85,6 +88,7 @@ FieldItem.propTypes = { isDragging: PropTypes.bool, isEditing: PropTypes.bool, name: PropTypes.string.isRequired, + onClickRemove: PropTypes.func, showLeftCarret: PropTypes.bool, showRightCarret: PropTypes.bool, size: PropTypes.number.isRequired, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js index c8a96699e8..7891d1e205 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js @@ -7,7 +7,16 @@ import FieldItem from '../FieldItem'; import ItemTypes from '../../utils/itemsTypes'; -const Item = ({ itemIndex, moveItem, moveRow, name, rowIndex, size, type }) => { +const Item = ({ + itemIndex, + moveItem, + moveRow, + name, + removeField, + rowIndex, + size, + type, +}) => { // console.log({ rowIndex }); const ref = useRef(null); const [{ clientOffset, isOver }, drop] = useDrop({ @@ -176,6 +185,7 @@ const Item = ({ itemIndex, moveItem, moveRow, name, rowIndex, size, type }) => { removeField(rowIndex, itemIndex)} showLeftCarret={showLeftCarret} showRightCarret={showRightCarret} size={size} @@ -194,6 +204,7 @@ Item.propTypes = { moveItem: PropTypes.func.isRequired, moveRow: PropTypes.func.isRequired, name: PropTypes.string.isRequired, + removeField: PropTypes.func.isRequired, rowIndex: PropTypes.number.isRequired, size: PropTypes.number.isRequired, type: PropTypes.string, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js index 4daa90b419..995b42407b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js @@ -1 +1,8 @@ -// import styled from 'styled-components'; +import styled from 'styled-components'; + +const Wrapper = styled.div` + display: flex; + margin-bottom: 24px; +`; + +export { Wrapper }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js index 634236e06c..15be541442 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js @@ -1,11 +1,24 @@ import React, { memo } from 'react'; -import PropTypes from 'prop-types'; + import { get } from 'lodash'; +import { useLayoutDnd } from '../../contexts/LayoutDnd'; + +import Add from '../AddDropdown'; import SortWrapper from '../SortWrapper'; +import { Wrapper } from './components'; import Item from './Item'; -const FieldsReorder = ({ attributes, layout, moveItem, moveRow }) => { +const FieldsReorder = () => { + const { + attributes, + buttonData, + layout, + moveItem, + moveRow, + onAddData, + removeField, + } = useLayoutDnd(); const getType = attributeName => { const attribute = get(attributes, [attributeName], {}); @@ -20,9 +33,8 @@ const FieldsReorder = ({ attributes, layout, moveItem, moveRow }) => {
{layout.map((row, rowIndex) => { - // return ( -
+ {row.rowContent.map((rowContent, index) => { const { name, size } = rowContent; @@ -33,31 +45,27 @@ const FieldsReorder = ({ attributes, layout, moveItem, moveRow }) => { moveRow={moveRow} moveItem={moveItem} name={name} + removeField={removeField} rowIndex={rowIndex} size={size} type={getType(name)} - // /> ); })} -
+ ); })} + + +
); }; -FieldsReorder.defaultProps = { - attributes: {}, - layout: [], -}; - -FieldsReorder.propTypes = { - attributes: PropTypes.object, - layout: PropTypes.array, - moveItem: PropTypes.func.isRequired, - moveRow: PropTypes.func.isRequired, -}; - export default memo(FieldsReorder); diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SortWrapper/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SortWrapper/index.js index 0e36a00a0c..4d7e9f7036 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SortWrapper/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SortWrapper/index.js @@ -3,7 +3,7 @@ import styled from 'styled-components'; const SortWrapper = styled.div` margin-top: 7px; margin-bottom: 10px; - padding-top: 10px; + padding-top: 11px; border: 1px dashed #e3e9f3; border-radius: 2px; > div { diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/ListLayout.js b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/ListLayout.js index 349b0be287..6cc6b4d74f 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/ListLayout.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/ListLayout.js @@ -10,7 +10,7 @@ import pluginId from '../../pluginId'; import FormWrapper from '../../components/SettingFormWrapper'; import { Wrapper } from './components'; -import Add from './Add'; +import Add from '../../components/AddDropdown'; import ListField from './ListField'; import ItemTypes from '../../utils/itemsTypes'; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/actions.js b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/actions.js index d20bf4d11c..782d475907 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/actions.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/actions.js @@ -6,10 +6,12 @@ import { GET_DATA_SUCCEEDED, MOVE_FIELD_LIST, MOVE_ROW, + ON_ADD_DATA, ON_CHANGE, ON_REMOVE_LIST_FIELD, ON_RESET, ON_SUBMIT, + REMOVE_FIELD, REORDER_DIFF_ROW, REORDER_ROW, RESET_PROPS, @@ -66,6 +68,13 @@ export function moveRow(dragRowIndex, hoverRowIndex) { }; } +export function onAddData(name) { + return { + type: ON_ADD_DATA, + name, + }; +} + export function onChange({ target: { name, value } }) { return { type: ON_CHANGE, @@ -94,6 +103,14 @@ export function onSubmit(uid, emitEvent) { }; } +export function removeField(rowIndex, fieldIndex) { + return { + type: REMOVE_FIELD, + rowIndex, + fieldIndex, + }; +} + export function reorderDiffRow( dragIndex, hoverIndex, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/constants.js b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/constants.js index 7bacbf2cb3..74ab92d1ba 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/constants.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/constants.js @@ -7,11 +7,13 @@ export const GET_DATA_SUCCEEDED = export const MOVE_FIELD_LIST = 'ContentManager/SettingViewModel/MOVE_FIELD_LIST'; export const MOVE_ROW = 'ContentManager/SettingViewModel/MOVE_ROW'; +export const ON_ADD_DATA = 'ContentManager/SettingViewModel/ON_ADD_DATA'; export const ON_CHANGE = 'ContentManager/SettingViewModel/ON_CHANGE'; export const ON_REMOVE_LIST_FIELD = 'ContentManager/SettingViewModel/ON_REMOVE_LIST_FIELD'; export const ON_RESET = 'ContentManager/SettingViewModel/ON_RESET'; export const ON_SUBMIT = 'ContentManager/SettingViewModel/ON_SUBMIT'; +export const REMOVE_FIELD = 'ContentManager/SettingViewModel/REMOVE_FIELD'; export const REORDER_ROW = 'ContentManager/SettingViewModel/REORDER_ROW'; export const REORDER_DIFF_ROW = 'ContentManager/SettingViewModel/REORDER_DIFF_ROW'; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js index cd685b09ee..175672ecdb 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useState } from 'react'; +import React, { memo, useEffect, useCallback, useState } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { bindActionCreators, compose } from 'redux'; @@ -12,7 +12,9 @@ import { PopUpWarning, LoadingIndicatorPage, } from 'strapi-helper-plugin'; + import pluginId from '../../pluginId'; +import { LayoutDndProvider } from '../../contexts/LayoutDnd'; import Block from '../../components/Block'; import Container from '../../components/Container'; @@ -30,10 +32,12 @@ import { getData, moveListField, moveRow, + onAddData, onChange, onReset, onSubmit, onRemoveListField, + removeField, reorderDiffRow, reorderRow, resetProps, @@ -64,10 +68,12 @@ function SettingViewModel({ modifiedData, moveListField, moveRow, + onAddData, onChange, onRemoveListField, onReset, onSubmit, + removeField, reorderDiffRow, reorderRow, resetProps, @@ -103,6 +109,14 @@ function SettingViewModel({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [didDrop]); + const getAttributes = useCallback(() => { + return get(modifiedData, ['schema', 'attributes'], {}); + }, [modifiedData]); + + const getEditLayout = useCallback(() => { + return get(modifiedData, ['layouts', 'edit'], []); + }, [modifiedData]); + if (isLoading) { return ; } @@ -135,8 +149,22 @@ function SettingViewModel({ }, ]; }; + const getListDisplayedFields = () => get(modifiedData, ['layouts', 'list'], []); + const getEditRemainingFields = () => { + const attributes = getAttributes(); + const displayedFields = getEditLayout().reduce( + (acc, curr) => [...acc, ...curr.rowContent], + [] + ); + + return Object.keys(attributes) + .filter(attr => get(attributes, [attr, 'type'], '') !== 'relation') + .filter(attr => { + return displayedFields.findIndex(el => el.name === attr) === -1; + }); + }; const getListRemainingFields = () => { const metadata = get(modifiedData, ['metadata'], {}); @@ -179,7 +207,15 @@ function SettingViewModel({ }; return ( - <> + goBack()} />
@@ -262,14 +298,7 @@ function SettingViewModel({ /> )} - {settingType === 'edit-settings' && ( - - )} + {settingType === 'edit-settings' && } @@ -302,7 +331,7 @@ function SettingViewModel({ popUpWarningType="danger" onConfirm={() => onSubmit(name, emitEvent)} /> - + ); } @@ -327,10 +356,12 @@ SettingViewModel.propTypes = { modifiedData: PropTypes.object.isRequired, moveListField: PropTypes.func.isRequired, moveRow: PropTypes.func.isRequired, + onAddData: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, onRemoveListField: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired, + removeField: PropTypes.func.isRequired, reorderDiffRow: PropTypes.func.isRequired, reorderRow: PropTypes.func.isRequired, resetProps: PropTypes.func.isRequired, @@ -348,10 +379,12 @@ export function mapDispatchToProps(dispatch) { getData, moveListField, moveRow, + onAddData, onChange, onRemoveListField, onReset, onSubmit, + removeField, reorderDiffRow, reorderRow, resetProps, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/reducer.js b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/reducer.js index ab3d72a568..8ecaa6772d 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/reducer.js @@ -12,9 +12,11 @@ import { GET_DATA_SUCCEEDED, MOVE_FIELD_LIST, MOVE_ROW, + ON_ADD_DATA, ON_CHANGE, ON_REMOVE_LIST_FIELD, ON_RESET, + REMOVE_FIELD, REORDER_DIFF_ROW, REORDER_ROW, RESET_PROPS, @@ -31,6 +33,21 @@ export const initialState = fromJS({ shouldToggleModalSubmit: true, }); +const getSize = type => { + switch (type) { + case 'boolean': + case 'date': + case 'datetime': + return 4; + case 'json': + case 'group': + case 'WYSIWYG': + return 12; + default: + return 6; + } +}; + function settingViewModelReducer(state = initialState, action) { const layoutPath = ['modifiedData', 'layouts', 'edit']; const { dragIndex, hoverIndex, dragRowIndex, hoverRowIndex } = action; @@ -66,6 +83,32 @@ function settingViewModelReducer(state = initialState, action) { .delete(dragRowIndex) .insert(hoverRowIndex, state.getIn([...layoutPath, dragRowIndex])); }); + case ON_ADD_DATA: { + const size = getSize( + state.getIn([ + 'modifiedData', + 'schema', + 'attributes', + action.name, + 'type', + ]) + ); + const listSize = state.getIn(layoutPath).size; + const newList = state + .getIn(layoutPath) + .updateIn([listSize - 1, 'rowContent'], list => { + return list.push({ + name: action.name, + size, + }); + }); + const formattedList = formatLayout(newList.toJS()); + + // NOTE we could use the diddrop part here but it causes an unecessary rerender... + // NOTE2: it would be great later to remove the didDrop key that is used to reformat the layout with the _TEMP_ divs + + return state.updateIn(layoutPath, () => fromJS(formattedList)); + } case ON_CHANGE: return state.updateIn(action.keys, () => action.value); @@ -98,6 +141,25 @@ function settingViewModelReducer(state = initialState, action) { return state .update('modifiedData', () => state.get('initialData')) .update('listFieldToEditIndex', () => 0); + case REMOVE_FIELD: { + const row = state.getIn([...layoutPath, action.rowIndex, 'rowContent']); + + // Delete the entire row if length is one or if lenght is equal to 2 and the second element is the hidden div used to make the dnd exp smoother + if ( + row.size === 1 || + (row.size == 2 && row.getIn([1, 'name']) === '_TEMP_') + ) { + return state + .updateIn(layoutPath, list => list.delete(action.rowIndex)) + .update('didDrop', v => !v); + } + return state + .updateIn([...layoutPath, action.rowIndex, 'rowContent'], list => + list.delete(action.fieldIndex) + ) + .update('didDrop', v => !v); + } + case REORDER_DIFF_ROW: return state .updateIn([...layoutPath, dragRowIndex, 'rowContent'], list => { diff --git a/packages/strapi-plugin-content-manager/admin/src/contexts/LayoutDnd/index.js b/packages/strapi-plugin-content-manager/admin/src/contexts/LayoutDnd/index.js new file mode 100644 index 0000000000..5b9574abfd --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/contexts/LayoutDnd/index.js @@ -0,0 +1,53 @@ +import React, { createContext, useContext } from 'react'; +import PropTypes from 'prop-types'; + +const LayoutDndContext = createContext(); + +export function LayoutDndProvider({ + attributes, + buttonData, + children, + layout, + moveItem, + moveRow, + onAddData, + removeField, +}) { + return ( + + {children} + + ); +} + +export function useLayoutDnd() { + return useContext(LayoutDndContext); +} + +LayoutDndProvider.defaultProps = { + attributes: {}, + buttonData: [], + layout: [], + onAddData: () => {}, +}; + +LayoutDndProvider.propTypes = { + attributes: PropTypes.object, + buttonData: PropTypes.array, + children: PropTypes.node.isRequired, + layout: PropTypes.array, + moveItem: PropTypes.func.isRequired, + moveRow: PropTypes.func.isRequired, + onAddData: PropTypes.func, + removeField: PropTypes.func.isRequired, +};