admin-on-rest-fr05t1k
Version:
A frontend Framework for building admin applications on top of REST services, using ES6, React and Material UI
402 lines (338 loc) • 15 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.List = undefined;
var _extends4 = require('babel-runtime/helpers/extends');
var _extends5 = _interopRequireDefault(_extends4);
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactRedux = require('react-redux');
var _queryString = require('query-string');
var _reactRouterRedux = require('react-router-redux');
var _Card = require('material-ui/Card');
var _compose = require('recompose/compose');
var _compose2 = _interopRequireDefault(_compose);
var _reselect = require('reselect');
var _inflection = require('inflection');
var _inflection2 = _interopRequireDefault(_inflection);
var _queryReducer = require('../../reducer/resource/list/queryReducer');
var _queryReducer2 = _interopRequireDefault(_queryReducer);
var _ViewTitle = require('../layout/ViewTitle');
var _ViewTitle2 = _interopRequireDefault(_ViewTitle);
var _Title = require('../layout/Title');
var _Title2 = _interopRequireDefault(_Title);
var _Pagination = require('./Pagination');
var _Pagination2 = _interopRequireDefault(_Pagination);
var _Actions = require('./Actions');
var _Actions2 = _interopRequireDefault(_Actions);
var _dataActions = require('../../actions/dataActions');
var _listActions = require('../../actions/listActions');
var _translate = require('../../i18n/translate');
var _translate2 = _interopRequireDefault(_translate);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var styles = {
noResults: { padding: 20 }
};
/**
* List page component
*
* The <List> component renders the list layout (title, buttons, filters, pagination),
* and fetches the list of records from the REST API.
* It then delegates the rendering of the list of records to its child component.
* Usually, it's a <Datagrid>, responsible for displaying a table with one row for each post.
*
* In Redux terms, <List> is a connected component, and <Datagrid> is a dumb component.
*
* Props:
* - title
* - perPage
* - sort
* - filter (the permanent filter to apply to the query)
* - actions
* - filters (a React Element used to display the filter form)
* - pagination
*
* @example
* const PostFilter = (props) => (
* <Filter {...props}>
* <TextInput label="Search" source="q" alwaysOn />
* <TextInput label="Title" source="title" />
* </Filter>
* );
* export const PostList = (props) => (
* <List {...props}
* title="List of posts"
* sort={{ field: 'published_at' }}
* filter={{ is_published: true }}
* filters={<PostFilter />}
* >
* <Datagrid>
* <TextField source="id" />
* <TextField source="title" />
* <EditButton />
* </Datagrid>
* </List>
* );
*/
var List = exports.List = function (_Component) {
(0, _inherits3.default)(List, _Component);
function List(props) {
(0, _classCallCheck3.default)(this, List);
var _this = (0, _possibleConstructorReturn3.default)(this, (List.__proto__ || Object.getPrototypeOf(List)).call(this, props));
_this.refresh = function (event) {
event.stopPropagation();
_this.fullRefresh = true;
_this.updateData();
};
_this.setSort = function (sort) {
return _this.changeParams({ type: _queryReducer.SET_SORT, payload: sort });
};
_this.setPage = function (page) {
return _this.changeParams({ type: _queryReducer.SET_PAGE, payload: page });
};
_this.setFilters = function (filters) {
return _this.changeParams({ type: _queryReducer.SET_FILTER, payload: filters });
};
_this.showFilter = function (filterName, defaultValue) {
_this.setState((0, _defineProperty3.default)({}, filterName, true));
if (typeof defaultValue !== 'undefined') {
_this.setFilters((0, _extends5.default)({}, _this.props.filterValues, (0, _defineProperty3.default)({}, filterName, defaultValue)));
}
};
_this.hideFilter = function (filterName) {
_this.setState((0, _defineProperty3.default)({}, filterName, false));
_this.setFilters((0, _extends5.default)({}, _this.props.filterValues, (0, _defineProperty3.default)({}, filterName, undefined)));
};
_this.state = { key: 0 };
return _this;
}
(0, _createClass3.default)(List, [{
key: 'componentDidMount',
value: function componentDidMount() {
this.updateData();
if (Object.keys(this.props.query).length > 0) {
this.props.changeListParams(this.props.resource, this.props.query);
}
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (nextProps.resource !== this.props.resource || nextProps.query.sort !== this.props.query.sort || nextProps.query.order !== this.props.query.order || nextProps.query.page !== this.props.query.page || nextProps.query.filter !== this.props.query.filter) {
this.updateData(Object.keys(nextProps.query).length > 0 ? nextProps.query : nextProps.params);
}
if (nextProps.data !== this.props.data && this.fullRefresh) {
this.fullRefresh = false;
this.setState({ key: this.state.key + 1 });
}
}
}, {
key: 'shouldComponentUpdate',
value: function shouldComponentUpdate(nextProps, nextState) {
if (nextProps.isLoading === this.props.isLoading && nextProps.width === this.props.width && nextState === this.state) {
return false;
}
return true;
}
}, {
key: 'getBasePath',
value: function getBasePath() {
return this.props.location.pathname;
}
}, {
key: 'getQuery',
/**
* Merge list params from 3 different sources:
* - the query string
* - the params stored in the state (from previous navigation)
* - the props passed to the List component
*/
value: function getQuery() {
var query = Object.keys(this.props.query).length > 0 ? this.props.query : (0, _extends5.default)({}, this.props.params);
if (!query.sort) {
query.sort = this.props.sort.field;
query.order = this.props.sort.order;
}
if (!query.perPage) {
query.perPage = this.props.perPage;
}
return query;
}
}, {
key: 'updateData',
value: function updateData(query) {
var params = query || this.getQuery();
var sort = params.sort,
order = params.order,
page = params.page,
perPage = params.perPage,
filter = params.filter;
var permanentFilter = this.props.filter;
this.props.crudGetList(this.props.resource, { page: page, perPage: perPage }, { field: sort, order: order }, (0, _extends5.default)({}, filter, permanentFilter));
}
}, {
key: 'changeParams',
value: function changeParams(action) {
var newParams = (0, _queryReducer2.default)(this.getQuery(), action);
this.props.push((0, _extends5.default)({}, this.props.location, { search: '?' + (0, _queryString.stringify)((0, _extends5.default)({}, newParams, { filter: JSON.stringify(newParams.filter) })) }));
this.props.changeListParams(this.props.resource, newParams);
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
filters = _props.filters,
_props$pagination = _props.pagination,
pagination = _props$pagination === undefined ? _react2.default.createElement(_Pagination2.default, null) : _props$pagination,
_props$actions = _props.actions,
actions = _props$actions === undefined ? _react2.default.createElement(_Actions2.default, null) : _props$actions,
resource = _props.resource,
hasCreate = _props.hasCreate,
title = _props.title,
data = _props.data,
ids = _props.ids,
total = _props.total,
children = _props.children,
isLoading = _props.isLoading,
translate = _props.translate;
var key = this.state.key;
var query = this.getQuery();
var filterValues = query.filter;
var basePath = this.getBasePath();
var resourceName = translate('resources.' + resource + '.name', {
smart_count: 2,
_: _inflection2.default.humanize(_inflection2.default.pluralize(resource))
});
var defaultTitle = translate('aor.page.list', { name: '' + resourceName });
var titleElement = _react2.default.createElement(_Title2.default, { title: title, defaultTitle: defaultTitle });
return _react2.default.createElement(
'div',
{ className: 'list-page' },
_react2.default.createElement(
_Card.Card,
{ style: { opacity: isLoading ? 0.8 : 1 }, key: key },
actions && _react2.default.cloneElement(actions, {
resource: resource,
filters: filters,
filterValues: filterValues,
basePath: basePath,
hasCreate: hasCreate,
displayedFilters: this.state,
showFilter: this.showFilter,
refresh: this.refresh
}),
_react2.default.createElement(_ViewTitle2.default, { title: titleElement }),
filters && _react2.default.cloneElement(filters, {
resource: resource,
hideFilter: this.hideFilter,
filterValues: filterValues,
displayedFilters: this.state,
setFilters: this.setFilters,
context: 'form'
}),
isLoading || total > 0 ? _react2.default.createElement(
'div',
null,
children && _react2.default.cloneElement(children, {
resource: resource,
ids: ids,
data: data,
currentSort: { field: query.sort, order: query.order },
basePath: basePath,
isLoading: isLoading,
setSort: this.setSort
}),
pagination && _react2.default.cloneElement(pagination, {
total: total,
page: parseInt(query.page, 10),
perPage: parseInt(query.perPage, 10),
setPage: this.setPage
})
) : _react2.default.createElement(
_Card.CardText,
{ style: styles.noResults },
translate('aor.navigation.no_results')
)
)
);
}
}]);
return List;
}(_react.Component);
List.propTypes = {
// the props you can change
title: _react.PropTypes.any,
filter: _react.PropTypes.object,
filters: _react.PropTypes.element,
pagination: _react.PropTypes.element,
actions: _react.PropTypes.element,
perPage: _react.PropTypes.number.isRequired,
sort: _react.PropTypes.shape({
field: _react.PropTypes.string,
order: _react.PropTypes.string
}),
children: _react.PropTypes.element.isRequired,
// the props managed by admin-on-rest
changeListParams: _react.PropTypes.func.isRequired,
crudGetList: _react.PropTypes.func.isRequired,
data: _react.PropTypes.object, // eslint-disable-line react/forbid-prop-types
filterValues: _react.PropTypes.object, // eslint-disable-line react/forbid-prop-types
hasCreate: _react.PropTypes.bool.isRequired,
ids: _react.PropTypes.array,
isLoading: _react.PropTypes.bool.isRequired,
location: _react.PropTypes.object.isRequired,
path: _react.PropTypes.string,
params: _react.PropTypes.object.isRequired,
push: _react.PropTypes.func.isRequired,
query: _react.PropTypes.object.isRequired,
resource: _react.PropTypes.string.isRequired,
total: _react.PropTypes.number.isRequired,
translate: _react.PropTypes.func.isRequired
};
List.defaultProps = {
filter: {},
filterValues: {},
perPage: 10,
sort: {
field: 'id',
order: _queryReducer.SORT_DESC
}
};
var getLocationSearch = function getLocationSearch(props) {
return props.location.search;
};
var getQuery = (0, _reselect.createSelector)(getLocationSearch, function (locationSearch) {
var query = (0, _queryString.parse)(locationSearch);
if (query.filter && typeof query.filter === 'string') {
query.filter = JSON.parse(query.filter);
}
return query;
});
function mapStateToProps(state, props) {
var resourceState = state.admin[props.resource];
return {
query: getQuery(props),
params: resourceState.list.params,
ids: resourceState.list.ids,
total: resourceState.list.total,
data: resourceState.data,
isLoading: state.admin.loading > 0,
filterValues: resourceState.list.params.filter
};
}
var enhance = (0, _compose2.default)((0, _reactRedux.connect)(mapStateToProps, {
crudGetList: _dataActions.crudGetList,
changeListParams: _listActions.changeListParams,
push: _reactRouterRedux.push
}), _translate2.default);
exports.default = enhance(List);