Use bindActionCreators, solve i18n issues

This commit is contained in:
Aurelsicoko 2017-09-14 11:10:05 +02:00
parent 6b6f1be98c
commit be4c757f5a
23 changed files with 140 additions and 124 deletions

View File

@ -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));

View File

@ -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>
); );

View File

@ -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() {

View File

@ -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,

View File

@ -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 };

View File

@ -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>
); );

View File

@ -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 ?

View File

@ -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>
)); ));

View File

@ -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} />

View File

@ -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
* *

View File

@ -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;

View File

@ -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(

View File

@ -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);
} }

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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({

View File

@ -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);

View File

@ -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}`;

View File

@ -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) => {