From 28f35f678b17798624d18248cb1e49d15a6306eb Mon Sep 17 00:00:00 2001 From: cyril lopez Date: Wed, 30 Aug 2017 16:38:58 +0200 Subject: [PATCH] Handle add attributes to content type --- .../src/components/ContentHeader/index.js | 51 ++++++++++++++----- .../src/components/ContentHeader/styles.scss | 10 ++++ .../admin/src/containers/App/actions.js | 7 +++ .../admin/src/containers/App/constants.js | 1 + .../admin/src/containers/App/index.js | 6 ++- .../admin/src/containers/App/reducer.js | 8 +++ .../admin/src/containers/App/sagas.js | 7 +-- .../admin/src/containers/Form/actions.js | 13 +++-- .../admin/src/containers/Form/constants.js | 1 + .../admin/src/containers/Form/index.js | 18 ++++++- .../admin/src/containers/Form/reducer.js | 3 ++ .../admin/src/containers/ModelPage/actions.js | 29 +++++++++++ .../src/containers/ModelPage/constants.js | 4 ++ .../admin/src/containers/ModelPage/index.js | 27 ++++++---- .../admin/src/containers/ModelPage/reducer.js | 19 +++++-- .../admin/src/containers/ModelPage/sagas.js | 37 +++++++++++++- .../admin/src/translations/en.json | 3 ++ 17 files changed, 204 insertions(+), 40 deletions(-) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js index abecdc0f04..c66185216d 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js @@ -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 = () => ( +
+ + {(message) => ( +
+ ) + renderContentHeader = () => { const containerClass = this.props.noMargin ? styles.contentHeaderNoMargin : styles.contentHeader; - const editIcon = this.props.editIcon ? - - : ''; - - const description = this.props.description || + const description = this.props.description || ; + const buttons = this.props.addButtons ? this.renderButtonContainer() : ''; return (
-
- {startCase(this.props.name)} - {editIcon} +
+
+ {startCase(this.props.name)} + +
+
{description}
-
{description}
+ {buttons}
); } @@ -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) ? '' : ; + const buttons = this.props.addButtons ? this.renderButtonContainer() : ''; - if (this.props.noI18n) return this.renderContentHeader(); + if (this.props.editIcon) return this.renderContentHeader(); return (
-
- +
+
+ +
+
{description}
-
{description}
+ {buttons}
); } } 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, }; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/styles.scss b/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/styles.scss index 486010ec7e..0fa7ace7f2 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/styles.scss +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/styles.scss @@ -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; + } +} diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/actions.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/actions.js index 7ed0d628f5..47ab64d90f 100755 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/actions.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/actions.js @@ -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, + }; +} diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/constants.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/constants.js index 7b44627936..f04275ab6e 100755 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/constants.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/constants.js @@ -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'; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js index 6d57606513..603d6ba1c5 100755 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js @@ -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 (
- {React.Children.toArray(content)} + {React.Children.toArray(content, 'fuck')}
); } @@ -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(), }); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/reducer.js index d9af383bfe..cad08444cd 100755 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/reducer.js @@ -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; } diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/sagas.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/sagas.js index 007b962b62..12f9316577 100755 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/sagas.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/sagas.js @@ -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 diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/actions.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/actions.js index 8ec32e158a..24d2c87835 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/actions.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/actions.js @@ -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, }), }); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/constants.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/constants.js index 7ff59359f5..4f524fa5af 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/constants.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/constants.js @@ -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'; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js index a15cc388bf..ce4c5185ed 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js @@ -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, diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/reducer.js index ba88f467ee..714b7c105b 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/reducer.js @@ -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)); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/actions.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/actions.js index ffa8006a88..067c1fec3d 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/actions.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/actions.js @@ -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, + } +} diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/constants.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/constants.js index 264e0bb067..21fba4d8db 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/constants.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/constants.js @@ -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'; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js index cd9267f7a2..29f4507c06 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js @@ -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
) - 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 ? : ; - return (
@@ -209,9 +212,12 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr {content}
@@ -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); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/reducer.js index fc245fcef8..b0b55f6f13 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/reducer.js @@ -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; } diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js index 5e04c08581..35ebe7dc7f 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js @@ -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 diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json index ae0bf57f9c..ccffd0c69a 100755 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json @@ -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",