mirror of
https://github.com/strapi/strapi.git
synced 2025-11-13 16:52:18 +00:00
Use bindActionCreators, solve i18n issues
This commit is contained in:
parent
6b6f1be98c
commit
be4c757f5a
@ -12,7 +12,7 @@ import ReactDOM from 'react-dom';
|
|||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { ConnectedRouter } from 'react-router-redux';
|
import { ConnectedRouter } from 'react-router-redux';
|
||||||
import createHistory from 'history/createBrowserHistory';
|
import createHistory from 'history/createBrowserHistory';
|
||||||
import _ from 'lodash';
|
import { merge, isFunction } from 'lodash';
|
||||||
import 'sanitize.css/sanitize.css';
|
import 'sanitize.css/sanitize.css';
|
||||||
|
|
||||||
import LanguageProvider from 'containers/LanguageProvider';
|
import LanguageProvider from 'containers/LanguageProvider';
|
||||||
@ -77,14 +77,19 @@ window.onload = function onLoad() {
|
|||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
const registerPlugin = (plugin) => {
|
const registerPlugin = (plugin) => {
|
||||||
const formattedPlugin = plugin;
|
|
||||||
|
|
||||||
// Merge admin translation messages
|
// Merge admin translation messages
|
||||||
_.merge(translationMessages, formattedPlugin.translationMessages);
|
merge(translationMessages, plugin.translationMessages);
|
||||||
|
|
||||||
formattedPlugin.leftMenuSections = formattedPlugin.leftMenuSections || [];
|
plugin.leftMenuSections = plugin.leftMenuSections || [];
|
||||||
|
|
||||||
store.dispatch(pluginLoaded(formattedPlugin));
|
// Execute bootstrap function.
|
||||||
|
if (isFunction(plugin.bootstrap)) {
|
||||||
|
plugin.bootstrap(plugin).then(plugin => {
|
||||||
|
store.dispatch(pluginLoaded(plugin));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
store.dispatch(pluginLoaded(plugin));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const displayNotification = (message, status) => {
|
const displayNotification = (message, status) => {
|
||||||
@ -114,7 +119,8 @@ window.Strapi = {
|
|||||||
apiUrl,
|
apiUrl,
|
||||||
refresh: (pluginId) => ({
|
refresh: (pluginId) => ({
|
||||||
translationMessages: (translationMessagesUpdated) => {
|
translationMessages: (translationMessagesUpdated) => {
|
||||||
render(_.merge({}, translationMessages, translationMessagesUpdated));
|
console.log(translationMessagesUpdated);
|
||||||
|
render(merge({}, translationMessages, translationMessagesUpdated));
|
||||||
},
|
},
|
||||||
leftMenuSections: (leftMenuSectionsUpdated) => {
|
leftMenuSections: (leftMenuSectionsUpdated) => {
|
||||||
store.dispatch(updatePlugin(pluginId, 'leftMenuSections', leftMenuSectionsUpdated));
|
store.dispatch(updatePlugin(pluginId, 'leftMenuSections', leftMenuSectionsUpdated));
|
||||||
|
|||||||
@ -21,7 +21,14 @@ class LeftMenuLink extends React.Component { // eslint-disable-line react/prefer
|
|||||||
<li className={styles.item}>
|
<li className={styles.item}>
|
||||||
<Link className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`} to={this.props.destination}>
|
<Link className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`} to={this.props.destination}>
|
||||||
<i className={`${styles.linkIcon} fa-${this.props.icon} fa`}></i>
|
<i className={`${styles.linkIcon} fa-${this.props.icon} fa`}></i>
|
||||||
<FormattedMessage id={this.props.label} className={styles.linkLabel} />
|
<FormattedMessage
|
||||||
|
id={this.props.label}
|
||||||
|
defaultMessage='{label}'
|
||||||
|
values={{
|
||||||
|
label: this.props.label,
|
||||||
|
}}
|
||||||
|
className={styles.linkLabel}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import { hideNotification } from 'containers/NotificationProvider/actions';
|
|||||||
|
|
||||||
import Header from 'components/Header/index';
|
import Header from 'components/Header/index';
|
||||||
|
|
||||||
import styles from './syles.scss';
|
import styles from './styles.scss';
|
||||||
|
|
||||||
export class AdminPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
export class AdminPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@ -36,10 +36,6 @@ export class PluginPage extends React.Component { // eslint-disable-line react/p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginPage.contextTypes = {
|
|
||||||
router: React.PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
PluginPage.propTypes = {
|
PluginPage.propTypes = {
|
||||||
match: React.PropTypes.object.isRequired,
|
match: React.PropTypes.object.isRequired,
|
||||||
plugins: React.PropTypes.object.isRequired,
|
plugins: React.PropTypes.object.isRequired,
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import App from 'containers/App'; // eslint-disable-line
|
import App, { bootstrap } from 'containers/App'; // eslint-disable-line
|
||||||
|
|
||||||
import configureStore from './store';
|
import configureStore from './store';
|
||||||
import { translationMessages } from './i18n';
|
import { translationMessages } from './i18n';
|
||||||
@ -27,7 +27,6 @@ const router = window.Strapi.router;
|
|||||||
// Create redux store with Strapi admin history
|
// Create redux store with Strapi admin history
|
||||||
const store = configureStore({}, window.Strapi.router);
|
const store = configureStore({}, window.Strapi.router);
|
||||||
|
|
||||||
|
|
||||||
// Define the plugin root component
|
// Define the plugin root component
|
||||||
function Comp(props) {
|
function Comp(props) {
|
||||||
return (
|
return (
|
||||||
@ -37,11 +36,6 @@ function Comp(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add contextTypes to get access to the admin router
|
|
||||||
Comp.contextTypes = {
|
|
||||||
router: React.PropTypes.object.isRequired.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hot reloadable translation json files
|
// Hot reloadable translation json files
|
||||||
if (module.hot) {
|
if (module.hot) {
|
||||||
// modules.hot.accept does not accept dynamic dependencies,
|
// modules.hot.accept does not accept dynamic dependencies,
|
||||||
@ -58,7 +52,7 @@ if (module.hot) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the plugin
|
// Register the plugin.
|
||||||
window.Strapi.registerPlugin({
|
window.Strapi.registerPlugin({
|
||||||
name: pluginPkg.strapi.name,
|
name: pluginPkg.strapi.name,
|
||||||
icon: pluginPkg.strapi.icon,
|
icon: pluginPkg.strapi.icon,
|
||||||
@ -66,8 +60,8 @@ window.Strapi.registerPlugin({
|
|||||||
leftMenuLinks: [],
|
leftMenuLinks: [],
|
||||||
mainComponent: Comp,
|
mainComponent: Comp,
|
||||||
translationMessages,
|
translationMessages,
|
||||||
|
bootstrap,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Export store
|
// Export store
|
||||||
export { store, apiUrl, pluginId, pluginName, pluginDescription, router };
|
export { store, apiUrl, pluginId, pluginName, pluginDescription, router };
|
||||||
|
|||||||
@ -15,7 +15,10 @@ class Button extends React.Component {
|
|||||||
const addShape = this.props.addShape ? <i className="fa fa-plus" /> : '';
|
const addShape = this.props.addShape ? <i className="fa fa-plus" /> : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className={`${styles[this.props.buttonSize]} ${styles[this.props.buttonBackground]} ${styles.button}`} {...this.props}>
|
<button
|
||||||
|
className={`${styles[this.props.buttonSize]} ${styles[this.props.buttonBackground]} ${styles.button}`}
|
||||||
|
onClick={this.props.onClick}
|
||||||
|
>
|
||||||
{addShape}{label}
|
{addShape}{label}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -146,7 +146,7 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
<div className={`${styles.inputCheckbox} col-md-12 ${requiredClass}`}>
|
<div className={`${styles.inputCheckbox} col-md-12 ${requiredClass}`}>
|
||||||
<div className="form-check">
|
<div className="form-check">
|
||||||
{title}
|
{title}
|
||||||
<FormattedMessage id={this.props.label}>
|
<FormattedMessage id={this.props.label} defaultMessage={this.props.label}>
|
||||||
{(message) => (
|
{(message) => (
|
||||||
<label className={`${styles.checkboxLabel} form-check-label`} htmlFor={this.props.label}>
|
<label className={`${styles.checkboxLabel} form-check-label`} htmlFor={this.props.label}>
|
||||||
<input className="form-check-input" type="checkbox" defaultChecked={this.props.value} onChange={this.handleChangeCheckbox} name={this.props.name} />
|
<input className="form-check-input" type="checkbox" defaultChecked={this.props.value} onChange={this.handleChangeCheckbox} name={this.props.name} />
|
||||||
@ -168,7 +168,7 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
return (
|
return (
|
||||||
<div className={`${styles.input} ${requiredClass} ${bootStrapClass}`}>
|
<div className={`${styles.input} ${requiredClass} ${bootStrapClass}`}>
|
||||||
<label htmlFor={this.props.label}>
|
<label htmlFor={this.props.label}>
|
||||||
<FormattedMessage id={`${this.props.label}`} />
|
<FormattedMessage id={`${this.props.label}`} defaultMessage={this.props.label} />
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
className="form-control"
|
className="form-control"
|
||||||
@ -179,7 +179,7 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
>
|
>
|
||||||
{map(this.props.selectOptions, (option, key) => (
|
{map(this.props.selectOptions, (option, key) => (
|
||||||
<FormattedMessage id={`${option.name}`} key={key}>
|
<FormattedMessage id={`${option.name}`} defaultMessage={option.name} key={key}>
|
||||||
{(message) => (
|
{(message) => (
|
||||||
<option value={option.value}>
|
<option value={option.value}>
|
||||||
{message}
|
{message}
|
||||||
@ -207,9 +207,9 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
return (
|
return (
|
||||||
<div className={`${styles.inputTextArea} ${bootStrapClass} ${requiredClass} ${bootStrapClassDanger}`}>
|
<div className={`${styles.inputTextArea} ${bootStrapClass} ${requiredClass} ${bootStrapClassDanger}`}>
|
||||||
<label htmlFor={this.props.label}>
|
<label htmlFor={this.props.label}>
|
||||||
<FormattedMessage id={`${this.props.label}`} />
|
<FormattedMessage id={`${this.props.label}`} defaultMessage={this.props.label} />
|
||||||
</label>
|
</label>
|
||||||
<FormattedMessage id={this.props.placeholder || this.props.label}>
|
<FormattedMessage id={this.props.placeholder || this.props.label} defaultMessage={this.props.label}>
|
||||||
{(placeholder) => (
|
{(placeholder) => (
|
||||||
<textarea
|
<textarea
|
||||||
className="form-control"
|
className="form-control"
|
||||||
@ -247,7 +247,7 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
return (
|
return (
|
||||||
<div className={`${styles.input} ${bootStrapClass} ${requiredClass}`}>
|
<div className={`${styles.input} ${bootStrapClass} ${requiredClass}`}>
|
||||||
<label htmlFor={this.props.label}>
|
<label htmlFor={this.props.label}>
|
||||||
<FormattedMessage id={`${this.props.label}`} />
|
<FormattedMessage id={`${this.props.label}`} defaultMessage={this.props.label} />
|
||||||
</label>
|
</label>
|
||||||
<DateTime
|
<DateTime
|
||||||
value={value}
|
value={value}
|
||||||
@ -275,7 +275,7 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderFormattedInput = (handleBlur, inputValue, placeholder) => (
|
renderFormattedInput = (handleBlur, inputValue, placeholder) => (
|
||||||
<FormattedMessage id={`${placeholder}`}>
|
<FormattedMessage id={`${placeholder}`} defaultMessage={placeholder}>
|
||||||
{(message) => (
|
{(message) => (
|
||||||
<input
|
<input
|
||||||
name={this.props.name}
|
name={this.props.name}
|
||||||
@ -305,7 +305,7 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel
|
|||||||
const placeholder = this.props.placeholder || this.props.label;
|
const placeholder = this.props.placeholder || this.props.label;
|
||||||
|
|
||||||
const label = this.props.label ?
|
const label = this.props.label ?
|
||||||
<label htmlFor={this.props.label}><FormattedMessage id={`${this.props.label}`} /></label>
|
<label htmlFor={this.props.label}><FormattedMessage id={`${this.props.label}`} defaultMessage={this.props.label} /></label>
|
||||||
: <label htmlFor={this.props.label} />;
|
: <label htmlFor={this.props.label} />;
|
||||||
|
|
||||||
const requiredClass = get(this.props.validations, 'required') && this.props.addRequiredInputDesign ?
|
const requiredClass = get(this.props.validations, 'required') && this.props.addRequiredInputDesign ?
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class PluginHeaderActions extends React.Component { // eslint-disable-line react
|
|||||||
{...action}
|
{...action}
|
||||||
key={action.label}
|
key={action.label}
|
||||||
>
|
>
|
||||||
<FormattedMessage id={action.label} />
|
<FormattedMessage id={action.label} defaultMessage={action.label} />
|
||||||
</Button>
|
</Button>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class PluginHeaderTitle extends React.Component { // eslint-disable-line react/p
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className={styles.pluginHeaderTitleName}>
|
<h1 className={styles.pluginHeaderTitleName}>
|
||||||
<FormattedMessage {...this.props.title} />
|
<FormattedMessage {...this.props.title} defaultMessage={this.props.title.id} />
|
||||||
</h1>
|
</h1>
|
||||||
<p className={styles.pluginHeaderTitleDescription}>
|
<p className={styles.pluginHeaderTitleDescription}>
|
||||||
<FormattedMessage {...this.props.description} />
|
<FormattedMessage {...this.props.description} />
|
||||||
|
|||||||
@ -8,9 +8,13 @@ import 'whatwg-fetch';
|
|||||||
* @return {object} The parsed JSON from the request
|
* @return {object} The parsed JSON from the request
|
||||||
*/
|
*/
|
||||||
function parseJSON(response) {
|
function parseJSON(response) {
|
||||||
|
if (response.json) {
|
||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a network request came back fine, and throws an error if not
|
* Checks if a network request came back fine, and throws an error if not
|
||||||
*
|
*
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class TableFooter extends React.Component {
|
|||||||
<div className="col-lg-6">
|
<div className="col-lg-6">
|
||||||
<LimitSelect
|
<LimitSelect
|
||||||
className="push-lg-right"
|
className="push-lg-right"
|
||||||
onLimitChange={this.props.onLimitChange}
|
handleLimit={this.props.handleLimit}
|
||||||
limit={this.props.limit}
|
limit={this.props.limit}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -42,8 +42,8 @@ TableFooter.propTypes = {
|
|||||||
React.PropTypes.bool,
|
React.PropTypes.bool,
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
currentPage: React.PropTypes.number.isRequired,
|
currentPage: React.PropTypes.number.isRequired,
|
||||||
|
handleLimit: React.PropTypes.func.isRequired,
|
||||||
limit: React.PropTypes.number.isRequired,
|
limit: React.PropTypes.number.isRequired,
|
||||||
onLimitChange: React.PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TableFooter;
|
export default TableFooter;
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import List from 'containers/List';
|
|||||||
import { loadModels, updateSchema } from './actions';
|
import { loadModels, updateSchema } from './actions';
|
||||||
import { makeSelectLoading } from './selectors';
|
import { makeSelectLoading } from './selectors';
|
||||||
|
|
||||||
import saga from './sagas';
|
import saga, { generateMenu } from './sagas';
|
||||||
|
|
||||||
const tryRequire = (path) => {
|
const tryRequire = (path) => {
|
||||||
try {
|
try {
|
||||||
@ -31,8 +31,19 @@ const tryRequire = (path) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This method is executed before the load of the plugin.
|
||||||
|
export const bootstrap = (plugin) => new Promise((resolve, reject) => {
|
||||||
|
generateMenu()
|
||||||
|
.then(menu => {
|
||||||
|
plugin.leftMenuSections = menu;
|
||||||
|
|
||||||
|
resolve(plugin);
|
||||||
|
})
|
||||||
|
.catch(e => reject(e));
|
||||||
|
});
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
const config = tryRequire('../../../../config/admin.json');
|
const config = tryRequire('../../../../config/admin.json');
|
||||||
|
|
||||||
if (!_.isEmpty(_.get(config, 'admin.schema'))) {
|
if (!_.isEmpty(_.get(config, 'admin.schema'))) {
|
||||||
@ -82,7 +93,6 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
const withSaga = injectSaga({ key: 'global', saga });
|
const withSaga = injectSaga({ key: 'global', saga });
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
|
|||||||
@ -5,9 +5,30 @@ import request from 'utils/request';
|
|||||||
import { generateSchema } from 'utils/schema';
|
import { generateSchema } from 'utils/schema';
|
||||||
|
|
||||||
import { loadedModels, updateSchema } from './actions';
|
import { loadedModels, updateSchema } from './actions';
|
||||||
import { LOAD_MODELS, LOADED_MODELS, UPDATE_SCHEMA } from './constants';
|
import { LOAD_MODELS, LOADED_MODELS } from './constants';
|
||||||
import { makeSelectModels } from './selectors';
|
import { makeSelectModels } from './selectors';
|
||||||
|
|
||||||
|
export const generateMenu = function () {
|
||||||
|
try {
|
||||||
|
return request(`${window.Strapi.apiUrl}/content-manager/models`, {
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
.then(response => generateSchema(response))
|
||||||
|
.then(displayedModels => {
|
||||||
|
return [{
|
||||||
|
name: 'Content Types',
|
||||||
|
links: _.map(displayedModels, (model, key) => ({
|
||||||
|
label: model.labelPlural || model.label || key,
|
||||||
|
destination: key,
|
||||||
|
})),
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
window.Strapi.notification.error(
|
||||||
|
'An error occurred during models config fetch.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function* getModels() {
|
export function* getModels() {
|
||||||
try {
|
try {
|
||||||
@ -40,27 +61,9 @@ export function* modelsLoaded() {
|
|||||||
yield put(updateSchema(schema));
|
yield put(updateSchema(schema));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* schemaUpdated(action) {
|
|
||||||
// Display the links only if the `displayed` attribute is not set to false
|
|
||||||
const displayedModels = _.pickBy(action.schema, model => (model.displayed !== false));
|
|
||||||
|
|
||||||
// Map links to format them
|
|
||||||
const leftMenuSections = [{
|
|
||||||
name: 'Content Types',
|
|
||||||
links: _.map(displayedModels, (model, key) => ({
|
|
||||||
label: model.labelPlural || model.label || key,
|
|
||||||
destination: key,
|
|
||||||
})),
|
|
||||||
}];
|
|
||||||
|
|
||||||
// Update the admin left menu links
|
|
||||||
window.Strapi.refresh('content-manager').leftMenuSections(leftMenuSections);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Individual exports for testing
|
// Individual exports for testing
|
||||||
export function* defaultSaga() {
|
export function* defaultSaga() {
|
||||||
yield fork(takeLatest, LOAD_MODELS, getModels);
|
yield fork(takeLatest, LOAD_MODELS, getModels);
|
||||||
yield fork(takeLatest, UPDATE_SCHEMA, schemaUpdated);
|
|
||||||
yield fork(takeLatest, LOADED_MODELS, modelsLoaded);
|
yield fork(takeLatest, LOADED_MODELS, modelsLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { compose } from 'redux';
|
import { bindActionCreators, compose } from 'redux';
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
import { get, isObject } from 'lodash';
|
import { get, isObject } from 'lodash';
|
||||||
import { router } from 'app';
|
import { router } from 'app';
|
||||||
@ -37,7 +37,6 @@ import {
|
|||||||
loadRecord,
|
loadRecord,
|
||||||
setRecordAttribute,
|
setRecordAttribute,
|
||||||
editRecord,
|
editRecord,
|
||||||
deleteRecord,
|
|
||||||
toggleNull,
|
toggleNull,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
|
|
||||||
@ -57,7 +56,11 @@ import reducer from './reducer';
|
|||||||
import saga from './sagas';
|
import saga from './sagas';
|
||||||
|
|
||||||
export class Edit extends React.Component {
|
export class Edit extends React.Component {
|
||||||
componentWillMount() {
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
@ -65,10 +68,15 @@ export class Edit extends React.Component {
|
|||||||
if (this.props.match.params.id === 'create') {
|
if (this.props.match.params.id === 'create') {
|
||||||
this.props.setIsCreating();
|
this.props.setIsCreating();
|
||||||
} else {
|
} else {
|
||||||
|
console.log("LOAD RECORD");
|
||||||
this.props.loadRecord(this.props.match.params.id);
|
this.props.loadRecord(this.props.match.params.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
console.log("UNMOUNTED");
|
||||||
|
}
|
||||||
|
|
||||||
handleChange = (e) => {
|
handleChange = (e) => {
|
||||||
if (isObject(e.target.value) && e.target.value._isAMomentObject === true) {
|
if (isObject(e.target.value) && e.target.value._isAMomentObject === true) {
|
||||||
e.target.value = moment(e.target.value, 'YYYY-MM-DD HH:mm:ss').format();
|
e.target.value = moment(e.target.value, 'YYYY-MM-DD HH:mm:ss').format();
|
||||||
@ -237,25 +245,18 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
return {
|
return bindActionCreators(
|
||||||
setInitialState: () => dispatch(setInitialState()),
|
{
|
||||||
setCurrentModelName: currentModelName =>
|
setInitialState,
|
||||||
dispatch(setCurrentModelName(currentModelName)),
|
setCurrentModelName,
|
||||||
setIsCreating: () => dispatch(setIsCreating()),
|
setIsCreating,
|
||||||
loadRecord: id => dispatch(loadRecord(id)),
|
loadRecord,
|
||||||
setRecordAttribute: (key, value) =>
|
setRecordAttribute,
|
||||||
dispatch(setRecordAttribute(key, value)),
|
editRecord,
|
||||||
editRecord: () => dispatch(editRecord()),
|
toggleNull,
|
||||||
deleteRecord: () => {
|
|
||||||
// TODO: improve confirmation UX.
|
|
||||||
if (window.confirm('Are you sure ?')) {
|
|
||||||
// eslint-disable-line no-alert
|
|
||||||
dispatch(deleteRecord());
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
toggleNull: () => dispatch(toggleNull()),
|
dispatch
|
||||||
dispatch,
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export function* getRecord(params) {
|
|||||||
const requestUrl = `${window.Strapi.apiUrl}/content-manager/explorer/${currentModelName}/${params.id}`;
|
const requestUrl = `${window.Strapi.apiUrl}/content-manager/explorer/${currentModelName}/${params.id}`;
|
||||||
|
|
||||||
// Call our request helper (see 'utils/request')
|
// Call our request helper (see 'utils/request')
|
||||||
const response = yield call(request, requestUrl, {
|
const response = yield request(requestUrl, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,14 +110,11 @@ export function* deleteRecord({ id, modelName }) {
|
|||||||
export function* defaultSaga() {
|
export function* defaultSaga() {
|
||||||
const loadRecordWatcher = yield fork(takeLatest, LOAD_RECORD, getRecord);
|
const loadRecordWatcher = yield fork(takeLatest, LOAD_RECORD, getRecord);
|
||||||
const editRecordWatcher = yield fork(takeLatest, EDIT_RECORD, editRecord);
|
const editRecordWatcher = yield fork(takeLatest, EDIT_RECORD, editRecord);
|
||||||
const deleteRecordWatcher = yield fork(
|
const deleteRecordWatcher = yield fork(takeLatest, DELETE_RECORD, deleteRecord);
|
||||||
takeLatest,
|
|
||||||
DELETE_RECORD,
|
|
||||||
deleteRecord
|
|
||||||
);
|
|
||||||
|
|
||||||
// Suspend execution until location changes
|
// Suspend execution until location changes
|
||||||
yield take(LOCATION_CHANGE);
|
yield take(LOCATION_CHANGE);
|
||||||
|
|
||||||
yield cancel(loadRecordWatcher);
|
yield cancel(loadRecordWatcher);
|
||||||
yield cancel(editRecordWatcher);
|
yield cancel(editRecordWatcher);
|
||||||
yield cancel(deleteRecordWatcher);
|
yield cancel(deleteRecordWatcher);
|
||||||
|
|||||||
@ -65,6 +65,7 @@ export function changePage(page) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function changeSort(sort) {
|
export function changeSort(sort) {
|
||||||
|
console.log("COUCOU", sort);
|
||||||
return {
|
return {
|
||||||
type: CHANGE_SORT,
|
type: CHANGE_SORT,
|
||||||
sort,
|
sort,
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { compose } from 'redux';
|
import { bindActionCreators, compose } from 'redux';
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
@ -65,17 +65,14 @@ export class List extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
// Init the view
|
// Init the view
|
||||||
this.init(this.props.match.params.slug);
|
this.init(this.props.match.params.slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
// Check if the current slug changed in the url
|
const locationChanged = nextProps.location.pathname !== this.props.location.pathname;
|
||||||
const locationChanged =
|
|
||||||
nextProps.location.pathname !== this.props.location.pathname;
|
|
||||||
|
|
||||||
// If the location changed, init the view
|
|
||||||
if (locationChanged) {
|
if (locationChanged) {
|
||||||
this.init(nextProps.match.params.slug);
|
this.init(nextProps.match.params.slug);
|
||||||
}
|
}
|
||||||
@ -85,7 +82,6 @@ export class List extends React.Component {
|
|||||||
// Set current model name
|
// Set current model name
|
||||||
this.props.setCurrentModelName(slug.toLowerCase());
|
this.props.setCurrentModelName(slug.toLowerCase());
|
||||||
|
|
||||||
// Set default sort value
|
|
||||||
this.props.changeSort(this.props.models[slug.toLowerCase()].primaryKey || 'desc');
|
this.props.changeSort(this.props.models[slug.toLowerCase()].primaryKey || 'desc');
|
||||||
|
|
||||||
// Load records
|
// Load records
|
||||||
@ -102,7 +98,7 @@ export class List extends React.Component {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
this.props.deleteRecord(this.state.target, this.props.currentModelName);
|
this.props.deleteRecord(this.state, this.props.currentModelName);
|
||||||
this.setState({ showWarning: false });
|
this.setState({ showWarning: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +203,7 @@ export class List extends React.Component {
|
|||||||
changePage={this.props.changePage}
|
changePage={this.props.changePage}
|
||||||
count={this.props.count}
|
count={this.props.count}
|
||||||
className="push-lg-right"
|
className="push-lg-right"
|
||||||
onLimitChange={this.props.onLimitChange}
|
handleLimit={this.props.changeLimit}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -222,6 +218,7 @@ List.contextTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
List.propTypes = {
|
List.propTypes = {
|
||||||
|
changeLimit: React.PropTypes.func.isRequired,
|
||||||
changePage: React.PropTypes.func.isRequired,
|
changePage: React.PropTypes.func.isRequired,
|
||||||
changeSort: React.PropTypes.func.isRequired,
|
changeSort: React.PropTypes.func.isRequired,
|
||||||
count: React.PropTypes.oneOfType([
|
count: React.PropTypes.oneOfType([
|
||||||
@ -245,7 +242,6 @@ List.propTypes = {
|
|||||||
React.PropTypes.object,
|
React.PropTypes.object,
|
||||||
React.PropTypes.bool,
|
React.PropTypes.bool,
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
onLimitChange: React.PropTypes.func.isRequired,
|
|
||||||
records: React.PropTypes.oneOfType([
|
records: React.PropTypes.oneOfType([
|
||||||
React.PropTypes.array,
|
React.PropTypes.array,
|
||||||
React.PropTypes.bool,
|
React.PropTypes.bool,
|
||||||
@ -260,29 +256,18 @@ List.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
return {
|
return bindActionCreators(
|
||||||
deleteRecord: (id, modelName) => dispatch(deleteRecord(id, modelName)),
|
{
|
||||||
setCurrentModelName: modelName => dispatch(setCurrentModelName(modelName)),
|
deleteRecord,
|
||||||
loadRecords: () => dispatch(loadRecords()),
|
setCurrentModelName,
|
||||||
loadCount: () => dispatch(loadCount()),
|
loadRecords,
|
||||||
changePage: page => {
|
loadCount,
|
||||||
dispatch(changePage(page));
|
changePage,
|
||||||
dispatch(loadRecords());
|
changeSort,
|
||||||
dispatch(loadCount());
|
changeLimit,
|
||||||
},
|
},
|
||||||
changeSort: sort => {
|
dispatch
|
||||||
dispatch(changeSort(sort));
|
);
|
||||||
dispatch(loadRecords());
|
|
||||||
},
|
|
||||||
onLimitChange: e => {
|
|
||||||
const newLimit = Number(e.target.value);
|
|
||||||
dispatch(changeLimit(newLimit));
|
|
||||||
dispatch(changePage(1));
|
|
||||||
dispatch(loadRecords());
|
|
||||||
e.target.blur();
|
|
||||||
},
|
|
||||||
dispatch,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
|||||||
@ -26,11 +26,13 @@ import {
|
|||||||
} from './selectors';
|
} from './selectors';
|
||||||
|
|
||||||
export function* getRecords() {
|
export function* getRecords() {
|
||||||
|
console.log("GET RECORDS");
|
||||||
const currentModel = yield select(makeSelectCurrentModelName());
|
const currentModel = yield select(makeSelectCurrentModelName());
|
||||||
const limit = yield select(makeSelectLimit());
|
const limit = yield select(makeSelectLimit());
|
||||||
const currentPage = yield select(makeSelectCurrentPage());
|
const currentPage = yield select(makeSelectCurrentPage());
|
||||||
const sort = yield select(makeSelectSort());
|
const sort = yield select(makeSelectSort());
|
||||||
|
console.log(sort);
|
||||||
|
console.log("#1");
|
||||||
// Calculate the number of values to be skip
|
// Calculate the number of values to be skip
|
||||||
const skip = (currentPage - 1) * limit;
|
const skip = (currentPage - 1) * limit;
|
||||||
|
|
||||||
@ -43,14 +45,17 @@ export function* getRecords() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const requestUrl = `${window.Strapi.apiUrl}/content-manager/explorer/${currentModel}`;
|
const requestUrl = `${window.Strapi.apiUrl}/content-manager/explorer/${currentModel}`;
|
||||||
|
console.log("#1.5");
|
||||||
// Call our request helper (see 'utils/request')
|
// Call our request helper (see 'utils/request')
|
||||||
const response = yield call(request, requestUrl, {
|
const response = yield call(request, requestUrl, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log("#2");
|
||||||
|
|
||||||
yield put(loadedRecord(response));
|
yield put(loadedRecord(response));
|
||||||
|
console.log("#3");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
window.Strapi.notification.error('An error occurred during records fetch.');
|
window.Strapi.notification.error('An error occurred during records fetch.');
|
||||||
}
|
}
|
||||||
@ -81,6 +86,7 @@ export function* defaultSaga() {
|
|||||||
|
|
||||||
// Suspend execution until location changes
|
// Suspend execution until location changes
|
||||||
yield take(LOCATION_CHANGE);
|
yield take(LOCATION_CHANGE);
|
||||||
|
|
||||||
yield cancel(loadRecordsWatcher);
|
yield cancel(loadRecordsWatcher);
|
||||||
yield cancel(loudCountWatcher);
|
yield cancel(loudCountWatcher);
|
||||||
yield cancel(deleteRecordWatcher);
|
yield cancel(deleteRecordWatcher);
|
||||||
|
|||||||
@ -52,15 +52,19 @@ function formatQueryParams(params) {
|
|||||||
* @return {object} The response data
|
* @return {object} The response data
|
||||||
*/
|
*/
|
||||||
export default function request(url, options) {
|
export default function request(url, options) {
|
||||||
|
console.log(url, options);
|
||||||
const optionsObj = options || {};
|
const optionsObj = options || {};
|
||||||
|
|
||||||
// Set headers
|
// Set headers
|
||||||
optionsObj.headers = {
|
optionsObj.headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'text/plain',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add parameters to url
|
// Add parameters to url
|
||||||
let urlFormatted = url;
|
let urlFormatted = _.startsWith(url, '/')
|
||||||
|
? `${Strapi.apiUrl}${url}`
|
||||||
|
: url;
|
||||||
|
|
||||||
if (optionsObj && optionsObj.params) {
|
if (optionsObj && optionsObj.params) {
|
||||||
const params = formatQueryParams(optionsObj.params);
|
const params = formatQueryParams(optionsObj.params);
|
||||||
urlFormatted = `${url}?${params}`;
|
urlFormatted = `${url}?${params}`;
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
find: async function (params) {
|
find: async function (params) {
|
||||||
console.log(params);
|
|
||||||
const entries = await this
|
const entries = await this
|
||||||
.forge()
|
.forge()
|
||||||
.query((qb) => {
|
.query((qb) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user