Commit 88d26275 authored by bugreport%peshkin.net's avatar bugreport%peshkin.net

Bug 224208 Add a higher level of categorization (.ie departments, locations, etc.)

patch by Albert Ting r=joel, glob a=myk
parent 2f9f28d0
......@@ -48,6 +48,7 @@ sub fields {
# Keep this ordering in sync with bugzilla.dtd
my @fields = qw(bug_id alias creation_ts short_desc delta_ts
reporter_accessible cclist_accessible
classification_id classification
product component version rep_platform op_sys
bug_status resolution
bug_file_loc status_whiteboard keywords
......@@ -137,7 +138,8 @@ sub initBug {
my $query = "
SELECT
bugs.bug_id, alias, bugs.product_id, products.name, version,
bugs.bug_id, alias, products.classification_id, classifications.name,
bugs.product_id, products.name, version,
rep_platform, op_sys, bug_status, resolution, priority,
bug_severity, bugs.component_id, components.name, assigned_to,
reporter, bug_file_loc, short_desc, target_milestone,
......@@ -147,8 +149,9 @@ sub initBug {
reporter_accessible, cclist_accessible,
estimated_time, remaining_time
from bugs left join votes using(bug_id),
products, components
classifications, products, components
where bugs.bug_id = $bug_id
AND classifications.id = products.classification_id
AND products.id = bugs.product_id
AND components.id = bugs.component_id
group by bugs.bug_id";
......@@ -159,7 +162,8 @@ sub initBug {
if ((@row = &::FetchSQLData()) && $self->{'who'}->can_see_bug($bug_id)) {
my $count = 0;
my %fields;
foreach my $field ("bug_id", "alias", "product_id", "product", "version",
foreach my $field ("bug_id", "alias", "classification_id", "classification",
"product_id", "product", "version",
"rep_platform", "op_sys", "bug_status", "resolution",
"priority", "bug_severity", "component_id", "component",
"assigned_to", "reporter", "bug_file_loc", "short_desc",
......
......@@ -96,6 +96,11 @@ sub init {
push @wherepart, "bugs.product_id = map_products.id";
}
if (lsearch($fieldsref, 'map_classifications.name') >= 0) {
push @supptables, "classifications AS map_classifications";
push @wherepart, "map_products.classification_id = map_classifications.id";
}
if (lsearch($fieldsref, 'map_components.name') >= 0) {
push @supptables, "components AS map_components";
push @wherepart, "bugs.component_id = map_components.id";
......@@ -152,7 +157,7 @@ sub init {
my @legal_fields = ("product", "version", "rep_platform", "op_sys",
"bug_status", "resolution", "priority", "bug_severity",
"assigned_to", "reporter", "component",
"assigned_to", "reporter", "component", "classification",
"target_milestone", "bug_group");
foreach my $field ($params->param()) {
......@@ -761,6 +766,16 @@ sub init {
$term);
},
"^classification,(?!changed)" => sub {
# Generate the restriction condition
$f = $ff = "classifications.name";
$funcsbykey{",$t"}->();
$term = build_subselect("map_products.classification_id",
"classifications.id",
"classifications",
$term);
},
"^keywords," => sub {
&::GetVersionTable();
my @list;
......
......@@ -458,6 +458,7 @@ DefineColumn("short_desc" , "bugs.short_desc" , "Summary"
DefineColumn("status_whiteboard" , "bugs.status_whiteboard" , "Status Summary" );
DefineColumn("component" , "map_components.name" , "Component" );
DefineColumn("product" , "map_products.name" , "Product" );
DefineColumn("classification" , "map_classifications.name" , "Classification" );
DefineColumn("version" , "bugs.version" , "Version" );
DefineColumn("op_sys" , "bugs.op_sys" , "OS" );
DefineColumn("target_milestone" , "bugs.target_milestone" , "Target Milestone" );
......@@ -554,6 +555,11 @@ if (grep('relevance', @displaycolumns) && !$fulltext) {
my @selectcolumns = ("bug_id", "bug_severity", "priority", "bug_status",
"resolution");
# if using classification, we also need to look in product.classification_id
if (Param("useclassification")) {
push (@selectcolumns,"product");
}
# remaining and actual_time are required for precentage_complete calculation:
if (lsearch(\@displaycolumns, "percentage_complete") >= 0) {
push (@selectcolumns, "remaining_time");
......
......@@ -5,7 +5,7 @@
maintainer CDATA #REQUIRED
exporter CDATA #IMPLIED
>
<!ELEMENT bug (bug_id, (alias?, creation_ts, short_desc, delta_ts, reporter_accessible, cclist_accessible, product, component, version, rep_platform, op_sys, bug_status, resolution?, bug_file_loc?, status_whiteboard?, keywords*, priority, bug_severity, target_milestone?, dependson*, blocked*, votes?, reporter, assigned_to, qa_contact?, cc*, (estimated_time, remaining_time, actual_time)?, groups*, long_desc*, attachment*)?)>
<!ELEMENT bug (bug_id, (alias?, creation_ts, short_desc, delta_ts, reporter_accessible, cclist_accessible, classification_id, classification, product, component, version, rep_platform, op_sys, bug_status, resolution?, bug_file_loc?, status_whiteboard?, keywords*, priority, bug_severity, target_milestone?, dependson*, blocked*, votes?, reporter, assigned_to, qa_contact?, cc*, (estimated_time, remaining_time, actual_time)?, groups*, long_desc*, attachment*)?)>
<!ATTLIST bug
error (NotFound | NotPermitted | InvalidBugId) #IMPLIED
>
......@@ -16,6 +16,8 @@
<!ELEMENT exporter (#PCDATA)>
<!ELEMENT urlbase (#PCDATA)>
<!ELEMENT bug_status (#PCDATA)>
<!ELEMENT classification_id (#PCDATA)>
<!ELEMENT classification (#PCDATA)>
<!ELEMENT product (#PCDATA)>
<!ELEMENT priority (#PCDATA)>
<!ELEMENT version (#PCDATA)>
......
......@@ -1786,10 +1786,17 @@ $table{logincookies} =
index(lastused)';
$table{classifications} =
'id smallint not null auto_increment primary key,
name varchar(64) not null,
description mediumtext,
unique(name)';
$table{products} =
'id smallint not null auto_increment primary key,
name varchar(64) not null,
classification_id smallint not null default 1,
description mediumtext,
milestoneurl tinytext not null,
disallownew tinyint not null,
......@@ -2153,6 +2160,7 @@ sub AddFDef ($$$) {
# be created with their associated schema change.
AddFDef("bug_id", "Bug \#", 1);
AddFDef("short_desc", "Summary", 1);
AddFDef("classification", "Classification", 1);
AddFDef("product", "Product", 1);
AddFDef("version", "Version", 1);
AddFDef("rep_platform", "Platform", 1);
......@@ -4021,6 +4029,7 @@ AddField("profiles", "extern_id", "varchar(64)");
AddGroup('tweakparams', 'Can tweak operating parameters');
AddGroup('editusers', 'Can edit or disable users');
AddGroup('creategroups', 'Can create and destroy groups.');
AddGroup('editclassifications', 'Can create, destroy, and edit classifications.');
AddGroup('editcomponents', 'Can create, destroy, and edit components.');
AddGroup('editkeywords', 'Can create, destroy, and edit keywords.');
AddGroup('admin', 'Administrators');
......@@ -4388,6 +4397,16 @@ if (GetFieldDef('bugs', 'short_desc')->[2]) { # if it allows nulls
$dbh->do("UPDATE groups SET last_changed = NOW() WHERE name = 'admin'");
# 2003-10-24 - alt@sonic.net, bug 224208
# Support classification level and make sure there is a default classification
AddField('products', 'classification_id', 'smallint DEFAULT 1');
$sth = $dbh->prepare("SELECT name FROM classifications WHERE id=1");
$sth->execute;
if (! $sth->rows) {
$dbh->do("INSERT INTO classifications (id,name,description) " .
"VALUES(1,'Unclassified','Unassigned to any classifications')");
}
#
# Final checks...
......
......@@ -47,8 +47,13 @@ my $cgi = Bugzilla->cgi;
my @masterlist = ("opendate", "changeddate", "bug_severity", "priority",
"rep_platform", "assigned_to", "assigned_to_realname",
"reporter", "reporter_realname", "bug_status",
"resolution", "product", "component", "version", "op_sys",
"votes");
"resolution");
if (Param("useclassification")) {
push(@masterlist, "classification");
}
push(@masterlist, ("product", "component", "version", "op_sys", "votes"));
if (Param("usebugaliases")) {
unshift(@masterlist, "alias");
......
......@@ -321,6 +321,23 @@ sub find_languages {
},
{
name => 'useclassification',
desc => 'If this is on, Bugzilla will associate each product with a ' .
'specific classification. But you must have "editclassification" ' .
'permissions enabled in order to edit classifications',
type => 'b',
default => 0
},
{
name => 'showallproducts',
desc => 'If this is on and useclassification is set, Bugzilla will add a' .
'"All" link in the "New Bug" page to list all available products',
type => 'b',
default => 0
},
{
name => 'makeproductgroups',
desc => 'If this is on, Bugzilla will associate a bug group with each ' .
'product in the database, and use it for querying bugs.',
......
......@@ -53,6 +53,7 @@ use vars qw(
$userid
%versions
$proddesc
$classdesc
);
# If we're using bug groups to restrict bug entry, we need to know who the
......@@ -67,12 +68,47 @@ if (!defined $product) {
GetVersionTable();
Bugzilla->login();
my %products;
if ( ! Param('useclassification') ) {
# just pick the default one
$::FORM{'classification'}=(keys %::classdesc)[0];
}
if (!defined $::FORM{'classification'}) {
my %classdesc;
my %classifications;
foreach my $c (GetSelectableClassifications()) {
$classdesc{$c} = $::classdesc{$c};
$classifications{$c} = $::classifications{$c};
}
my $classification_size = scalar(keys %classdesc);
if ($classification_size == 0) {
ThrowUserError("no_products");
}
elsif ($classification_size > 1) {
$vars->{'classdesc'} = \%classdesc;
$vars->{'classifications'} = \%classifications;
$vars->{'target'} = "enter_bug.cgi";
$vars->{'format'} = $::FORM{'format'};
print "Content-type: text/html\n\n";
$template->process("global/choose-classification.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
exit;
}
$::FORM{'classification'} = (keys %classdesc)[0];
$::MFORM{'classification'} = [$::FORM{'classification'}];
}
my %products;
foreach my $p (@enterable_products) {
if (CanEnterProduct($p))
{
$products{$p} = $::proddesc{$p};
if (CanEnterProduct($p)) {
if (IsInClassification($::FORM{'classification'},$p) ||
$::FORM{'classification'} eq "__all") {
$products{$p} = $::proddesc{$p};
}
}
}
......@@ -81,7 +117,19 @@ if (!defined $product) {
ThrowUserError("no_products");
}
elsif ($prodsize > 1) {
my %classifications;
if ( ! Param('useclassification') ) {
@{$classifications{"all"}} = keys %products;
}
elsif ($::FORM{'classification'} eq "__all") {
%classifications = %::classifications;
} else {
$classifications{$::FORM{'classification'}} =
$::classifications{$::FORM{'classification'}};
}
$vars->{'proddesc'} = \%products;
$vars->{'classifications'} = \%classifications;
$vars->{'classdesc'} = \%::classdesc;
$vars->{'target'} = "enter_bug.cgi";
$vars->{'format'} = $cgi->param('format');
......@@ -252,6 +300,7 @@ SendSQL("SELECT name, description, login_name, realname
ORDER BY name");
while (MoreSQLData()) {
my ($name, $description, $login, $realname) = FetchSQLData();
push @components, {
name => $name,
description => $description,
......
......@@ -55,6 +55,7 @@ sub globals_pl_sillyness {
$zz = @main::legal_versions;
$zz = @main::milestoneurl;
$zz = %main::proddesc;
$zz = %main::classdesc;
$zz = @main::prodmaxvotes;
$zz = $main::template;
$zz = $main::userid;
......@@ -184,6 +185,19 @@ sub GenerateVersionTable {
$carray{$c} = 1;
}
SendSQL("SELECT products.name, classifications.name " .
"FROM products, classifications " .
"WHERE classifications.id = products.classification_id " .
"ORDER BY classifications.name");
while (@line = FetchSQLData()) {
my ($p,$c) = (@line);
if (!defined $::classifications{$c}) {
$::classifications{$c} = [];
}
my $ref = $::classifications{$c};
push @$ref, $p;
}
my $dotargetmilestone = 1; # This used to check the param, but there's
# enough code that wants to pretend we're using
# target milestones, even if they don't get
......@@ -191,6 +205,13 @@ sub GenerateVersionTable {
# about them anyway.
my $mpart = $dotargetmilestone ? ", milestoneurl" : "";
SendSQL("select name, description from classifications ORDER BY name");
while (@line = FetchSQLData()) {
my ($n, $d) = (@line);
$::classdesc{$n} = $d;
}
SendSQL("select name, description, votesperuser, disallownew$mpart from products ORDER BY name");
while (@line = FetchSQLData()) {
my ($p, $d, $votesperuser, $dis, $u) = (@line);
......@@ -275,8 +296,10 @@ sub GenerateVersionTable {
'*::legal_bug_status', '*::legal_resolution']));
print $fh (Data::Dumper->Dump([\@::settable_resolution, \%::proddesc,
\%::classifications, \%::classdesc,
\@::enterable_products, \%::prodmaxvotes],
['*::settable_resolution', '*::proddesc',
'*::classifications', '*::classdesc',
'*::enterable_products', '*::prodmaxvotes']));
if ($dotargetmilestone) {
......@@ -494,6 +517,24 @@ sub CanEditProductId {
return (!defined($result));
}
sub IsInClassification {
my ($classification,$productname) = @_;
if (! Param('useclassification')) {
return 1;
} else {
my $query = "SELECT classifications.name " .
"FROM products,classifications " .
"WHERE products.classification_id=classifications.id ";
$query .= "AND products.name = " . SqlQuote($productname);
PushGlobalSQLState();
SendSQL($query);
my ($ret) = FetchSQLData();
PopGlobalSQLState();
return ($ret eq $classification);
}
}
#
# This function determines if a user can enter bugs in the named
# product.
......@@ -527,18 +568,21 @@ sub GetEnterableProducts {
return (@products);
}
#
# This function returns an alphabetical list of product names to which
# the user can enter bugs. If the $by_id parameter is true, also retrieves IDs
# and pushes them onto the list as id, name [, id, name...] for easy slurping
# into a hash by the calling code.
sub GetSelectableProducts {
my ($by_id) = @_;
my ($by_id,$by_classification) = @_;
my $extra_sql = $by_id ? "id, " : "";
my $query = "SELECT $extra_sql name " .
"FROM products " .
my $extra_from_sql = $by_classification ? ", classifications" : "";
my $query = "SELECT $extra_sql products.name " .
"FROM products $extra_from_sql " .
"LEFT JOIN group_control_map " .
"ON group_control_map.product_id = products.id ";
if (Param('useentrygroupdefault')) {
......@@ -551,7 +595,13 @@ sub GetSelectableProducts {
$query .= "AND group_id NOT IN(" .
join(',', values(%{Bugzilla->user->groups})) . ") ";
}
$query .= "WHERE group_id IS NULL ORDER BY name";
$query .= "WHERE group_id IS NULL ";
if ($by_classification) {
$query .= "AND classifications.id = products.classification_id ";
$query .= "AND classifications.name = ";
$query .= SqlQuote($by_classification) . " ";
}
$query .= "ORDER BY name";
PushGlobalSQLState();
SendSQL($query);
my @products = ();
......@@ -609,6 +659,18 @@ sub GetSelectableProductHash {
return $selectables;
}
#
# This function returns an alphabetical list of classifications that has products the user can enter bugs.
sub GetSelectableClassifications {
my @selectable_classes = ();
foreach my $c (keys %::classdesc) {
if ( scalar(GetSelectableProducts(0,$c)) > 0) {
push(@selectable_classes,$c);
}
}
return (@selectable_classes);
}
sub GetFieldDefs {
my $extra = "";
......@@ -740,6 +802,25 @@ sub DBNameToIdAndCheck {
{ name => $name }, "abort");
}
sub get_classification_id {
my ($classification) = @_;
PushGlobalSQLState();
SendSQL("SELECT id FROM classifications WHERE name = " . SqlQuote($classification));
my ($classification_id) = FetchSQLData();
PopGlobalSQLState();
return $classification_id;
}
sub get_classification_name {
my ($classification_id) = @_;
die "non-numeric classification_id '$classification_id' passed to get_classification_name"
unless ($classification_id =~ /^\d+$/);
PushGlobalSQLState();
SendSQL("SELECT name FROM classifications WHERE id = $classification_id");
my ($classification) = FetchSQLData();
PopGlobalSQLState();
return $classification;
}
......
......@@ -21,6 +21,72 @@
/* this file contains functions to update form controls based on a
* collection of javascript arrays containing strings */
/* selectClassification reads the selection from f.classification and updates
* f.product accordingly
* - f: a form containing classification, product, component, varsion and
* target_milestone select boxes.
* globals (3vil!):
* - prods, indexed by classification name
* - first_load: boolean, specifying if it is the first time we load
* the query page.
* - last_sel: saves our last selection list so we know what has
* changed, and optimize for additions.
*/
function selectClassification(classfield, product, component, version, milestone) {
/* this is to avoid handling events that occur before the form
* itself is ready, which could happen in buggy browsers.
*/
if (!classfield) {
return;
}
/* if this is the first load and nothing is selected, no need to
* merge and sort all components; perl gives it to us sorted.
*/
if ((first_load) && (classfield.selectedIndex == -1)) {
first_load = false;
return;
}
/* don't reset first_load as done in selectProduct. That's because we
want selectProduct to handle the first_load attribute
*/
/* - sel keeps the array of classifications we are selected.
* - merging says if it is a full list or just a list of classifications
* that were added to the current selection.
*/
var merging = false;
var sel = Array();
/* if nothing selected, pick all */
var findall = classfield.selectedIndex == -1;
sel = get_selection(classfield, findall, false);
if (!findall) {
/* save sel for the next invocation of selectClassification() */
var tmp = sel;
/* this is an optimization: if we have just added classifications to an
* existing selection, no need to clear the form controls and add
* everybody again; just merge the new ones with the existing
* options.
*/
if ((last_sel.length > 0) && (last_sel.length < sel.length)) {
sel = fake_diff_array(sel, last_sel);
merging = true;
}
last_sel = tmp;
}
/* save original options selected */
var saved_prods = get_selection(product, false, true);
/* do the actual fill/update, reselect originally selected options */
updateSelect(prods, sel, product, merging);
restoreSelection(product, saved_prods);
selectProduct(product, component, version, milestone);
}
/* selectProduct reads the selection from the product control and
* updates version, component and milestone controls accordingly.
*
......@@ -68,7 +134,15 @@ function selectProduct(product, component, version, milestone) {
/* if nothing selected, pick all */
var findall = product.selectedIndex == -1;
sel = get_selection(product, findall, false);
if (useclassification) {
/* update index based on the complete product array */
sel = get_selection(product, findall, true);
for (var i=0; i<sel.length; i++) {
sel[i] = prods[sel[i]];
}
} else {
sel = get_selection(product, findall, false);
}
if (!findall) {
/* save sel for the next invocation of selectProduct() */
var tmp = sel;
......
......@@ -43,6 +43,7 @@ my $generic_query = "
SELECT
bugs.bug_id,
COALESCE(bugs.alias, ''),
classifications.name,
products.name,
bugs.version,
bugs.rep_platform,
......@@ -63,9 +64,10 @@ my $generic_query = "
bugs.estimated_time,
bugs.remaining_time,
date_format(creation_ts,'%Y.%m.%d %H:%i')
FROM bugs,profiles assign,profiles report, products, components
FROM bugs,profiles assign,profiles report, classifications, products, components
WHERE assign.userid = bugs.assigned_to AND report.userid = bugs.reporter
AND bugs.product_id=products.id AND bugs.component_id=components.id";
AND bugs.product_id=products.id AND bugs.component_id=components.id
AND products.classification_id = classifications.id";
my $buglist = $cgi->param('buglist') ||
$cgi->param('bug_id') ||
......@@ -81,7 +83,8 @@ foreach my $bug_id (split(/[:,]/, $buglist)) {
my %bug;
my @row = FetchSQLData();
foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
foreach my $field ("bug_id", "alias", "classification", "product",
"version", "rep_platform",
"op_sys", "bug_status", "resolution", "priority",
"bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone",
......
......@@ -127,7 +127,7 @@ sub PrefillForm {
# Nothing must be undef, otherwise the template complains.
foreach my $name ("bug_status", "resolution", "assigned_to",
"rep_platform", "priority", "bug_severity",
"product", "reporter", "op_sys",
"classification", "product", "reporter", "op_sys",
"component", "version", "chfield", "chfieldfrom",
"chfieldto", "chfieldvalue", "target_milestone",
"email", "emailtype", "emailreporter",
......@@ -274,9 +274,24 @@ for (my $i = 0; $i < @products; ++$i) {
# Assign hash back to product array.
$products[$i] = \%product;
}
$vars->{'product'} = \@products;
# Create data structures representing each classification
if (Param('useclassification')) {
my @classifications = ();
foreach my $c (sort(GetSelectableClassifications())) {
# Create hash to hold attributes for each classification.
my %classification = (
'name' => $c,
'products' => [ GetSelectableProducts(0,$c) ]
);
# Assign hash back to classification array.
push @classifications, \%classification;
}
$vars->{'classification'} = \@classifications;
}
# We use 'component_' because 'component' is a Template Toolkit reserved word.
$vars->{'component_'} = \@components;
......@@ -300,7 +315,9 @@ push @chfields, "[Bug creation]";
# This is what happens when you have variables whose definition depends
# on the DB schema, and then the underlying schema changes...
foreach my $val (@::log_columns) {
if ($val eq 'product_id') {
if ($val eq 'classification_id') {
$val = 'classification';
} elsif ($val eq 'product_id') {
$val = 'product';
} elsif ($val eq 'component_id') {
$val = 'component';
......
......@@ -113,6 +113,7 @@ $columns{'bug_status'} = "bugs.bug_status";
$columns{'resolution'} = "bugs.resolution";
$columns{'component'} = "map_components.name";
$columns{'product'} = "map_products.name";
$columns{'classification'} = "map_classifications.name";
$columns{'version'} = "bugs.version";
$columns{'op_sys'} = "bugs.op_sys";
$columns{'votes'} = "bugs.votes";
......@@ -134,8 +135,13 @@ $columns{''} = "42217354";
|| ThrowCodeError("report_axis_invalid", {fld => "z", val => $tbl_field});
my @axis_fields = ($row_field, $col_field, $tbl_field);
my @selectnames = map($columns{$_}, @axis_fields);
# add product if person is requesting classification
if (lsearch(\@axis_fields,"classification") >= 0) {
if (lsearch(\@axis_fields,"product") < 0) {
push(@selectnames,($columns{'product'}));
}
}
# Clone the params, so that Bugzilla::Search can modify them
my $params = new Bugzilla::CGI($cgi);
......
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Add new classification"
%]
<form method=post action="editclassifications.cgi">
<table border=0 cellpadding=4 cellspacing=0>
<tr>
<th align="right">Classification:</th>
<td><input size=64 maxlength=64 name="classification"></td>
</tr>
<tr>
<th align="right">Description:</th>
<td><textarea rows=4 cols=64 wrap=virtual name="description"></textarea></td>
</tr>
</table>
<hr>
<input type=submit value="Add">
<input type=hidden name="action" value="new">
</FORM>
<p>Back to the <a href="./">main [% terms.bugs %] page</a>
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Delete classification"
%]
<table border=1 cellpadding=4 cellspacing=0>
<tr bgcolor="#6666ff">
<th valign="top" align="left">Part</th>
<th valign="top" align="left">Value</th>
</tr><tr>
<td valign="top">Classification:</td>
<td valign="top">[% classification FILTER html %]</td>
</tr><tr>
<td valign="top">Description:</td>
<td valign="top">
[% IF description %]
[% description FILTER html %]
[% ELSE %]
<font color="red">description missing</font>
[% END %]
</td>
</tr>
</table>
<h2>Confirmation</h2>
<p>Do you really want to delete this classification?<p>
<form method=post action="editclassifications.cgi">
<input type=submit value="Yes, delete">
<input type=hidden name="action" value="delete">
<input type=hidden name="classification" value="[% classification FILTER html %]">
</form>
<p>Back to the <a href="./">main [% terms.bugs %] page</a>
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Classification deleted"
%]
Classification [% classification FILTER html %] deleted.<br>
<p>Back to the <a href="./">main [% terms.bugs %] page</a>
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Edit classification"
%]
<form method=post action="editclassifications.cgi">
<table border=0 cellpadding=4 cellspacing=0>
<tr>
<th align="right">Classification:</th>
<td><input size=64 maxlength=64 name="classification" value="[% classification FILTER html %]"></TD>
</tr>
<tr>
<th align="right">Description:</th>
<td><textarea rows=4 cols=64 name="description">[% description FILTER html %]</textarea></TD>
</tr>
<tr valign=top>
<th align="right"><a href="editproducts.cgi?classification=[% classification FILTER html %]">Edit products</a></th>
<td>
[% IF products AND products.size > 0 %]
<table>
[% FOREACH product = products %]
<tr>
<th align=right valign=top>[% product.name FILTER html %]</th>
<td valign=top>
[% IF product.description %]
[% product.description FILTER html %]
[% ELSE %]
<font color="red">description missing</font>
[% END %]
</td>
</tr>
[% END %]
</table>
[% ELSE %]
<font color="red">none</font>
[% END %]
</td>
</tr>
</table>
<input type=hidden name="classificationold" value="[% classification FILTER html %]">
<input type=hidden name="descriptionold" value="[% description FILTER html %]">
<input type=hidden name="action" value="update">
<input type=submit value="Update">
</form>
<p>Back to the <a href="./">main [% terms.bugs %] page</a>
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Adding new classification"
%]
OK, done.
<p>Back to the <a href="./">main [% terms.bugs %] page</a>,
<a href="editproducts.cgi?action=add&amp;classification=[% classification FILTER html %]">add</a> products to this new classification,
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Reclassify products"
%]
[% main_classification = classification %]
<form method=post action="editclassifications.cgi">
<table border=0 cellpadding=4 cellspacing=0>
<tr>
<td valign="top">Classification:</td>
<td valign="top" colspan=3>[% main_classification FILTER html %]</td>
</tr><tr>
<td valign="top">Description:</td>
<td valign="top" colspan=3>
[% IF description %]
[% description FILTER html %]
[% ELSE %]
<font color="red">description missing</font>
[% END %]
</td>
</tr><tr>
<td valign="top">Products:</td>
<td valign="top">Products</td>
<td></td>
<td valign="top">[% main_classification FILTER html %] Products</td>
</tr><tr>
<td></td>
<td valign="top">
<select name="prodlist" id="prodlist" multiple="multiple" size="20">
[% FOREACH cl = class_products %]
<option value="[% cl.value FILTER html %]">
[% cl.name FILTER html %]
</option>
[% END %]
</select></td>
<td align="center">
<input type=submit value=" Add &gt;&gt; " name="add_products"><br><br>
<input type=submit value="&lt;&lt; Remove" name="remove_products">
</td>
<td valign="middle" rowspan=2>
<select name="myprodlist" id="myprodlist" multiple="multiple" size="20">
[% FOREACH product = selected_products %]
<option value="[% product FILTER html %]">
[% product FILTER html %]
</option>
[% END %]
</select></td>
</tr>
</table>
<input type=hidden name="action" value="reclassify">
<input type=hidden name="classification" value="[% main_classification FILTER html %]">
</form>
<p>Back to the <a href="./">main [% terms.bugs %] page</a>,
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Select classification"
%]
[% filt_classification = classification FILTER html %]
<table border=1 cellpadding=4 cellspacing=0>
<tr bgcolor="#6666ff">
<th align="left">Edit Classification ...</th>
<th align="left">Description</th>
<th align="left">Products</th>
<th align="left">Action</th>
</tr>
[% FOREACH cl = classifications %]
<tr>
<td valign="top"><a href="editclassifications.cgi?action=edit&amp;classification=[% cl.classification FILTER html %]"><b>[% cl.classification FILTER html %]</b></a></td>
<td valign="top">
[% IF cl.description %]
[% cl.description FILTER html %]
[% ELSE %]
<font color="red">none</font>
[% END %]
</td>
[% IF (cl.id == 1) %]
<td valign="top">[% cl.total FILTER html %]</td>
[% ELSE %]
<td valign="top"><a href="editclassifications.cgi?action=reclassify&amp;classification=[% cl.classification FILTER html %]">reclassify ([% cl.total FILTER html %])</a></td>
[% END %]
[%# don't allow user to delete the default id. %]
[% IF (cl.id == 1) %]
<td valign="top">&nbsp;</td>
[% ELSE %]
<td valign="top"><a href="editclassifications.cgi?action=del&amp;classification=[% cl.classification FILTER html %]">delete</a></td>
[% END %]
</tr>
[% END %]
<tr>
<td valign="top" colspan=3>Add a new classification</td>
<td valign="top" align="center"><a href="editclassifications.cgi?action=add">Add</a></td>
</tr>
</table>
<p>Back to the <a href="./">main [% terms.bugs %] page</a>
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
[%# 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): Albert Ting <alt@sonic.net>
#%]
[% PROCESS global/header.html.tmpl
title = "Update classification"
%]
[% IF updated_description %]
Updated description.<br>
[% END %]
[% IF updated_classification %]
Updated classification name.<br>
[% END %]
<p>Back to the <a href="./">main [% terms.bugs %] page</a>
or <a href="editclassifications.cgi"> edit</a> more classifications.
[% PROCESS global/footer.html.tmpl %]
......@@ -22,6 +22,7 @@
[% PROCESS global/variables.none.tmpl %]
[% filt_product = product FILTER html %]
[% filt_classification = classification FILTER html %]
[% PROCESS global/header.html.tmpl
title = "Edit Group Controls for '$filt_product'"
%]
......@@ -29,6 +30,7 @@
<form method="post" action="editproducts.cgi">
<input type="hidden" name="action" value="updategroupcontrols">
<input type="hidden" name="product" value="[% filt_product %]">
<input type="hidden" name="classification" value="[% filt_classification %]">
<table id="form" cellspacing="0" cellpadding="4" border="1">
<tr bgcolor="#6666ff">
......
......@@ -119,6 +119,11 @@
<table cellspacing="1" cellpadding="1" border="0">
<tr>
<td align="right">
[% IF Param('useclassification') %]
[% IF bug.classification_id != "1" %]
<b>[[% bug.classification FILTER html %]]</b>
[% END %]
[% END %]
<b>[% terms.Bug %]#:</b>
</td>
<td>
......
......@@ -62,8 +62,14 @@
([% bug.alias FILTER html %])
[% END %]
</td>
[% PROCESS cell attr = { description => "Product",
name => "product" } %]
<td>
<b> Product: </b>&nbsp;
[% IF Param("useclassification") %]
[[% bug.classification FILTER html %]]&nbsp;
[% END %]
[% bug.product FILTER html %]
</td>
[% PROCESS cell attr = { description => "Version",
name => "version" } %]
[% PROCESS cell attr = { description => "Platform",
......
......@@ -500,6 +500,7 @@
],
'admin/products/groupcontrol/edit.html.tmpl' => [
'filt_classification',
'filt_product',
'group.bugcount',
'group.id',
......
<!-- 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 Albert Ting
#
# Contributor(s): Albert Ting <alt@sonic.net>
#%]
[%# INTERFACE:
# classdesc: hash. May be empty. The hash keys are the classifications, and the values
# are their descriptions.
#%]
[% IF target == "enter_bug.cgi" %]
[% title = "Select Classification" %]
[% h2 = "Please select the classification." %]
[% END %]
[% DEFAULT title = "Choose the classification" %]
[% PROCESS global/header.html.tmpl %]
<table>
[% IF Param('showallproducts') %]
<tr>
<th align="right" valign="center" height=50>
<a href="[% target FILTER url_quote %]?classification=__all
[% IF format %]&amp;format=[% format FILTER url_quote %][% END %]">
All</a>:
</th>
<td valign="center">&nbsp;Show all products</td>
</tr>
[% END %]
[% FOREACH p = classdesc.keys.sort %]
[% IF classifications.$p.size > 0 %]
<tr>
<th align="right" valign="top">
<a href="[% target FILTER url_quote %]?classification=[% p FILTER url_quote %]
[% IF format %]&amp;format=[% format FILTER url_quote %][% END %]">
[% p FILTER html %]</a>:
</th>
[% IF classdesc.$p %]
<td valign="top">&nbsp;[% classdesc.$p FILTER html %]</td>
[% END %]
</tr>
[% END %]
[% END %]
</table>
[% PROCESS global/footer.html.tmpl %]
......@@ -32,6 +32,7 @@
"bug_status" => "Status",
"changeddate" => "Last Changed Date",
"cc" => "CC",
"classification" => "Classification",
"cclist_accessible" => "CC list accessible?",
"component_id" => "Component ID",
"component" => "Component",
......
......@@ -77,8 +77,17 @@
IF user.groups.tweakparams %]
[% ' | <a href="editusers.cgi">Users</a>' IF user.groups.editusers
|| user.can_bless %]
[% ' | <a href="editproducts.cgi">Products</a>'
[% IF Param('useclassification') %]
[% IF user.groups.editclassifications %]
[% ' | <a href="editclassifications.cgi">Classifications</a>' %]
[% END %]
[% IF user.groups.editcomponents %]
[% ' | <a href="editproducts.cgi">Products</a>' %]
[% END %]
[% ELSE %]
[% ' | <a href="editproducts.cgi">Products</a>'
IF user.groups.editcomponents %]
[% END %]
[% ' | <a href="editflagtypes.cgi">Flags</a>'
IF user.groups.editcomponents %]
[% ' | <a href="editgroups.cgi">Groups</a>'
......
......@@ -142,6 +142,40 @@
[% title = "Comment Too Long" %]
Comments cannot be longer than 65,535 characters.
[% ELSIF error == "auth_classification_not_enabled" %]
[% title = "Classification Not Enabled" %]
Sorry, classification is not enabled.
[% ELSIF error == "auth_cant_edit_classifications" %]
[% title = "Access Denied" %]
Sorry, you aren't a member of the 'editclassifications' group, and so
you aren't allowed to add, modify or delete classifications.
[% ELSIF error == "classification_not_specified" %]
[% title = "You Must Supply A Classification Name" %]
You must enter a classification name.
[% ELSIF error == "classification_already_exists" %]
[% title = "Classification Already Exists" %]
A classification with the name '[% name FILTER html %]' already exists.
[% ELSIF error == "classification_doesnt_exist" %]
[% title = "Classification Does Not Exist" %]
The classification '[% name FILTER html %]' does not exist.
[% ELSIF error == "classification_not_deletable" %]
[% title = "Default Classification Can Not Be Deleted" %]
You can not delete the default classification
[% ELSIF error == "classification_has_products" %]
Sorry, there are products for this classification. You
must reassign those products to another classification before you
can delete this one.
[% ELSIF error == "cant_delete_default_classification" %]
Sorry, but you can not delete the default classification,
'[% name FILTER html %]'.
[% ELSIF error == "auth_cant_edit_components" %]
[% title = "Access Denied" %]
Sorry, you aren't a member of the 'editcomponents' group, and so
......@@ -463,6 +497,10 @@
[% title = "Invalid group name" %]
The group you specified, [% name FILTER html %], is not valid here.
[% ELSIF error == "invalid_group_name" %]
[% title = "Invalid group name" %]
The group you specified, [% name FILTER html %], is not valid here.
[% ELSIF error == "invalid_maxrows" %]
[% title = "Invalid Max Rows" %]
The maximum number of rows, '[% maxrows FILTER html %]', must be
......
......@@ -21,6 +21,81 @@
# Gervase Markham <gerv@gerv.net>
#%]
<script type="text/javascript" language="JavaScript">
var first_load = true; [%# is this the first time we load the page? %]
var last_sel = new Array(); [%# caches last selection %]
[% IF Param('useclassification') %]
var useclassification = true;
var prods = new Array();
[% ELSE %]
var useclassification = false;
[% END %]
var cpts = new Array();
var vers = new Array();
[% IF Param('usetargetmilestone') %]
var tms = new Array();
[% END %]
[%# Create an array of products, indexed by the classification #%]
[% nclass = 0 %]
[% FOREACH c = classification %]
prods[[% nclass FILTER js %]] = [
[%- FOREACH item = c.products %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
[% nclass = nclass+1 %]
[% END %]
[%# Create three arrays of components, versions and target milestones, indexed
# numerically according to the product they refer to. #%]
[% n = 0 %]
[% FOREACH p = product %]
[% IF Param('useclassification') %]
prods['[% p.name FILTER js %]'] = [% n %]
[% END %]
cpts[[% n %]] = [
[%- FOREACH item = p.components %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
vers[[% n %]] = [
[%- FOREACH item = p.versions -%]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
[% IF Param('usetargetmilestone') %]
tms[[% n %]] = [
[%- FOREACH item = p.milestones %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
[% END %]
[% n = n+1 %]
[% END %]
/*
* doOnSelectProduct determines which selection should get updated
*
* - selectmode = 0 - init
* selectmode = 1 - classification selected
* selectmode = 2 - product selected
*
* globals:
* queryform - string holding the name of the selection form
*/
function doOnSelectProduct(selectmode) {
var f = document.forms[queryform];
milestone = (typeof(f.target_milestone) == "undefined" ?
null : f.target_milestone);
if (selectmode == 0) {
if (useclassification) {
selectClassification(f.classification, f.product, f.component, f.version, milestone);
} else {
selectProduct(f.product, f.component, f.version, milestone);
}
} else if (selectmode == 1) {
selectClassification(f.classification, f.product, f.component, f.version, milestone);
} else {
selectProduct(f.product, f.component, f.version, milestone);
}
}
</script>
[% PROCESS global/variables.none.tmpl %]
[% query_variants = [
......@@ -56,7 +131,7 @@
<input name="short_desc" size="40" accesskey="s"
value="[% default.short_desc.0 FILTER html %]">
<script language="JavaScript" type="text/javascript"> <!--
document.forms['queryform'].short_desc.focus();
document.forms[queryform].short_desc.focus();
// -->
</script>
</td>
......@@ -67,12 +142,35 @@
</td>
</tr>
[%# *** Product Component Version Target *** %]
[%# *** Classification Product Component Version Target *** %]
<tr>
<td colspan="4">
<table>
<tr>
[% IF Param('useclassification') %]
<td valign="top">
<table>
<tr valign="bottom">
<th align="left"><u>C</u>lassification:</th>
</tr>
<tr valign="top">
<td align="left">
<label for="classification">
<select name="classification" multiple="multiple" size="5" id="classification"
onchange="doOnSelectProduct(1);">
[% FOREACH cat = classification %]
<option value="[% cat.name FILTER html %]"
[% " selected" IF lsearch(default.classification, cat.name) != -1 %]>
[% cat.name FILTER html %]
</option>
[% END %]
</select>
</label>
</td>
</tr>
</table>
</td>
[% END %]
<td valign="top">
<table>
<tr valign="bottom">
......@@ -83,7 +181,7 @@
<td align="left">
<label for="product" accesskey="p">
<select name="product" multiple="multiple" size="5" id="product"
onchange="doOnSelectProduct();">
onchange="doOnSelectProduct(2);">
[% FOREACH p = product %]
<option value="[% p.name FILTER html %]"
[% " selected" IF lsearch(default.product, p.name) != -1 %]>
......
......@@ -32,44 +32,13 @@
[% js_data = BLOCK %]
function doOnSelectProduct() {
var f = document.forms['queryform'];
milestone = (typeof(f.target_milestone) == "undefined" ?
null : f.target_milestone);
selectProduct(f.product, f.component, f.version, milestone);
}
var first_load = true; [%# is this the first time we load the page? %]
var last_sel = new Array(); [%# caches last selection %]
var cpts = new Array();
var vers = new Array();
[% IF Param('usetargetmilestone') %]
var tms = new Array();
[% END %]
[%# Create three arrays of components, versions and target milestones, indexed
# numerically according to the product they refer to. #%]
[% n = 0 %]
[% FOREACH p = product %]
cpts[[% n %]] = [
[%- FOREACH item = p.components %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
vers[[% n %]] = [
[%- FOREACH item = p.versions -%]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
[% IF Param('usetargetmilestone') %]
tms[[% n %]] = [
[%- FOREACH item = p.milestones %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
[% END %]
[% n = n+1 %]
[% END %]
var queryform = "queryform"
[% END %]
[% PROCESS global/header.html.tmpl
title = "Search for $terms.bugs"
h1 = ""
onload = "doOnSelectProduct(); initHelp();"
onload = "doOnSelectProduct(0); initHelp();"
javascript = js_data
javascript_urls = [ "js/productform.js" ]
style = "td.selected_tab {
......
......@@ -25,8 +25,13 @@
{ id => "short_desc",
html => "The $terms.bug summary is a short sentence which succinctly
describes <br> what the $terms.bug is about." },
{ id => "classification",
html => "$terms.Bugs are categorised into Classifications, Products and Components. classifications is the<br>
top-level categorisation." },
{ id => "product",
html => "$terms.Bugs are categorised into Products and Components. Product is
html => Param('useclassification') ?
"$terms.Bugs are categorised into Products and Components. Select a Classification to narrow down this list" :
"$terms.Bugs are categorised into Products and Components. Product is
the<br>top-level categorisation." },
{ id => "component",
html => "Components are second-level categories; each belongs to a<br>
......
......@@ -26,9 +26,15 @@
[% PROCESS global/variables.none.tmpl %]
[% js_data = BLOCK %]
var queryform = "reportform"
[% END %]
[% PROCESS global/header.html.tmpl
title = "Generate Graphical Report"
onload = "selectProduct(document.forms['reportform']);chartTypeChanged()"
onload = "doOnSelectProduct(0); chartTypeChanged()"
javascript = js_data
javascript_urls = [ "js/productform.js" ]
%]
[% PROCESS "search/search-report-select.html.tmpl" %]
......
......@@ -27,7 +27,7 @@
[% PROCESS "global/field-descs.none.tmpl" %]
[% BLOCK select %]
[% rep_fields = ["product", "component", "version", "rep_platform",
[% rep_fields = ["classification", "product", "component", "version", "rep_platform",
"op_sys", "bug_status", "resolution", "bug_severity",
"priority", "target_milestone", "assigned_to",
"reporter", "qa_contact", "votes" ] %]
......
......@@ -26,9 +26,15 @@
[% PROCESS global/variables.none.tmpl %]
[% js_data = BLOCK %]
var queryform = "reportform"
[% END %]
[% PROCESS global/header.html.tmpl
title = "Generate Tabular Report"
onload = "selectProduct(document.forms['reportform']);"
onload = "doOnSelectProduct(0)"
javascript = js_data
javascript_urls = [ "js/productform.js" ]
%]
[% PROCESS "search/search-report-select.html.tmpl" %]
......
......@@ -75,10 +75,24 @@ for "crash secure SSL flash".
<td>
<select name="product" id="product">
<option value="">All</option>
[% FOREACH p = product %]
<option value="[% p.name FILTER html %]"
[% " selected" IF lsearch(default.product, p.name) != -1 %]>
[% p.name FILTER html %]</option>
[% IF Param('useclassification') %]
[% FOREACH c = classification %]
<optgroup label="[% c.name FILTER html %]">
[% FOREACH p = c.products %]
<option value="[% p FILTER html %]"
[% " selected" IF lsearch(default.product, p) != -1 %]>
[% p FILTER html %]
</option>
[% END %]
</optgroup>
[% END %]
[% ELSE %]
[% FOREACH p = product %]
<option value="[% p.name FILTER html %]"
[% " selected" IF lsearch(default.product, p.name) != -1 %]>
[% p.name FILTER html %]
</option>
[% END %]
[% END %]
</select>
</td>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment