From 423e084ddc5a927a12b5ec078b1c0a69e7f6bbe0 Mon Sep 17 00:00:00 2001 From: Rene Krenn Date: Tue, 8 Nov 2022 14:57:54 +0100 Subject: [PATCH] MT#55694 MT#55419 provide generated datatable search tooltips the search field of admin-panel datatables was tuned/configured over time to allow fastest possible search, "as-you-type". for large tabels it eg. will only include indexed columns, which never was transparent to the users. the UI will now display tooltip texts with detailed hints about included columns, wildcard support, etc. Change-Id: I737732a55003d50068236bb0150a2f47d06deaf5 (cherry picked from commit ff198cef49ad685f48e8414ba6532f6cf77885ad) --- lib/NGCP/Panel/Controller/Contract.pm | 1 + lib/NGCP/Panel/Controller/Customer.pm | 1 + lib/NGCP/Panel/Controller/Subscriber.pm | 2 ++ lib/NGCP/Panel/Field/DataTable.pm | 2 +- lib/NGCP/Panel/Utils/Datatables.pm | 15 ++++++++----- share/static/css/bootstrap/bootstrap.css | 6 ++++- share/templates/helpers/datatables.tt | 28 +++++++++++++++++------- 7 files changed, 40 insertions(+), 15 deletions(-) diff --git a/lib/NGCP/Panel/Controller/Contract.pm b/lib/NGCP/Panel/Controller/Contract.pm index 1c70bb0fc6..9b1d6c4110 100644 --- a/lib/NGCP/Panel/Controller/Contract.pm +++ b/lib/NGCP/Panel/Controller/Contract.pm @@ -32,6 +32,7 @@ sub contract_list :Chained('/') :PathPart('contract') :CaptureArgs(0) { { name => 'billing_profile_name', accessor => "billing_profile_name", search => 0, title => $c->loc('Billing Profile'), literal_sql => NGCP::Panel::Utils::BillingMappings::get_actual_billing_mapping_stmt(c => $c, now => $now, projection => 'billing_profile.name' ) }, { name => "status", search => 0, title => $c->loc("Status") }, + { title => $c->loc("Contact Email"), search => 1, no_column => 1 }, ]); my $rs = NGCP::Panel::Utils::Contract::get_contract_rs( diff --git a/lib/NGCP/Panel/Controller/Customer.pm b/lib/NGCP/Panel/Controller/Customer.pm index ee70394001..6eb4d57a61 100644 --- a/lib/NGCP/Panel/Controller/Customer.pm +++ b/lib/NGCP/Panel/Controller/Customer.pm @@ -57,6 +57,7 @@ sub list_customer :Chained('/') :PathPart('customer') :CaptureArgs(0) { literal_sql => '""' }, { name => "status", search => 0, title => $c->loc("Status") }, { name => "max_subscribers", search => 0, title => $c->loc("Max. Subscribers") }, + { title => $c->loc("Contact Email"), search => 1, no_column => 1 }, ]); my $rs = NGCP::Panel::Utils::Contract::get_customer_rs(c => $c); #, now => $now); diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm index bc6b8bddbc..f69152f747 100644 --- a/lib/NGCP/Panel/Controller/Subscriber.pm +++ b/lib/NGCP/Panel/Controller/Subscriber.pm @@ -100,6 +100,8 @@ sub sub_list :Chained('/') :PathPart('subscriber') :CaptureArgs(0) { { name => "status", search => 0, title => $c->loc('Status') }, { name => "number", search => 0, title => $c->loc('Number'), literal_sql => "concat(primary_number.cc, primary_number.ac, primary_number.sn)" }, { name => "provisioning_voip_subscriber.voip_subscriber_profile.name", search => 0, title => $c->loc('Profile') }, + { title => $c->loc("Contact Email"), search => 1, no_column => 1 }, + { title => $c->loc("Aliases"), search => 1, no_column => 1 }, ]); } diff --git a/lib/NGCP/Panel/Field/DataTable.pm b/lib/NGCP/Panel/Field/DataTable.pm index f3c8b7d573..b954ff70d5 100644 --- a/lib/NGCP/Panel/Field/DataTable.pm +++ b/lib/NGCP/Panel/Field/DataTable.pm @@ -18,7 +18,7 @@ has 'no_ordering' => ( isa => 'Bool', is => 'rw' ); has 'no_pagination' => ( isa => 'Bool', is => 'rw', default => 0 ); has 'only_visible_values' => ( isa => 'Bool', is => 'rw', default => 0 ); has 'language_file' => (isa => 'Str', is => 'rw', default => 'dataTables.default.js' ); -has 'search_tooltip' => (isa => 'Str', is => 'rw', default => 'Filter for column values matching the pattern string, e.g. 12*45. The * (wildcard) is implicitly prepended and appended.' ); +has 'search_tooltip' => (isa => 'Str', is => 'rw' ); #didn't want to include some complex role related logic here, #as these DataTable fields also are used in API diff --git a/lib/NGCP/Panel/Utils/Datatables.pm b/lib/NGCP/Panel/Utils/Datatables.pm index e923f51af7..7c171d70ac 100644 --- a/lib/NGCP/Panel/Utils/Datatables.pm +++ b/lib/NGCP/Panel/Utils/Datatables.pm @@ -35,7 +35,7 @@ sub process { ### Search processing section - ($rs,my @searchColumns) = _apply_search_filters($c,$rs,$cols,$use_rs_cb,$params->{extra_or}); + ($rs,my @searchColumns) = _apply_search_filters($c,$rs,$cols,$use_rs_cb,$params->{extra_or},$params->{extra_or_descr}); my $is_set_operations = 0; ($displayRecords, $displayRecordCountClipped, $is_set_operations) = _get_count_safe($c,$rs,$params) if (!$use_rs_cb); @@ -109,6 +109,7 @@ sub process { # first, get the fields we're actually showing my @displayedFields = (); for my $col(@{ $cols }) { + next if $col->{no_column}; next unless $col->{title}; my $name = get_column_order_name($col); push @displayedFields, $name; @@ -197,9 +198,9 @@ sub process { } sub apply_dt_joins_filters { - my ($c,$rs, $cols, $extra_or) = @_; + my ($c,$rs, $cols, $extra_or, $extra_or_descr) = @_; $rs = _resolve_joins($rs, $cols, undef, 1, 1); - ($rs,my @searchColumns) = _apply_search_filters($c, $rs, $cols, $extra_or); + ($rs,my @searchColumns) = _apply_search_filters($c, $rs, $cols, $extra_or, $extra_or_descr); return $rs; } @@ -207,6 +208,7 @@ sub _resolve_joins { my ($rs, $cols, $aggregate_cols, $skip_aggregates,$join_only) = @_; for my $col(@{ $cols }) { + next unless $col->{name}; if ($col->{show_total}) { push(@$aggregate_cols, $col) if defined $aggregate_cols; next if $skip_aggregates; @@ -264,7 +266,7 @@ sub get_search_string_pattern { sub _apply_search_filters { - my ($c,$rs,$cols,$use_rs_cb,$extra_or) = @_; + my ($c,$rs,$cols,$use_rs_cb,$extra_or,$extra_or_descr) = @_; # generic searching my @searchColumns = (); my %conjunctSearchColumns = (); @@ -273,6 +275,7 @@ sub _apply_search_filters { if (length($searchString) && !$use_rs_cb) { #for search string from one search input we need to check all columns which contain the 'search' spec (now: qw/search search_lower_column search_upper_column/). so, for example user entered into search input ip address - we don't know that it is ip address, so we check that name like search OR id like search OR search is between network_lower_value and network upper value foreach my $col(@{ $cols }) { + next unless $col->{name}; my ($name,$search_value,$op,$convert); # avoid amigious column names if we have the same column in different joined tables if($col->{search} or $col->{strict_search} or $col->{int_search}){ @@ -352,6 +355,7 @@ sub _apply_search_filters { $to_date = NGCP::Panel::Utils::DateTime::from_forminput_string($to_date_in, $c->session->{user_tz}); } foreach my $col(@{ $cols }) { + next unless $col->{name}; # avoid amigious column names if we have the same column in different joined tables my $name = _get_joined_column_name_($col->{name}); if($col->{search_from_epoch} && $from_date) { @@ -466,6 +470,7 @@ sub set_columns { for my $col(@{ $cols }) { next if defined $col->{accessor}; + next unless $col->{name}; $col->{accessor} = $col->{name}; $col->{accessor} =~ s/\./_/g; } @@ -475,7 +480,7 @@ sub set_columns { sub _prune_row { my ($user_tz, $columns, %row) = @_; while (my ($k,$v) = each %row) { - unless (first { $_->{accessor} eq $k && ($_->{title} || $_->{field}) } @{ $columns }) { + unless (first { !$_->{no_column} && $_->{accessor} eq $k && ($_->{title} || $_->{field}) } @{ $columns }) { delete $row{$k}; next; } diff --git a/share/static/css/bootstrap/bootstrap.css b/share/static/css/bootstrap/bootstrap.css index 5b7fe7e856..788a19506d 100644 --- a/share/static/css/bootstrap/bootstrap.css +++ b/share/static/css/bootstrap/bootstrap.css @@ -5332,7 +5332,6 @@ input[type="submit"].btn.btn-mini { } .tooltip-inner { - max-width: 200px; padding: 8px; color: #ffffff; text-align: center; @@ -5341,6 +5340,11 @@ input[type="submit"].btn.btn-mini { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; + +} + +.tooltip-inner dl { + test-align: left; } .tooltip-arrow { diff --git a/share/templates/helpers/datatables.tt b/share/templates/helpers/datatables.tt index cba2ae1db5..ead18b416c 100644 --- a/share/templates/helpers/datatables.tt +++ b/share/templates/helpers/datatables.tt @@ -6,14 +6,27 @@ helper.custom_renderers = helper.custom_renderers ? helper.custom_renderers : {}; helper.options = {}; helper.columns_hidden = {}; - helper.strict_search = 0; + helper.search_tooltip = c.loc('Filter records for values of columns matching either condition:') _ '
'; FOR col IN helper.dt_columns; IF !col.accessor; col.accessor = col.name; col.accessor = col.accessor.replace('\.','_'); END; - IF col.strict_search; - helper.strict_search = 1; + search_dt = col.title; + UNLESS search_dt; + search_dt = col.accessor; + END; + search_dd = ''; + IF col.search; + search_dd = c.loc('Search by wildcard pattern. A wildcard is implicitly appended at the end of the search string if no wildcard is used. A leading wildcard prevents using databases indexes (slow).'); + ELSIF col.strict_search; + search_dd = c.loc('Search by the exact search string value (The * wildcard is considered as a literal string).'); + ELSIF col.int_search; + search_dd = c.loc('Search string is converted to an integer value to search for.'); + END; + IF search_dd; + helper.search_tooltip = helper.search_tooltip _ '
' _ search_dt _ '
'; + helper.search_tooltip = helper.search_tooltip _ '
' _ search_dd _ '
'; END; NEXT UNLESS col.title; helper.column_titles.push(col.title); @@ -30,6 +43,7 @@ helper.options.${col.accessor}.dont_skip_empty_data = 1; END; END; + helper.search_tooltip = helper.search_tooltip _ '
'; END; backuri = c.req.uri; tmp = backuri.query_param_delete('back'); @@ -38,10 +52,6 @@ helper.identifier = 0; # make sure we don't use the same identifier twice IF search_tooltip; helper.search_tooltip = c.loc(search_tooltip); - ELSIF helper.strict_search; - helper.search_tooltip = c.loc('Filter for column values matching the string, e.g. 12345. A leading * (wildcard) can result in long response times.'); - ELSE; - helper.search_tooltip = c.loc('Filter for column values matching the pattern string, e.g. 12*45. The * (wildcard) is implicitly prepended and appended.'); END; -%] @@ -285,7 +295,9 @@ $(document).ready(function() { "initComplete": function(settings, json) { if ("[% helper.search_tooltip %]".length > 0) { $( "#[% helper.id_from_name %]_table_filter input" ).tooltip({ - title: "[% helper.search_tooltip %]" + title: "[% helper.search_tooltip %]", + html: true, + placement: 'bottom' }); } }