use ajax to load campaign listing instead of prerendering
This commit is contained in:
parent
4132ef8913
commit
5876977f43
5 changed files with 144 additions and 75 deletions
|
@ -32,6 +32,84 @@ module.exports.list = (start, limit, callback) => {
|
|||
});
|
||||
};
|
||||
|
||||
module.exports.filter = (request, callback) => {
|
||||
let columns = ['#', 'name', 'description', 'status', 'created'];
|
||||
let processQuery = queryData => {
|
||||
|
||||
db.getConnection((err, connection) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let query = 'SELECT COUNT(id) AS total FROM `campaigns`';
|
||||
let values = [];
|
||||
|
||||
if (queryData.where) {
|
||||
query += ' WHERE ' + queryData.where;
|
||||
values = values.concat(queryData.values || []);
|
||||
}
|
||||
|
||||
connection.query(query, values, (err, total) => {
|
||||
if (err) {
|
||||
connection.release();
|
||||
return callback(err);
|
||||
}
|
||||
total = total && total[0] && total[0].total || 0;
|
||||
|
||||
let ordering = [];
|
||||
|
||||
if (request.order && request.order.length) {
|
||||
|
||||
request.order.forEach(order => {
|
||||
let orderField = columns[Number(order.column)];
|
||||
let orderDirection = (order.dir || '').toString().toLowerCase() === 'desc' ? 'DESC' : 'ASC';
|
||||
if (orderField) {
|
||||
ordering.push('`' + orderField + '` ' + orderDirection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!ordering.length) {
|
||||
ordering.push('`created` DESC');
|
||||
}
|
||||
|
||||
let args = [Number(request.length) || 50, Number(request.start) || 0];
|
||||
let query;
|
||||
|
||||
if (request.search && request.search.value) {
|
||||
query = 'SELECT SQL_CALC_FOUND_ROWS * FROM `campaigns` WHERE name LIKE ? ' + (queryData.where ? ' AND (' + queryData.where + ')' : '') + ' ORDER BY ' + ordering.join(', ') + ' LIMIT ? OFFSET ?';
|
||||
|
||||
let searchVal = '%' + request.search.value.replace(/\\/g, '\\\\').replace(/([%_])/g, '\\$1') + '%';
|
||||
args = [searchVal].concat(queryData.values || []).concat(args);
|
||||
} else {
|
||||
query = 'SELECT SQL_CALC_FOUND_ROWS * FROM `campaigns` WHERE 1 ' + (queryData.where ? ' AND (' + queryData.where + ')' : '') + ' ORDER BY ' + ordering.join(', ') + ' LIMIT ? OFFSET ?';
|
||||
args = [].concat(queryData.values || []).concat(args);
|
||||
}
|
||||
|
||||
connection.query(query, args, (err, rows) => {
|
||||
if (err) {
|
||||
connection.release();
|
||||
return callback(err);
|
||||
}
|
||||
connection.query('SELECT FOUND_ROWS() AS total', (err, filteredTotal) => {
|
||||
connection.release();
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let subscriptions = rows.map(row => tools.convertKeys(row));
|
||||
|
||||
filteredTotal = filteredTotal && filteredTotal[0] && filteredTotal[0].total || 0;
|
||||
return callback(null, subscriptions, total, filteredTotal);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
processQuery(false);
|
||||
};
|
||||
|
||||
module.exports.getByCid = (cid, callback) => {
|
||||
cid = (cid || '').toString().trim();
|
||||
if (!cid) {
|
||||
|
|
|
@ -29,8 +29,20 @@ $('.data-table').each(function () {
|
|||
$('.data-table-ajax').each(function () {
|
||||
var rowSort = $(this).data('rowSort') || false;
|
||||
var columns = false;
|
||||
var listArgs = $(this).data('listArgs') || false;
|
||||
var ajaxUrl = '/lists/ajax/' + $(this).data('listId') + (listArgs ? '?' + listArgs : '');
|
||||
|
||||
var topicUrl = $(this).data('topicUrl') || '/lists';
|
||||
var topicArgs = $(this).data('topicArgs') || false;
|
||||
var topicId = $(this).data('topicId') || '';
|
||||
|
||||
var sortColumn = Number($(this).data('sortColumn')) || 1;
|
||||
var sortOrder = ($(this).data('sortOrder') || 'asc').toString().trim().toLowerCase();
|
||||
|
||||
// allow only asc and desc
|
||||
if (sortOrder !== 'desc') {
|
||||
sortOrder = 'asc';
|
||||
}
|
||||
|
||||
var ajaxUrl = topicUrl + '/ajax/' + topicId + (topicArgs ? '?' + topicArgs : '');
|
||||
|
||||
if (rowSort) {
|
||||
columns = rowSort.split(',').map(function (sort) {
|
||||
|
@ -48,11 +60,15 @@ $('.data-table-ajax').each(function () {
|
|||
type: 'POST'
|
||||
},
|
||||
order: [
|
||||
[1, 'asc']
|
||||
[sortColumn, sortOrder]
|
||||
],
|
||||
columns: columns,
|
||||
pageLength: 50,
|
||||
processing: true
|
||||
}).on('draw', function () {
|
||||
$('.datestring').each(function () {
|
||||
$(this).html(moment($(this).data('date')).fromNow());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ let settings = require('../lib/models/settings');
|
|||
let tools = require('../lib/tools');
|
||||
let striptags = require('striptags');
|
||||
let passport = require('../lib/passport');
|
||||
let htmlescape = require('escape-html');
|
||||
|
||||
router.all('/*', (req, res, next) => {
|
||||
if (!req.user) {
|
||||
|
@ -20,43 +21,8 @@ router.all('/*', (req, res, next) => {
|
|||
});
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
let limit = 999999999;
|
||||
let start = 0;
|
||||
|
||||
campaigns.list(start, limit, (err, rows, total) => {
|
||||
if (err) {
|
||||
req.flash('danger', err.message || err);
|
||||
return res.redirect('/');
|
||||
}
|
||||
|
||||
res.render('campaigns/campaigns', {
|
||||
rows: rows.map((row, i) => {
|
||||
row.index = start + i + 1;
|
||||
row.description = striptags(row.description);
|
||||
switch (row.status) {
|
||||
case 1:
|
||||
row.statusText = 'Idling';
|
||||
break;
|
||||
case 2:
|
||||
if (row.scheduled && row.scheduled > new Date()) {
|
||||
row.statusText = 'Scheduled';
|
||||
} else {
|
||||
row.statusText = 'Sending';
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
row.statusText = 'Finished';
|
||||
break;
|
||||
case 4:
|
||||
row.statusText = 'Paused';
|
||||
break;
|
||||
}
|
||||
row.createdTimestamp = row.created.getTime();
|
||||
row.created = row.created.toISOString();
|
||||
return row;
|
||||
}),
|
||||
total
|
||||
});
|
||||
res.render('campaigns/campaigns', {
|
||||
title: 'Campaigns'
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -211,6 +177,47 @@ router.post('/delete', passport.parseForm, passport.csrfProtection, (req, res) =
|
|||
});
|
||||
});
|
||||
|
||||
router.post('/ajax', (req, res) => {
|
||||
campaigns.filter(req.body, (err, data, total, filteredTotal) => {
|
||||
if (err) {
|
||||
return res.json({
|
||||
error: err.message || err,
|
||||
data: []
|
||||
});
|
||||
}
|
||||
|
||||
let getStatusText = data => {
|
||||
switch (data.status) {
|
||||
case 1:
|
||||
return 'Idling';
|
||||
case 2:
|
||||
if (data.scheduled && data.scheduled > new Date()) {
|
||||
return 'Scheduled';
|
||||
}
|
||||
return 'Sending';
|
||||
case 3:
|
||||
return 'Finished';
|
||||
case 4:
|
||||
return 'Paused';
|
||||
}
|
||||
return 'Other';
|
||||
};
|
||||
|
||||
res.json({
|
||||
draw: req.body.draw,
|
||||
recordsTotal: total,
|
||||
recordsFiltered: filteredTotal,
|
||||
data: data.map((row, i) => [
|
||||
(Number(req.body.start) || 0) + 1 + i,
|
||||
htmlescape(row.name || ''),
|
||||
htmlescape(striptags(row.description) || ''),
|
||||
getStatusText(row),
|
||||
'<span class="datestring" data-date="' + row.created.toISOString() + '" title="' + row.created.toISOString() + '">' + row.created.toISOString() + '</span>'
|
||||
].concat('<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span><a href="/campaigns/edit/' + row.id + '">Edit</a>'))
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/view/:id', passport.csrfProtection, (req, res) => {
|
||||
campaigns.get(req.params.id, true, (err, campaign) => {
|
||||
if (err || !campaign) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<hr>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover data-table display nowrap" width="100%" data-row-sort="0,1,0,1,1,0">
|
||||
<table data-topic-url="/campaigns" data-sort-column="4" data-sort-order="desc" class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,0,1,1,0">
|
||||
<thead>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
|
@ -33,37 +33,5 @@
|
|||
|
||||
</th>
|
||||
</thead>
|
||||
{{#if rows}}
|
||||
<tbody>
|
||||
{{#each rows}}
|
||||
<tr>
|
||||
<th scope="row">
|
||||
{{index}}
|
||||
</th>
|
||||
<td>
|
||||
<span class="glyphicon glyphicon-inbox" aria-hidden="true"></span>
|
||||
<a href="/campaigns/view/{{id}}">
|
||||
{{name}}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<p class="text-muted">{{description}}</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>{{statusText}}</p>
|
||||
</td>
|
||||
<td>
|
||||
<span class="datestring" data-date="{{created}}" title="{{created}}">{{createdTimestamp}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
|
||||
<a href="/campaigns/edit/{{id}}">
|
||||
Edit
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
{{/if}}
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
<p></p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table data-list-id="{{id}}" {{#if useSegment}} data-list-args="segment={{useSegment}}" {{/if}} class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,1,1{{customSort}},1,0">
|
||||
<table data-topic-url="/list" data-topic-id="{{id}}" data-sort-column="1" data-sort-order="asc" {{#if useSegment}} data-topic-args="segment={{useSegment}}" {{/if}} class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,1,1{{customSort}},1,0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1">
|
||||
|
@ -166,7 +166,7 @@
|
|||
{{updated}}
|
||||
</td>
|
||||
<td>
|
||||
{{#if failed}}<a href="/lists/subscription/{{../id}}/import/{{id}}/failed">{{failed}}</a>{{else}} 0 {{/if}}
|
||||
{{#if failed}}<a href="/lists/subscription/{{../id}}/import/{{id}}/failed">{{failed}}</a>{{else}}0 {{/if}}
|
||||
</td>
|
||||
<td class="{{#if error}}text-danger{{/if}}">
|
||||
{{#if error}}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue