From 1c7fb3a78108dd722c148e563f82867e1101d331 Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Wed, 11 Feb 2015 16:56:16 +0100 Subject: [PATCH] MT#5435 option to show table summaries showing any supported aggregation method Change-Id: If439731261cb148105f4c1fb9608839610935e75 --- lib/NGCP/Panel.pm | 2 +- lib/NGCP/Panel/Controller/Subscriber.pm | 6 ++-- lib/NGCP/Panel/Utils/Datatables.pm | 23 +++++++++++++++ share/static/css/main.css | 15 ++++++++++ share/templates/helpers/datatables.tt | 39 +++++++++++++++++++++++++ share/templates/subscriber/master.tt | 1 + 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/lib/NGCP/Panel.pm b/lib/NGCP/Panel.pm index 25e8ce6462..9cebc6e369 100644 --- a/lib/NGCP/Panel.pm +++ b/lib/NGCP/Panel.pm @@ -70,7 +70,7 @@ __PACKAGE__->config( 'View::JSON' => { #Set the stash keys to be exposed to a JSON response #(sEcho iTotalRecords iTotalDisplayRecords aaData) for datatables - expose_stash => [ qw(sEcho iTotalRecords iTotalDisplayRecords aaData) ], + expose_stash => [ qw(sEcho iTotalRecords iTotalDisplayRecords aaData dt_custom_footer) ], }, 'View::TT' => { INCLUDE_PATH => [ diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm index c192af728d..669ed6f980 100644 --- a/lib/NGCP/Panel/Controller/Subscriber.pm +++ b/lib/NGCP/Panel/Controller/Subscriber.pm @@ -2048,14 +2048,14 @@ sub master :Chained('base') :PathPart('details') :CaptureArgs(0) { { name => "destination_user", search => 1, title => $c->loc('Callee') }, { name => "call_status", search => 1, title => $c->loc('Status') }, { name => "start_time", search_from_epoch => 1, search_to_epoch => 1, title => $c->loc('Start Time') }, - { name => "duration", search => 1, title => $c->loc('Duration') }, + { name => "duration", search => 1, title => $c->loc('Duration'), show_total => 'sum' }, ]; push @{ $call_cols }, ( { name => "call_id", search => 1, title => $c->loc('Call-ID') }, ) if($c->user->roles eq "admin" || $c->user->roles eq "reseller"); push @{ $call_cols }, ( - { name => "source_customer_cost", search => 1, title => $c->loc('Source Cust Cost (cents)') }, + { name => "source_customer_cost", search => 1, title => $c->loc('Source Cust Cost (cents)'), show_total => 'sum' }, ) ; $c->stash->{calls_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, $call_cols); @@ -3043,7 +3043,7 @@ sub ajax_calls :Chained('master') :PathPart('calls/ajax') :Args(0) { $data{destination_user} = uri_unescape($result->destination_user); } return %data; - } + }, ); $c->detach( $c->view("JSON") ); diff --git a/lib/NGCP/Panel/Utils/Datatables.pm b/lib/NGCP/Panel/Utils/Datatables.pm index 572d18709e..7c48990cfc 100644 --- a/lib/NGCP/Panel/Utils/Datatables.pm +++ b/lib/NGCP/Panel/Utils/Datatables.pm @@ -13,6 +13,8 @@ sub process { my $use_rs_cb = ('CODE' eq (ref $rs)); my $aaData = []; my $displayRecords = 0; + my $aggregate_cols = {}; + my $aggregations = {}; # check if we need to join more tables @@ -20,6 +22,9 @@ sub process { set_columns($c, $cols); unless ($use_rs_cb) { for my $col(@{ $cols }) { + if ($col->{show_total}) { + $aggregate_cols->{$col->{accessor}} = $col->{show_total}; + } my @parts = split /\./, $col->{name}; if($col->{literal_sql}) { $rs = $rs->search_rs(undef, { @@ -92,6 +97,10 @@ sub process { } } $displayRecords = $use_rs_cb ? 0 : $rs->count; + for my $sum_col (keys %{ $aggregate_cols }) { + my $aggregation_method = $aggregate_cols->{$sum_col}; + $aggregations->{$sum_col} = $rs->get_column($sum_col)->$aggregation_method; + } # show specific row on top (e.g. if we come back from a newly created entry) my $topId = $c->request->params->{iIdOnTop}; @@ -157,6 +166,9 @@ sub process { } } + if (keys %{ $aggregations }) { + $c->stash(dt_custom_footer => $aggregations); + } $c->stash( aaData => $aaData, iTotalRecords => $totalRecords, @@ -262,6 +274,17 @@ NGCP::Panel::Utils::Datatables =head1 DESCRIPTION +=head2 Format of Columns + +Array with the following fields (preprocessed by set_columns): + name: String + search: Boolean + search_from_epoch: Boolean + search_to_epoch: Boolean + title: String (Should be localized) + show_total: String (if set, something like sum,max,...) + + =head1 METHODS =head2 C diff --git a/share/static/css/main.css b/share/static/css/main.css index c0c31c559d..26f8b9bfd2 100644 --- a/share/static/css/main.css +++ b/share/static/css/main.css @@ -206,6 +206,21 @@ table.ngcp-datatable .header { cursor: pointer; } +/* tfoot styles from application header styles */ +table.ngcp-datatable tfoot td { + color: #FFF; + border-right: 1px solid #3E662C; + border-left: 1px solid #77B75A; + box-shadow: 0px 1px 0px #95C77D inset; + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); +} + +table.ngcp-datatable tfoot tr { + background-color: #568D3D; + background-image: linear-gradient(to bottom, #5F9B43, #497734); + background-repeat: repeat-x; +} + table.ngcp-datatable .header:after { content: ""; float: right; diff --git a/share/templates/helpers/datatables.tt b/share/templates/helpers/datatables.tt index 417db30f34..96435e6775 100644 --- a/share/templates/helpers/datatables.tt +++ b/share/templates/helpers/datatables.tt @@ -32,6 +32,7 @@ $.extend( $.fn.dataTableExt.oStdClasses, { $(document).ready(function() { var date_search_rendered = 0; + var [% helper.id_from_name %]_tmp_footer; var [% helper.id_from_name %]_table = $('#[% helper.id_from_name %]_table') .dataTable( { "sDom": "<'row-fluid ngcp_dt_top_elements'lf>t<'row-fluid'<'pull-left'i><'pull-right'p>>", @@ -128,6 +129,31 @@ $(document).ready(function() { "sClass": "ngcp-actions-column" } ], + "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) { + oSettings.jqXHR = $.ajax( { + "dataType": 'json', + "url": sSource, + "data": aoData, + "success": function(data, textStatus, jqXHR) { + if (data.dt_custom_footer) { + [% helper.id_from_name %]_tmp_footer = data.dt_custom_footer; + } + fnCallback(data, textStatus, jqXHR); + } + } ); + }, + [% IF helper.show_footer -%] + "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) { + if ([% helper.id_from_name %]_tmp_footer) { + nFoot.getElementsByTagName('td')[0].innerHTML = '[% c.loc("Total") %]'; + for (var col in [% helper.id_from_name %]_tmp_footer) { + if ([% helper.id_from_name %]_tmp_footer.hasOwnProperty(col)) { + nFoot.getElementsByClassName('footer-'+col)[0].innerHTML = [% helper.id_from_name %]_tmp_footer[col]; + } + } + } + }, + [% END -%] "fnDrawCallback": function( oSettings ) { $('.sw_actions').css('visibility','hidden'); $('.sw_action_row').hover( @@ -231,6 +257,16 @@ $(document).ready(function() { + [% IF helper.show_footer -%] + + + [% FOREACH f IN helper.column_fields -%] + + [% END -%] + + + + [% END -%] [% c.loc('Loading...') %] @@ -252,5 +288,8 @@ $(document).ready(function() { modal_script(m.close_target = helper.close_target); -%] [% END -%] +[% # cleanup + helper.show_footer = 0; + -%] [% # vim: set tabstop=4 syntax=html expandtab: -%] diff --git a/share/templates/subscriber/master.tt b/share/templates/subscriber/master.tt index 964b749471..d21a210c36 100644 --- a/share/templates/subscriber/master.tt +++ b/share/templates/subscriber/master.tt @@ -177,6 +177,7 @@ helper.column_sort = 'start_time'; helper.form_object = form; helper.ajax_uri = c.uri_for_action('/subscriber/ajax_calls', [c.req.captures.0]); + helper.show_footer = 1; IF (c.user.roles == "admin" || c.user.roles == "reseller") && c.config.features.callflow; helper.dt_buttons = [