Implement new datatables ajax dispatching.

It works with single-nested joins both for searching and ordering,
and the definition of what is searchable and what is displayed is
done in the controller once during setup.
agranig/1_0_subfix
Andreas Granig 12 years ago
parent a976854f9e
commit ba30dde294

@ -6,6 +6,7 @@ use NGCP::Panel::Utils;
use NGCP::Panel::Utils::Navigation;
use NGCP::Panel::Utils::Contract;
use NGCP::Panel::Utils::Subscriber;
use NGCP::Panel::Utils::Datatables;
use NGCP::Panel::Form::Subscriber;
use NGCP::Panel::Form::SubscriberCFSimple;
use NGCP::Panel::Form::SubscriberCFTSimple;
@ -41,6 +42,14 @@ sub sub_list :Chained('/') :PathPart('subscriber') :CaptureArgs(0) {
$c->stash(
template => 'subscriber/list.tt',
);
NGCP::Panel::Utils::Datatables::set_columns($c, [
{ name => "id", title => "#" },
{ name => "username", "search" => 1, title => 'Username' },
{ name => "domain.domain", "search" => 1, title => 'Domain' },
{ name => "contract.status", "search" => 1, title => 'Contract Status' },
{ name => "status", "search" => 1, title => 'Status' },
]);
#NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
}
@ -190,24 +199,16 @@ sub ajax :Chained('sub_list') :PathPart('ajax') :Args(0) {
my ($self, $c) = @_;
my $dispatch_to = '_ajax_resultset_' . $c->user->auth_realm;
my $resultset = $self->$dispatch_to($c);
$c->forward( "/ajax_process_resultset", [$resultset,
["id", "username", "domain_name", "contract_id", "status",],
["username", "domain.domain", "contract_id", "status",]]);
NGCP::Panel::Utils::Datatables::process($c, $resultset);
$c->detach( $c->view("JSON") );
}
sub _ajax_resultset_admin {
my ($self, $c) = @_;
return $c->model('DB')->resultset('voip_subscribers')->search_rs({},
{
'join' => 'domain',
'+select' => [
'domain.domain',
],
'+as' => [
'domain_name',
]
});
return $c->model('DB')->resultset('voip_subscribers')->search;
}
sub _ajax_resultset_reseller {

@ -0,0 +1,135 @@
package NGCP::Panel::Utils::Datatables;
use strict;
use warnings;
use Sipwise::Base;
use List::Util qw/first/;
use Scalar::Util qw/blessed/;
sub process {
my ($c, $rs) = @_;
my $cols = $c->stash->{dt_columns};
my $aaData = [];
my $totalRecords = $rs->count;
my $displayRecords = 0;
# check if we need to join more tables
# TODO: can we nest it deeper than once level?
for my $c(@{ $cols }) {
my @parts = split /\./, $c->{name};
if(@parts == 2) {
$rs = $rs->search_rs(undef, {
join => $parts[0],
'+select' => [ $c->{name} ],
'+as' => [ $c->{accessor} ],
});
} elsif(@parts > 2) {
# TODO throw an error for now as we only support one level
}
}
# searching
my @searchColumns = ();
foreach my $c(@{ $cols }) {
# avoid amigious column names if we have the same column in different joined tables
my $name = $c->{name} =~ /\./ ? $c->{name} : 'me.'.$c->{name};
push @searchColumns, $name if $c->{search};
}
my $searchString = $c->request->params->{sSearch} // "";
if($searchString) {
$rs = $rs->search([ map{ +{ $_ => { like => '%'.$searchString.'%' } } } @searchColumns ]);
}
$displayRecords = $rs->count;
# show specific row on top (e.g. if we come back from a newly created entry)
my $topId = $c->request->params->{iIdOnTop};
if(defined $topId) {
if(defined(my $row = $rs->find($topId))) {
push @{ $aaData }, _prune_row($cols, $row->get_inflated_columns);
$rs = $rs->search({ 'me.id' => { '!=', $topId} });
} else {
$c->log->error("iIdOnTop $topId not found in resultset " . ref $rs);
}
}
# sorting
my $sortColumn = $c->request->params->{iSortCol_0};
my $sortDirection = $c->request->params->{sSortDir_0} || 'asc';
if(defined $sortColumn && defined $sortDirection) {
if('desc' eq lc $sortDirection) {
$sortDirection = 'desc';
} else {
$sortDirection = 'asc';
}
# first, get the fields we're actually showing
my @displayedFields = ();
for my $c(@{ $cols }) {
next unless $c->{title};
# again, add 'me' to avoid ambiguous column names
my $name = $c->{name} =~ /\./ ? $c->{name} : 'me.'.$c->{name};
push @displayedFields, $name;
}
# ... and pick the name defined by the dt index
my $sortName = $displayedFields[$sortColumn];
$rs = $rs->search(undef, {
order_by => {
"-$sortDirection" => $sortName,
}
});
}
# pagination
my $pageStart = $c->request->params->{iDisplayStart};
my $pageSize = $c->request->params->{iDisplayLength};
if(defined $pageStart && defined $pageSize && $pageSize > 0) {
$rs = $rs->search(undef, {
offset => $pageStart,
rows => $pageSize,
});
}
for my $row ($rs->all) {
push @{ $aaData }, _prune_row($cols, $row->get_inflated_columns);
}
$c->stash(
aaData => $aaData,
iTotalRecords => $totalRecords,
iTotalDisplayRecords => $displayRecords,
sEcho => int($c->request->params->{sEcho} // 1),
);
}
sub set_columns {
my ($c, $cols) = @_;
for my $c(@{ $cols }) {
$c->{accessor} = $c->{name};
$c->{accessor} =~ s/\./_/g;
}
$c->stash->{dt_columns} = $cols;
}
sub _prune_row {
my ($columns, %row) = @_;
while (my ($k,$v) = each %row) {
unless (first { $_->{accessor} eq $k && $_->{title} } @{ $columns }) {
delete $row{$k};
next;
}
$row{$k} = $v->datetime if blessed($v) && $v->isa('DateTime');
}
return { %row };
}
1;
# vim: set tabstop=4 expandtab:

@ -3,15 +3,23 @@
helper.name = 'Subscriber';
helper.data = subscribers;
helper.messages = messages;
helper.column_titles = [ '#', 'Username', 'Domain', 'Contract #', 'Status' ];
helper.column_fields = [ 'id', 'username', 'domain_name', 'contract_id', 'status' ];
helper.column_sort = 'status';
#helper.column_titles = [ '#', 'Username', 'Domain', 'Contract #', 'Status' ];
#helper.column_fields = [ 'id', 'username', 'domain_name', 'contract_id', 'status' ];
#helper.column_sort = 'status';
helper.column_titles = [];
helper.column_fields = [];
FOR col IN dt_columns;
NEXT UNLESS col.title;
helper.column_titles.push(col.title);
helper.column_fields.push(col.accessor);
END;
helper.close_target = close_target;
helper.create_flag = create_flag;
helper.edit_flag = edit_flag;
helper.form_object = form;
helper.ajax_uri = c.uri_for( c.controller.action_for('ajax') );
helper.ajax_uri = c.uri_for_action('/subscriber/ajax');
helper.dt_buttons = [
{ name = 'Terminate', uri = "/subscriber/'+full.id+'/terminate", class = 'btn-small btn-secondary', icon = 'icon-trash', condition = 'full.status != "terminated"' },

Loading…
Cancel
Save