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:
@@ -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 = (
|
||||
@@ -55,27 +49,27 @@ define([
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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 = (
|
||||
<a onClick={this.handleSort}>
|
||||
<a onClick={ this.handleSort }>
|
||||
<span>{ this.props.column.label }</span>
|
||||
<span className="sorting-indicator"></span>
|
||||
</a>
|
||||
@@ -92,7 +86,6 @@ define([
|
||||
>{label}</th>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return ListingHeader;
|
||||
});
|
||||
|
||||
module.exports = ListingHeader;
|
@@ -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
|
||||
@@ -56,7 +39,7 @@ define(
|
||||
render: function() {
|
||||
var checkbox = false;
|
||||
|
||||
if(this.props.is_selectable === true) {
|
||||
if (this.props.is_selectable === true) {
|
||||
checkbox = (
|
||||
<th className="check-column" scope="row">
|
||||
<label className="screen-reader-text">{
|
||||
@@ -77,18 +60,18 @@ define(
|
||||
const custom_actions = this.props.item_actions;
|
||||
let item_actions = false;
|
||||
|
||||
if(custom_actions.length > 0) {
|
||||
if (custom_actions.length > 0) {
|
||||
let is_first = true;
|
||||
item_actions = custom_actions.map(function(action, index) {
|
||||
if(action.display !== undefined) {
|
||||
if(action.display(this.props.item) === false) {
|
||||
if (action.display !== undefined) {
|
||||
if (action.display(this.props.item) === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let custom_action = null;
|
||||
|
||||
if(action.name === 'trash') {
|
||||
if (action.name === 'trash') {
|
||||
custom_action = (
|
||||
<span key={ 'action-'+index } className="trash">
|
||||
{(!is_first) ? ' | ' : ''}
|
||||
@@ -102,7 +85,7 @@ define(
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if(action.refresh) {
|
||||
} else if (action.refresh) {
|
||||
custom_action = (
|
||||
<span
|
||||
onClick={ this.props.onRefreshItems }
|
||||
@@ -111,7 +94,7 @@ define(
|
||||
{ action.link(this.props.item) }
|
||||
</span>
|
||||
);
|
||||
} else if(action.link) {
|
||||
} else if (action.link) {
|
||||
custom_action = (
|
||||
<span
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
@@ -136,7 +119,7 @@ define(
|
||||
);
|
||||
}
|
||||
|
||||
if(custom_action !== null && is_first === true) {
|
||||
if (custom_action !== null && is_first === true) {
|
||||
is_first = false;
|
||||
}
|
||||
|
||||
@@ -150,8 +133,10 @@ define(
|
||||
);
|
||||
}
|
||||
|
||||
if(this.props.group === 'trash') {
|
||||
var actions = (
|
||||
let actions;
|
||||
|
||||
if (this.props.group === 'trash') {
|
||||
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 }>
|
||||
@@ -206,12 +191,12 @@ define(
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var ListingItems = React.createClass({
|
||||
const ListingItems = React.createClass({
|
||||
render: function() {
|
||||
if(this.props.items.length === 0) {
|
||||
if (this.props.items.length === 0) {
|
||||
return (
|
||||
<tbody>
|
||||
<tr className="no-items">
|
||||
@@ -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)
|
||||
@@ -292,9 +276,9 @@ 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',
|
||||
@@ -318,7 +302,7 @@ define(
|
||||
},
|
||||
componentDidUpdate: function(prevProps, prevState) {
|
||||
// reset group to "all" if trash gets emptied
|
||||
if(
|
||||
if (
|
||||
// we were viewing the trash
|
||||
(prevState.group === 'trash' && prevState.count > 0)
|
||||
&&
|
||||
@@ -332,15 +316,15 @@ 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) {
|
||||
if (params.splat !== undefined) {
|
||||
params.splat.split('/').map(param => {
|
||||
let [key, value] = this.getParam(param);
|
||||
switch(key) {
|
||||
@@ -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
|
||||
if(this.props.limit !== undefined) {
|
||||
// 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 (
|
||||
[
|
||||
@@ -385,32 +380,33 @@ define(
|
||||
})
|
||||
.map(key => {
|
||||
let value = this.state[key]
|
||||
if(value === Object(value)) {
|
||||
if (value === Object(value)) {
|
||||
value = jQuery.param(value)
|
||||
} else if(value === Boolean(value)) {
|
||||
} else if (value === Boolean(value)) {
|
||||
value = value.toString()
|
||||
}
|
||||
|
||||
if(value !== '') {
|
||||
if (value !== '') {
|
||||
return `${key}[${value}]`
|
||||
}
|
||||
})
|
||||
.filter(key => { return (key !== undefined) })
|
||||
.join('/');
|
||||
params = '/'+params
|
||||
|
||||
if(this.props.location) {
|
||||
if(this.props.location.pathname !== params) {
|
||||
params = '/' + params;
|
||||
|
||||
if (this.props.location) {
|
||||
if (this.props.location.pathname !== params) {
|
||||
this.context.router.push(`${params}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
componentDidMount: function() {
|
||||
if(this.isMounted()) {
|
||||
if (this.isMounted()) {
|
||||
const params = this.props.params || {}
|
||||
this.initWithParams(params)
|
||||
this.initWithParams(params);
|
||||
|
||||
if(this.props.auto_refresh) {
|
||||
if (this.props.auto_refresh) {
|
||||
jQuery(document).on('heartbeat-tick.mailpoet', function(e, data) {
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
@@ -422,7 +418,7 @@ define(
|
||||
this.initWithParams(params)
|
||||
},
|
||||
getItems: function() {
|
||||
if(this.isMounted()) {
|
||||
if (this.isMounted()) {
|
||||
this.setState({ loading: true });
|
||||
|
||||
this.clearSelection();
|
||||
@@ -448,7 +444,7 @@ define(
|
||||
count: response.count || 0,
|
||||
loading: false
|
||||
}, function() {
|
||||
if(this.props['onGetItems'] !== undefined) {
|
||||
if (this.props['onGetItems'] !== undefined) {
|
||||
this.props.onGetItems(
|
||||
~~(this.state.groups[0]['count'])
|
||||
);
|
||||
@@ -468,7 +464,7 @@ define(
|
||||
action: 'restore',
|
||||
data: id
|
||||
}).done(function(response) {
|
||||
if(
|
||||
if (
|
||||
this.props.messages !== undefined
|
||||
&& this.props.messages['onRestore'] !== undefined
|
||||
) {
|
||||
@@ -488,7 +484,7 @@ define(
|
||||
action: 'trash',
|
||||
data: id
|
||||
}).done(function(response) {
|
||||
if(
|
||||
if (
|
||||
this.props.messages !== undefined
|
||||
&& this.props.messages['onTrash'] !== undefined
|
||||
) {
|
||||
@@ -508,7 +504,7 @@ define(
|
||||
action: 'delete',
|
||||
data: id
|
||||
}).done(function(response) {
|
||||
if(
|
||||
if (
|
||||
this.props.messages !== undefined
|
||||
&& this.props.messages['onDelete'] !== undefined
|
||||
) {
|
||||
@@ -528,7 +524,7 @@ define(
|
||||
});
|
||||
},
|
||||
handleBulkAction: function(selected_ids, params, callback) {
|
||||
if(
|
||||
if (
|
||||
this.state.selection === false
|
||||
&& this.state.selected_ids.length === 0
|
||||
&& selected_ids !== 'all'
|
||||
@@ -547,7 +543,7 @@ define(
|
||||
group: this.state.group,
|
||||
search: this.state.search
|
||||
}
|
||||
if(selected_ids !== 'all') {
|
||||
if (selected_ids !== 'all') {
|
||||
data.listing.selection = selected_ids;
|
||||
}
|
||||
|
||||
@@ -568,7 +564,6 @@ define(
|
||||
selected_ids: []
|
||||
}, function() {
|
||||
this.setParams();
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
handleSort: function(sort_by, sort_order = 'asc') {
|
||||
@@ -577,17 +572,16 @@ define(
|
||||
sort_order: sort_order,
|
||||
}, function() {
|
||||
this.setParams();
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
handleSelectItem: function(id, is_checked) {
|
||||
var selected_ids = this.state.selected_ids,
|
||||
selection = false;
|
||||
|
||||
if(is_checked) {
|
||||
if (is_checked) {
|
||||
selected_ids = jQuery.merge(selected_ids, [ id ]);
|
||||
// check whether all items on the page are selected
|
||||
if(
|
||||
if (
|
||||
jQuery('tbody .check-column :checkbox:not(:checked)').length === 0
|
||||
) {
|
||||
selection = 'page';
|
||||
@@ -602,7 +596,7 @@ define(
|
||||
});
|
||||
},
|
||||
handleSelectItems: function(is_checked) {
|
||||
if(is_checked === false) {
|
||||
if (is_checked === false) {
|
||||
this.clearSelection();
|
||||
} else {
|
||||
var selected_ids = this.state.items.map(function(item) {
|
||||
@@ -616,7 +610,7 @@ define(
|
||||
}
|
||||
},
|
||||
handleSelectAll: function() {
|
||||
if(this.state.selection === 'all') {
|
||||
if (this.state.selection === 'all') {
|
||||
this.clearSelection();
|
||||
} else {
|
||||
this.setState({
|
||||
@@ -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,31 +653,30 @@ 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) {
|
||||
if (this.state.group === 'trash' && bulk_actions.length > 0) {
|
||||
bulk_actions = [
|
||||
{
|
||||
name: 'restore',
|
||||
@@ -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,25 +704,25 @@ define(
|
||||
);
|
||||
|
||||
// search
|
||||
var search = (
|
||||
let search = (
|
||||
<ListingSearch
|
||||
onSearch={ this.handleSearch }
|
||||
search={ this.state.search }
|
||||
/>
|
||||
);
|
||||
if(this.props.search === false) {
|
||||
if (this.props.search === false) {
|
||||
search = false;
|
||||
}
|
||||
|
||||
// groups
|
||||
var groups = (
|
||||
let groups = (
|
||||
<ListingGroups
|
||||
groups={ this.state.groups }
|
||||
group={ this.state.group }
|
||||
onSelectGroup={ this.handleGroup }
|
||||
/>
|
||||
);
|
||||
if(this.props.groups === false) {
|
||||
if (this.props.groups === false) {
|
||||
groups = false;
|
||||
}
|
||||
|
||||
@@ -818,8 +809,6 @@ define(
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return Listing;
|
||||
}
|
||||
);
|
||||
module.exports = Listing;
|
@@ -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>
|
||||
);
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user