Bulk actions + Extra data

- fixed issue on bulk action being run even without any items selected
- added WP like feature regarding item selection, if all items are checked, it also checks the header/footer checkboxes
- fixed issue where the selection state was not properly reset
- added List column to subscribers
- added json_encode/json_decode to Twig
This commit is contained in:
Jonathan Labreuille
2015-09-23 14:13:25 +02:00
parent 239e2583d2
commit 56e40feb56
8 changed files with 113 additions and 9 deletions

View File

@@ -32,9 +32,15 @@ function(
e.preventDefault(); e.preventDefault();
var action = this.getSelectedAction(); var action = this.getSelectedAction();
if(action === null) {
return;
}
var selected_ids = (this.props.selection !== 'all') var selected_ids = (this.props.selection !== 'all')
? this.props.selected_ids ? this.props.selected_ids
: []; : [];
var data = (action['getData'] !== undefined) var data = (action['getData'] !== undefined)
? action.getData() ? action.getData()
: {}; : {};
@@ -78,17 +84,17 @@ function(
<select ref="action" value={ this.state.action } onChange={this.handleChangeAction}> <select ref="action" value={ this.state.action } onChange={this.handleChangeAction}>
<option value="">Bulk Actions</option> <option value="">Bulk Actions</option>
{this.props.bulk_actions.map(function(action, index) { { this.props.bulk_actions.map(function(action, index) {
return ( return (
<option <option
value={ action.name } value={ action.name }
key={ 'action-' + index } key={ 'action-' + index }
>{ action.label }</option> >{ action.label }</option>
); );
}.bind(this))} }.bind(this)) }
</select> </select>
<input <input
onClick={this.handleApplyAction} onClick={ this.handleApplyAction }
type="submit" type="submit"
defaultValue="Apply" defaultValue="Apply"
className="button action" /> className="button action" />

View File

@@ -237,6 +237,10 @@ define(
}.bind(this)); }.bind(this));
}, },
handleBulkAction: function(selected_ids, params) { handleBulkAction: function(selected_ids, params) {
if(this.state.selection === false) {
return;
}
this.setState({ loading: true }); this.setState({ loading: true });
var data = params || {}; var data = params || {};
@@ -275,21 +279,29 @@ define(
}.bind(this)); }.bind(this));
}, },
handleSelectItem: function(id, is_checked) { handleSelectItem: function(id, is_checked) {
var selected_ids = this.state.selected_ids; var selected_ids = this.state.selected_ids,
selection = false;
if(is_checked) { if(is_checked) {
selected_ids = jQuery.merge(selected_ids, [ id ]); selected_ids = jQuery.merge(selected_ids, [ id ]);
// check whether all items on the page are selected
if(
jQuery('tbody .check-column :checkbox:not(:checked)').length === 0
) {
selection = 'page';
}
} else { } else {
selected_ids.splice(selected_ids.indexOf(id), 1); selected_ids.splice(selected_ids.indexOf(id), 1);
} }
this.setState({ this.setState({
selection: false, selection: selection,
selected_ids: selected_ids selected_ids: selected_ids
}); });
}, },
handleSelectItems: function(is_checked) { handleSelectItems: function(is_checked) {
if(is_checked === false) { if(is_checked === false) {
this.clearSelection();
} else { } else {
var selected_ids = this.state.items.map(function(item) { var selected_ids = this.state.items.map(function(item) {
return ~~item.id; return ~~item.id;

View File

@@ -1,6 +1,7 @@
define( define(
[ [
'react', 'react',
'react-router',
'listing/listing.jsx', 'listing/listing.jsx',
'classnames', 'classnames',
'mailpoet', 'mailpoet',
@@ -9,11 +10,14 @@ define(
], ],
function( function(
React, React,
Router,
Listing, Listing,
classNames, classNames,
MailPoet, MailPoet,
jQuery jQuery
) { ) {
var Link = Router.Link;
var columns = [ var columns = [
{ {
name: 'email', name: 'email',
@@ -35,6 +39,12 @@ define(
label: 'Status', label: 'Status',
sortable: true sortable: true
}, },
{
name: 'lists',
label: 'Lists',
sortable: false
},
{ {
name: 'created_at', name: 'created_at',
label: 'Subscribed on', label: 'Subscribed on',
@@ -57,7 +67,16 @@ define(
} }
}, },
componentDidMount: function() { componentDidMount: function() {
this.loadItems(); // this.loadItems();
this.loadCachedItems();
},
loadCachedItems: function() {
if(typeof(window['mailpoet_'+this.props.endpoint]) !== 'undefined') {
var items = window['mailpoet_'+this.props.endpoint];
this.setState({
items: items
});
}
}, },
loadItems: function() { loadItems: function() {
this.setState({ loading: true }); this.setState({ loading: true });
@@ -222,11 +241,19 @@ define(
break; break;
} }
var segments = mailpoet_segments.filter(function(segment) {
return (jQuery.inArray(segment.id, subscriber.segments) !== -1);
}).map(function(segment) {
return segment.name;
}).join(', ');
return ( return (
<div> <div>
<td className={ row_classes }> <td className={ row_classes }>
<strong> <strong>
<a>{ subscriber.email }</a> <Link to="edit" params={{ id: subscriber.id }}>
{ subscriber.email }
</Link>
</strong> </strong>
{ actions } { actions }
</td> </td>
@@ -239,6 +266,9 @@ define(
<td className="column" data-colname="Status"> <td className="column" data-colname="Status">
{ status } { status }
</td> </td>
<td className="column" data-colname="Status">
{ segments }
</td>
<td className="column-date" data-colname="Subscribed on"> <td className="column-date" data-colname="Subscribed on">
<abbr>{ subscriber.created_at }</abbr> <abbr>{ subscriber.created_at }</abbr>
</td> </td>

View File

@@ -1,5 +1,6 @@
<?php <?php
namespace MailPoet\Config; namespace MailPoet\Config;
use \MailPoet\Models\Segment;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
@@ -80,6 +81,9 @@ class Menu {
function subscribers() { function subscribers() {
$data = array(); $data = array();
$data['segments'] = Segment::findArray();
echo $this->renderer->render('subscribers.html', $data); echo $this->renderer->render('subscribers.html', $data);
} }

View File

@@ -18,6 +18,7 @@ class Renderer {
function init() { function init() {
$this->setupTranslations(); $this->setupTranslations();
$this->setupFunctions();
$this->setupHandlebars(); $this->setupHandlebars();
$this->setupGlobalVariables(); $this->setupGlobalVariables();
$this->setupSyntax(); $this->setupSyntax();
@@ -28,6 +29,10 @@ class Renderer {
$this->renderer->addExtension(new Twig\i18n(Env::$plugin_name)); $this->renderer->addExtension(new Twig\i18n(Env::$plugin_name));
} }
function setupFunctions() {
$this->renderer->addExtension(new Twig\Functions());
}
function setupHandlebars() { function setupHandlebars() {
$this->renderer->addExtension(new Twig\Handlebars()); $this->renderer->addExtension(new Twig\Handlebars());
} }
@@ -51,7 +56,9 @@ class Renderer {
function detectCache() { function detectCache() {
$cache_path = Env::$views_path . '/cache'; $cache_path = Env::$views_path . '/cache';
if (WP_DEBUG === false) return $cache_path; if(WP_DEBUG === false) {
return $cache_path;
}
return false; return false;
} }
} }

View File

@@ -27,7 +27,21 @@ class Subscribers {
\Model::factory('\MailPoet\Models\Subscriber'), \Model::factory('\MailPoet\Models\Subscriber'),
$data $data
); );
wp_send_json($listing->get());
$listing_data = $listing->get();
// fetch segments relations for each returned item
foreach($listing_data['items'] as &$item) {
$segments = SubscriberSegment::select('segment_id')
->where('subscriber_id', $item['id'])
->findMany();
$item['segments'] = array_map(function($relation) {
return $relation->segment_id;
}, $segments);
}
wp_send_json($listing_data);
} }
function getAll() { function getAll() {

27
lib/Twig/Functions.php Normal file
View File

@@ -0,0 +1,27 @@
<?php
namespace MailPoet\Twig;
class Functions extends \Twig_Extension {
public function __construct() {
}
public function getName() {
return 'functions';
}
public function getFunctions() {
return array(
new \Twig_SimpleFunction(
'json_encode',
'json_encode',
array('is_safe' => array('all'))
),
new \Twig_SimpleFunction(
'json_decode',
'json_decode',
array('is_safe' => array('all'))
)
);
}
}

View File

@@ -12,4 +12,8 @@
'selectAllLink': __('Select all pages.'), 'selectAllLink': __('Select all pages.'),
'clearSelection': __('Clear selection.') 'clearSelection': __('Clear selection.')
}) %> }) %>
<script type="text/javascript">
var mailpoet_segments = <%= json_encode(segments) %>;
</script>
<% endblock %> <% endblock %>