Merge branch 'ctm/repeatable-list-view' of github.com:strapi/strapi into ctm/repeatable-list-view

This commit is contained in:
soupette 2019-07-12 14:12:24 +02:00
commit d0ee52fdcc
7 changed files with 148 additions and 149 deletions

View File

@ -43,6 +43,8 @@ module.exports = {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/fileTransformer.js', '<rootDir>/fileTransformer.js',
}, },
transformIgnorePatterns: ['node_modules/(?!(react-dnd|dnd-core|react-dnd-html5-backend)/)'], transformIgnorePatterns: [
'node_modules/(?!(react-dnd|dnd-core|react-dnd-html5-backend)/)',
],
testURL: 'http://localhost:4000/admin', testURL: 'http://localhost:4000/admin',
}; };

View File

@ -1,6 +1,5 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, InfoLabel } from './components';
import { DragSource, DropTarget } from 'react-dnd'; import { DragSource, DropTarget } from 'react-dnd';
import GrabIcon from '../../assets/images/icon_grab.svg'; import GrabIcon from '../../assets/images/icon_grab.svg';
@ -8,6 +7,7 @@ import GrabIconBlue from '../../assets/images/icon_grab_blue.svg';
import ClickOverHint from '../../components/ClickOverHint'; import ClickOverHint from '../../components/ClickOverHint';
import RemoveIcon from '../../components/DraggedRemovedIcon'; import RemoveIcon from '../../components/DraggedRemovedIcon';
import EditIcon from '../../components/VariableEditIcon'; import EditIcon from '../../components/VariableEditIcon';
import { Field, InfoLabel } from './components';
import ItemTypes from './itemsTypes'; import ItemTypes from './itemsTypes';
@ -33,34 +33,32 @@ function ListField({
connectDropTarget(ref); connectDropTarget(ref);
return ( return (
<> <Field
<Field onMouseEnter={() => setIsOver(true)}
onMouseEnter={() => setIsOver(true)} onMouseLeave={() => setIsOver(false)}
onMouseLeave={() => setIsOver(false)} onClick={() => {
onClick={() => { onClick(index);
onClick(index); }}
}} ref={ref}
ref={ref} isSelected={isSelected}
isSelected={isSelected} style={{ opacity }}
style={{ opacity }} >
> <img src={isSelected ? GrabIconBlue : GrabIcon} />
<img src={isSelected ? GrabIconBlue : GrabIcon} /> <span>{name}</span>
<span>{name}</span> <ClickOverHint show={isOver && !isSelected} />
<ClickOverHint show={isOver && !isSelected} /> {showLabel && <InfoLabel>{label}</InfoLabel>}
{showLabel && <InfoLabel>{label}</InfoLabel>} {isSelected && !isOver ? (
{isSelected && !isOver ? ( <EditIcon />
<EditIcon /> ) : (
) : ( <RemoveIcon
<RemoveIcon isDragging={isSelected && isOver}
isDragging={isSelected && isOver} onRemove={e => {
onRemove={e => { e.stopPropagation();
e.stopPropagation(); onRemove(index);
onRemove(index); }}
}} />
/> )}
)} </Field>
</Field>
</>
); );
} }

View File

@ -93,7 +93,7 @@ function ListLayout({
<div className="col-lg-5 col-md-12" ref={ref}> <div className="col-lg-5 col-md-12" ref={ref}>
{displayedData.map((data, index) => ( {displayedData.map((data, index) => (
<Fragment key={data}> <Fragment key={data}>
<Wrapper style={{ display: 'flex' }}> <Wrapper>
<div>{index + 1}.</div> <div>{index + 1}.</div>
<ListField <ListField
findField={findField} findField={findField}

View File

@ -52,7 +52,7 @@ const InfoLabel = styled.div`
position: absolute; position: absolute;
top: 0; top: 0;
right: 40px; right: 40px;
// color: #858b9a;
font-weight: 400; font-weight: 400;
color: #007eff; color: #007eff;
`; `;

View File

@ -134,124 +134,119 @@ function SettingViewModel({
}; };
return ( return (
<> <DndProvider backend={HTML5Backend}>
<DndProvider backend={HTML5Backend}> <BackHeader onClick={() => goBack()} />
<BackHeader onClick={() => goBack()} /> <Container className="container-fluid">
<Container className="container-fluid"> <PluginHeader
<PluginHeader actions={getPluginHeaderActions()}
actions={getPluginHeaderActions()} title={{
title={{ id: `${pluginId}.containers.SettingViewModel.pluginHeader.title`,
id: `${pluginId}.containers.SettingViewModel.pluginHeader.title`, values: { name: upperFirst(name) },
values: { name: upperFirst(name) }, }}
description={{
id:
'content-manager.containers.SettingPage.pluginHeaderDescription',
}}
/>
<HeaderNav
links={[
{
name: 'content-manager.containers.SettingPage.listSettings.title',
to: getUrl(name, 'list-settings'),
},
{
name: 'content-manager.containers.SettingPage.editSettings.title',
to: getUrl(name, 'edit-settings'),
},
]}
/>
<div className="row">
<Block
style={{
marginBottom: '13px',
paddingBottom: '30px',
paddingTop: '30px',
}} }}
description={{ >
id: <SectionTitle isSettings />
'content-manager.containers.SettingPage.pluginHeaderDescription', <div className="row">
}} {forms[settingType].map(input => {
/> return (
<HeaderNav <Input
links={[ key={input.name}
{ {...input}
name:
'content-manager.containers.SettingPage.listSettings.title',
to: getUrl(name, 'list-settings'),
},
{
name:
'content-manager.containers.SettingPage.editSettings.title',
to: getUrl(name, 'edit-settings'),
},
]}
/>
<div className="row">
<Block
style={{
marginBottom: '13px',
paddingBottom: '30px',
paddingTop: '30px',
}}
>
<SectionTitle isSettings />
<div className="row">
{forms[settingType].map(input => {
return (
<Input
key={input.name}
{...input}
onChange={onChange}
selectOptions={getSelectOptions(input)}
value={get(modifiedData, input.name)}
/>
);
})}
<div className="col-12">
<Separator />
</div>
</div>
<SectionTitle />
<div className="row">
<LayoutTitle className="col-12">
<FormTitle
title={`${pluginId}.global.displayedFields`}
description={`${pluginId}.containers.SettingPage.${
settingType === 'list-settings'
? 'attributes'
: 'editSettings'
}.description`}
/>
</LayoutTitle>
{settingType === 'list-settings' && (
<ListLayout
addField={addFieldToList}
displayedData={getListDisplayedFields()}
availableData={getListRemainingFields()}
fieldToEditIndex={listFieldToEditIndex}
modifiedData={modifiedData}
moveListField={moveListField}
onClick={setListFieldToEditIndex}
onChange={onChange} onChange={onChange}
onRemove={onRemoveListField} selectOptions={getSelectOptions(input)}
value={get(modifiedData, input.name)}
/> />
)} );
})}
<div className="col-12">
<Separator />
</div> </div>
</Block> </div>
</div> <SectionTitle />
</Container>
<PopUpWarning <div className="row">
isOpen={showWarningCancel} <LayoutTitle className="col-12">
toggleModal={toggleWarningCancel} <FormTitle
content={{ title={`${pluginId}.global.displayedFields`}
title: 'content-manager.popUpWarning.title', description={`${pluginId}.containers.SettingPage.${
message: 'content-manager.popUpWarning.warning.cancelAllSettings', settingType === 'list-settings'
cancel: 'content-manager.popUpWarning.button.cancel', ? 'attributes'
confirm: 'content-manager.popUpWarning.button.confirm', : 'editSettings'
}} }.description`}
popUpWarningType="danger" />
onConfirm={() => { </LayoutTitle>
onReset();
toggleWarningCancel(); {settingType === 'list-settings' && (
}} <ListLayout
/> addField={addFieldToList}
<PopUpWarning displayedData={getListDisplayedFields()}
isOpen={showWarningSubmit} availableData={getListRemainingFields()}
toggleModal={toggleWarningSubmit} fieldToEditIndex={listFieldToEditIndex}
content={{ modifiedData={modifiedData}
title: 'content-manager.popUpWarning.title', moveListField={moveListField}
message: 'content-manager.popUpWarning.warning.updateAllSettings', onClick={setListFieldToEditIndex}
cancel: 'content-manager.popUpWarning.button.cancel', onChange={onChange}
confirm: 'content-manager.popUpWarning.button.confirm', onRemove={onRemoveListField}
}} />
popUpWarningType="danger" )}
onConfirm={() => onSubmit(name, emitEvent)} </div>
/> </Block>
</DndProvider> </div>
</> </Container>
<PopUpWarning
isOpen={showWarningCancel}
toggleModal={toggleWarningCancel}
content={{
title: 'content-manager.popUpWarning.title',
message: 'content-manager.popUpWarning.warning.cancelAllSettings',
cancel: 'content-manager.popUpWarning.button.cancel',
confirm: 'content-manager.popUpWarning.button.confirm',
}}
popUpWarningType="danger"
onConfirm={() => {
onReset();
toggleWarningCancel();
}}
/>
<PopUpWarning
isOpen={showWarningSubmit}
toggleModal={toggleWarningSubmit}
content={{
title: 'content-manager.popUpWarning.title',
message: 'content-manager.popUpWarning.warning.updateAllSettings',
cancel: 'content-manager.popUpWarning.button.cancel',
confirm: 'content-manager.popUpWarning.button.confirm',
}}
popUpWarningType="danger"
onConfirm={() => onSubmit(name, emitEvent)}
/>
</DndProvider>
); );
} }
SettingViewModel.defaultProps = {};
SettingViewModel.propTypes = { SettingViewModel.propTypes = {
addFieldToList: PropTypes.func.isRequired, addFieldToList: PropTypes.func.isRequired,
emitEvent: PropTypes.func.isRequired, emitEvent: PropTypes.func.isRequired,

View File

@ -36,11 +36,15 @@ function settingViewModelReducer(state = initialState, action) {
.update('isLoading', () => false) .update('isLoading', () => false)
.update('modifiedData', () => fromJS(action.layout)); .update('modifiedData', () => fromJS(action.layout));
case MOVE_FIELD_LIST: case MOVE_FIELD_LIST:
return state.updateIn(['modifiedData', 'layouts', 'list'], list => { return state
return list .updateIn(['modifiedData', 'layouts', 'list'], list => {
.delete(action.dragIndex) return list
.insert(action.overIndex, list.get(action.dragIndex)); .delete(action.dragIndex)
}); .insert(action.overIndex, list.get(action.dragIndex));
})
.update('listFieldToEditIndex', () => {
return action.overIndex;
});
case ON_CHANGE: case ON_CHANGE:
return state.updateIn(action.keys, () => action.value); return state.updateIn(action.keys, () => action.value);
case ON_REMOVE_LIST_FIELD: { case ON_REMOVE_LIST_FIELD: {

View File

@ -126,5 +126,5 @@
"popUpWarning.warning.updateAllSettings": "Cela modifiera tous vos précédents paramètres.", "popUpWarning.warning.updateAllSettings": "Cela modifiera tous vos précédents paramètres.",
"success.record.delete": "Supprimé", "success.record.delete": "Supprimé",
"success.record.save": "Sauvegardé", "success.record.save": "Sauvegardé",
"notification.info.minimumFields": "Vous devez avoir au moins un champs d'affiché" "notification.info.minimumFields": "Vous devez avoir au moins un champ d'affiché"
} }