summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xchecksetup.pl36
-rwxr-xr-xquery.cgi3
-rwxr-xr-xreport.cgi162
-rw-r--r--template/en/default/global/code-error.html.tmpl4
-rw-r--r--template/en/default/global/field-descs.html.tmpl2
-rw-r--r--template/en/default/global/user-error.html.tmpl13
-rw-r--r--template/en/default/index.html.tmpl2
-rw-r--r--template/en/default/reports/menu.html.tmpl8
-rw-r--r--template/en/default/reports/report-bar.png.tmpl54
-rw-r--r--template/en/default/reports/report-line.png.tmpl53
-rw-r--r--template/en/default/reports/report-pie.png.tmpl35
-rw-r--r--template/en/default/reports/report-table.csv.tmpl54
-rw-r--r--template/en/default/reports/report-table.html.tmpl123
-rw-r--r--template/en/default/reports/report.csv.tmpl26
-rw-r--r--template/en/default/reports/report.html.tmpl156
-rw-r--r--template/en/default/search/search-report-graph.html.tmpl112
-rw-r--r--template/en/default/search/search-report-select.html.tmpl47
-rw-r--r--template/en/default/search/search-report-table.html.tmpl43
18 files changed, 738 insertions, 195 deletions
diff --git a/checksetup.pl b/checksetup.pl
index 1acec457c..58c2c130f 100755
--- a/checksetup.pl
+++ b/checksetup.pl
@@ -258,25 +258,38 @@ foreach my $module (@{$modules}) {
}
print "\nThe following Perl modules are optional:\n" unless $silent;
-my $charts = 0;
-$charts++ if have_vers("GD","1.19");
-$charts++ if have_vers("Chart::Base","0.99");
-my $xmlparser = have_vers("XML::Parser",0);
+my $gd = have_vers("GD","1.20");
+my $chartbase = have_vers("Chart::Base","0.99");
+my $xmlparser = have_vers("XML::Parser",0);
+my $gdgraph = have_vers("GD::Graph",0);
+my $gdtextalign = have_vers("GD::Text::Align",0);
print "\n" unless $silent;
-if (($charts != 2) && !$silent) {
- print "If you you want to see graphical bug dependency charts, you may install\n",
- "the optional libgd and the Perl modules GD-1.19 and Chart::Base-0.99b, e.g. by\n",
- "running (as root)\n\n",
- " perl -MCPAN -e'install \"LDS/GD-1.19.tar.gz\"'\n",
- " perl -MCPAN -e'install \"N/NI/NINJAZ/Chart-0.99b.tar.gz\"'\n\n";
+if ((!$gd || !$chartbase) && !$silent) {
+ print "If you you want to see graphical bug charts (plotting historical ";
+ print "data over \ntime), you should install libgd and the following Perl "; print "modules:\n\n";
+ print "GD: perl -MCPAN -e'install \"GD\"'\n" if !$gd;
+ print "Chart 0.99b: perl -MCPAN " .
+ "-e'install \"N/NI/NINJAZ/Chart-0.99b.tar.gz\"'\n" if !$chartbase;
+ print "\n";
}
if (!$xmlparser && !$silent) {
print "If you want to use the bug import/export feature to move bugs to or from\n",
"other bugzilla installations, you will need to install the XML::Parser module by\n",
- "running (as root)\n\n",
+ "running (as root):\n\n",
" perl -MCPAN -e'install \"XML::Parser\"'\n\n";
}
+if ((!$gd || !$gdgraph || !$gdtextalign) && !$silent) {
+ print "If you you want to see graphical bug reports (bar, pie and line ";
+ print "charts of \ncurrent data), you should install libgd and the ";
+ print "following Perl modules:\n\n";
+ print "GD: perl -MCPAN -e'install \"GD\"'\n" if !$gd;
+ print "GD::Graph: perl -MCPAN " .
+ "-e'install \"GD::Graph\"'\n" if !$gdgraph;
+ print "GD::Text::Align: perl -MCPAN " .
+ "-e'install \"GD::Text::Align\"'\n" if !$gdtextalign;
+ print "\n";
+}
if (%missing) {
print "\n\n";
print "Bugzilla requires some Perl modules which are either missing from your\n",
@@ -580,6 +593,7 @@ $contenttypes = {
"xml" => "text/xml" ,
"js" => "application/x-javascript" ,
"csv" => "text/plain" ,
+ "png" => "image/png" ,
};
');
diff --git a/query.cgi b/query.cgi
index 18e6c7956..dec75628d 100755
--- a/query.cgi
+++ b/query.cgi
@@ -131,7 +131,8 @@ sub PrefillForm {
"bug_file_loc_type", "status_whiteboard",
"status_whiteboard_type", "bug_id",
"bugidtype", "keywords", "keywords_type",
- "x_axis_field", "y_axis_field", "z_axis_field")
+ "x_axis_field", "y_axis_field", "z_axis_field",
+ "chart_format", "cumulate")
{
# This is a bit of a hack. The default, empty list has
# three entries to accommodate the needs of the email fields -
diff --git a/report.cgi b/report.cgi
index f4cb74dad..9543bc5b7 100755
--- a/report.cgi
+++ b/report.cgi
@@ -34,24 +34,58 @@ ConnectToDatabase();
GetVersionTable();
-quietly_check_login();
+confirm_login();
-if ($::FORM{'action'} ne "plot") {
+my $action = $cgi->param('action') || 'menu';
+
+if ($action eq "menu") {
+ # No need to do any searching in this case, so bail out early.
print "Content-Type: text/html\n\n";
$template->process("reports/menu.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
exit;
}
-$::FORM{'y_axis_field'} || ThrowCodeError("no_y_axis_defined");
+my $col_field = $cgi->param('x_axis_field') || '';
+my $row_field = $cgi->param('y_axis_field') || '';
+my $tbl_field = $cgi->param('z_axis_field') || '';
+
+if (!($col_field || $row_field || $tbl_field)) {
+ ThrowUserError("no_axes_defined");
+}
+
+my $width = $cgi->param('width');
+my $height = $cgi->param('height');
-if ($::FORM{'z_axis_field'} && !$::FORM{'x_axis_field'}) {
- ThrowUserError("z_axis_defined_with_no_x_axis");
+if (defined($width)) {
+ (detaint_natural($width) && $width > 0)
+ || ThrowCodeError("invalid_dimensions");
+ $width <= 2000 || ThrowUserError("chart_too_large");
}
-my $col_field = $::FORM{'x_axis_field'};
-my $row_field = $::FORM{'y_axis_field'};
-my $tbl_field = $::FORM{'z_axis_field'};
+if (defined($height)) {
+ (detaint_natural($height) && $height > 0)
+ || ThrowCodeError("invalid_dimensions");
+ $height <= 2000 || ThrowUserError("chart_too_large");
+}
+
+# These shenanigans are necessary to make sure that both vertical and
+# horizontal 1D tables convert to the correct dimension when you ask to
+# display them as some sort of chart.
+if ($::FORM{'format'} && $::FORM{'format'} eq "table") {
+ if ($col_field && !$row_field) {
+ # 1D *tables* should be displayed vertically (with a row_field only)
+ $row_field = $col_field;
+ $col_field = '';
+ }
+}
+else {
+ if ($row_field && !$col_field) {
+ # 1D *charts* should be displayed horizontally (with an col_field only)
+ $col_field = $row_field;
+ $row_field = '';
+ }
+}
my %columns;
$columns{'bug_severity'} = "bugs.bug_severity";
@@ -83,6 +117,9 @@ my $search = new Bugzilla::Search('fields' => \@selectnames,
'params' => $params);
my $query = $search->getSQL();
+$::SIG{TERM} = 'DEFAULT';
+$::SIG{PIPE} = 'DEFAULT';
+
SendSQL($query);
# We have a hash of hashes for the data itself, and a hash to hold the
@@ -90,9 +127,11 @@ SendSQL($query);
my %data;
my %names;
-# Read the bug data and increment the counts.
+# Read the bug data and count the bugs for each possible value of row, column
+# and table.
while (MoreSQLData()) {
my ($row, $col, $tbl) = FetchSQLData();
+ $row = "" if ($row eq $columns{''});
$col = "" if ($col eq $columns{''});
$tbl = "" if ($tbl eq $columns{''});
@@ -102,25 +141,106 @@ while (MoreSQLData()) {
$names{"tbl"}{$tbl}++;
}
-# Determine the labels for the rows and columns
+my @col_names = sort(keys(%{$names{"col"}}));
+my @row_names = sort(keys(%{$names{"row"}}));
+my @tbl_names = sort(keys(%{$names{"tbl"}}));
+
+# The GD::Graph package requires a particular format of data, so once we've
+# gathered everything into the hashes and made sure we know the size of the
+# data, we reformat it into an array of arrays of arrays of data.
+push(@tbl_names, "-total-") if (scalar(@tbl_names) > 1);
+
+my @image_data;
+foreach my $tbl (@tbl_names) {
+ my @tbl_data;
+ push(@tbl_data, \@col_names);
+ foreach my $row (@row_names) {
+ my @col_data;
+ foreach my $col (@col_names) {
+ $data{$tbl}{$col}{$row} = $data{$tbl}{$col}{$row} || 0;
+ push(@col_data, $data{$tbl}{$col}{$row});
+ if ($tbl ne "-total-") {
+ # This is a bit sneaky. We spend every loop except the last
+ # building up the -total- data, and then last time round,
+ # we process it as another tbl, and push() the total values
+ # into the image_data array.
+ $data{"-total-"}{$col}{$row} += $data{$tbl}{$col}{$row};
+ }
+ }
+
+ push(@tbl_data, \@col_data);
+ }
+
+ push(@image_data, \@tbl_data);
+}
+
$vars->{'col_field'} = $col_field;
$vars->{'row_field'} = $row_field;
$vars->{'tbl_field'} = $tbl_field;
-$vars->{'names'} = \%names;
-$vars->{'data'} = \%data;
$vars->{'time'} = time();
-$cgi->delete('format');
+$vars->{'col_names'} = \@col_names;
+$vars->{'row_names'} = \@row_names;
+$vars->{'tbl_names'} = \@tbl_names;
+
+$vars->{'width'} = $width if $width;
+$vars->{'height'} = $height if $height;
+
+$vars->{'query'} = $query;
+$vars->{'debug'} = $::FORM{'debug'};
+
+my $formatparam = $cgi->param('format');
+
+if ($action eq "wrap") {
+ # So which template are we using? If action is "wrap", we will be using
+ # no format (it gets passed through to be the format of the actual data),
+ # and either report.csv.tmpl (CSV), or report.html.tmpl (everything else).
+ # report.html.tmpl produces an HTML framework for either tables of HTML
+ # data, or images generated by calling report.cgi again with action as
+ # "plot".
+ $formatparam =~ s/[^a-zA-Z\-]//g;
+ trick_taint($formatparam);
+ $vars->{'format'} = $formatparam;
+ $formatparam = '';
+
+ # We need a number of different variants of the base URL for different
+ # URLs in the HTML.
+ $vars->{'buglistbase'} = $cgi->canonicalise_query(
+ "x_axis_field", "y_axis_field", "z_axis_field", "format", @axis_fields);
+ $vars->{'imagebase'} = $cgi->canonicalise_query(
+ $tbl_field, "action", "ctype", "format", "width", "height");
+ $vars->{'switchbase'} = $cgi->canonicalise_query(
+ "action", "ctype", "format", "width", "height");
+ $vars->{'data'} = \%data;
+}
+elsif ($action eq "plot") {
+ # If action is "plot", we will be using a format as normal (pie, bar etc.)
+ # and a ctype as normal (currently only png.)
+ $vars->{'cumulate'} = $cgi->param('cumulate') ? 1 : 0;
+ $vars->{'data'} = \@image_data;
+}
+else {
+ ThrowUserError("unknown_action", {action => $cgi->param('action')});
+}
+
+my $format = GetFormat("reports/report", $formatparam, $cgi->param('ctype'));
-# Calculate the base query URL for the hyperlinked numbers
-$vars->{'querybase'} = $cgi->canonicalise_query("x_axis_field",
- "y_axis_field",
- "z_axis_field",
- @axis_fields);
-$vars->{'query'} = $cgi->query_string();
+# If we get a template or CGI error, it comes out as HTML, which isn't valid
+# PNG data, and the browser just displays a "corrupt PNG" message. So, you can
+# set debug=1 to always get an HTML content-type, and view the error.
+$format->{'ctype'} = "text/html" if $::FORM{'debug'};
-# Generate and return the result from the appropriate template.
-my $format = GetFormat("reports/report", $::FORM{'format'}, $::FORM{'ctype'});
print "Content-Type: $format->{'ctype'}\n\n";
+
+# Problems with this CGI are often due to malformed data. Setting debug=1
+# prints out both data structures.
+if ($::FORM{'debug'}) {
+ use Data::Dumper;
+ print "<pre>data hash:\n";
+ print Dumper(%data) . "\n\n";
+ print "data array:\n";
+ print Dumper(@image_data) . "\n\n</pre>";
+}
+
$template->process("$format->{'template'}", $vars)
|| ThrowTemplateError($template->error());
diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl
index baad2f5f0..42c07ab2d 100644
--- a/template/en/default/global/code-error.html.tmpl
+++ b/template/en/default/global/code-error.html.tmpl
@@ -119,6 +119,10 @@
The [% component FILTER html %] component doesn't exist in the
[% product FILTER html %] product.
+ [% ELSIF error == "invalid_dimensions" %]
+ [% title = "Invalid Dimensions" %]
+ The width or height specified is not a positive integer.
+
[% ELSIF error == "mismatched_bug_ids_on_obsolete" %]
Attachment [% attach_id FILTER html %] ([% description FILTER html %])
is attached to bug [% attach_bug_id FILTER html %], but you tried to
diff --git a/template/en/default/global/field-descs.html.tmpl b/template/en/default/global/field-descs.html.tmpl
index 6349b6b1b..3e83da7c0 100644
--- a/template/en/default/global/field-descs.html.tmpl
+++ b/template/en/default/global/field-descs.html.tmpl
@@ -1,4 +1,4 @@
-<!-- 1.0@bugzilla.org -->
+[%# 1.0@bugzilla.org %]
[%# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index ddc9ce11c..d08c96c4b 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -114,6 +114,10 @@
[% title = "Bugs Not Changed" %]
Um, you apparently did not change anything on the selected bugs.
+ [% ELSIF error == "chart_too_large" %]
+ [% title = "Chart Too Large" %]
+ Sorry, but 2000 x 2000 is the maximum size for a chart.
+
[% ELSIF error == "comment_required" %]
[% title = "Comment Required" %]
You have to specify a <b>comment</b> on this change.
@@ -361,6 +365,10 @@
[% title = "New Password Missing" %]
You must enter a new password.
+ [% ELSIF error == "no_axes_defined" %]
+ [% title = "No Axes Defined" %]
+ You didn't define any axes to plot.
+
[% ELSIF error == "no_bugs_chosen" %]
[% title = "No Bugs Chosen" %]
You apparently didn't choose any bugs to modify.
@@ -547,11 +555,6 @@
[% title = "Value Out Of Range" %]
Value is out of range for field <em>[% field_descs.$field %]</em>.
- [% ELSIF error == "z_axis_defined_with_no_x_axis" %]
- [% title = "Nonsensical Options" %]
- You've defined a field for multiple tables without having defined
- a horizontal axis for those tables.
-
[% ELSIF error == "zero_length_file" %]
[% title = "File Is Empty" %]
The file you are trying to attach is empty!
diff --git a/template/en/default/index.html.tmpl b/template/en/default/index.html.tmpl
index d13ccbc43..9b34d15ee 100644
--- a/template/en/default/index.html.tmpl
+++ b/template/en/default/index.html.tmpl
@@ -55,7 +55,7 @@ function addSidebar() {
<p>
<a href="query.cgi">Query existing bug reports</a><br>
<a href="enter_bug.cgi">Enter a new bug report</a><br>
- <a href="reports.cgi">Get summary reports</a><br>
+ <a href="report.cgi">Summary reports and charts</a><br>
</p><p>
[% IF username %]
<a href="userprefs.cgi">Change password or user preferences</a><br>
diff --git a/template/en/default/reports/menu.html.tmpl b/template/en/default/reports/menu.html.tmpl
index d93717532..4e21bf4d6 100644
--- a/template/en/default/reports/menu.html.tmpl
+++ b/template/en/default/reports/menu.html.tmpl
@@ -29,7 +29,7 @@
%]
<p>
- Bugzilla allows you to view and track the state of your bug database in
+ Bugzilla allows you to view and track the state of the bug database in
all manner of exciting ways.
</p>
@@ -46,6 +46,12 @@
</strong> -
tables of bug counts in 1, 2 or 3 dimensions, as HTML or CSV.
</li>
+ <li>
+ <strong>
+ <a href="query.cgi?format=report-graph">Graphical reports</a>
+ </strong> -
+ line graphs, bar and pie charts.
+ </li>
</ul>
<h2>Change Over Time</h2>
diff --git a/template/en/default/reports/report-bar.png.tmpl b/template/en/default/reports/report-bar.png.tmpl
new file mode 100644
index 000000000..a3d73d45c
--- /dev/null
+++ b/template/en/default/reports/report-bar.png.tmpl
@@ -0,0 +1,54 @@
+[%# 1.0@bugzilla.org %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Gervase Markham <gerv@gerv.net>
+ #%]
+
+[% y_label = "Bugs" %]
+
+[% PROCESS "global/field-descs.html.tmpl" %]
+
+[% col_field_disp = field_descs.$col_field || col_field %]
+
+[% FILTER null;
+ USE graph = GD.Graph.bars(width, height);
+
+ graph.set(x_label => col_field_disp,
+ y_label => y_label,
+ y_tick_number => 8,
+ y_number_format => "%d",
+ x_label_position => 0.5,
+ bar_spacing => 8,
+ shadow_depth => 4,
+ shadowclr => 'dred',
+ show_values => 1,
+ legend_placement => "RT");
+
+ graph.set(cumulate => "true",
+ show_values => 0) IF cumulate;
+
+ # Workaround for the fact that set_legend won't take row_names directly,
+ # because row_names is an array reference rather than an array.
+ graph.set_legend(row_names.0, row_names.1, row_names.2, row_names.3,
+ row_names.4, row_names.5, row_names.6, row_names.7,
+ row_names.8, row_names.9, row_names.10, row_names.11,
+ row_names.12, row_names.13, row_names.14, row_names.15);
+
+ graph.plot(data.0).png | stdout(1);
+ END;
+-%]
diff --git a/template/en/default/reports/report-line.png.tmpl b/template/en/default/reports/report-line.png.tmpl
new file mode 100644
index 000000000..d0c7b2541
--- /dev/null
+++ b/template/en/default/reports/report-line.png.tmpl
@@ -0,0 +1,53 @@
+[%# 1.0@bugzilla.org %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Gervase Markham <gerv@gerv.net>
+ #%]
+
+[% y_label = "Bugs" %]
+
+[% PROCESS "global/field-descs.html.tmpl" %]
+
+[% col_field_disp = field_descs.$col_field || col_field %]
+
+[% IF cumulate %]
+ [% USE graph = GD.Graph.area(width, height) %]
+ [% graph.set(cumulate => "true") %]
+[% ELSE %]
+ [% USE graph = GD.Graph.lines(width, height) %]
+[% END %]
+
+[% FILTER null;
+ graph.set(x_label => col_field_disp,
+ y_label => y_label,
+ y_tick_number => 8,
+ x_label_position => 0.5,
+ legend_placement => "RT",
+ line_width => 2);
+
+ # Workaround for the fact that set_legend won't take row_names directly,
+ # because row_names is an array reference rather than an array.
+ graph.set_legend(row_names.0, row_names.1, row_names.2, row_names.3,
+ row_names.4, row_names.5, row_names.6, row_names.7,
+ row_names.8, row_names.9, row_names.10, row_names.11,
+ row_names.12, row_names.13, row_names.14, row_names.15);
+
+ graph.plot(data.0).png | stdout(1);
+ END;
+-%]
+
diff --git a/template/en/default/reports/report-pie.png.tmpl b/template/en/default/reports/report-pie.png.tmpl
new file mode 100644
index 000000000..f34397e12
--- /dev/null
+++ b/template/en/default/reports/report-pie.png.tmpl
@@ -0,0 +1,35 @@
+[%# 1.0@bugzilla.org %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Gervase Markham <gerv@gerv.net>
+ #%]
+
+[% PROCESS "global/field-descs.html.tmpl" %]
+
+[% col_field_disp = field_descs.$col_field || col_field %]
+
+[% FILTER null;
+ USE graph = GD.Graph.pie(width, height);
+
+ graph.set(title => col_field_disp,
+ pie_height => 20,
+ start_angle => 180);
+
+ graph.plot(data.0).png | stdout(1);
+ END;
+-%]
diff --git a/template/en/default/reports/report-table.csv.tmpl b/template/en/default/reports/report-table.csv.tmpl
index a80a618c8..60f3a4eef 100644
--- a/template/en/default/reports/report-table.csv.tmpl
+++ b/template/en/default/reports/report-table.csv.tmpl
@@ -19,39 +19,33 @@
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
[%# INTERFACE:
- # See report.html.tmpl.
+ # See report-table.html.tmpl.
#%]
-
-[% tbl_names = names.tbl.keys.sort %]
-[% col_names = names.col.keys.sort %]
-[% row_names = names.row.keys.sort %]
+[% num_bugs = "Number of bugs" %]
+[% tbl_field_disp = field_descs.$tbl_field || tbl_field %]
+[% col_field_disp = field_descs.$col_field || col_field %]
+[% row_field_disp = field_descs.$row_field || row_field %]
-[% FOREACH tbl = tbl_names %]
- [% IF tbl_field -%]
- [% tbl FILTER html %]
- [% END %]
-
- [% row_field FILTER csv -%]
-
- [% IF col_field -%]
- \ [% col_field FILTER csv -%],
- [% FOREACH col = col_names -%]
- [% col FILTER csv -%],
- [% END -%]
- [% ELSE -%]
- [% -%],Number of bugs
- [% END %]
+[% "$tbl_field_disp: $tbl\n" FILTER csv IF tbl_field %]
+[% row_field_disp FILTER csv IF row_field %]
+[% " / " IF col_field AND row_field %]
+[% col_field_disp FILTER csv %],
+[% IF col_field -%]
+[% FOREACH col = col_names -%]
+ [% col FILTER csv -%],
+[% END -%]
+[% ELSE -%]
+ [% num_bugs %],
+[% END %]
- [% FOREACH row = row_names %]
- [% row FILTER csv -%],
- [% FOREACH col = col_names %]
- [% IF data.$tbl AND data.$tbl.$col AND data.$tbl.$col.$row %]
- [% data.$tbl.$col.$row -%],
- [% ELSE %]
- [% -%]0,
- [% END %]
+[% FOREACH row = row_names %]
+ [% row FILTER csv -%],
+ [% FOREACH col = col_names %]
+ [% IF data.$tbl AND data.$tbl.$col AND data.$tbl.$col.$row %]
+ [% data.$tbl.$col.$row -%],
+ [% ELSE %]
+ [% -%]0,
[% END %]
-
[% END %]
-
+
[% END %]
diff --git a/template/en/default/reports/report-table.html.tmpl b/template/en/default/reports/report-table.html.tmpl
index 9767f5030..5074484c3 100644
--- a/template/en/default/reports/report-table.html.tmpl
+++ b/template/en/default/reports/report-table.html.tmpl
@@ -21,92 +21,51 @@
#%]
[%# INTERFACE:
- # querybase: The base query for this table, in URL form
- # query: The query for this table, in URL form
- # data: hash of hash of hash of numbers. Bug counts.
- # names: hash of hash of strings. Names of tables, rows and columns.
+ # buglistbase: The base query for this table, in URL form
# col_field: string. Name of the field being plotted as columns.
# row_field: string. Name of the field being plotted as rows.
# tbl_field: string. Name of the field being plotted as tables.
+ # col_names: array. List of values for the field being plotted as columns.
+ # row_names: array. List of values for the field being plotted as rows.
+ # data: <depends on format>. Data to plot. Only data.$tbl is accessed.
+ # tbl: Name of a hash in data which is the table to be plotted.
#%]
[% PROCESS "global/field-descs.html.tmpl" %]
-[% tbl_field_disp = field_descs.$tbl_field || tbl_field %]
[% col_field_disp = field_descs.$col_field || col_field %]
[% row_field_disp = field_descs.$row_field || row_field %]
-
-[% title = BLOCK %]
- Report:
- [% "$tbl_field_disp / " IF tbl_field %]
- [% "$col_field_disp / " IF col_field %]
- [% row_field_disp %]
-[% END %]
-
-[% PROCESS global/header.html.tmpl
- style = "
- .t1 { background-color: #ffffff } /* white */
- .t2 { background-color: #dfefff } /* light blue */
- .t3 { background-color: #dddddd } /* grey */
- .t4 { background-color: #c3d3ed } /* darker blue */
- .ttotal { background-color: #cfffdf } /* light green */
- "
-%]
-
-<div align="right">
- [% time2str("%Y-%m-%d %H:%M:%S", time) %]
-</div>
-
-[% tbl_names = names.tbl.keys.sort %]
-[% col_names = names.col.keys.sort %]
-[% row_names = names.row.keys.sort %]
-
-[% total_name = "Total" %]
-
-[% FOREACH tbl = tbl_names %]
- [% FOREACH row = row_names %]
- [% FOREACH col = col_names %]
- [% data.$tbl.$col.$row = (data.$tbl.$col.$row || 0) %]
-
- [% IF tbl_field %]
- [%# Calculate values for the Total table %]
- [% data.$total_name.$col.$row =
- (data.$total_name.$col.$row || 0) + data.$tbl.$col.$row %]
- [% END %]
- [% END %]
- [% END %]
-[% END %]
-[% IF tbl_field %]
- [% tbl_names.push(total_name) %]
+[% IF tbl == "-total-" %]
+ [% urlbase = BLOCK %]buglist.cgi?[% buglistbase %][% END %]
+[% ELSE %]
+ [% urlbase = BLOCK %]buglist.cgi?[% buglistbase %]&amp;
+ [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %][% END %]
[% END %]
-<div align="center">
-
-[% FOREACH tbl = tbl_names %]
- <table>
- [% IF tbl_field %]
- <tr>
- <td>
- </td>
- <td align="center">
- <h2>[% tbl FILTER html %]</h2>
- </td>
- </tr>
- [% END %]
+<table>
+ [% IF tbl_field %]
<tr>
<td>
</td>
- <td align="center">
- <strong>[% col_field_disp FILTER html %]</strong>
+ <td align="center">
+ <h2>[% tbl_disp %]</h2>
</td>
</tr>
+ [% END %]
+ <tr>
+ <td>
+ </td>
+ <td align="center">
+ <strong>[% col_field_disp FILTER html %]</strong>
+ </td>
+ </tr>
- <tr>
- <td valign="middle">
- <strong>[% row_field_disp FILTER html %]</strong>
- </td>
- <td>
+ <tr>
+ <td valign="middle">
+ <strong>[% row_field_disp FILTER html %]</strong>
+ </td>
+ <td>
[% classes = [ [ "t1", "t2" ] , [ "t3", "t4" ] ] %]
@@ -150,8 +109,7 @@
[% col_idx = 1 - col_idx %]
<td class="[% classes.$row_idx.$col_idx %]" align="center">
[% IF data.$tbl.$col.$row AND data.$tbl.$col.$row > 0 %]
- <a href="buglist.cgi?[% querybase FILTER html %]&amp;
- [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %]&amp;
+ <a href="[% urlbase %]&amp;
[% row_field FILTER url_quote %]=[% row FILTER url_quote %]&amp;
[% col_field FILTER url_quote %]=[% col FILTER url_quote %]">
[% data.$tbl.$col.$row %]</a>
@@ -161,8 +119,7 @@
</td>
[% END %]
<td class="ttotal" align="right">
- <a href="buglist.cgi?[% querybase FILTER html %]&amp;
- [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %]&amp;
+ <a href="[% urlbase %]&amp;
[% row_field FILTER url_quote %]=[% row FILTER url_quote %]">
[% row_total %]</a>
[% grand_total = grand_total + row_total %]
@@ -179,8 +136,7 @@
[% NEXT IF col == "" %]
<td class="ttotal" align="center">
- <a href="buglist.cgi?[% querybase FILTER html %]&amp;
- [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %]&amp;
+ <a href="[% urlbase %]&amp;
[% col_field FILTER url_quote %]=[% col FILTER url_quote %]">
[% col_totals.$col %]</a>
<strong>
@@ -188,24 +144,13 @@
[% END %]
<td class="ttotal" align="right">
<strong>
- <a href="buglist.cgi?[% querybase FILTER html %]">[% grand_total %]</a>
+ <a href="buglist.cgi?[% urlbase %]">[% grand_total %]</a>
</strong>
</td>
</tr>
</table>
- </td>
- </tr>
- </table>
-
- <br>
-
-[% END %]
-
- <a href="query.cgi?[% query FILTER html %]&amp;format=report-table">Edit this report</a>
-</div>
-
-<br>
-
-[% PROCESS global/footer.html.tmpl %]
+ </td>
+ </tr>
+</table>
diff --git a/template/en/default/reports/report.csv.tmpl b/template/en/default/reports/report.csv.tmpl
new file mode 100644
index 000000000..727acb311
--- /dev/null
+++ b/template/en/default/reports/report.csv.tmpl
@@ -0,0 +1,26 @@
+[%# 1.0@bugzilla.org %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Gervase Markham <gerv@gerv.net>
+ #%]
+[% PROCESS "global/field-descs.html.tmpl" %]
+[% FOREACH tbl = tbl_names %]
+ [% PROCESS "reports/report-table.csv.tmpl" %]
+
+
+[% END %]
diff --git a/template/en/default/reports/report.html.tmpl b/template/en/default/reports/report.html.tmpl
new file mode 100644
index 000000000..c4a3edd56
--- /dev/null
+++ b/template/en/default/reports/report.html.tmpl
@@ -0,0 +1,156 @@
+ <!-- 1.0@bugzilla.org -->
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Gervase Markham <gerv@gerv.net>
+ #%]
+
+[%# INTERFACE:
+ # col_field: string. Name of the field being plotted as columns.
+ # row_field: string. Name of the field being plotted as rows.
+ # tbl_field: string. Name of the field being plotted as tables.
+ # tbl_names: array. List of values for the field being plotted as tables.
+ # time: integer. Seconds since the epoch.
+ # data: <depends on format>. Data to plot.
+ # format: string. Format of the individual reports.
+ # width: integer. For image charts, height of the image.
+ # height: integer. For image charts, width of the image.
+ # switchbase: string. Base URL for format switching.
+ # cumulate: boolean. For bar/line charts, whether to cumulate data sets.
+ #%]
+
+[% DEFAULT width = 600
+ height = 350
+%]
+
+[%# We ignore row_field for pie charts %]
+[% IF format == "pie" %]
+ [% row_field = "" %]
+[% END %]
+
+[% PROCESS "global/field-descs.html.tmpl" %]
+
+[% tbl_field_disp = field_descs.$tbl_field || tbl_field %]
+[% col_field_disp = field_descs.$col_field || col_field %]
+[% row_field_disp = field_descs.$row_field || row_field %]
+
+[% title = BLOCK %]
+ Report:
+ [% tbl_field_disp IF tbl_field %]
+ [% " / " IF tbl_field AND (col_field OR row_field) %]
+ [% row_field_disp IF row_field %]
+ [% " / " IF col_field AND row_field %]
+ [% col_field_disp %]
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ style = "
+ .t1 { background-color: #ffffff } /* white */
+ .t2 { background-color: #dfefff } /* light blue */
+ .t3 { background-color: #dddddd } /* grey */
+ .t4 { background-color: #c3d3ed } /* darker blue */
+ .ttotal { background-color: #cfffdf } /* light green */
+ "
+ h3 = time2str("%Y-%m-%d %H:%M:%S", time)
+%]
+
+[% IF debug %]
+ <p>[% query FILTER html %]</p>
+[% END %]
+
+<div align="center">
+
+ [% FOREACH tbl = tbl_names %]
+ [% IF tbl == "-total-" %]
+ [% tbl_disp = "Total" %]
+ [% ELSE %]
+ [% tbl_disp = tbl %]
+ [% END %]
+
+ [% IF format == "table" %]
+ [% PROCESS "reports/report-table.html.tmpl" %]
+ [% ELSE %]
+ [% IF tbl %]
+ <h2>[% tbl_disp FILTER html %]</h2>
+ [% END %]
+
+ [% imageurl = BLOCK %]report.cgi?[% imagebase %]&amp;format=
+ [% format FILTER url_quote %]&amp;ctype=png&amp;action=plot&amp;
+ [% IF tbl_field AND tbl != "-total-" %]
+ [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %]&amp;
+ [% END %]width=[% width %]&amp;height=[% height %]
+ [% END %]
+
+ <img src="[% imageurl %]" width="[% width %]" height="[% height %]">
+ [% END %]
+ <br>
+ [% END %]
+
+ <table>
+ <tr>
+ <td>
+ [% formats = [ { name => "pie", description => "Pie" },
+ { name => "bar", description => "Bar" },
+ { name => "line", description => "Line" },
+ { name => "table", description => "Table" } ] %]
+
+ [% formaturl = "report.cgi?$switchbase&width=$width&height=$height" _
+ "&action=wrap" %]
+ [% FOREACH other_format = formats %]
+ [% NEXT IF other_format.name == "pie" AND row_field %]
+ [% UNLESS other_format.name == format %]
+ <a href="[% formaturl %]&format=[% other_format.name %]">
+ [% END %]
+ [% other_format.description %]
+ [% "</a>" UNLESS other_format.name == format %] |
+ [% END %]
+ <a href="[% formaturl %]&ctype=csv">CSV</a>
+ </td>
+
+ [% IF format != "table" %]
+ <td>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </td>
+
+ [% sizeurl = "report.cgi?$switchbase&action=wrap&format=$format" %]
+ <td align="center">
+ <a href="[% sizeurl %]&width=[% width %]&height=
+ [% height + 100 %]">Taller</a><br>
+ <a href="[% sizeurl %]&width=[% width - 100 %]&height=
+ [% height %]">Thinner</a> *
+ <a href="[% sizeurl %]&width=[% width + 100 %]&height=
+ [% height %]">Fatter</a>&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ <a href="[% sizeurl %]&width=[% width %]&height=
+ [% height - 100 %]">Shorter</a><br>
+ </td>
+ [% END %]
+ <tr>
+ </table>
+
+ <p>
+ [% IF format == "table" %]
+ <a href="query.cgi?[% switchbase %]&format=report-table">Edit
+ this report</a>
+ [% ELSE %]
+ <a href="query.cgi?[% switchbase %]&format=report-graph&chart_format=
+ [% format %]&cumulate=[% cumulate %]">Edit this report</a>
+ [% END %]
+ </p>
+
+</div>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/template/en/default/search/search-report-graph.html.tmpl b/template/en/default/search/search-report-graph.html.tmpl
new file mode 100644
index 000000000..8280fb0bb
--- /dev/null
+++ b/template/en/default/search/search-report-graph.html.tmpl
@@ -0,0 +1,112 @@
+<!-- 1.0@bugzilla.org -->
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Gervase Markham <gerv@gerv.net>
+ #%]
+
+[%# INTERFACE:
+ # This template has no interface. However, to use it, you need to fulfill
+ # the interfaces of the templates it contains.
+ #%]
+
+[% PROCESS global/header.html.tmpl
+ title = "Generate Report"
+ onload = "selectProduct(document.forms['reportform']);"
+%]
+
+[% PROCESS "search/search-report-select.html.tmpl" %]
+
+<p>
+ Produce a pictorial graph of bug counts by choosing one or more fields as
+ your axes, and then refining your set of bugs using the rest of the form.
+ If you choose a third axis, it will be represented by multiple tables of data.
+ Note: vertical axis settings will be ignored for pie charts.
+</p>
+
+[% button_name = "Generate Report" %]
+
+<form method="get" action="report.cgi" name="reportform">
+
+<table align="center">
+ <tr>
+ <td valign="middle">
+ <b>Vertical Axis:</b><br>
+ [% PROCESS select name = 'y_axis_field' %]<br>
+ <br>
+ <b>Plot Data Sets:</b><br>
+ <input type="radio" name="cumulate" value="0"
+ [% " checked" IF default.cumulate.0 != "1" %]>
+ Individually<br>
+ <input type="radio" name="cumulate" value="1"
+ [% " checked" IF default.cumulate.0 == "1" %]>
+ Added
+
+ </td>
+ <td width="150px" height="150px">
+ <table border="1" width="100%" height="100%">
+ <tr>
+ <td align="center" valign="middle">
+ <b>Multiple Images:</b><br>
+ [% PROCESS select name = 'z_axis_field' %]
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td rowspan="2">
+ <b>Format:</b><br>
+ [% chart_formats = [
+ { name => "line", description => "Line Graph" },
+ { name => "bar", description => "Bar Chart" },
+ { name => "pie", description => "Pie Chart" } ] %]
+ [% default.chart_format.0 = default.chart_format.0 || "bar" %]
+
+ [% FOREACH chart_format = chart_formats %]
+ <input type="radio" name="format"
+ value="[% chart_format.name FILTER html %]"
+ [% " checked" IF default.chart_format.0 == chart_format.name %]>
+ [% chart_format.description FILTER html %]<br>
+ [% END %]
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ <td align="center">
+ <b>Horizontal Axis:</b>
+ [% PROCESS select name = 'x_axis_field' %]
+ </td>
+ <td>
+ </td>
+ </tr>
+</table>
+
+<hr>
+
+[% PROCESS search/form.html.tmpl %]
+
+<br>
+<input type="submit" value="[% button_name %]">
+<input type="hidden" name="action" value="wrap">
+<hr>
+
+[% PROCESS "search/boolean-charts.html.tmpl" %]
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/template/en/default/search/search-report-select.html.tmpl b/template/en/default/search/search-report-select.html.tmpl
new file mode 100644
index 000000000..75716eac7
--- /dev/null
+++ b/template/en/default/search/search-report-select.html.tmpl
@@ -0,0 +1,47 @@
+<!-- 1.0@bugzilla.org -->
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Gervase Markham <gerv@gerv.net>
+ #%]
+
+[%# INTERFACE:
+ # name: string. The name of the select block to output.
+ # default.$name.0: string. The default value for the block, if any.
+ #%]
+
+[% PROCESS "global/field-descs.html.tmpl" %]
+
+[% BLOCK select %]
+ [% fields = ["product", "component", "version", "rep_platform",
+ "op_sys", "bug_status", "resolution", "bug_severity",
+ "priority", "target_milestone", "keywords", "assigned_to",
+ "reporter", "qa_contact", "votes" ] %]
+
+ <select name="[% name FILTER html %]">
+ <option value="">&lt;none&gt;</option>
+
+ [% FOREACH field = fields %]
+ [% NEXT IF field == "target_milestone" AND !Param('usetargetmilestone') %]
+ [% NEXT IF field == "qa_contact" AND !Param('useqacontact') %]
+ [% NEXT IF field == "votes" AND !Param('usevotes') %]
+ <option value="[% field FILTER html %]"
+ [% " selected" IF default.$name.0 == field %]>
+ [% field_descs.$field || field FILTER html %]</option>
+ [% END %]
+ </select>
+[% END %]
diff --git a/template/en/default/search/search-report-table.html.tmpl b/template/en/default/search/search-report-table.html.tmpl
index 73d542124..a26553602 100644
--- a/template/en/default/search/search-report-table.html.tmpl
+++ b/template/en/default/search/search-report-table.html.tmpl
@@ -29,12 +29,12 @@
onload = "selectProduct(document.forms['reportform']);"
%]
-[% PROCESS "global/field-descs.html.tmpl" %]
+[% PROCESS "search/search-report-select.html.tmpl" %]
<p>
- Produce a table of bug counts by choosing one or more fields to plot against
- each other, and then refining your set of bugs using the rest of the form. If
- you choose a third axis, it will be represented by multiple tables of data.
+ Produce a table of bug counts by choosing one or more fields as your axes,
+ and then refining your set of bugs using the rest of the form.
+ If you choose a third axis, it will be represented by multiple tables of data.
</p>
[% button_name = "Generate Report" %]
@@ -47,7 +47,7 @@
</td>
<td align="center">
<b>Horizontal Axis:</b>
- [% PROCESS select sel = { name => 'x_axis_field', noop = 1 } %]
+ [% PROCESS select name = 'x_axis_field' %]
</td>
<td>&nbsp;&nbsp;</td>
<td rowspan="2">
@@ -60,14 +60,14 @@
<tr>
<td valign="middle" align="center">
<b>Vertical Axis:</b><br>
- [% PROCESS select sel = { name => 'y_axis_field' } %]
+ [% PROCESS select name = 'y_axis_field' %]
</td>
<td width="150px" height="150px">
<table border="1" width="100%" height="100%">
<tr>
<td align="center" valign="middle">
<b>Multiple Tables:</b><br>
- [% PROCESS select sel = { name => 'z_axis_field', noop = 1 } %]
+ [% PROCESS select name = 'z_axis_field' %]
</td>
</tr>
</table>
@@ -82,7 +82,7 @@
<br>
<input type="submit" value="[% button_name %]">
<input type="hidden" name="format" value="table">
-<input type="hidden" name="action" value="plot">
+<input type="hidden" name="action" value="wrap">
<hr>
[% PROCESS "search/boolean-charts.html.tmpl" %]
@@ -90,30 +90,3 @@
</form>
[% PROCESS global/footer.html.tmpl %]
-
-[%############################################################################%]
-[%# Block for SELECT fields #%]
-[%############################################################################%]
-
-[% BLOCK select %]
- [% fields = ["product", "component", "version", "rep_platform",
- "op_sys", "bug_status", "resolution", "bug_severity",
- "priority", "target_milestone", "keywords", "assigned_to",
- "reporter", "qa_contact", "votes" ] %]
-
- <select name="[% sel.name %]">
- [% IF sel.noop %]
- <option value="">&lt;none&gt;</option>
- [% END %]
-
- [% FOREACH field = fields %]
- [% NEXT IF field == "target_milestone" AND !Param('usetargetmilestone') %]
- [% NEXT IF field == "qa_contact" AND !Param('useqacontact') %]
- [% NEXT IF field == "votes" AND !Param('usevotes') %]
-
- <option value="[% field FILTER html %]"
- [% " selected" IF default.${sel.name}.0 == field %]>
- [% field_descs.$field || field FILTER html %]</option>
- [% END %]
- </select>
-[% END %]