mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 18:33:55 +00:00
Handle add attributes to content type
This commit is contained in:
parent
7bf1f3183c
commit
28f35f678b
@ -8,6 +8,7 @@ import React from 'react';
|
||||
import { isEmpty, startCase } from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { router } from 'app';
|
||||
import Button from 'components/Button';
|
||||
import styles from './styles.scss';
|
||||
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
@ -16,20 +17,35 @@ class ContentHeader extends React.Component { // eslint-disable-line react/prefe
|
||||
router.push(this.props.editPath);
|
||||
}
|
||||
|
||||
renderButtonContainer = () => (
|
||||
<div className={styles.buttonContainer}>
|
||||
<FormattedMessage id="form.button.cancel">
|
||||
{(message) => (
|
||||
<Button type="button" label={message} buttonSize={"buttonMd"} buttonBackground={"secondary"} onClick={this.props.handleCancel} />
|
||||
)}
|
||||
</FormattedMessage>
|
||||
<FormattedMessage id="form.button.save">
|
||||
{(message) => (
|
||||
<Button type="submit" label={message} buttonSize={"buttonLg"} buttonBackground={"primary"} onClick={this.props.handleSubmit} />
|
||||
)}
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
)
|
||||
|
||||
renderContentHeader = () => {
|
||||
const containerClass = this.props.noMargin ? styles.contentHeaderNoMargin : styles.contentHeader;
|
||||
const editIcon = this.props.editIcon ?
|
||||
<i className="fa fa-pencil" onClick={this.edit} role="button" />
|
||||
: '';
|
||||
|
||||
const description = this.props.description || <FormattedMessage id="modelPage.contentHeader.emptyDescription.description" />
|
||||
const description = this.props.description || <FormattedMessage id="modelPage.contentHeader.emptyDescription.description" />;
|
||||
const buttons = this.props.addButtons ? this.renderButtonContainer() : '';
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
<div className={`${styles.title} ${styles.flex}`}>
|
||||
<span>{startCase(this.props.name)}</span>
|
||||
{editIcon}
|
||||
<div>
|
||||
<div className={`${styles.title} ${styles.flex}`}>
|
||||
<span>{startCase(this.props.name)}</span>
|
||||
<i className={`fa fa-${this.props.icoType}`} onClick={this.edit} role="button" />
|
||||
</div>
|
||||
<div className={styles.subTitle}>{description}</div>
|
||||
</div>
|
||||
<div className={styles.subTitle}>{description}</div>
|
||||
{buttons}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -37,25 +53,32 @@ class ContentHeader extends React.Component { // eslint-disable-line react/prefe
|
||||
render() {
|
||||
const containerClass = this.props.noMargin ? styles.contentHeaderNoMargin : styles.contentHeader;
|
||||
const description = isEmpty(this.props.description) ? '' : <FormattedMessage id={this.props.description} />;
|
||||
const buttons = this.props.addButtons ? this.renderButtonContainer() : '';
|
||||
|
||||
if (this.props.noI18n) return this.renderContentHeader();
|
||||
if (this.props.editIcon) return this.renderContentHeader();
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
<div className={styles.title}>
|
||||
<FormattedMessage id={this.props.name} />
|
||||
<div>
|
||||
<div className={styles.title}>
|
||||
<FormattedMessage id={this.props.name} />
|
||||
</div>
|
||||
<div className={styles.subTitle}>{description}</div>
|
||||
</div>
|
||||
<div className={styles.subTitle}>{description}</div>
|
||||
{buttons}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ContentHeader.propTypes = {
|
||||
addButtons: React.PropTypes.bool,
|
||||
description: React.PropTypes.string,
|
||||
editIcon: React.PropTypes.bool,
|
||||
editPath: React.PropTypes.string,
|
||||
handleCancel: React.PropTypes.func,
|
||||
handleSubmit: React.PropTypes.func,
|
||||
icoType: React.PropTypes.string,
|
||||
name: React.PropTypes.string,
|
||||
noI18n: React.PropTypes.bool,
|
||||
noMargin: React.PropTypes.bool,
|
||||
};
|
||||
|
||||
|
||||
@ -2,12 +2,16 @@
|
||||
position: relative;
|
||||
margin: 2.4rem 0rem 3.3rem 0rem;
|
||||
font-family: Lato;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.contentHeaderNoMargin {
|
||||
position: relative;
|
||||
margin-bottom: 3.2rem;
|
||||
font-family: Lato;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.title {
|
||||
@ -46,3 +50,9 @@
|
||||
}
|
||||
// color: #101622;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
> button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
MODELS_FETCH,
|
||||
MODELS_FETCH_SUCCEEDED,
|
||||
STORE_TEMPORARY_MENU,
|
||||
TEMPORARY_CONTENT_TYPE_POSTED,
|
||||
} from './constants';
|
||||
|
||||
export function deleteContentType(itemToDelete) {
|
||||
@ -90,3 +91,9 @@ export function storeTemporaryMenu(newMenu, position, nbElementToRemove) {
|
||||
nbElementToRemove,
|
||||
};
|
||||
}
|
||||
|
||||
export function temporaryContentTypePosted() {
|
||||
return {
|
||||
type: TEMPORARY_CONTENT_TYPE_POSTED,
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,3 +8,4 @@ export const DELETE_CONTENT_TYPE = 'ContentTypeBuilder/App/DELETE_CONTENT_TYPE';
|
||||
export const MODELS_FETCH = 'ContentTypeBuilder/App/MODELS_FETCH';
|
||||
export const MODELS_FETCH_SUCCEEDED = 'ContentTypeBuilder/App/MODELS_FETCH_SUCCEEDED';
|
||||
export const STORE_TEMPORARY_MENU = 'ContentTypeBuilder/App/STORE_TEMPORARY_MENU';
|
||||
export const TEMPORARY_CONTENT_TYPE_POSTED = 'ContentTypeBuilder/App/TEMPORARY_CONTENT_TYPE_POSTED';
|
||||
|
||||
@ -21,6 +21,7 @@ import messages from '../../translations/en.json';
|
||||
|
||||
import styles from './styles.scss';
|
||||
import { modelsFetch } from './actions';
|
||||
import { makeSelectMenu } from './selectors';
|
||||
|
||||
define(map(messages, (message, id) => ({
|
||||
id,
|
||||
@ -50,12 +51,13 @@ class App extends React.Component {
|
||||
const content = React.Children.map(this.props.children, child =>
|
||||
React.cloneElement(child, {
|
||||
exposedComponents: this.props.exposedComponents,
|
||||
menu: this.props.menu,
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={`${pluginId} ${styles.app}`}>
|
||||
{React.Children.toArray(content)}
|
||||
{React.Children.toArray(content, 'fuck')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -68,6 +70,7 @@ App.contextTypes = {
|
||||
App.propTypes = {
|
||||
children: React.PropTypes.node,
|
||||
exposedComponents: React.PropTypes.object.isRequired,
|
||||
menu: React.PropTypes.array,
|
||||
modelsFetch: React.PropTypes.func,
|
||||
shouldRefetchContentType: React.PropTypes.bool,
|
||||
};
|
||||
@ -82,6 +85,7 @@ export function mapDispatchToProps(dispatch) {
|
||||
}
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
menu: makeSelectMenu(),
|
||||
shouldRefetchContentType: makeSelectShouldRefetchContentType(),
|
||||
});
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
MODELS_FETCH,
|
||||
MODELS_FETCH_SUCCEEDED,
|
||||
STORE_TEMPORARY_MENU,
|
||||
TEMPORARY_CONTENT_TYPE_POSTED,
|
||||
} from './constants';
|
||||
|
||||
/* eslint-disable new-cap */
|
||||
@ -39,6 +40,13 @@ function appReducer(state = initialState, action) {
|
||||
.updateIn(['menu', '0', 'items'], (list) => list.splice(action.position, action.nbElementToRemove, action.newLink))
|
||||
.update('models', array => array.splice(action.nbElementToRemove === 0 ? modelsSize : modelsSize - 1 , 1, action.newModel));
|
||||
}
|
||||
case TEMPORARY_CONTENT_TYPE_POSTED: {
|
||||
const oldMenuItem = state.getIn(['menu', '0', 'items', size(state.getIn(['menu', '0', 'items']).toJS()) -2]);
|
||||
oldMenuItem.isTemporary = false;
|
||||
const newData = oldMenuItem;
|
||||
return state
|
||||
.updateIn(['menu', '0', 'items', size(state.getIn(['menu', '0', 'items']).toJS()) -2], () => newData);
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -34,14 +34,9 @@ export function* fetchModels() {
|
||||
|
||||
// Individual exports for testing
|
||||
export function* defaultSaga() {
|
||||
// TODO check if problems
|
||||
yield fork(takeLatest, MODELS_FETCH, fetchModels);
|
||||
yield fork(takeLatest, DELETE_CONTENT_TYPE, deleteContentType);
|
||||
// const loadModelsWatcher = yield fork(takeLatest, MODELS_FETCH, fetchModels);
|
||||
yield fork(takeLatest, MODELS_FETCH, fetchModels);
|
||||
|
||||
// Suspend execution until location changes
|
||||
// yield take(MODELS_FETCH_SUCCEEDED);
|
||||
// yield cancel(loadModelsWatcher);
|
||||
}
|
||||
|
||||
// All sagas to be loaded
|
||||
|
||||
@ -21,6 +21,7 @@ import {
|
||||
CONTENT_TYPE_FETCH,
|
||||
CONTENT_TYPE_FETCH_SUCCEEDED,
|
||||
RESET_DID_FETCH_MODEL_PROP,
|
||||
RESET_IS_FORM_SET,
|
||||
SET_ATTRIBUTE_FORM,
|
||||
SET_FORM,
|
||||
} from './constants';
|
||||
@ -112,6 +113,12 @@ export function resetDidFetchModelProp() {
|
||||
};
|
||||
}
|
||||
|
||||
export function resetIsFormSet() {
|
||||
return {
|
||||
type: RESET_IS_FORM_SET,
|
||||
};
|
||||
}
|
||||
|
||||
export function setAttributeForm(hash) {
|
||||
const hashArray = hash.split('::');
|
||||
const formType = replace(hashArray[1], 'attribute', '');
|
||||
@ -122,10 +129,10 @@ export function setAttributeForm(hash) {
|
||||
name: '',
|
||||
params: Map({
|
||||
type: formType,
|
||||
required: false,
|
||||
required: true,
|
||||
// TODO remove with correct value
|
||||
minLength: true,
|
||||
minLengthValue: 0,
|
||||
// minLength: true,
|
||||
// minLengthValue: 0,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -14,5 +14,6 @@ export const CONTENT_TYPE_EDIT = 'ContentTypeBuilder/Form/CONTENT_TYPE_EDIT';
|
||||
export const CONTENT_TYPE_FETCH = 'ContentTypeBuilder/Form/CONTENT_TYPE_FETCH';
|
||||
export const CONTENT_TYPE_FETCH_SUCCEEDED = 'ContentTypeBuilder/Form/CONTENT_TYPE_FETCH_SUCCEEDED';
|
||||
export const RESET_DID_FETCH_MODEL_PROP = 'ContentTypeBuilder/Form/RESET_DID_FETCH_MODEL_PROP';
|
||||
export const RESET_IS_FORM_SET = 'ContentTypeBuilder/Form/RESET_IS_FORM_SET';
|
||||
export const SET_ATTRIBUTE_FORM = 'ContentTypeBuilder/Form/SET_ATTRIBUTE_FORM';
|
||||
export const SET_FORM = 'ContentTypeBuilder/Form/SET_FORM';
|
||||
|
||||
@ -23,7 +23,7 @@ import {
|
||||
import { router, store } from 'app';
|
||||
|
||||
import { storeTemporaryMenu } from 'containers/App/actions';
|
||||
|
||||
import { addAttributeToContentType } from 'containers/ModelPage/actions';
|
||||
import AttributeCard from 'components/AttributeCard';
|
||||
import InputCheckboxWithNestedInputs from 'components/InputCheckboxWithNestedInputs';
|
||||
import PopUpForm from 'components/PopUpForm';
|
||||
@ -44,6 +44,7 @@ import {
|
||||
contentTypeFetch,
|
||||
contentTypeFetchSucceeded,
|
||||
resetDidFetchModelProp,
|
||||
resetIsFormSet,
|
||||
setAttributeForm,
|
||||
setForm,
|
||||
} from './actions';
|
||||
@ -100,6 +101,13 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
||||
}
|
||||
}
|
||||
|
||||
addAttributeToContentType = () => {
|
||||
this.props.addAttributeToContentType(this.props.modifiedDataAttribute);
|
||||
// this.props.resetDidFetchModelProp();
|
||||
this.props.resetIsFormSet();
|
||||
router.push(`${this.props.redirectRoute}/${replace(this.props.hash.split('::')[0], '#create', '')}`);
|
||||
}
|
||||
|
||||
addAttributeToTempContentType = () => {
|
||||
const contentType = this.props.modifiedDataEdit;
|
||||
contentType.attributes.push(this.props.modifiedDataAttribute);
|
||||
@ -209,6 +217,8 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
||||
this.testContentType(
|
||||
replace(split(this.props.hash, '::')[0], '#create', ''),
|
||||
this.addAttributeToTempContentType,
|
||||
null,
|
||||
this.addAttributeToContentType,
|
||||
);
|
||||
} else {
|
||||
this.createContentType(this.props.modifiedData);
|
||||
@ -263,7 +273,7 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
||||
this.props.toggle();
|
||||
// Set the didFetchModel props to false when the modal is closing so the store is emptied
|
||||
if (this.state.showModal) {
|
||||
this.props.resetDidFetchModelProp();
|
||||
this.props.resetIsFormSet();
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,6 +337,7 @@ const mapStateToProps = selectForm();
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return bindActionCreators(
|
||||
{
|
||||
addAttributeToContentType,
|
||||
changeInput,
|
||||
changeInputAttribute,
|
||||
connectionsFetch,
|
||||
@ -335,6 +346,7 @@ function mapDispatchToProps(dispatch) {
|
||||
contentTypeFetch,
|
||||
contentTypeFetchSucceeded,
|
||||
resetDidFetchModelProp,
|
||||
resetIsFormSet,
|
||||
setAttributeForm,
|
||||
setForm,
|
||||
storeTemporaryMenu,
|
||||
@ -344,6 +356,7 @@ function mapDispatchToProps(dispatch) {
|
||||
}
|
||||
|
||||
Form.propTypes = {
|
||||
addAttributeToContentType: React.PropTypes.func,
|
||||
changeInput: React.PropTypes.func.isRequired,
|
||||
changeInputAttribute: React.PropTypes.func,
|
||||
connectionsFetch: React.PropTypes.func.isRequired,
|
||||
@ -365,6 +378,7 @@ Form.propTypes = {
|
||||
popUpHeaderNavLinks: React.PropTypes.array,
|
||||
redirectRoute: React.PropTypes.string.isRequired,
|
||||
resetDidFetchModelProp: React.PropTypes.func,
|
||||
resetIsFormSet: React.PropTypes.func,
|
||||
routePath: React.PropTypes.string,
|
||||
selectOptions: React.PropTypes.array,
|
||||
selectOptionsFetchSucceeded: React.PropTypes.bool,
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
CONTENT_TYPE_CREATE,
|
||||
CONTENT_TYPE_FETCH_SUCCEEDED,
|
||||
RESET_DID_FETCH_MODEL_PROP,
|
||||
RESET_IS_FORM_SET,
|
||||
SET_ATTRIBUTE_FORM,
|
||||
SET_FORM,
|
||||
} from './constants';
|
||||
@ -67,6 +68,8 @@ function formReducer(state = initialState, action) {
|
||||
return state
|
||||
.set('didFetchModel', true)
|
||||
.set('isFormSet', false);
|
||||
case RESET_IS_FORM_SET:
|
||||
return state.set('isFormSet', false);
|
||||
case SET_ATTRIBUTE_FORM: {
|
||||
if (state.get('isFormSet')) {
|
||||
return state.set('form', Map(action.form));
|
||||
|
||||
@ -7,12 +7,29 @@ import { get } from 'lodash';
|
||||
import { storeData } from '../../utils/storeData';
|
||||
|
||||
import {
|
||||
ADD_ATTRIBUTE_TO_CONTENT_TYPE,
|
||||
CANCEL_CHANGES,
|
||||
DEFAULT_ACTION,
|
||||
DELETE_ATTRIBUTE,
|
||||
MODEL_FETCH,
|
||||
MODEL_FETCH_SUCCEEDED,
|
||||
POST_CONTENT_TYPE_SUCCEEDED,
|
||||
SUBMIT,
|
||||
} from './constants';
|
||||
|
||||
export function addAttributeToContentType(newAttribute) {
|
||||
return {
|
||||
type: ADD_ATTRIBUTE_TO_CONTENT_TYPE,
|
||||
newAttribute,
|
||||
};
|
||||
}
|
||||
|
||||
export function cancelChanges() {
|
||||
return {
|
||||
type: CANCEL_CHANGES,
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteAttribute(position, modelName) {
|
||||
const temporaryContentType = storeData.getContentType();
|
||||
let sendRequest = true;
|
||||
@ -50,3 +67,15 @@ export function modelFetchSucceeded(model) {
|
||||
model,
|
||||
};
|
||||
}
|
||||
|
||||
export function postContentTypeSucceeded() {
|
||||
return {
|
||||
type: POST_CONTENT_TYPE_SUCCEEDED,
|
||||
};
|
||||
}
|
||||
|
||||
export function submit() {
|
||||
return {
|
||||
type: SUBMIT,
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
export const ADD_ATTRIBUTE_TO_CONTENT_TYPE = 'ContentTypeBuilder/ModelPage/ADD_ATTRIBUTE_TO_CONTENT_TYPE';
|
||||
export const CANCEL_CHANGES = 'ContentTypeBuilder/ModelPage/CANCEL_CHANGES';
|
||||
export const DEFAULT_ACTION = 'ContentTypeBuilder/ModelPage/DEFAULT_ACTION';
|
||||
export const DELETE_ATTRIBUTE = 'ContentTypeBuilder/ModelPage/DELETE_ATTRIBUTE';
|
||||
export const MODEL_FETCH = 'ContentTypeBuilder/ModelPage/MODEL_FETCH';
|
||||
export const MODEL_FETCH_SUCCEEDED = 'ContentTypeBuilder/ModelPage/MODEL_FETCH_SUCCEEDED';
|
||||
export const POST_CONTENT_TYPE_SUCCEEDED = 'ContentTypeBuilder/ModelPage/POST_CONTENT_TYPE_SUCCEEDED';
|
||||
export const SUBMIT = 'ContentTypeBuilder/ModelPage/SUBMIT';
|
||||
|
||||
@ -14,7 +14,6 @@ import { Link } from 'react-router';
|
||||
import { router } from 'app';
|
||||
|
||||
// Global selectors
|
||||
import { makeSelectMenu } from 'containers/App/selectors';
|
||||
import { makeSelectDidFetchModel } from 'containers/Form/selectors';
|
||||
|
||||
import AttributeRow from 'components/AttributeRow';
|
||||
@ -27,9 +26,11 @@ import PluginLeftMenu from 'components/PluginLeftMenu';
|
||||
import { storeData } from '../../utils/storeData';
|
||||
|
||||
import {
|
||||
cancelChanges,
|
||||
deleteAttribute,
|
||||
modelFetch,
|
||||
modelFetchSucceeded,
|
||||
submit,
|
||||
} from './actions';
|
||||
|
||||
import selectModelPage from './selectors';
|
||||
@ -88,11 +89,6 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
|
||||
</div>
|
||||
)
|
||||
|
||||
handleEditAttribute = (attributeName) => {
|
||||
const index = findIndex(this.props.modelPage.model.attributes, ['name', attributeName]);
|
||||
console.log(index);
|
||||
}
|
||||
|
||||
fetchModel = () => {
|
||||
if (storeData.getIsModelTemporary() && get(storeData.getContentType(), 'name') === this.props.params.modelName) {
|
||||
this.props.modelFetchSucceeded({ model: storeData.getContentType() });
|
||||
@ -118,6 +114,12 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
|
||||
this.props.deleteAttribute(index, this.props.params.modelName);
|
||||
}
|
||||
|
||||
handleEditAttribute = (attributeName) => {
|
||||
const index = findIndex(this.props.modelPage.model.attributes, ['name', attributeName]);
|
||||
console.log(index);
|
||||
}
|
||||
|
||||
|
||||
toggleModal = () => {
|
||||
const locationHash = this.props.location.hash ? '' : '#create::contentType::baseSettings';
|
||||
router.push(`plugins/content-type-builder/models/${this.props.params.modelName}${locationHash}`);
|
||||
@ -185,6 +187,8 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
|
||||
render() {
|
||||
// Url to redirects the user if he modifies the temporary content type name
|
||||
const redirectRoute = replace(this.props.route.path, '/:modelName', '');
|
||||
const addButtons = size(get(this.props.modelPage.model, 'attributes')) > 0;
|
||||
|
||||
const content = size(this.props.modelPage.model.attributes) === 0 ?
|
||||
<EmptyAttributesView handleClick={this.handleClickAddAttribute} /> :
|
||||
<List
|
||||
@ -194,7 +198,6 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
|
||||
renderCustomLi={this.renderCustomLi}
|
||||
handleButtonClick={this.handleClickAddAttribute}
|
||||
/>;
|
||||
|
||||
return (
|
||||
<div className={styles.modelPage}>
|
||||
<div className="container-fluid">
|
||||
@ -209,9 +212,12 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
|
||||
<ContentHeader
|
||||
name={this.props.modelPage.model.name}
|
||||
description={this.props.modelPage.model.description}
|
||||
noI18n
|
||||
icoType="pencil"
|
||||
editIcon
|
||||
editPath={`${redirectRoute}/${this.props.params.modelName}#edit${this.props.params.modelName}::contentType::baseSettings`}
|
||||
addButtons={addButtons}
|
||||
handleSubmit={this.props.submit}
|
||||
handleCancel={this.props.cancelChanges}
|
||||
/>
|
||||
{content}
|
||||
</div>
|
||||
@ -234,22 +240,24 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
modelPage: selectModelPage(),
|
||||
menu: makeSelectMenu(),
|
||||
didFetchModel: makeSelectDidFetchModel(),
|
||||
});
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return bindActionCreators(
|
||||
{
|
||||
cancelChanges,
|
||||
deleteAttribute,
|
||||
modelFetch,
|
||||
modelFetchSucceeded,
|
||||
submit,
|
||||
},
|
||||
dispatch,
|
||||
);
|
||||
}
|
||||
|
||||
ModelPage.propTypes = {
|
||||
cancelChanges: React.PropTypes.func,
|
||||
deleteAttribute: React.PropTypes.func,
|
||||
didFetchModel: React.PropTypes.bool,
|
||||
location: React.PropTypes.object,
|
||||
@ -259,6 +267,7 @@ ModelPage.propTypes = {
|
||||
modelPage: React.PropTypes.object,
|
||||
params: React.PropTypes.object,
|
||||
route: React.PropTypes.object,
|
||||
submit: React.PropTypes.func,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ModelPage);
|
||||
|
||||
@ -7,27 +7,40 @@
|
||||
import { fromJS, Map, List } from 'immutable';
|
||||
/* eslint-disable new-cap */
|
||||
import {
|
||||
ADD_ATTRIBUTE_TO_CONTENT_TYPE,
|
||||
CANCEL_CHANGES,
|
||||
DELETE_ATTRIBUTE,
|
||||
MODEL_FETCH_SUCCEEDED,
|
||||
POST_CONTENT_TYPE_SUCCEEDED,
|
||||
} from './constants';
|
||||
|
||||
const initialState = fromJS({
|
||||
initialModel: Map({
|
||||
attributes: List(),
|
||||
}),
|
||||
model: Map({
|
||||
attributes: List(),
|
||||
}),
|
||||
postContentTypeSuccess: false,
|
||||
});
|
||||
|
||||
function modelPageReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case ADD_ATTRIBUTE_TO_CONTENT_TYPE:
|
||||
return state.updateIn(['model', 'attributes'], (list) => list.push(action.newAttribute));
|
||||
case CANCEL_CHANGES:
|
||||
return state.set('model', state.get('initialModel'));
|
||||
case DELETE_ATTRIBUTE:
|
||||
// console.log(action.position);
|
||||
// console.log(state.getIn(['model', 'attributes']))
|
||||
return state
|
||||
.updateIn(['model', 'attributes'], (list) => list.splice(action.position, 1));
|
||||
case MODEL_FETCH_SUCCEEDED:
|
||||
return state
|
||||
.set('model', Map(action.model.model))
|
||||
.setIn(['model', 'attributes'], List(action.model.model.attributes));
|
||||
.set('initialModel', Map(action.model.model))
|
||||
.setIn(['model', 'attributes'], List(action.model.model.attributes))
|
||||
.setIn(['initialModel', 'attributes'], List(action.model.model.attributes));
|
||||
case POST_CONTENT_TYPE_SUCCEEDED:
|
||||
return state.set('postContentTypeSuccess', !state.get('postContentTypeSuccess'));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -1,9 +1,16 @@
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import { get } from 'lodash';
|
||||
import { takeLatest } from 'redux-saga';
|
||||
import { call, take, put, fork, cancel, select } from 'redux-saga/effects';
|
||||
|
||||
import request from 'utils/request';
|
||||
import { DELETE_ATTRIBUTE, MODEL_FETCH } from './constants';
|
||||
import { modelFetchSucceeded } from './actions';
|
||||
|
||||
import { temporaryContentTypePosted } from 'containers/App/actions';
|
||||
|
||||
import { storeData } from '../../utils/storeData';
|
||||
|
||||
import { DELETE_ATTRIBUTE, MODEL_FETCH, SUBMIT } from './constants';
|
||||
import { modelFetchSucceeded, postContentTypeSucceeded } from './actions';
|
||||
import { makeSelectModel } from './selectors';
|
||||
|
||||
// Individual exports for testing
|
||||
@ -37,14 +44,40 @@ export function* fetchModel(action) {
|
||||
}
|
||||
}
|
||||
|
||||
export function* submitChanges() {
|
||||
try {
|
||||
const modelName = get(storeData.getContentType(), 'name');
|
||||
|
||||
const body = yield select(makeSelectModel());
|
||||
|
||||
const method = modelName === body.name ? 'POST' : 'PUT';
|
||||
const baseUrl = '/content-type-builder/models/';
|
||||
const requestUrl = method === 'POST' ? baseUrl : `${baseUrl}${body.name}`;
|
||||
const opts = { method, body };
|
||||
|
||||
yield call(request, requestUrl, opts);
|
||||
|
||||
if (method === 'POST') {
|
||||
storeData.clearAppStorage();
|
||||
yield put(temporaryContentTypePosted());
|
||||
yield put(postContentTypeSucceeded());
|
||||
}
|
||||
|
||||
} catch(error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
export function* defaultSaga() {
|
||||
const loadModelWatcher = yield fork(takeLatest, MODEL_FETCH, fetchModel);
|
||||
const deleteAttributeWatcher = yield fork(takeLatest, DELETE_ATTRIBUTE, attributeDelete);
|
||||
const loadSubmitChanges = yield fork(takeLatest, SUBMIT, submitChanges);
|
||||
|
||||
yield take(LOCATION_CHANGE);
|
||||
|
||||
yield cancel(loadModelWatcher);
|
||||
yield cancel(deleteAttributeWatcher);
|
||||
yield cancel(loadSubmitChanges);
|
||||
}
|
||||
|
||||
// All sagas to be loaded
|
||||
|
||||
@ -23,6 +23,9 @@
|
||||
"form.attribute.item.requiredField.description": "You won't be able to create an entry if this field is empty",
|
||||
"form.attribute.item.uniqueField.description": "You won't be able to create an entry if there is an existing entry with identical content",
|
||||
|
||||
"form.button.cancel": "Cancel",
|
||||
"form.button.save": "Save",
|
||||
|
||||
"form.contentType.item.connections": "Connection",
|
||||
"form.contentType.item.name": "Name",
|
||||
"form.contentType.item.description": "Description",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user