# or simply don't work with the current reporting system.
my @no_report_columns =
qw(bug_id alias short_short_desc opendate changeddate
- flagtypes.name keywords relevance);
-
- # Multi-select fields are not currently supported.
- my @multi_selects = @{Bugzilla->fields(
- { obsolete => 0, type => FIELD_TYPE_MULTI_SELECT })};
- push(@no_report_columns, map { $_->name } @multi_selects);
+ flagtypes.name relevance);
# If you're not a time-tracker, you can't use time-tracking
# columns.
sub _multiselect_term {
my ($self, $args, $not) = @_;
my ($operator) = $args->{operator};
+ my $value = $args->{value} || '';
# 'empty' operators require special handling
return $self->_multiselect_isempty($args, $not)
- if $operator =~ /^is(not)?empty$/;
+ if ($operator =~ /^is(not)?empty$/ || $value eq '---');
my $table = $self->_multiselect_table($args);
$self->_do_operator_function($args);
my $term = $args->{term};
my $row_isnumeric = 1;
my $tbl_isnumeric = 1;
+# define which fields are multiselect
+my @multi_selects = map { $_->name } @{Bugzilla->fields(
+ {
+ obsolete => 0,
+ type => [FIELD_TYPE_MULTI_SELECT, FIELD_TYPE_KEYWORDS]
+ }
+)};
+my $col_ismultiselect = scalar grep {$col_field eq $_} @multi_selects;
+my $row_ismultiselect = scalar grep {$row_field eq $_} @multi_selects;
+my $tbl_ismultiselect = scalar grep {$tbl_field eq $_} @multi_selects;
+
+
foreach my $result (@$results) {
# handle empty dimension member names
- my $row = check_value($row_field, $result);
- my $col = check_value($col_field, $result);
- my $tbl = check_value($tbl_field, $result);
-
- $data{$tbl}{$col}{$row}++;
- $names{"col"}{$col}++;
- $names{"row"}{$row}++;
- $names{"tbl"}{$tbl}++;
- $col_isnumeric &&= ($col =~ /^-?\d+(\.\d+)?$/o);
- $row_isnumeric &&= ($row =~ /^-?\d+(\.\d+)?$/o);
- $tbl_isnumeric &&= ($tbl =~ /^-?\d+(\.\d+)?$/o);
+ my @rows = check_value($row_field, $result, $row_ismultiselect);
+ my @cols = check_value($col_field, $result, $col_ismultiselect);
+ my @tbls = check_value($tbl_field, $result, $tbl_ismultiselect);
+
+ my %in_total_row;
+ my %in_total_col;
+ for my $tbl (@tbls) {
+ my %in_row_total;
+ for my $col (@cols) {
+ for my $row (@rows) {
+ $data{$tbl}{$col}{$row}++;
+ $names{"row"}{$row}++;
+ $row_isnumeric &&= ($row =~ /^-?\d+(\.\d+)?$/o);
+ if ($formatparam eq "table") {
+ if (!$in_row_total{$row}) {
+ $data{$tbl}{'-total-'}{$row}++;
+ $in_row_total{$row} = 1;
+ }
+ if (!$in_total_row{$row}) {
+ $data{'-total-'}{'-total-'}{$row}++;
+ $in_total_row{$row} = 1;
+ }
+ }
+ }
+ if ($formatparam eq "table") {
+ $data{$tbl}{$col}{'-total-'}++;
+ if (!$in_total_col{$col}) {
+ $data{'-total-'}{$col}{'-total-'}++;
+ $in_total_col{$col} = 1;
+ }
+ }
+ $names{"col"}{$col}++;
+ $col_isnumeric &&= ($col =~ /^-?\d+(\.\d+)?$/o);
+ }
+ $names{"tbl"}{$tbl}++;
+ $tbl_isnumeric &&= ($tbl =~ /^-?\d+(\.\d+)?$/o);
+ if ($formatparam eq "table") {
+ $data{$tbl}{'-total-'}{'-total-'}++;
+ }
+ }
+ if ($formatparam eq "table") {
+ $data{'-total-'}{'-total-'}{'-total-'}++;
+ }
}
my @col_names = get_names($names{"col"}, $col_isnumeric, $col_field);
$vars->{'col_names'} = \@col_names;
$vars->{'row_names'} = \@row_names;
$vars->{'tbl_names'} = \@tbl_names;
+$vars->{'note_multi_select'} = $row_ismultiselect || $col_ismultiselect;
# Below a certain width, we don't see any bars, so there needs to be a minimum.
if ($formatparam eq "bar") {
foreach my $value (@{$field->legal_values}) {
push(@sorted, $value->name) if $names->{$value->name};
}
- unshift(@sorted, '---') if $field_name eq 'resolution';
+ unshift(@sorted, '---') if ($field_name eq 'resolution'
+ || $field->type == FIELD_TYPE_MULTI_SELECT);
@sorted = uniq @sorted;
}
elsif ($isnumeric) {
}
sub check_value {
- my ($field, $result) = @_;
+ my ($field, $result, $ismultiselect) = @_;
my $value;
if (!defined $field) {
else {
$value = shift @$result;
$value = ' ' if (!defined $value || $value eq '');
- $value = '---' if ($field eq 'resolution' && $value eq ' ');
+ $value = '---' if (($field eq 'resolution' || $ismultiselect ) &&
+ $value eq ' ');
+ }
+ if ($ismultiselect) {
+ # Some DB servers have a space after the comma, some others don't.
+ return split(/, ?/, $value);
+ } else {
+ return ($value);
}
- return $value;
}
sub get_field_restrictions {
[% classes = [ [ "t1", "t2" ] , [ "t3", "t4" ] ] %]
[% col_idx = 0 %]
[% row_idx = 0 %]
-[% grand_total = 0 %]
+[% total_key = '-total-' %]
<div id="tabular_report_container_[% tbl FILTER html %]">
<table id="tabular_report" border="1">
[% IF col_field %]
<th class="[% classes.$row_idx.$col_idx %]">
</th>
[% FOREACH col = col_names %]
- [% col_totals.$col = 0 %]
[% NEXT IF col == "" %]
[% col_idx = 1 - col_idx %]
[% END %]
<tbody>
[% FOREACH row = row_names %]
- [% row_total = 0 %]
-
[% row_idx = 1 - row_idx %]
<tr>
<td class="[% classes.$row_idx.$col_idx %]" align="right">
[% PROCESS value_display value = row field = row_field %]
</td>
[% FOREACH col = col_names %]
- [% row_total = row_total + data.$tbl.$col.$row %]
[% NEXT IF col == "" %]
- [% col_totals.$col = (col_totals.$col || 0) + data.$tbl.$col.$row %]
[% col_idx = 1 - col_idx %]
<td class="[% classes.$row_idx.$col_idx %]" align="center">
<a href="[% urlbase %]&
[% row_field FILTER uri %]=[% row FILTER uri %]
[% "&$col_vals" IF col_vals %]">
- [% row_total %]</a>
- [% grand_total = grand_total + row_total %]
+ [% data.$tbl.$total_key.$row OR 0 FILTER html %]</a>
</td>
</tr>
[% END %]
</td>
[% FOREACH col = col_names %]
[% NEXT IF col == "" %]
-
+
<td class="ttotal" align="center">
<a href="[% urlbase %]&
[% col_field FILTER uri %]=[% col FILTER uri %]
[% "&$row_vals" IF row_vals %]">
- [% col_totals.$col %]</a>
+ [% data.$tbl.$col.$total_key OR 0 FILTER html %]</a>
</td>
[% END %]
<td class="ttotal" align="right">
<strong>
<a href="[% urlbase %]
[% "&$row_vals" IF row_vals %]
- [% "&$col_vals" IF col_vals %]">[% grand_total %]</a>
+ [% "&$col_vals" IF col_vals %]">[% data.$tbl.$total_key.$total_key OR 0 FILTER html %]</a>
</strong>
</td>
</tr>
</tr>
</table>
+[% IF note_multi_select %]
+ <p class="extra_info">
+ NOTE: Axes contain multi-value fields, so the total numbers might not add up,
+ as a single [% terms.bug %] can match several rows or columns.
+ </p>
+[% END %]
+
[% BLOCK value_display %]
[% SET disp_value = display_value(field, value) %]
[% IF field == 'assigned_to' OR field == 'reporter'