mirror of
https://github.com/strapi/strapi.git
synced 2025-08-13 11:17:42 +00:00
Merge branch 'plugin/settings-manager-dev' of github.com:soupette/strapi into plugin/settings-manager-dev
This commit is contained in:
commit
1b0e48014d
@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* InputNumber
|
||||||
|
* Customization
|
||||||
|
* - deactivateErrorHighlight: bool
|
||||||
|
* allow the user to remove bootstrap class 'has-danger' on the inputText
|
||||||
|
* - customBootstrapClass : string
|
||||||
|
* overrides the default 'col-md-6' on the inputText
|
||||||
|
* - handleBlur: function
|
||||||
|
* overrides the default input validations
|
||||||
|
* - errors : array
|
||||||
|
* custom errors if set to false it deactivate error display
|
||||||
|
*
|
||||||
|
* Required
|
||||||
|
* - name : string
|
||||||
|
* - handleChange : function
|
||||||
|
* - value : string
|
||||||
|
* - validations : object
|
||||||
|
*
|
||||||
|
* Optionnal
|
||||||
|
* - description : input description
|
||||||
|
* - handleFocus : function
|
||||||
|
* - placeholder : string if set to "" nothing will display
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
class InputNumber extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
errors: false,
|
||||||
|
hasInitialValue: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.value && this.props.value.length !== '') {
|
||||||
|
this.setState({ hasInitialValue: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (this.props.errors !== nextProps.errors) {
|
||||||
|
let errors = false;
|
||||||
|
if (_.isEmpty(nextProps.errors)) {
|
||||||
|
errors = nextProps.errors === true ? [] : false;
|
||||||
|
} else {
|
||||||
|
errors = nextProps.errors;
|
||||||
|
}
|
||||||
|
this.setState({ errors });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBlur = ({ target }) => {
|
||||||
|
// prevent error display if input is initially empty
|
||||||
|
if (target.value.length > 0 || this.state.hasInitialValue) {
|
||||||
|
// validates basic string validations
|
||||||
|
// add custom logic here such as alerts...
|
||||||
|
const errors = this.validate(target.value);
|
||||||
|
this.setState({ errors, hasInitialValue: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate = (value) => {
|
||||||
|
const errors = !_.isEmpty(_.pick(this.props.validations, 'required')) && value.length > 0 ?
|
||||||
|
false : ['This field is required'];
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const inputValue = this.props.value || '';
|
||||||
|
// override default onBlur
|
||||||
|
const handleBlur = this.props.handleBlur || this.handleBlur;
|
||||||
|
// override bootStrapClass
|
||||||
|
const bootStrapClass = this.props.customBootstrapClass ? this.props.customBootstrapClass : 'col-md-4';
|
||||||
|
// set error class with override possibility
|
||||||
|
const bootStrapClassDanger = !this.props.deactivateErrorHighlight && this.state.errors ? 'has-danger' : '';
|
||||||
|
const placeholder = this.props.placeholder || `Change ${this.props.name} field`;
|
||||||
|
return (
|
||||||
|
<div className={`${styles.inputNumber} ${bootStrapClass} ${bootStrapClassDanger}`}>
|
||||||
|
<label htmlFor={this.props.name}>{this.props.name}</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name={this.props.name}
|
||||||
|
id={this.props.name}
|
||||||
|
value={inputValue}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
onChange={this.props.handleChange}
|
||||||
|
onFocus={this.props.handleFocus}
|
||||||
|
className={`form-control ${this.state.errors? 'form-control-danger' : ''}`}
|
||||||
|
placeholder={placeholder}
|
||||||
|
/>
|
||||||
|
<small>{this.props.inputDescription}</small>
|
||||||
|
{_.map(this.state.errors, (error, key) => (
|
||||||
|
<div key={key} className="form-control-feedback">{error}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputNumber.propTypes = {
|
||||||
|
customBootstrapClass: React.PropTypes.string,
|
||||||
|
deactivateErrorHighlight: React.PropTypes.bool,
|
||||||
|
errors: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.bool,
|
||||||
|
React.PropTypes.array,
|
||||||
|
]),
|
||||||
|
handleBlur: React.PropTypes.func,
|
||||||
|
handleChange: React.PropTypes.func.isRequired,
|
||||||
|
handleFocus: React.PropTypes.func,
|
||||||
|
inputDescription: React.PropTypes.string,
|
||||||
|
name: React.PropTypes.string.isRequired,
|
||||||
|
placeholder: React.PropTypes.string,
|
||||||
|
validations: React.PropTypes.object.isRequired,
|
||||||
|
value: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.number.isRequired,
|
||||||
|
React.PropTypes.string.isRequired,
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputNumber;
|
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* InputNumber Messages
|
||||||
|
*
|
||||||
|
* This contains all the text for the InputNumber component.
|
||||||
|
*/
|
||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
export default defineMessages({
|
||||||
|
header: {
|
||||||
|
id: 'app.components.InputNumber.header',
|
||||||
|
defaultMessage: 'This is the InputNumber component !',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,11 @@
|
|||||||
|
.inputNumber { /* stylelint-disable */
|
||||||
|
margin-top: 1.8rem;
|
||||||
|
> label {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
> small {
|
||||||
|
margin-top: .5rem;
|
||||||
|
display: block;
|
||||||
|
color: #ABAFBB;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
// import InputNumber from '../index';
|
||||||
|
|
||||||
|
import expect from 'expect';
|
||||||
|
// import { shallow } from 'enzyme';
|
||||||
|
// import React from 'react';
|
||||||
|
|
||||||
|
describe('<InputNumber />', () => {
|
||||||
|
it('Expect to have unit tests specified', () => {
|
||||||
|
expect(true).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,154 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* InputText
|
||||||
|
* Customization
|
||||||
|
* - deactivateErrorHighlight: bool
|
||||||
|
* allow the user to remove bootstrap class 'has-danger' on the inputText
|
||||||
|
* - customBootstrapClass : string
|
||||||
|
* overrides the default 'col-md-6' on the inputText
|
||||||
|
* - handleBlur: function
|
||||||
|
* overrides the default input validations
|
||||||
|
* - errors : array
|
||||||
|
* custom errors if set to false it deactivate error display
|
||||||
|
*
|
||||||
|
* Required
|
||||||
|
* - name : string
|
||||||
|
* - handleChange : function
|
||||||
|
* - value : string
|
||||||
|
* - validations : object
|
||||||
|
*
|
||||||
|
* Optionnal
|
||||||
|
* - description : input description
|
||||||
|
* - handleFocus : function
|
||||||
|
* - placeholder : string if set to "" nothing will display
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
class InputText extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
errors: false,
|
||||||
|
hasInitialValue: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.value && this.props.value.length > 0) {
|
||||||
|
this.setState({ hasInitialValue: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (this.props.errors !== nextProps.errors) {
|
||||||
|
let errors = false;
|
||||||
|
if (_.isEmpty(nextProps.errors)) {
|
||||||
|
errors = nextProps.errors === true ? [] : false;
|
||||||
|
} else {
|
||||||
|
errors = nextProps.errors;
|
||||||
|
}
|
||||||
|
this.setState({ errors });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBlur = ({ target }) => {
|
||||||
|
// prevent error display if input is initially empty
|
||||||
|
if (target.value.length > 0 || this.state.hasInitialValue) {
|
||||||
|
// validates basic string validations
|
||||||
|
// add custom logic here such as alerts...
|
||||||
|
const errors = this.validate(target.value);
|
||||||
|
this.setState({ errors, hasInitialValue: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic string validations
|
||||||
|
validate = (value) => {
|
||||||
|
let errors = [];
|
||||||
|
const requiredError = 'Field is required';
|
||||||
|
_.mapKeys(this.props.validations, (validationValue, validationKey) => {
|
||||||
|
switch (validationKey) {
|
||||||
|
case 'maxLength':
|
||||||
|
if (value.length > validationValue) {
|
||||||
|
errors.push('Field is too long');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'minLength':
|
||||||
|
if (value.length < validationValue) {
|
||||||
|
errors.push('Field is too short');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'required':
|
||||||
|
if (value.length === 0) {
|
||||||
|
errors.push(requiredError);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'regex':
|
||||||
|
if (!validationValue.test(value)) {
|
||||||
|
errors.push('Field is not valid');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errors = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_.isEmpty(errors)) {
|
||||||
|
errors = false;
|
||||||
|
} else if (_.includes(errors, requiredError)) {
|
||||||
|
errors = _.reject(errors, (error) => error !== requiredError);
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const inputValue = this.props.value || '';
|
||||||
|
// override default onBlur
|
||||||
|
const handleBlur = this.props.handleBlur || this.handleBlur;
|
||||||
|
// override bootStrapClass
|
||||||
|
const bootStrapClass = this.props.customBootstrapClass ? this.props.customBootstrapClass : 'col-md-6';
|
||||||
|
// set error class with override possibility
|
||||||
|
const bootStrapClassDanger = !this.props.deactivateErrorHighlight && this.state.errors ? 'has-danger' : '';
|
||||||
|
const placeholder = this.props.placeholder || `Change ${this.props.name} field`;
|
||||||
|
return (
|
||||||
|
<div className={`${styles.inputText} ${bootStrapClass} ${bootStrapClassDanger}`}>
|
||||||
|
<label htmlFor={this.props.name}>{this.props.name}</label>
|
||||||
|
<input
|
||||||
|
name={this.props.name}
|
||||||
|
id={this.props.name}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
onFocus={this.props.handleFocus}
|
||||||
|
onChange={this.props.handleChange}
|
||||||
|
value={inputValue}
|
||||||
|
type="text"
|
||||||
|
className={`form-control ${this.state.errors? 'form-control-danger' : ''}`}
|
||||||
|
placeholder={placeholder}
|
||||||
|
/>
|
||||||
|
<small>{this.props.inputDescription}</small>
|
||||||
|
{_.map(this.state.errors, (error, key) => (
|
||||||
|
<div key={key} className="form-control-feedback">{error}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputText.propTypes = {
|
||||||
|
customBootstrapClass: React.PropTypes.string,
|
||||||
|
deactivateErrorHighlight: React.PropTypes.bool,
|
||||||
|
errors: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.bool,
|
||||||
|
React.PropTypes.array,
|
||||||
|
]),
|
||||||
|
handleBlur: React.PropTypes.func,
|
||||||
|
handleChange: React.PropTypes.func.isRequired,
|
||||||
|
handleFocus: React.PropTypes.func,
|
||||||
|
inputDescription: React.PropTypes.string,
|
||||||
|
name: React.PropTypes.string.isRequired,
|
||||||
|
placeholder: React.PropTypes.string,
|
||||||
|
validations: React.PropTypes.object.isRequired,
|
||||||
|
value: React.PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputText;
|
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* InputText Messages
|
||||||
|
*
|
||||||
|
* This contains all the text for the InputText component.
|
||||||
|
*/
|
||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
export default defineMessages({
|
||||||
|
header: {
|
||||||
|
id: 'app.components.InputText.header',
|
||||||
|
defaultMessage: 'This is the InputText component !',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,11 @@
|
|||||||
|
.inputText { /* stylelint-disable */
|
||||||
|
margin-top: 1.8rem;
|
||||||
|
> label {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
> small {
|
||||||
|
margin-top: .5rem;
|
||||||
|
display: block;
|
||||||
|
color: #ABAFBB;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
// import InputText from '../index';
|
||||||
|
|
||||||
|
import expect from 'expect';
|
||||||
|
// import { shallow } from 'enzyme';
|
||||||
|
// import React from 'react';
|
||||||
|
|
||||||
|
describe('<InputText />', () => {
|
||||||
|
it('Expect to have unit tests specified', () => {
|
||||||
|
expect(true).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* InputToggle
|
||||||
|
* Customization
|
||||||
|
* - customBootstrapClass : string
|
||||||
|
* overrides the default col-md-4 class
|
||||||
|
*
|
||||||
|
* Required
|
||||||
|
* - handleChange: function
|
||||||
|
* - name: string
|
||||||
|
* - isChecked: bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
class InputToggle extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isChecked: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const isChecked = this.props.isChecked ? this.props.isChecked : false;
|
||||||
|
this.setState({ isChecked });
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle = (e) => {
|
||||||
|
let isChecked = this.state.isChecked;
|
||||||
|
|
||||||
|
// prevent the toggle if the user clicks on the already selected input
|
||||||
|
if (e.target.id === "on" && !this.state.isChecked) {
|
||||||
|
isChecked = true;
|
||||||
|
} else if (e.target.id === "off" && this.state.isChecked) {
|
||||||
|
isChecked = false;
|
||||||
|
}
|
||||||
|
const target = {
|
||||||
|
name: this.props.name,
|
||||||
|
value: isChecked,
|
||||||
|
};
|
||||||
|
this.setState({ isChecked });
|
||||||
|
this.props.handleChange({target});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const btnClassOff = this.state.isChecked ? 'btn ' : `btn ${styles.gradientOff}`;
|
||||||
|
const btnClassOn = this.state.isChecked ? `btn ${styles.gradientOn}` : 'btn';
|
||||||
|
const customBootstrapClass = this.props.customBootstrapClass ? this.props.customBootstrapClass : 'col-md-4';
|
||||||
|
return (
|
||||||
|
<div className={customBootstrapClass}>
|
||||||
|
<div className={`${styles.inputToggle} btn-group`} data-toggle="buttons">
|
||||||
|
<button className={btnClassOff} id="off" onClick={this.toggle}>OFF</button>
|
||||||
|
<button className={btnClassOn} id="on" onClick={this.toggle}>ON</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputToggle.propTypes = {
|
||||||
|
customBootstrapClass: React.PropTypes.string,
|
||||||
|
handleChange: React.PropTypes.func.isRequired,
|
||||||
|
isChecked: React.PropTypes.bool.isRequired,
|
||||||
|
name: React.PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputToggle;
|
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* InputRadio Messages
|
||||||
|
*
|
||||||
|
* This contains all the text for the InputRadio component.
|
||||||
|
*/
|
||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
export default defineMessages({
|
||||||
|
header: {
|
||||||
|
id: 'app.components.InputRadio.header',
|
||||||
|
defaultMessage: 'This is the InputRadio component !',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,36 @@
|
|||||||
|
.inputToggle { /* stylelint-disable */
|
||||||
|
> button {
|
||||||
|
// display and box model
|
||||||
|
width: 5.3rem;
|
||||||
|
height: 3.4rem;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 3.2rem;
|
||||||
|
border: 1px solid #E3E9F3;
|
||||||
|
// color
|
||||||
|
color: #333740;
|
||||||
|
background-color: white;
|
||||||
|
// text
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
letter-spacing: 0.07rem;
|
||||||
|
&:first-of-type {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
&:nth-of-type(2) {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
z-index: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradientOff {
|
||||||
|
background-image: linear-gradient( to bottom right, #F65A1D, #F68E0E );
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradientOn {
|
||||||
|
background-image: linear-gradient( to bottom right, #005EEA, #0097F6);
|
||||||
|
color: white !important;
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
// import InputRadio from '../index';
|
||||||
|
|
||||||
|
import expect from 'expect';
|
||||||
|
// import { shallow } from 'enzyme';
|
||||||
|
// import React from 'react';
|
||||||
|
|
||||||
|
describe('<InputRadio />', () => {
|
||||||
|
it('Expect to have unit tests specified', () => {
|
||||||
|
expect(true).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
@ -9,12 +9,28 @@ import React from 'react';
|
|||||||
import PluginLeftMenuHeader from 'components/PluginLeftMenuHeader';
|
import PluginLeftMenuHeader from 'components/PluginLeftMenuHeader';
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
|
|
||||||
function PluginLeftMenu() {
|
class PluginLeftMenu extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.pluginLeftMenu} col-md-3`}>
|
<div className={`${styles.pluginLeftMenu} col-md-3`}>
|
||||||
<PluginLeftMenuHeader />
|
<PluginLeftMenuHeader />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// function PluginLeftMenu() {
|
||||||
|
// return (
|
||||||
|
// <div className={`${styles.pluginLeftMenu} col-md-3`}>
|
||||||
|
// <PluginLeftMenuHeader />
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
export default PluginLeftMenu;
|
export default PluginLeftMenu;
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* PluginLeftMenuSection
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
class PluginLeftMenuSection extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className={styles.pluginLeftMenuSection}>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PluginLeftMenuSection;
|
@ -0,0 +1,3 @@
|
|||||||
|
.pluginLeftMenuSection { /* stylelint-disable */
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
// import PluginLeftMenuSection from '../index';
|
||||||
|
|
||||||
|
import expect from 'expect';
|
||||||
|
// import { shallow } from 'enzyme';
|
||||||
|
// import React from 'react';
|
||||||
|
|
||||||
|
describe('<PluginLeftMenuSection />', () => {
|
||||||
|
it('Expect to have unit tests specified', () => {
|
||||||
|
expect(true).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
@ -3,3 +3,22 @@
|
|||||||
* App actions
|
* App actions
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
MENU_FETCH,
|
||||||
|
MENU_FETCH_SUCCEEDED,
|
||||||
|
} from './constants';
|
||||||
|
|
||||||
|
|
||||||
|
export function menuFetch() {
|
||||||
|
return {
|
||||||
|
type: MENU_FETCH,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchMenuSucceeded(menu) {
|
||||||
|
return {
|
||||||
|
type: MENU_FETCH_SUCCEEDED,
|
||||||
|
menu,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -3,3 +3,6 @@
|
|||||||
* App constants
|
* App constants
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export const MENU_FETCH = 'SettingsManager/App/MENU_FETCH';
|
||||||
|
export const MENU_FETCH_SUCCEEDED = 'SettingsManager/App/MENU_FETCH_SUCCEEDED';
|
||||||
|
@ -8,9 +8,32 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
import { pluginId } from 'app';
|
import { pluginId } from 'app';
|
||||||
|
import PluginLeftMenu from 'components/PluginLeftMenu';
|
||||||
|
|
||||||
|
import { menuFetch } from './actions';
|
||||||
|
import selectGlobalDomain from './selectors';
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
value: false,
|
||||||
|
value1: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.menuFetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange = ({ target }) => {
|
||||||
|
this.setState({ value: target.value});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// Assign plugin component to children
|
// Assign plugin component to children
|
||||||
const content = React.Children.map(this.props.children, child =>
|
const content = React.Children.map(this.props.children, child =>
|
||||||
@ -18,9 +41,14 @@ class App extends React.Component {
|
|||||||
exposedComponents: this.props.exposedComponents,
|
exposedComponents: this.props.exposedComponents,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={pluginId}>
|
<div className={`${pluginId} ${styles.app}`}>
|
||||||
|
<div className={styles.baseline}></div>
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="row">
|
||||||
|
<PluginLeftMenu sections={this.props.app.sections} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{React.Children.toArray(content)}
|
{React.Children.toArray(content)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -32,17 +60,22 @@ App.contextTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
App.propTypes = {
|
App.propTypes = {
|
||||||
children: React.PropTypes.node.isRequired,
|
children: React.PropTypes.node,
|
||||||
exposedComponents: React.PropTypes.object.isRequired,
|
exposedComponents: React.PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function mapDispatchToProps(dispatch) {
|
export function mapDispatchToProps(dispatch) {
|
||||||
return {
|
return bindActionCreators(
|
||||||
dispatch,
|
{
|
||||||
};
|
menuFetch,
|
||||||
|
},
|
||||||
|
dispatch
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({});
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
app: selectGlobalDomain(),
|
||||||
|
});
|
||||||
|
|
||||||
// Wrap the component to inject dispatch and state into it
|
// Wrap the component to inject dispatch and state into it
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||||
|
@ -4,12 +4,19 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { fromJS } from 'immutable';
|
import { fromJS, List } from 'immutable';
|
||||||
|
import {
|
||||||
|
MENU_FETCH_SUCCEEDED,
|
||||||
|
} from './constants';
|
||||||
|
|
||||||
const initialState = fromJS({});
|
const initialState = fromJS({
|
||||||
|
sections: List(),
|
||||||
|
});
|
||||||
|
|
||||||
function appReducer(state = initialState, action) {
|
function appReducer(state = initialState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case MENU_FETCH_SUCCEEDED:
|
||||||
|
return state.set('menuSections', action.menu.sections);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
import { takeLatest } from 'redux-saga';
|
||||||
|
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||||
|
import { put, fork } from 'redux-saga/effects';
|
||||||
|
|
||||||
|
import { fetchMenuSucceeded } from './actions';
|
||||||
|
import { MENU_FETCH } from './constants';
|
||||||
|
|
||||||
|
export function* fetchMenu() {
|
||||||
|
try {
|
||||||
|
const opts = {
|
||||||
|
method: 'GET',
|
||||||
|
};
|
||||||
|
const response = yield fetch('/settings-manager/menu', opts);
|
||||||
|
const data = yield response.json();
|
||||||
|
|
||||||
|
yield put(fetchMenuSucceeded(data));
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
window.Strapi.notification.error(
|
||||||
|
'An error occurred.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function* defaultSaga() {
|
||||||
|
yield fork(takeLatest, MENU_FETCH, fetchMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default [defaultSaga];
|
@ -1,10 +1,10 @@
|
|||||||
// import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Direct selector to the list state domain
|
* Direct selector to the list state domain
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// const selectGlobalDomain = () => state => state.get('global');
|
const selectGlobalDomain = () => state => state.get('global');
|
||||||
|
|
||||||
const selectLocationState = () => {
|
const selectLocationState = () => {
|
||||||
let prevRoutingState;
|
let prevRoutingState;
|
||||||
@ -23,3 +23,4 @@ const selectLocationState = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export { selectLocationState };
|
export { selectLocationState };
|
||||||
|
export default selectGlobalDomain;
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
.app { /* stylelint-disable */
|
||||||
|
min-height: calc(100vh - 6rem); // TODO should be variable
|
||||||
|
background: rgba(14,22,34,0.02);
|
||||||
|
}
|
||||||
|
.baseline {
|
||||||
|
// display: none;
|
||||||
|
z-index: 100001;
|
||||||
|
opacity: .2;
|
||||||
|
position: absolute;
|
||||||
|
top:0; left:0;
|
||||||
|
width: 100%;
|
||||||
|
height: 500%;
|
||||||
|
min-height: 100%;
|
||||||
|
background: url('../../assets/images/baseline-18.png');
|
||||||
|
// background: url('../../assets/images/baseline-20.png');
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
@ -8,24 +8,40 @@ import React from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import PluginLeftMenu from 'components/PluginLeftMenu';
|
import PluginLeftMenu from 'components/PluginLeftMenu';
|
||||||
|
import InputToggle from 'components/InputToggle';
|
||||||
import selectHome from './selectors';
|
import selectHome from './selectors';
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
|
|
||||||
export class Home extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
export class Home extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
// constructor(props) {
|
constructor(props) {
|
||||||
// super(props);
|
super(props);
|
||||||
// // this.leftMenuItems = [
|
this.state = {
|
||||||
// // {
|
value: false,
|
||||||
// // header: 'global settings',
|
value1: null,
|
||||||
// // items: [
|
}
|
||||||
// // general, 'languages', 'advanced'],
|
}
|
||||||
// // }
|
|
||||||
// // ]
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
handleChange = ({ target }) => {
|
||||||
|
console.log('ok');
|
||||||
|
console.log(target);
|
||||||
|
this.setState({ value: !this.state.value});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
|
const test = {
|
||||||
|
"name": "bame",
|
||||||
|
"slug": "name",
|
||||||
|
"target": "general.name",
|
||||||
|
"type": "text",
|
||||||
|
"value": "ExperienceApp",
|
||||||
|
"validations" : {
|
||||||
|
"maxLength": 12,
|
||||||
|
"required": true,
|
||||||
|
"regex": /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.home}>
|
<div className={styles.home}>
|
||||||
<div className={styles.baseline}></div>
|
<div className={styles.baseline}></div>
|
||||||
@ -39,7 +55,20 @@ export class Home extends React.Component { // eslint-disable-line react/prefer-
|
|||||||
<div className="row">
|
<div className="row">
|
||||||
<PluginLeftMenu />
|
<PluginLeftMenu />
|
||||||
<div className="col-md-9">
|
<div className="col-md-9">
|
||||||
f
|
<div className="form-group">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<InputToggle
|
||||||
|
handleChange={this.handleChange}
|
||||||
|
isChecked={this.state.value}
|
||||||
|
name={test.name}
|
||||||
|
validations={test.validations}
|
||||||
|
customBootstrapClass={'col-lg-2 offset-lg-4'}
|
||||||
|
errors={[]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"/": {
|
"/": {
|
||||||
"name": "home",
|
"name": "app",
|
||||||
"container": "Home"
|
"container": "App"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user