mirror of
https://github.com/strapi/strapi.git
synced 2025-07-26 02:20:32 +00:00
Merge branch 'plugin/content-manager-dev' of github.com:strapi/strapi into plugin/content-manager-dev
This commit is contained in:
commit
4d2ec1f5b0
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { get, isEmpty, map, mapKeys, isObject, reject, includes } from 'lodash';
|
import { get, isEmpty, map, mapKeys, isObject, reject, includes } from 'lodash';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import DateTime from 'react-datetime';
|
import DateTime from 'react-datetime';
|
||||||
@ -67,37 +68,37 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
validate = (value) => {
|
validate = (value) => {
|
||||||
let errors = [];
|
let errors = [];
|
||||||
// handle i18n
|
// handle i18n
|
||||||
const requiredError = { id: 'error.validation.required' };
|
const requiredError = { id: `${this.props.pluginID}.error.validation.required` };
|
||||||
mapKeys(this.props.validations, (validationValue, validationKey) => {
|
mapKeys(this.props.validations, (validationValue, validationKey) => {
|
||||||
switch (validationKey) {
|
switch (validationKey) {
|
||||||
case 'max':
|
case 'max':
|
||||||
if (parseInt(value, 10) > validationValue) {
|
if (parseInt(value, 10) > validationValue) {
|
||||||
errors.push({ id: 'error.validation.max' });
|
errors.push({ id: `${this.props.pluginID}.error.validation.max` });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'maxLength':
|
case 'maxLength':
|
||||||
if (value.length > validationValue) {
|
if (value.length > validationValue) {
|
||||||
errors.push({ id: 'error.validation.maxLength' });
|
errors.push({ id: `${this.props.pluginID}.error.validation.maxLength` });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'min':
|
case 'min':
|
||||||
if (parseInt(value, 10) < validationValue) {
|
if (parseInt(value, 10) < validationValue) {
|
||||||
errors.push({ id: 'error.validation.min' });
|
errors.push({ id: `${this.props.pluginID}.error.validation.min` });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'minLength':
|
case 'minLength':
|
||||||
if (value.length < validationValue) {
|
if (value.length < validationValue) {
|
||||||
errors.push({ id: 'error.validation.minLength' });
|
errors.push({ id: `${this.props.pluginID}.error.validation.minLength` });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'required':
|
case 'required':
|
||||||
if (value.length === 0) {
|
if (value.length === 0) {
|
||||||
errors.push({ id: 'error.validation.required' });
|
errors.push({ id: `${this.props.pluginID}.error.validation.required` });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'regex':
|
case 'regex':
|
||||||
if (!new RegExp(validationValue).test(value)) {
|
if (!new RegExp(validationValue).test(value)) {
|
||||||
errors.push({ id: 'error.validation.regex' });
|
errors.push({ id: `${this.props.pluginID}.error.validation.regex` });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -367,36 +368,37 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
}
|
}
|
||||||
|
|
||||||
Input.propTypes = {
|
Input.propTypes = {
|
||||||
addon: React.PropTypes.oneOfType([
|
addon: PropTypes.oneOfType([
|
||||||
React.PropTypes.bool,
|
PropTypes.bool,
|
||||||
React.PropTypes.string,
|
PropTypes.string,
|
||||||
]),
|
]),
|
||||||
addRequiredInputDesign: React.PropTypes.bool,
|
addRequiredInputDesign: PropTypes.bool,
|
||||||
customBootstrapClass: React.PropTypes.string,
|
customBootstrapClass: PropTypes.string,
|
||||||
deactivateErrorHighlight: React.PropTypes.bool,
|
deactivateErrorHighlight: PropTypes.bool,
|
||||||
didCheckErrors: React.PropTypes.bool,
|
didCheckErrors: PropTypes.bool,
|
||||||
disabled: React.PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
errors: React.PropTypes.array,
|
errors: PropTypes.array,
|
||||||
handleBlur: React.PropTypes.oneOfType([
|
handleBlur: PropTypes.oneOfType([
|
||||||
React.PropTypes.func,
|
PropTypes.func,
|
||||||
React.PropTypes.bool,
|
PropTypes.bool,
|
||||||
]),
|
]),
|
||||||
handleChange: React.PropTypes.func.isRequired,
|
handleChange: PropTypes.func.isRequired,
|
||||||
handleFocus: React.PropTypes.func,
|
handleFocus: PropTypes.func,
|
||||||
inputDescription: React.PropTypes.string,
|
inputDescription: PropTypes.string,
|
||||||
label: React.PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
name: React.PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
noErrorsDescription: React.PropTypes.bool,
|
noErrorsDescription: PropTypes.bool,
|
||||||
placeholder: React.PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
selectOptions: React.PropTypes.array,
|
pluginID: PropTypes.string,
|
||||||
selectOptionsFetchSucceeded: React.PropTypes.bool,
|
selectOptions: PropTypes.array,
|
||||||
title: React.PropTypes.string,
|
selectOptionsFetchSucceeded: PropTypes.bool,
|
||||||
type: React.PropTypes.string.isRequired,
|
title: PropTypes.string,
|
||||||
validations: React.PropTypes.object.isRequired,
|
type: PropTypes.string.isRequired,
|
||||||
value: React.PropTypes.oneOfType([
|
validations: PropTypes.object.isRequired,
|
||||||
React.PropTypes.string,
|
value: PropTypes.oneOfType([
|
||||||
React.PropTypes.bool,
|
PropTypes.string,
|
||||||
React.PropTypes.number,
|
PropTypes.bool,
|
||||||
|
PropTypes.number,
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// Dependencies.
|
// Dependencies.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { omit } from 'lodash';
|
import { findIndex, get, omit } from 'lodash';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import Input from 'components/Input';
|
import Input from 'components/Input';
|
||||||
@ -43,6 +43,10 @@ class EditForm extends React.Component {
|
|||||||
// List fields inputs
|
// List fields inputs
|
||||||
const fields = Object.keys(displayedFields).map(attr => {
|
const fields = Object.keys(displayedFields).map(attr => {
|
||||||
const details = displayedFields[attr];
|
const details = displayedFields[attr];
|
||||||
|
const errorIndex = findIndex(this.props.formErrors, ['name', attr]);
|
||||||
|
const errors = errorIndex !== -1 ? this.props.formErrors[errorIndex].errors : [];
|
||||||
|
const validationsIndex = findIndex(this.props.formValidations, ['name', attr]);
|
||||||
|
const validations = get(this.props.formValidations[validationsIndex], 'validations') || {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Input
|
<Input
|
||||||
@ -53,7 +57,10 @@ class EditForm extends React.Component {
|
|||||||
value={this.props.record.get(attr) || ''}
|
value={this.props.record.get(attr) || ''}
|
||||||
placeholder={details.placeholder || details.label || attr || ''}
|
placeholder={details.placeholder || details.label || attr || ''}
|
||||||
handleChange={this.props.handleChange}
|
handleChange={this.props.handleChange}
|
||||||
validations={{}}
|
validations={validations}
|
||||||
|
errors={errors}
|
||||||
|
didCheckErrors={this.props.didCheckErrors}
|
||||||
|
pluginID="content-manager"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -70,6 +77,9 @@ class EditForm extends React.Component {
|
|||||||
|
|
||||||
EditForm.propTypes = {
|
EditForm.propTypes = {
|
||||||
currentModelName: PropTypes.string.isRequired,
|
currentModelName: PropTypes.string.isRequired,
|
||||||
|
didCheckErrors: PropTypes.bool.isRequired,
|
||||||
|
formErrors: PropTypes.array.isRequired,
|
||||||
|
formValidations: PropTypes.array.isRequired,
|
||||||
handleChange: PropTypes.func.isRequired,
|
handleChange: PropTypes.func.isRequired,
|
||||||
record: PropTypes.oneOfType([
|
record: PropTypes.oneOfType([
|
||||||
PropTypes.object,
|
PropTypes.object,
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { fromJS } from 'immutable';
|
import { fromJS, List } from 'immutable';
|
||||||
|
|
||||||
import { LOAD_MODELS, LOADED_MODELS, UPDATE_SCHEMA } from './constants';
|
import { LOAD_MODELS, LOADED_MODELS, UPDATE_SCHEMA } from './constants';
|
||||||
|
|
||||||
@ -12,6 +12,7 @@ const initialState = fromJS({
|
|||||||
loading: true,
|
loading: true,
|
||||||
models: false,
|
models: false,
|
||||||
schema: false,
|
schema: false,
|
||||||
|
formValidations: List(),
|
||||||
});
|
});
|
||||||
|
|
||||||
function appReducer(state = initialState, action) {
|
function appReducer(state = initialState, action) {
|
||||||
|
@ -3,40 +3,46 @@
|
|||||||
* Edit actions
|
* Edit actions
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
import { get } from 'lodash';
|
||||||
|
import { getValidationsFromForm } from '../../utils/formValidations';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SET_INITIAL_STATE,
|
CANCEL_CHANGES,
|
||||||
|
DELETE_RECORD,
|
||||||
|
DELETE_RECORD_ERROR,
|
||||||
|
DELETE_RECORD_SUCCESS,
|
||||||
|
EDIT_RECORD,
|
||||||
|
EDIT_RECORD_ERROR,
|
||||||
|
EDIT_RECORD_SUCCESS,
|
||||||
SET_CURRENT_MODEL_NAME,
|
SET_CURRENT_MODEL_NAME,
|
||||||
SET_IS_CREATING,
|
SET_IS_CREATING,
|
||||||
|
SET_INITIAL_STATE,
|
||||||
LOAD_RECORD,
|
LOAD_RECORD,
|
||||||
LOAD_RECORD_SUCCESS,
|
LOAD_RECORD_SUCCESS,
|
||||||
SET_RECORD_ATTRIBUTE,
|
SET_RECORD_ATTRIBUTE,
|
||||||
EDIT_RECORD,
|
|
||||||
EDIT_RECORD_SUCCESS,
|
|
||||||
EDIT_RECORD_ERROR,
|
|
||||||
DELETE_RECORD,
|
|
||||||
DELETE_RECORD_SUCCESS,
|
|
||||||
DELETE_RECORD_ERROR,
|
|
||||||
TOGGLE_NULL,
|
TOGGLE_NULL,
|
||||||
CANCEL_CHANGES,
|
SET_FORM_VALIDATIONS,
|
||||||
|
SET_FORM,
|
||||||
|
SET_FORM_ERRORS,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
export function setInitialState() {
|
export function cancelChanges() {
|
||||||
return {
|
return {
|
||||||
type: SET_INITIAL_STATE,
|
type: CANCEL_CHANGES,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setCurrentModelName(currentModelName) {
|
export function deleteRecord(id, modelName) {
|
||||||
return {
|
return {
|
||||||
type: SET_CURRENT_MODEL_NAME,
|
type: DELETE_RECORD,
|
||||||
currentModelName,
|
id,
|
||||||
|
modelName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setIsCreating() {
|
export function editRecord() {
|
||||||
return {
|
return {
|
||||||
type: SET_IS_CREATING,
|
type: EDIT_RECORD,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,24 +53,17 @@ export function loadRecord(id) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recordLoaded(record) {
|
|
||||||
|
export function recordDeleted(id) {
|
||||||
return {
|
return {
|
||||||
type: LOAD_RECORD_SUCCESS,
|
type: DELETE_RECORD_SUCCESS,
|
||||||
record,
|
id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setRecordAttribute(key, value) {
|
export function recordDeleteError() {
|
||||||
return {
|
return {
|
||||||
type: SET_RECORD_ATTRIBUTE,
|
type: DELETE_RECORD_ERROR,
|
||||||
key,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function editRecord() {
|
|
||||||
return {
|
|
||||||
type: EDIT_RECORD,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,24 +79,71 @@ export function recordEditError() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteRecord(id, modelName) {
|
export function recordLoaded(record) {
|
||||||
return {
|
return {
|
||||||
type: DELETE_RECORD,
|
type: LOAD_RECORD_SUCCESS,
|
||||||
id,
|
record,
|
||||||
modelName,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recordDeleted(id) {
|
export function setCurrentModelName(currentModelName) {
|
||||||
return {
|
return {
|
||||||
type: DELETE_RECORD_SUCCESS,
|
type: SET_CURRENT_MODEL_NAME,
|
||||||
id,
|
currentModelName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recordDeleteError() {
|
export function setForm(data) {
|
||||||
|
const form = [];
|
||||||
|
Object.keys(data).map(attr => {
|
||||||
|
form.push([attr, '']);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: DELETE_RECORD_ERROR,
|
type: SET_FORM,
|
||||||
|
form,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setFormErrors(formErrors) {
|
||||||
|
return {
|
||||||
|
type: SET_FORM_ERRORS,
|
||||||
|
formErrors,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setFormValidations(data) {
|
||||||
|
const form = Object.keys(data).map(attr => {
|
||||||
|
return { name: attr, validations: get(data[attr], ['params']) || {} }
|
||||||
|
});
|
||||||
|
|
||||||
|
const formValidations = getValidationsFromForm(form, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: SET_FORM_VALIDATIONS,
|
||||||
|
formValidations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setInitialState() {
|
||||||
|
return {
|
||||||
|
type: SET_INITIAL_STATE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function setIsCreating() {
|
||||||
|
return {
|
||||||
|
type: SET_IS_CREATING,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setRecordAttribute(key, value) {
|
||||||
|
return {
|
||||||
|
type: SET_RECORD_ATTRIBUTE,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,9 +152,3 @@ export function toggleNull() {
|
|||||||
type: TOGGLE_NULL,
|
type: TOGGLE_NULL,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cancelChanges() {
|
|
||||||
return {
|
|
||||||
type: CANCEL_CHANGES,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
export const SET_INITIAL_STATE = 'app/Edit/SET_INITIAL_STATE';
|
export const SET_INITIAL_STATE = 'app/Edit/SET_INITIAL_STATE';
|
||||||
export const SET_CURRENT_MODEL_NAME = 'app/Edit/SET_CURRENT_MODEL_NAME';
|
export const SET_CURRENT_MODEL_NAME = 'app/Edit/SET_CURRENT_MODEL_NAME';
|
||||||
export const SET_IS_CREATING = 'app/Edit/SET_IS_CREATING';
|
export const SET_IS_CREATING = 'app/Edit/SET_IS_CREATING';
|
||||||
|
export const SET_FORM_VALIDATIONS = 'app/Edit/SET_FORM_VALIDATIONS';
|
||||||
|
export const SET_FORM = 'app/Edit/SET_FORM';
|
||||||
|
export const SET_FORM_ERRORS = 'app/Edit/SET_FORM_ERRORS';
|
||||||
|
|
||||||
export const LOAD_RECORD = 'app/Edit/LOAD_RECORD';
|
export const LOAD_RECORD = 'app/Edit/LOAD_RECORD';
|
||||||
export const LOAD_RECORD_SUCCESS = 'app/Edit/LOAD_RECORD_SUCCESS';
|
export const LOAD_RECORD_SUCCESS = 'app/Edit/LOAD_RECORD_SUCCESS';
|
||||||
|
@ -11,7 +11,7 @@ import { connect } from 'react-redux';
|
|||||||
import { bindActionCreators, compose } from 'redux';
|
import { bindActionCreators, compose } from 'redux';
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { get, isObject } from 'lodash';
|
import { map, get, isObject, isEmpty } from 'lodash';
|
||||||
import { router } from 'app';
|
import { router } from 'app';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
@ -26,6 +26,7 @@ import { makeSelectModels, makeSelectSchema } from 'containers/App/selectors';
|
|||||||
import injectReducer from 'utils/injectReducer';
|
import injectReducer from 'utils/injectReducer';
|
||||||
import injectSaga from 'utils/injectSaga';
|
import injectSaga from 'utils/injectSaga';
|
||||||
import templateObject from 'utils/templateObject';
|
import templateObject from 'utils/templateObject';
|
||||||
|
import { checkFormValidity } from '../../utils/formValidations';
|
||||||
|
|
||||||
// Styles.
|
// Styles.
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
@ -40,6 +41,9 @@ import {
|
|||||||
editRecord,
|
editRecord,
|
||||||
toggleNull,
|
toggleNull,
|
||||||
cancelChanges,
|
cancelChanges,
|
||||||
|
setFormValidations,
|
||||||
|
setForm,
|
||||||
|
setFormErrors,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
|
|
||||||
// Selectors.
|
// Selectors.
|
||||||
@ -52,6 +56,10 @@ import {
|
|||||||
makeSelectDeleting,
|
makeSelectDeleting,
|
||||||
makeSelectIsCreating,
|
makeSelectIsCreating,
|
||||||
makeSelectIsRelationComponentNull,
|
makeSelectIsRelationComponentNull,
|
||||||
|
makeSelectForm,
|
||||||
|
makeSelectFormValidations,
|
||||||
|
makeSelectFormErrors,
|
||||||
|
makeSelectDidCheckErrors,
|
||||||
} from './selectors';
|
} from './selectors';
|
||||||
|
|
||||||
import reducer from './reducer';
|
import reducer from './reducer';
|
||||||
@ -74,7 +82,7 @@ export class Edit extends React.Component {
|
|||||||
buttonBackground: 'primary',
|
buttonBackground: 'primary',
|
||||||
buttonSize: 'buttonLg',
|
buttonSize: 'buttonLg',
|
||||||
label: this.props.editing ? 'content-manager.containers.Edit.editing' : 'content-manager.containers.Edit.submit',
|
label: this.props.editing ? 'content-manager.containers.Edit.editing' : 'content-manager.containers.Edit.submit',
|
||||||
onClick: this.props.editRecord,
|
onClick: this.handleSubmit,
|
||||||
disabled: this.props.editing,
|
disabled: this.props.editing,
|
||||||
type: 'submit',
|
type: 'submit',
|
||||||
},
|
},
|
||||||
@ -94,7 +102,8 @@ export class Edit extends React.Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.setInitialState();
|
this.props.setInitialState();
|
||||||
this.props.setCurrentModelName(this.props.match.params.slug.toLowerCase());
|
this.props.setCurrentModelName(this.props.match.params.slug.toLowerCase());
|
||||||
|
this.props.setFormValidations(this.props.models[this.props.match.params.slug.toLowerCase()].attributes);
|
||||||
|
this.props.setForm(this.props.models[this.props.match.params.slug.toLowerCase()].attributes);
|
||||||
// Detect that the current route is the `create` route or not
|
// Detect that the current route is the `create` route or not
|
||||||
if (this.props.match.params.id === 'create') {
|
if (this.props.match.params.id === 'create') {
|
||||||
this.props.setIsCreating();
|
this.props.setIsCreating();
|
||||||
@ -118,12 +127,20 @@ export class Edit extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = () => {
|
handleSubmit = () => {
|
||||||
this.props.editRecord();
|
const form = this.props.form.toJS();
|
||||||
|
map(this.props.record.toJS(), (value, key) => form[key] = value);
|
||||||
|
const formErrors = checkFormValidity(form, this.props.formValidations.toJS());
|
||||||
|
|
||||||
|
if (isEmpty(formErrors)) {
|
||||||
|
this.props.editRecord();
|
||||||
|
} else {
|
||||||
|
this.props.setFormErrors(formErrors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmitOnEnterPress = (e) => {
|
handleSubmitOnEnterPress = (e) => {
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
this.props.editRecord();
|
this.handleSubmit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +181,9 @@ export class Edit extends React.Component {
|
|||||||
handleChange={this.handleChange}
|
handleChange={this.handleChange}
|
||||||
handleSubmit={this.handleSubmit}
|
handleSubmit={this.handleSubmit}
|
||||||
editing={this.props.editing}
|
editing={this.props.editing}
|
||||||
|
formErrors={this.props.formErrors.toJS()}
|
||||||
|
didCheckErrors={this.props.didCheckErrors}
|
||||||
|
formValidations={this.props.formValidations.toJS()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -185,17 +205,25 @@ export class Edit extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* eslint-disable react/require-default-props */
|
||||||
Edit.propTypes = {
|
Edit.propTypes = {
|
||||||
cancelChanges: PropTypes.func.isRequired,
|
cancelChanges: PropTypes.func.isRequired,
|
||||||
currentModelName: PropTypes.oneOfType([
|
currentModelName: PropTypes.oneOfType([
|
||||||
PropTypes.bool,
|
PropTypes.bool,
|
||||||
PropTypes.string,
|
PropTypes.string,
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
// deleteRecord: PropTypes.func.isRequired,
|
didCheckErrors: PropTypes.bool.isRequired,
|
||||||
// deleting: PropTypes.bool.isRequired,
|
|
||||||
editing: PropTypes.bool.isRequired,
|
editing: PropTypes.bool.isRequired,
|
||||||
editRecord: PropTypes.func.isRequired,
|
editRecord: PropTypes.func.isRequired,
|
||||||
|
form: PropTypes.object.isRequired,
|
||||||
|
formErrors: PropTypes.oneOfType([
|
||||||
|
PropTypes.array,
|
||||||
|
PropTypes.object,
|
||||||
|
]),
|
||||||
|
formValidations: PropTypes.oneOfType([
|
||||||
|
PropTypes.array,
|
||||||
|
PropTypes.object,
|
||||||
|
]),
|
||||||
isCreating: PropTypes.bool.isRequired,
|
isCreating: PropTypes.bool.isRequired,
|
||||||
isRelationComponentNull: PropTypes.bool.isRequired,
|
isRelationComponentNull: PropTypes.bool.isRequired,
|
||||||
loading: PropTypes.bool.isRequired,
|
loading: PropTypes.bool.isRequired,
|
||||||
@ -219,6 +247,9 @@ Edit.propTypes = {
|
|||||||
PropTypes.bool,
|
PropTypes.bool,
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
setCurrentModelName: PropTypes.func.isRequired,
|
setCurrentModelName: PropTypes.func.isRequired,
|
||||||
|
setForm: PropTypes.func.isRequired,
|
||||||
|
setFormErrors: PropTypes.func.isRequired,
|
||||||
|
setFormValidations: PropTypes.func.isRequired,
|
||||||
setInitialState: PropTypes.func.isRequired,
|
setInitialState: PropTypes.func.isRequired,
|
||||||
setIsCreating: PropTypes.func.isRequired,
|
setIsCreating: PropTypes.func.isRequired,
|
||||||
setRecordAttribute: PropTypes.func.isRequired,
|
setRecordAttribute: PropTypes.func.isRequired,
|
||||||
@ -235,6 +266,10 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
schema: makeSelectSchema(),
|
schema: makeSelectSchema(),
|
||||||
models: makeSelectModels(),
|
models: makeSelectModels(),
|
||||||
isRelationComponentNull: makeSelectIsRelationComponentNull(),
|
isRelationComponentNull: makeSelectIsRelationComponentNull(),
|
||||||
|
form: makeSelectForm(),
|
||||||
|
formValidations: makeSelectFormValidations(),
|
||||||
|
formErrors: makeSelectFormErrors(),
|
||||||
|
didCheckErrors: makeSelectDidCheckErrors(),
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
@ -248,6 +283,9 @@ function mapDispatchToProps(dispatch) {
|
|||||||
editRecord,
|
editRecord,
|
||||||
toggleNull,
|
toggleNull,
|
||||||
cancelChanges,
|
cancelChanges,
|
||||||
|
setFormValidations,
|
||||||
|
setForm,
|
||||||
|
setFormErrors,
|
||||||
},
|
},
|
||||||
dispatch
|
dispatch
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { fromJS, Map } from 'immutable';
|
import { fromJS, Map, List } from 'immutable';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SET_INITIAL_STATE,
|
SET_INITIAL_STATE,
|
||||||
@ -21,6 +21,9 @@ import {
|
|||||||
DELETE_RECORD_ERROR,
|
DELETE_RECORD_ERROR,
|
||||||
TOGGLE_NULL,
|
TOGGLE_NULL,
|
||||||
CANCEL_CHANGES,
|
CANCEL_CHANGES,
|
||||||
|
SET_FORM_VALIDATIONS,
|
||||||
|
SET_FORM,
|
||||||
|
SET_FORM_ERRORS,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
const initialState = fromJS({
|
const initialState = fromJS({
|
||||||
@ -31,6 +34,10 @@ const initialState = fromJS({
|
|||||||
deleting: false,
|
deleting: false,
|
||||||
isCreating: false,
|
isCreating: false,
|
||||||
isRelationComponentNull: false,
|
isRelationComponentNull: false,
|
||||||
|
formValidations: List(),
|
||||||
|
formErrors: List(),
|
||||||
|
form: Map({}),
|
||||||
|
didCheckErrors: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
function editReducer(state = initialState, action) {
|
function editReducer(state = initialState, action) {
|
||||||
@ -50,9 +57,12 @@ function editReducer(state = initialState, action) {
|
|||||||
.set('model', action.model)
|
.set('model', action.model)
|
||||||
.set('id', action.id);
|
.set('id', action.id);
|
||||||
case LOAD_RECORD_SUCCESS:
|
case LOAD_RECORD_SUCCESS:
|
||||||
return state.set('loading', false).set('record', fromJS(action.record));
|
return state
|
||||||
|
.set('loading', false)
|
||||||
|
.set('record', fromJS(action.record));
|
||||||
case SET_RECORD_ATTRIBUTE:
|
case SET_RECORD_ATTRIBUTE:
|
||||||
return state.setIn(['record', action.key], fromJS(action.value));
|
return state
|
||||||
|
.setIn(['record', action.key], fromJS(action.value));
|
||||||
case EDIT_RECORD:
|
case EDIT_RECORD:
|
||||||
return state.set('editing', true);
|
return state.set('editing', true);
|
||||||
case EDIT_RECORD_SUCCESS:
|
case EDIT_RECORD_SUCCESS:
|
||||||
@ -69,6 +79,15 @@ function editReducer(state = initialState, action) {
|
|||||||
return state.set('isRelationComponentNull', !state.get('isRelationComponentNull'));
|
return state.set('isRelationComponentNull', !state.get('isRelationComponentNull'));
|
||||||
case CANCEL_CHANGES:
|
case CANCEL_CHANGES:
|
||||||
return state.set('record', Map({}));
|
return state.set('record', Map({}));
|
||||||
|
case SET_FORM_VALIDATIONS:
|
||||||
|
return state
|
||||||
|
.set('formValidations', List(action.formValidations));
|
||||||
|
case SET_FORM:
|
||||||
|
return state.set('form', Map(action.form));
|
||||||
|
case SET_FORM_ERRORS:
|
||||||
|
return state
|
||||||
|
.set('formErrors', List(action.formErrors))
|
||||||
|
.set('didCheckErrors', !state.didCheckErrors);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,18 @@ const makeSelectIsCreating = () =>
|
|||||||
const makeSelectIsRelationComponentNull = () =>
|
const makeSelectIsRelationComponentNull = () =>
|
||||||
createSelector(selectEditDomain(), substate => substate.get('isRelationComponentNull'));
|
createSelector(selectEditDomain(), substate => substate.get('isRelationComponentNull'));
|
||||||
|
|
||||||
|
const makeSelectForm = () =>
|
||||||
|
createSelector(selectEditDomain(), substate => substate.get('form'));
|
||||||
|
|
||||||
|
const makeSelectFormValidations = () =>
|
||||||
|
createSelector(selectEditDomain(), substate => substate.get('formValidations'));
|
||||||
|
|
||||||
|
const makeSelectFormErrors = () =>
|
||||||
|
createSelector(selectEditDomain(), substate => substate.get('formErrors'));
|
||||||
|
|
||||||
|
const makeSelectDidCheckErrors = () =>
|
||||||
|
createSelector(selectEditDomain(), substate => substate.get('didCheckErrors'));
|
||||||
|
|
||||||
export default selectEditDomain;
|
export default selectEditDomain;
|
||||||
export {
|
export {
|
||||||
makeSelectRecord,
|
makeSelectRecord,
|
||||||
@ -45,4 +57,8 @@ export {
|
|||||||
makeSelectDeleting,
|
makeSelectDeleting,
|
||||||
makeSelectIsCreating,
|
makeSelectIsCreating,
|
||||||
makeSelectIsRelationComponentNull,
|
makeSelectIsRelationComponentNull,
|
||||||
|
makeSelectForm,
|
||||||
|
makeSelectFormValidations,
|
||||||
|
makeSelectFormErrors,
|
||||||
|
makeSelectDidCheckErrors,
|
||||||
};
|
};
|
||||||
|
@ -87,14 +87,6 @@ export class List extends React.Component {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changePage = (page) => {
|
|
||||||
router.push({
|
|
||||||
pathname: this.props.location.pathname,
|
|
||||||
search: `?page=${page}&limit=${this.props.limit}&sort=${this.props.sort}`,
|
|
||||||
});
|
|
||||||
this.props.changePage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(props) {
|
init(props) {
|
||||||
const slug = props.match.params.slug;
|
const slug = props.match.params.slug;
|
||||||
// Set current model name
|
// Set current model name
|
||||||
@ -132,6 +124,14 @@ export class List extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChangePage = (page) => {
|
||||||
|
router.push({
|
||||||
|
pathname: this.props.location.pathname,
|
||||||
|
search: `?page=${page}&limit=${this.props.limit}&sort=${this.props.sort}`,
|
||||||
|
});
|
||||||
|
this.props.changePage(page);
|
||||||
|
}
|
||||||
|
|
||||||
handleChangeSort = (sort) => {
|
handleChangeSort = (sort) => {
|
||||||
router.push({
|
router.push({
|
||||||
pathname: this.props.location.pathname,
|
pathname: this.props.location.pathname,
|
||||||
@ -248,7 +248,7 @@ export class List extends React.Component {
|
|||||||
<TableFooter
|
<TableFooter
|
||||||
limit={this.props.limit}
|
limit={this.props.limit}
|
||||||
currentPage={this.props.currentPage}
|
currentPage={this.props.currentPage}
|
||||||
changePage={this.changePage}
|
changePage={this.handleChangePage}
|
||||||
count={this.props.count}
|
count={this.props.count}
|
||||||
className="push-lg-right"
|
className="push-lg-right"
|
||||||
handleChangeLimit={this.handleChangeLimit}
|
handleChangeLimit={this.handleChangeLimit}
|
||||||
|
@ -12,6 +12,19 @@
|
|||||||
"containers.List.pluginHeaderDescription": "Manage your {label}",
|
"containers.List.pluginHeaderDescription": "Manage your {label}",
|
||||||
"components.LimitSelect.itemsPerPage": "Items per page",
|
"components.LimitSelect.itemsPerPage": "Items per page",
|
||||||
"containers.List.errorFetchRecords": "Error",
|
"containers.List.errorFetchRecords": "Error",
|
||||||
|
|
||||||
|
"error.validation.required": "This value input is required.",
|
||||||
|
"error.validation.regex": "The value not match the regex.",
|
||||||
|
"error.validation.max": "The value is too high.",
|
||||||
|
"error.validation.min": "The value is too low.",
|
||||||
|
"error.validation.maxLength": "The value is too long.",
|
||||||
|
"error.validation.minLength": "The value is too shot.",
|
||||||
|
"error.contentTypeName.taken": "This name already exists",
|
||||||
|
"error.attribute.taken": "This field name already exists",
|
||||||
|
"error.attribute.key.taken": "This value already exists",
|
||||||
|
"error.attribute.sameKeyAndName": "Can't be equals",
|
||||||
|
"error.validation.minSupMax": "Can't be superior",
|
||||||
|
|
||||||
"pageNotFound": "Page not found",
|
"pageNotFound": "Page not found",
|
||||||
|
|
||||||
"popUpWarning.button.cancel": "Cancel",
|
"popUpWarning.button.cancel": "Cancel",
|
||||||
|
@ -13,6 +13,18 @@
|
|||||||
"components.LimitSelect.itemsPerPage": "Éléments par page",
|
"components.LimitSelect.itemsPerPage": "Éléments par page",
|
||||||
"containers.List.errorFetchRecords": "Erreur",
|
"containers.List.errorFetchRecords": "Erreur",
|
||||||
|
|
||||||
|
"error.validation.required": "Ce champ est obligatoire.",
|
||||||
|
"error.validation.regex": "La valeur ne correspond pas au format attendu.",
|
||||||
|
"error.validation.max": "La valeur est trop grande.",
|
||||||
|
"error.validation.min": "La valeur est trop basse.",
|
||||||
|
"error.validation.maxLength": "La valeur est trop longue.",
|
||||||
|
"error.validation.minLength": "La valeur est trop courte.",
|
||||||
|
"error.contentTypeName.taken": "Ce nom existe déjà",
|
||||||
|
"error.attribute.taken": "Ce champ existe déjà",
|
||||||
|
"error.attribute.key.taken": "Cette valeur existe déjà",
|
||||||
|
"error.attribute.sameKeyAndName": "Ne peuvent pas être égaux",
|
||||||
|
"error.validation.minSupMax": "Ne peut pas être plus grand",
|
||||||
|
|
||||||
"popUpWarning.button.cancel": "Annuler",
|
"popUpWarning.button.cancel": "Annuler",
|
||||||
"popUpWarning.button.confirm": "Confirmer",
|
"popUpWarning.button.confirm": "Confirmer",
|
||||||
"popUpWarning.title": "Confirmation requise",
|
"popUpWarning.title": "Confirmation requise",
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
import { forEach, isObject, isArray, map, mapKeys, includes, reject, isEmpty, findIndex, isUndefined } from 'lodash';
|
||||||
|
|
||||||
|
/* eslint-disable consistent-return */
|
||||||
|
export function getValidationsFromForm(form, formValidations) {
|
||||||
|
map(form, (value, key) => {
|
||||||
|
|
||||||
|
// Check if the object
|
||||||
|
if (isObject(value) && !isArray(value)) {
|
||||||
|
forEach(value, (subValue) => {
|
||||||
|
// Check if it has nestedInputs
|
||||||
|
if (isArray(subValue) && value.type !== 'select') {
|
||||||
|
return getValidationsFromForm(subValue, formValidations);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isArray(value) && value.type !== 'select') {
|
||||||
|
return getValidationsFromForm(form[key], formValidations);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Push the target and the validation
|
||||||
|
if (value.name) {
|
||||||
|
formValidations.push({ name: value.name, validations: value.validations });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return formValidations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function checkFormValidity(formData, formValidations) {
|
||||||
|
const errors = [];
|
||||||
|
forEach(formData, (value, key) => {
|
||||||
|
const validationValue = formValidations[findIndex(formValidations, ['name', key])];
|
||||||
|
|
||||||
|
if (!isUndefined(validationValue)) {
|
||||||
|
const inputErrors = validate(value, validationValue.validations);
|
||||||
|
if (!isEmpty(inputErrors)) {
|
||||||
|
errors.push({ name: key, errors: inputErrors });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate(value, validations) {
|
||||||
|
let errors = [];
|
||||||
|
// Handle i18n
|
||||||
|
const requiredError = { id: 'content-manager.error.validation.required' };
|
||||||
|
mapKeys(validations, (validationValue, validationKey) => {
|
||||||
|
switch (validationKey) {
|
||||||
|
case 'max':
|
||||||
|
if (parseInt(value, 10) > validationValue) {
|
||||||
|
errors.push({ id: 'content-manager.error.validation.max' });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'min':
|
||||||
|
if (parseInt(value, 10) < validationValue) {
|
||||||
|
errors.push({ id: 'content-manager.error.validation.min' });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'maxLength':
|
||||||
|
if (value.length > validationValue) {
|
||||||
|
errors.push({ id: 'content-manager.error.validation.maxLength' });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'minLength':
|
||||||
|
if (value.length < validationValue) {
|
||||||
|
errors.push({ id: 'content-manager.error.validation.minLength' });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'required':
|
||||||
|
if (value.length === 0) {
|
||||||
|
errors.push({ id: 'content-manager.error.validation.required' });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'regex':
|
||||||
|
if (!new RegExp(validationValue).test(value)) {
|
||||||
|
errors.push({ id: 'content-manager.error.validation.regex' });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errors = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (includes(errors, requiredError)) {
|
||||||
|
errors = reject(errors, (error) => error !== requiredError);
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user