Allowed ability to set default sort_by/order on listings

- improved performance of listings (less refresh of items)
- fixed sorting issue where the order would not be reversed
This commit is contained in:
Jonathan Labreuille
2016-06-17 17:26:17 +02:00
parent 4bb1acf493
commit 7af2775972
4 changed files with 879 additions and 895 deletions

View File

@@ -1,21 +1,15 @@
define([
'react',
'classnames',
'mailpoet'
], function(
React,
classNames,
MailPoet
) {
import MailPoet from 'mailpoet'
import React from 'react'
import classNames from 'classnames'
var ListingHeader = React.createClass({
const ListingHeader = React.createClass({
handleSelectItems: function() {
return this.props.onSelectItems(
this.refs.toggle.checked
);
},
render: function() {
var columns = this.props.columns.map(function(column, index) {
const columns = this.props.columns.map(function(column, index) {
column.is_primary = (index === 0);
column.sorted = (this.props.sort_by === column.name)
? this.props.sort_order
@@ -29,7 +23,7 @@ define([
);
}.bind(this));
var checkbox = false;
let checkbox;
if(this.props.is_selectable === true) {
checkbox = (
@@ -57,21 +51,21 @@ define([
}
});
var ListingColumn = React.createClass({
const ListingColumn = React.createClass({
handleSort: function() {
var sort_by = this.props.column.name,
sort_order = (this.props.column.sorted === 'asc') ? 'desc' : 'asc';
const sort_by = this.props.column.name;
const sort_order = (this.props.column.sorted === 'asc') ? 'desc' : 'asc';
this.props.onSort(sort_by, sort_order);
},
render: function() {
var classes = classNames(
const classes = classNames(
'manage-column',
{ 'column-primary': this.props.column.is_primary },
{ 'sortable': this.props.column.sortable },
this.props.column.sorted,
{ 'sorted': (this.props.sort_by === this.props.column.name) }
);
var label;
let label;
if(this.props.column.sortable === true) {
label = (
@@ -94,5 +88,4 @@ define([
}
});
return ListingHeader;
});
module.exports = ListingHeader;

View File

@@ -1,33 +1,16 @@
define(
[
'mailpoet',
'jquery',
'react',
'react-router',
'classnames',
'listing/bulk_actions.jsx',
'listing/header.jsx',
'listing/pages.jsx',
'listing/search.jsx',
'listing/groups.jsx',
'listing/filters.jsx'
],
function(
MailPoet,
jQuery,
React,
Router,
classNames,
ListingBulkActions,
ListingHeader,
ListingPages,
ListingSearch,
ListingGroups,
ListingFilters
) {
var Link = Router.Link;
import MailPoet from 'mailpoet'
import jQuery from 'jquery'
import React from 'react'
import { Router, Link } from 'react-router'
import classNames from 'classnames'
import ListingBulkActions from 'listing/bulk_actions.jsx'
import ListingHeader from 'listing/header.jsx'
import ListingPages from 'listing/pages.jsx'
import ListingSearch from 'listing/search.jsx'
import ListingGroups from 'listing/groups.jsx'
import ListingFilters from 'listing/filters.jsx'
var ListingItem = React.createClass({
const ListingItem = React.createClass({
getInitialState: function() {
return {
toggled: true
@@ -150,8 +133,10 @@ define(
);
}
let actions;
if (this.props.group === 'trash') {
var actions = (
actions = (
<div>
<div className="row-actions">
<span>
@@ -183,7 +168,7 @@ define(
</div>
);
} else {
var actions = (
actions = (
<div>
<div className="row-actions">
{ item_actions }
@@ -197,7 +182,7 @@ define(
);
}
var row_classes = classNames({ 'is-expanded': !this.state.toggled })
const row_classes = classNames({ 'is-expanded': !this.state.toggled });
return (
<tr className={ row_classes }>
@@ -209,7 +194,7 @@ define(
});
var ListingItems = React.createClass({
const ListingItems = React.createClass({
render: function() {
if (this.props.items.length === 0) {
return (
@@ -231,8 +216,7 @@ define(
</tbody>
);
} else {
var selectAllClasses = classNames(
const select_all_classes = classNames(
'mailpoet_select_all',
{ 'mailpoet_hidden': (
this.props.selection === false
@@ -243,7 +227,7 @@ define(
return (
<tbody>
<tr className={ selectAllClasses }>
<tr className={ select_all_classes }>
<td colSpan={
this.props.columns.length
+ (this.props.is_selectable ? 1 : 0)
@@ -294,7 +278,7 @@ define(
}
});
var Listing = React.createClass({
const Listing = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired
},
@@ -305,8 +289,8 @@ define(
page: 1,
count: 0,
limit: 10,
sort_by: 'id',
sort_order: 'desc',
sort_by: null,
sort_order: null,
items: [],
groups: [],
group: 'all',
@@ -332,13 +316,13 @@ define(
}
},
getParam: function(param) {
var regex = /(.*)\[(.*)\]/
var matches = regex.exec(param)
const regex = /(.*)\[(.*)\]/;
const matches = regex.exec(param);
return [matches[1], matches[2]]
},
initWithParams: function(params) {
let state = this.state || {}
let original_state = state
let state = this.state || {};
let original_state = state;
// check for url params
if (params.splat !== undefined) {
params.splat.split('/').map(param => {
@@ -350,27 +334,38 @@ define(
let [k, v] = pair.split('=')
filters[k] = v
}
)
);
state.filter = filters
state.filter = filters;
break;
default:
state[key] = value
state[key] = value;
}
})
});
}
// default overrides
// defaults override
// limit per page
if (this.props.limit !== undefined) {
state.limit = Math.abs(~~this.props.limit);
}
// sort by
if (state.sort_by === null && this.props.sort_by !== undefined) {
state.sort_by = this.props.sort_by;
}
// sort order
if (state.sort_order === null && this.props.sort_order !== undefined) {
state.sort_order = this.props.sort_order;
}
this.setState(state, function() {
this.getItems();
}.bind(this));
},
setParams: function() {
var params = Object.keys(this.state)
let params = Object.keys(this.state)
.filter(key => {
return (
[
@@ -397,7 +392,8 @@ define(
})
.filter(key => { return (key !== undefined) })
.join('/');
params = '/'+params
params = '/' + params;
if (this.props.location) {
if (this.props.location.pathname !== params) {
@@ -408,7 +404,7 @@ define(
componentDidMount: function() {
if (this.isMounted()) {
const params = this.props.params || {}
this.initWithParams(params)
this.initWithParams(params);
if (this.props.auto_refresh) {
jQuery(document).on('heartbeat-tick.mailpoet', function(e, data) {
@@ -568,7 +564,6 @@ define(
selected_ids: []
}, function() {
this.setParams();
this.getItems();
}.bind(this));
},
handleSort: function(sort_by, sort_order = 'asc') {
@@ -577,7 +572,6 @@ define(
sort_order: sort_order,
}, function() {
this.setParams();
this.getItems();
}.bind(this));
},
handleSelectItem: function(id, is_checked) {
@@ -637,7 +631,6 @@ define(
page: 1
}, function() {
this.setParams();
this.getItems();
}.bind(this));
},
handleGroup: function(group) {
@@ -651,7 +644,6 @@ define(
page: 1
}, function() {
this.setParams();
this.getItems();
}.bind(this));
},
handleSetPage: function(page) {
@@ -661,29 +653,28 @@ define(
selected_ids: []
}, function() {
this.setParams();
this.getItems();
}.bind(this));
},
handleRenderItem: function(item, actions) {
var render = this.props.onRenderItem(item, actions);
const render = this.props.onRenderItem(item, actions);
return render.props.children;
},
handleRefreshItems: function() {
this.getItems();
},
render: function() {
var items = this.state.items,
sort_by = this.state.sort_by,
sort_order = this.state.sort_order;
const items = this.state.items;
const sort_by = this.state.sort_by;
const sort_order = this.state.sort_order;
// columns
var columns = this.props.columns || [];
let columns = this.props.columns || [];
columns = columns.filter(function(column) {
return (column.display === undefined || !!(column.display) === true);
});
// bulk actions
var bulk_actions = this.props.bulk_actions || [];
let bulk_actions = this.props.bulk_actions || [];
if (this.state.group === 'trash' && bulk_actions.length > 0) {
bulk_actions = [
@@ -701,9 +692,9 @@ define(
}
// item actions
var item_actions = this.props.item_actions || [];
const item_actions = this.props.item_actions || [];
var table_classes = classNames(
const table_classes = classNames(
'mailpoet_listing_table',
'wp-list-table',
'widefat',
@@ -713,7 +704,7 @@ define(
);
// search
var search = (
let search = (
<ListingSearch
onSearch={ this.handleSearch }
search={ this.state.search }
@@ -724,7 +715,7 @@ define(
}
// groups
var groups = (
let groups = (
<ListingGroups
groups={ this.state.groups }
group={ this.state.group }
@@ -820,6 +811,4 @@ define(
}
});
return Listing;
}
);
module.exports = Listing;

View File

@@ -244,6 +244,8 @@ const SegmentList = React.createClass({
columns={ columns }
bulk_actions={ bulk_actions }
item_actions={ item_actions }
sort_by="name"
sort_order="asc"
/>
</div>
);

View File

@@ -27,8 +27,8 @@ class Handler {
// searching
'search' => (isset($data['search']) ? $data['search'] : null),
// sorting
'sort_by' => (isset($data['sort_by']) ? $data['sort_by'] : 'id'),
'sort_order' => (isset($data['sort_order']) ? $data['sort_order'] : 'asc'),
'sort_by' => (!empty($data['sort_by']) ? $data['sort_by'] : 'id'),
'sort_order' => (!empty($data['sort_order']) ? $data['sort_order'] : 'asc'),
// grouping
'group' => (isset($data['group']) ? $data['group'] : null),
// filters