From: gerv%gerv.net <> Date: Tue, 29 Oct 2002 15:43:57 +0000 (+0000) Subject: Bug 173005 - Add bar charts, pie charts etc. to reporting. Patch by gerv; 2xr=joel. X-Git-Tag: bugzilla-2.17.1~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dad297316ae335ccc20e5d0546525d1c117131c0;p=thirdparty%2Fbugzilla.git Bug 173005 - Add bar charts, pie charts etc. to reporting. Patch by gerv; 2xr=joel. --- diff --git a/checksetup.pl b/checksetup.pl index 1acec457c3..58c2c130fe 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 18e6c79564..dec75628dc 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 f4cb74dada..9543bc5b73 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 "
data hash:\n";
+    print Dumper(%data) . "\n\n";
+    print "data array:\n";
+    print Dumper(@image_data) . "\n\n
"; +} + $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 baad2f5f03..42c07ab2d2 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 6349b6b1bb..3e83da7c0c 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 %] [%# 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 ddc9ce11c1..d08c96c4bd 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 comment 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 [% field_descs.$field %]. - [% 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 d13ccbc438..9b34d15ee2 100644 --- a/template/en/default/index.html.tmpl +++ b/template/en/default/index.html.tmpl @@ -55,7 +55,7 @@ function addSidebar() {

Query existing bug reports
Enter a new bug report
- Get summary reports
+ Summary reports and charts

[% IF username %] Change password or user preferences
diff --git a/template/en/default/reports/menu.html.tmpl b/template/en/default/reports/menu.html.tmpl index d937175322..4e21bf4d62 100644 --- a/template/en/default/reports/menu.html.tmpl +++ b/template/en/default/reports/menu.html.tmpl @@ -29,7 +29,7 @@ %]

- 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.

@@ -46,6 +46,12 @@ - tables of bug counts in 1, 2 or 3 dimensions, as HTML or CSV. +
  • + + Graphical reports + - + line graphs, bar and pie charts. +
  • Change Over Time

    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 0000000000..a3d73d45c3 --- /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 + #%] + +[% 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 0000000000..d0c7b2541c --- /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 + #%] + +[% 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 0000000000..f34397e121 --- /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 + #%] + +[% 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 a80a618c85..60f3a4eefd 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 #%] [%# 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 9767f50301..5074484c36 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: . 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 */ - " -%] - -
    - [% time2str("%Y-%m-%d %H:%M:%S", time) %] -
    - -[% 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 %]& + [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %][% END %] [% END %] -
    - -[% FOREACH tbl = tbl_names %] - - [% IF tbl_field %] - - - - - [% END %] +
    - -

    [% tbl FILTER html %]

    -
    + [% IF tbl_field %] - + [% END %] + + + + - - - + + [% END %]
    - [% col_field_disp FILTER html %] + +

    [% tbl_disp %]

    + + [% col_field_disp FILTER html %] +
    - [% row_field_disp FILTER html %] - +
    + [% row_field_disp FILTER html %] + [% classes = [ [ "t1", "t2" ] , [ "t3", "t4" ] ] %] @@ -150,8 +109,7 @@ [% col_idx = 1 - col_idx %] [% IF data.$tbl.$col.$row AND data.$tbl.$col.$row > 0 %] - [% data.$tbl.$col.$row %] @@ -161,8 +119,7 @@ - [% row_total %] [% grand_total = grand_total + row_total %] @@ -179,8 +136,7 @@ [% NEXT IF col == "" %] - [% col_totals.$col %] @@ -188,24 +144,13 @@ [% END %] - [% grand_total %] + [% grand_total %]
    - - - - -
    - -[% END %] - - Edit this report -
    - -
    - -[% PROCESS global/footer.html.tmpl %] + + + diff --git a/template/en/default/reports/report.csv.tmpl b/template/en/default/reports/report.csv.tmpl new file mode 100644 index 0000000000..727acb3110 --- /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 + #%] +[% 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 0000000000..c4a3edd56a --- /dev/null +++ b/template/en/default/reports/report.html.tmpl @@ -0,0 +1,156 @@ + +[%# 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 + #%] + +[%# 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: . 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 %] +

    [% query FILTER html %]

    +[% END %] + +
    + + [% 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 %] +

    [% tbl_disp FILTER html %]

    + [% END %] + + [% imageurl = BLOCK %]report.cgi?[% imagebase %]&format= + [% format FILTER url_quote %]&ctype=png&action=plot& + [% IF tbl_field AND tbl != "-total-" %] + [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %]& + [% END %]width=[% width %]&height=[% height %] + [% END %] + + + [% END %] +
    + [% END %] + + + + + + [% IF format != "table" %] + + + [% sizeurl = "report.cgi?$switchbase&action=wrap&format=$format" %] + + [% END %] + +
    + [% 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 %] + + [% END %] + [% other_format.description %] + [% "" UNLESS other_format.name == format %] | + [% END %] + CSV + +        + + Taller
    + Thinner * + Fatter    
    + Shorter
    +
    + +

    + [% IF format == "table" %] + Edit + this report + [% ELSE %] + Edit this report + [% END %] +

    + +
    + +[% 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 0000000000..8280fb0bbc --- /dev/null +++ b/template/en/default/search/search-report-graph.html.tmpl @@ -0,0 +1,112 @@ + +[%# 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 + #%] + +[%# 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" %] + +

    + 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. +

    + +[% button_name = "Generate Report" %] + +
    + + + + + + + + + + + + + +
    + Vertical Axis:
    + [% PROCESS select name = 'y_axis_field' %]
    +
    + Plot Data Sets:
    + + Individually
    + + Added + +
    + + + + +
    + Multiple Images:
    + [% PROCESS select name = 'z_axis_field' %] +
    +
    + Format:
    + [% 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 %] + + [% chart_format.description FILTER html %]
    + [% END %] +
    + + Horizontal Axis: + [% PROCESS select name = 'x_axis_field' %] + +
    + +
    + +[% PROCESS search/form.html.tmpl %] + +
    + + +
    + +[% PROCESS "search/boolean-charts.html.tmpl" %] + +
    + +[% 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 0000000000..75716eac7b --- /dev/null +++ b/template/en/default/search/search-report-select.html.tmpl @@ -0,0 +1,47 @@ + +[%# 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 + #%] + +[%# 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" ] %] + + +[% END %] diff --git a/template/en/default/search/search-report-table.html.tmpl b/template/en/default/search/search-report-table.html.tmpl index 73d542124a..a26553602b 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" %]

    - 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.

    [% button_name = "Generate Report" %] @@ -47,7 +47,7 @@ Horizontal Axis: - [% PROCESS select sel = { name => 'x_axis_field', noop = 1 } %] + [% PROCESS select name = 'x_axis_field' %]    @@ -60,14 +60,14 @@ Vertical Axis:
    - [% PROCESS select sel = { name => 'y_axis_field' } %] + [% PROCESS select name = 'y_axis_field' %]
    Multiple Tables:
    - [% PROCESS select sel = { name => 'z_axis_field', noop = 1 } %] + [% PROCESS select name = 'z_axis_field' %]
    @@ -82,7 +82,7 @@
    - +
    [% PROCESS "search/boolean-charts.html.tmpl" %] @@ -90,30 +90,3 @@ [% 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" ] %] - - -[% END %]