Add search based on bug fields as well as numerous other search additions.

Edit searches.


git-svn-id: svn://10.0.0.236/trunk@253059 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ghendricks%novell.com
2008-07-16 16:51:10 +00:00
parent 1cb0645440
commit e545779432
14 changed files with 1200 additions and 114 deletions

View File

@@ -61,6 +61,9 @@ use Bugzilla::Error;
use Bugzilla::Testopia::Util;
use Bugzilla::Testopia::TestCase;
use Date::Format;
use Date::Parse;
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
@@ -538,6 +541,12 @@ sub init {
"ON test_plans.type_id = test_plan_types.type_id");
$f = 'test_plan_types.name';
},
"^plan_perms," => sub {
push(@supptables,
"INNER JOIN test_plan_permissions ".
"ON test_plans.plan_id = test_plan_permissions.plan_id");
$f = 'test_plan_permissions.permissions';
},
"^case_run_status," => sub {
push(@supptables,
"INNER JOIN test_case_run_status AS tcrs ".
@@ -550,41 +559,41 @@ sub init {
ON test_environments.product_id = env_products.id");
$f = 'env_products.id'
},
"^env_categories," => sub {
push(@supptables,
"^env_.*," => sub {
if ($obj eq 'run'){
push(@supptables,
"INNER JOIN test_environment_map
ON test_environments.environment_id = test_environment_map.environment_id");
ON test_runs.environment_id = test_environment_map.environment_id");
}
elsif ($obj eq 'case_run'){
push(@supptables,
"INNER JOIN test_environment_map
ON test_case_runs.environment_id = test_environment_map.environment_id");
}
},
"^env_category," => sub {
push(@supptables,
"INNER JOIN test_environment_element
ON test_environment_map.element_id = test_environment_element.element_id");
push(@supptables,
"INNER JOIN test_environment_category
ON test_environment_element.env_category_id = test_environment_category.env_category_id");
$f = 'test_environment_category.env_category_id'
$f = 'test_environment_category.name'
},
"^env_elements," => sub {
push(@supptables,
"INNER JOIN test_environment_map as env_map_elements
ON test_environments.environment_id = env_map_elements.environment_id");
"^env_element," => sub {
push(@supptables,
"INNER JOIN test_environment_element as env_element
ON env_map_elements.element_id = env_element.element_id");
$f = 'env_element.element_id'
ON test_environment_map.element_id = env_element.element_id");
$f = 'env_element.name'
},
"^env_properties," => sub {
push(@supptables,
"INNER JOIN test_environment_map as env_map_properties
ON test_environments.environment_id = env_map_properties.environment_id");
"^env_property," => sub {
push(@supptables,
"INNER JOIN test_environment_property as env_property
ON env_map_properties.property_id = env_property.property_id");
$f = 'env_property.property_id'
ON test_environment_map.property_id = env_property.property_id");
$f = 'env_property.name'
},
"^env_expressions," => sub {
push(@supptables,
"INNER JOIN test_environment_map as env_map_value
ON test_environments.environment_id = env_map_value.environment_id");
$f = 'env_map_value.value_selected'
"^env_value," => sub {
$f = 'test_environment_map.value_selected'
},
"^env_value_selected," => sub {
push(@supptables,
@@ -631,7 +640,7 @@ sub init {
"ON milestones.value = builds.milestone");
$f = "milestones.value";
},
"^bug," => sub {
"^(?:assigned_to|reporter|qa_contact|bug.*)," => sub {
if ($obj eq 'case_run'){
push(@supptables,
"INNER JOIN test_case_bugs AS case_bugs " .
@@ -648,8 +657,91 @@ sub init {
"INNER JOIN bugs ".
"ON case_bugs.bug_id = bugs.bug_id");
}
push(@supptables,
"INNER JOIN bugs " .
"ON case_bugs.bug_id = bugs.bug_id");
},
"^bug," => sub {
$f = "bugs.bug_id";
},
"^bug_status," => sub {
$f = "bugs.bug_status";
},
"^bug_resolution," => sub {
$f = "bugs.resolution";
},
"^bug_priority," => sub {
$f = "bugs.priority";
},"^bug_op_sys," => sub {
$f = "bugs.op_sys";
},
"^bug_severity," => sub {
$f = "bugs.bug_severity";
},
"^bug_rep_platform," => sub {
$f = "bugs.rep_platform";
},
"^bug_short_desc," => sub {
$f = "bugs.short_desc";
},
"^bug_file_loc," => sub {
$f = "bugs.bug_file_loc";
},
"^bug_status_whiteboard," => sub {
$f = "bugs.status_whiteboard";
},
"^bug_long_desc," => sub {
my $table = "longdescs";
my $extra = "";
if (Bugzilla->params->{"insidergroup"}
&& !Bugzilla->user->in_group(Bugzilla->params->{"insidergroup"}))
{
$extra = "AND $table.isprivate < 1";
}
push(@supptables, "INNER JOIN longdescs AS $table " .
"ON $table.bug_id = bugs.bug_id $extra");
$f = "$table.thetext";
},
"^bug_keywords," => sub {
my @list;
my $table = "keywords";
foreach my $value (split(/[\s,]+/, $v)) {
if ($value eq '') {
next;
}
my $keyword = new Bugzilla::Keyword({name => $value});
if ($keyword) {
push(@list, "$table.keywordid = " . $keyword->id);
}
else {
ThrowUserError("unknown_keyword",
{ keyword => $v });
}
}
my $haveawordterm;
if (@list) {
$haveawordterm = "(" . join(' OR ', @list) . ")";
if ($t eq "anywords") {
$term = $haveawordterm;
} elsif ($t eq "allwords") {
my $ref = $funcsbykey{",$t"};
&$ref;
if ($term && $haveawordterm) {
$term = "(($term) AND $haveawordterm)";
}
}
}
if ($term) {
push(@supptables, "LEFT JOIN keywords AS $table " .
"ON $table.bug_id = bugs.bug_id");
}
$f = "bugs.keywords";
},
"^(?:assigned_to|reporter|qa_contact)," => sub {
push(@supptables, "INNER JOIN profiles AS map_$f " .
"ON bugs.$f = map_$f.userid");
$f = "map_$f.login_name";
},
"^case_summary," => sub {
push(@supptables,
"INNER JOIN test_cases AS cases " .
@@ -755,6 +847,52 @@ sub init {
}
},
"^classification," => sub {
if ($obj eq 'run'){
push(@supptables,
"INNER JOIN test_plans " .
"ON test_runs.plan_id = test_plans.plan_id");
push(@supptables,
"INNER JOIN products " .
"ON test_plans.product_id = products.id");
}
elsif ($obj eq 'case'){
push(@supptables,
"INNER JOIN test_case_plans AS case_plans " .
"ON test_cases.case_id = case_plans.case_id");
push(@supptables,
"INNER JOIN test_plans " .
"ON case_plans.plan_id = test_plans.plan_id");
push(@supptables,
"INNER JOIN products " .
"ON test_plans.product_id = products.id");
}
elsif ($obj eq 'case_run'){
push(@supptables,
"INNER JOIN test_runs " .
"ON test_case_runs.run_id = test_runs.run_id");
push(@supptables,
"INNER JOIN test_plans " .
"ON test_runs.plan_id = test_plans.plan_id");
push(@supptables,
"INNER JOIN products " .
"ON test_plans.product_id = products.id");
}
elsif ($obj eq 'environment'){
push(@supptables,
"INNER JOIN products
ON test_environments.product_id = products.id");
}
else{
push(@supptables,
"INNER JOIN products ".
"ON test_". $obj ."s.product_id = products.id");
}
push(@supptables,
"INNER JOIN classifications " .
"ON products.classification_id = classifications.id");
$f = "classifications.name";
},
"^caserun_prod," => sub {
push(@supptables,
"INNER JOIN test_runs " .
@@ -899,6 +1037,97 @@ sub init {
$term = "test_". $obj ."s.". $obj ."_id NOT IN (SELECT junc.". $obj ."_id FROM test_". $obj ."_tags AS junc JOIN test_tags AS junc_tags ON junc.tag_id = junc_tags.tag_id WHERE junc_tags.tag_name = " . $q .")";
},
);
my $chfieldfrom = trim(lc($cgi->param('chfieldfrom'))) || '';
my $chfieldto = trim(lc($cgi->param('chfieldto'))) || '';
$chfieldfrom = '' if ($chfieldfrom eq 'now');
$chfieldto = '' if ($chfieldto eq 'now');
my @chfield = $cgi->param('chfield_type');
my $chvalue = trim($cgi->param('chfieldvalue')) || '';
if ($chfieldfrom ne '' || $chfieldto ne '') {
my $sql_chfrom = $chfieldfrom ? $dbh->quote(SqlifyDate($chfieldfrom)):'';
my $sql_chto = $chfieldto ? $dbh->quote(SqlifyDate($chfieldto)) :'';
my $sql_chvalue = $chvalue ne '' ? $dbh->quote($chvalue) : '';
trick_taint($sql_chvalue);
if(!@chfield) {
push(@supptables,
"INNER JOIN test_" . $obj ."_activity " .
"ON test_". $obj ."s.". $obj ."_id = test_" . $obj ."_activity." . $obj ."_id");
push(@wherepart, "test_" . $obj ."_activity.changed >= $sql_chfrom") if ($sql_chfrom);
push(@wherepart, "test_" . $obj ."_activity.changed <= $sql_chto") if ($sql_chto);
} else {
my $bug_creation_clause;
my @list;
my @actlist;
foreach my $f (@chfield) {
if ($f eq "[Creation]") {
my @l;
if ($obj eq 'run'){
push(@l, "test_" . $obj ."s.start_date >= $sql_chfrom") if($sql_chfrom);
push(@l, "test_" . $obj ."s.start_date <= $sql_chto") if($sql_chto);
}
else{
push(@l, "test_" . $obj ."s.creation_date >= $sql_chfrom") if($sql_chfrom);
push(@l, "test_" . $obj ."s.creation_date <= $sql_chto") if($sql_chto);
}
$bug_creation_clause = "(" . join(' AND ', @l) . ")";
}
elsif ($f eq "text"){
push(@supptables,
"INNER JOIN test_" . $obj ."_texts " .
"ON test_". $obj ."s.". $obj ."_id = test_" . $obj ."_texts." . $obj ."_id");
push(@wherepart, "test_" . $obj ."_texts.creation_ts >= $sql_chfrom") if ($sql_chfrom);
push(@wherepart, "test_" . $obj ."_texts.creation_ts <= $sql_chto") if ($sql_chto);
}
else {
push(@actlist, $f);
}
}
# @actlist won't have any elements if the only field being searched
# is [Bug creation] (in which case we don't need bugs_activity).
if(@actlist) {
my $extra = " actcheck." . $obj . "_id = test_" . $obj ."s." . $obj . "_id";
push(@list, "(actcheck.changed IS NOT NULL)");
if($sql_chfrom) {
$extra .= " AND actcheck.changed >= $sql_chfrom";
}
if($sql_chto) {
$extra .= " AND actcheck.changed <= $sql_chto";
}
if($sql_chvalue) {
$extra .= " AND actcheck.newvalue = $sql_chvalue";
}
push(@supptables, "LEFT JOIN test_" . $obj ."_activity AS actcheck " .
"ON $extra AND actcheck.fieldid IN (" .
join(",", @actlist) . ")");
}
# Now that we're done using @list to determine if there are any
# regular fields to search (and thus we need bugs_activity),
# add the [Bug creation] criterion to the list so we can OR it
# together with the others.
push(@list, $bug_creation_clause) if $bug_creation_clause;
push(@wherepart, "(" . join(" OR ", @list) . ")") if scalar @list;
}
}
if ($cgi->param('permuser')) {
my $permuser = login_to_id($cgi->param('permuser'), "BARF");
my $perm = $cgi->param('permission');
detaint_natural($permuser);
push(@wherepart, "test_plan_permissions.userid = $permuser");
push(@specialchart, ["plan_perms", 'equals', $perm]);
}
if ($cgi->param('bug_keywords')) {
my $t = $cgi->param('bug_keywords_type');
if (!$t || $t eq "or") {
$t = "anywords";
}
push(@specialchart, ["bug_keywords", $t, $cgi->param('keywords')]);
}
if ($cgi->param('case_id')) {
my $type = "anyexact";
@@ -1010,7 +1239,32 @@ sub init {
push(@specialchart, ["product_id", $type, join(',', $cgi->param($attribute))]);
}
}
}
}
my $email = trim($cgi->param("bug_email"));
my $type = $cgi->param("bug_emailtype");
if ($type eq "exact") {
$type = "anyexact";
foreach my $name (split(',', $email)) {
$name = trim($name);
if ($name) {
login_to_id($name, "BARF");
}
}
}
my @clist;
foreach my $field ("assigned_to", "reporter", "cc", "qa_contact", "infoprovider") {
if ($cgi->param("bug_email$field")) {
push(@clist, $field, $type, $email);
}
}
if ($cgi->param("bug_emaillongdesc")) {
push(@clist, "commenter", $type, $email);
}
if (@clist) {
push(@specialchart, \@clist);
}
# Check the Multi select fields and add them to the chart
my @legal_fields = ("case_status_id", "category", "category_id", "priority_id",
"component", "isautomated", "case_run_status_id",
@@ -1018,7 +1272,9 @@ sub init {
"build", "build_id", "environment_id", "milestone", "env_products",
"env_categories", "env_elements", "env_properties",
"env_expressions", "case_status", "priority", "environment",
"plan_type", "case_run_status");
"plan_type", "case_run_status", "classification",
"bug_severity", "bug_resolution","bug_priority", "bug_status",
"bug_rep_platform","bug_os_sys");
foreach my $field ($cgi->param()) {
if (lsearch(\@legal_fields, $field) != -1) {
@@ -1107,7 +1363,9 @@ sub init {
# check static text fields
foreach my $f ("case_summary", "summary", "tcaction", "tceffect", "script",
"requirement", "name", "plan_text", "environment_name",
"notes", "env_value_selected") {
"notes", "env_value_selected","bug_short_desc","bug_long_desc",
"bug_file_loc","bug_status_whiteboard","bug_keywords",
"env_category","env_element","env_property","env_value") {
if (defined $cgi->param($f)) {
my $s = trim($cgi->param($f));
if ($s ne "") {
@@ -1297,7 +1555,7 @@ sub init {
$str =~ /^(.*?)\s+ON\s+(.*)$/i;
my ($leftside, $rightside) = ($1, $2);
if ($suppseen{$leftside}) {
$supplist[$suppseen{$leftside}] .= " AND ($rightside)";
$supplist[$suppseen{$leftside}] .= " AND ($rightside)" unless ($rightside eq 'case_bugs.bug_id = bugs.bug_id' || 'test_runs.environment_id = test_environment_map.environment_id');
} else {
$suppseen{$leftside} = scalar @supplist;
push @supplist, " $leftside ON ($rightside)";
@@ -1315,7 +1573,7 @@ sub init {
# Make sure we create a legal SQL query.
@andlist = ("1 = 1") if !@andlist;
print "WHEREPART: " . Data::Dumper::Dumper(\@wherepart) if $debug;
my $query;
if ($self->{'fields'}){
$query = "SELECT $distinct". join(",", @{$self->{'fields'}});
@@ -1378,6 +1636,54 @@ sub query {
return $self->{'sql'};
}
sub SqlifyDate {
my ($str) = @_;
$str = "" if !defined $str;
if ($str eq "") {
my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime(time());
return sprintf("%4d-%02d-%02d 00:00:00", $year+1900, $month+1, $mday);
}
if ($str =~ /^(-|\+)?(\d+)([hHdDwWmMyY])$/) { # relative date
my ($sign, $amount, $unit, $date) = ($1, $2, lc $3, time);
my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime($date);
if ($sign && $sign eq '+') { $amount = -$amount; }
if ($unit eq 'w') { # convert weeks to days
$amount = 7*$amount + $wday;
$unit = 'd';
}
if ($unit eq 'd') {
$date -= $sec + 60*$min + 3600*$hour + 24*3600*$amount;
return time2str("%Y-%m-%d %H:%M:%S", $date);
}
elsif ($unit eq 'y') {
return sprintf("%4d-01-01 00:00:00", $year+1900-$amount);
}
elsif ($unit eq 'm') {
$month -= $amount;
while ($month<0) { $year--; $month += 12; }
return sprintf("%4d-%02d-01 00:00:00", $year+1900, $month+1);
}
elsif ($unit eq 'h') {
# Special case 0h for 'beginning of this hour'
if ($amount == 0) {
$date -= $sec + 60*$min;
} else {
$date -= 3600*$amount;
}
return time2str("%Y-%m-%d %H:%M:%S", $date);
}
return undef; # should not happen due to regexp at top
}
my $date = str2time($str);
if (!defined($date)) {
ThrowUserError("illegal_date", { date => $str });
}
return time2str("%Y-%m-%d %H:%M:%S", $date);
}
sub GetByWordList {
my ($field, $strs) = (@_);
my @list;

View File

@@ -1139,6 +1139,8 @@ sub get_fields {
FROM test_fielddefs
WHERE table_name=?",
{"Slice"=>{}}, "test_cases");
unshift @$types, {id => 'text', name => 'Text (Action, Setup, etc.)'};
unshift @$types, {id => '[Creation]', name => '[Created]'};
return $types;
}

View File

@@ -553,6 +553,8 @@ sub get_fields {
FROM test_fielddefs
WHERE table_name=?",
{"Slice"=>{}}, "test_plans");
unshift @$types, {id => 'text', name => 'Document'};
unshift @$types, {id => '[Creation]', name => '[Created]'};
return $types;
}

View File

@@ -765,6 +765,27 @@ sub get_status_list {
return \@status;
}
=head2 get_fields
Returns a reference to a list of test run field descriptions from
the test_fielddefs table.
=cut
sub get_fields {
my $self = shift;
my $dbh = Bugzilla->dbh;
my $types = $dbh->selectall_arrayref(
"SELECT fieldid AS id, description AS name
FROM test_fielddefs
WHERE table_name=?",
{"Slice"=>{}}, "test_runs");
unshift @$types, {id => '[Creation]', name => '[Started]'};
return $types;
}
=head2 get_distinct_builds
Returns a list of build names for use in searches

View File

@@ -31,7 +31,11 @@
[%- sel.events IF sel.events %]
[%- sel.style IF sel.style %]>
[% FOREACH item = sel.list %]
<option value="[% sel.byname ? item.name : item.id FILTER html %]" [% 'selected="selected"' IF (sel.default == item.name && item.name != '') || (sel.default == item.id || sel.default == 'all') %][% 'selected="selected"' IF (sel.deflist == 1 AND lsearch(sel.default, item.id)> -1) %]>
<option value="[% sel.byname ? item.name : item.id FILTER html %]"
[%- 'selected="selected"' IF (sel.default == item.name && item.name != '') %]
[%- 'selected="selected"' IF sel.default == item.id && item.id != ''%]
[%- 'selected="selected"' IF sel.default == 'all' %]
[%- 'selected="selected"' IF (sel.deflist == 1 AND lsearch(sel.default, item.id)> -1) %]>
[% item.name FILTER html %]</option>
[% END %]
</select>

View File

@@ -133,7 +133,7 @@ Ext.onReady(function(){
},{
text: 'Test Results Search',
handler: function(){
SearchPopup('case_run');
SearchPopup('caserun');
}
}]
});

View File

@@ -64,16 +64,35 @@
</table>
<table>
<tr class="bz_row_header">
[% IF Param('useclassification') %]
<th>Classification</th>
[% END %]
<th>Product</th>
<th>Components</th>
<th>Category</th>
</tr>
<tr>
[% IF Param('useclassification') %]
<td style="padding-right: 30px;">
[% PROCESS select sel = { name => 'product_id',
[% PROCESS select sel = { name => 'classification',
accesskey => 'p',
list => user.get_selectable_classifications,
elements => 5,
byname => 1,
mult => 1
events => 'onChange="document.getElementById(\'component\').disabled=true;
document.getElementById(\'category\').disabled=true;
document.getElementById(\'product\').disabled=true;
t.onProductSelection(this)"' } %]
</td>
[% END %]
<td style="padding-right: 30px;">
[% PROCESS select sel = { name => 'product',
accesskey => 'p',
list => user.get_selectable_products,
elements => 5,
byname => 1,
mult => 1
events => 'onChange="document.getElementById(\'component\').disabled=true;
document.getElementById(\'category\').disabled=true;
@@ -168,7 +187,6 @@
</table>
</fieldset>
<!--
<fieldset>
<legend><strong>Case Changes</strong></legend>
@@ -194,7 +212,259 @@
</dl>
</fieldset>
-->
<fieldset>
<legend><strong>Linked Bug Attributes</strong></legend>
<table>
<tr>
<td>
<table>
<tr>
<th align="left">
<label for="bug_status" accesskey="a">St<u>a</u>tus</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_status',
list => bug_status,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="resolution" accesskey="r"><u>R</u>esolution</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_resolution',
list => resolution,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="bug_severity">Severity</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_severity',
list => bug_severity,
elements => 5,
mult => 1}%]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="priority" accesskey="i">Pr<u>i</u>ority</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_priority',
list => bug_priority,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="rep_platform" accesskey="h"><u>H</u>ardware</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_rep_platform',
list => rep_platform,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="op_sys" accesskey="o"><u>O</u>S</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_op_sys',
list => op_sys,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
</tr>
</table>
<table>
<tr>
<th align="right">
<label for="short_desc" accesskey="s"><u>S</u>ummary</label>:
</th>
<td>
[% PROCESS select sel = { name => 'bug_short_desc_type',
list => query_variants } %]
</td>
<td>
<input name="bug_short_desc" id="bug_short_desc" size="40"
value="[% default.bug_short_desc.0 FILTER html %]">
</td>
</tr>
[% FOREACH field = [
{ name => "bug_long_desc", description => "A&nbsp;<u>C</u>omment",
accesskey => 'c' },
{ name => "bug_file_loc", description => "The&nbsp;<u>U</u>RL",
accesskey => 'u' },
{ name => "bug_status_whiteboard", description => "<u>W</u>hiteboard",
accesskey => 'w' } ] %]
[% UNLESS field.name == 'status_whiteboard' AND NOT Param('usestatuswhiteboard') %]
<tr>
<th align="right">
<label for="[% field.name %]" accesskey="[% field.accesskey %]">[% field.description %]</label>:
</th>
<td>
<select name="[% field.name %]_type">
[% FOREACH qv = query_variants %]
[% type = "${field.name}_type" %]
<option value="[% qv.id %]"
[% " selected" IF default.$type.0 == qv.id %]>[% qv.name %]</option>
[% END %]
</select>
</td>
<td><input name="[% field.name %]" id="[% field.name %]" size="40"
value="[% default.${field.name}.0 FILTER html %]">
</td>
<td></td>
</tr>
[% END %]
[% END %]
<tr>
<th align="right">
<label for="keywords" accesskey="k"><a href="describekeywords.cgi"><u>K</u>eywords</a></label>:
</th>
<td>
<select name="keywords_type">
[% FOREACH qv = [
{ name => "allwords", description => "contains all of the keywords" },
{ name => "anywords", description => "contains any of the keywords" },
{ name => "nowords", description => "contains none of the keywords" } ] %]
<option value="[% qv.name %]"
[% " selected" IF default.keywords_type.0 == qv.name %]>
[% qv.description %]</option>
[% END %]
</select>
</td>
<td>
<input name="bug_keywords" id="bug_keywords" size="40"
value="[% default.bug_keywords.0 FILTER html %]">
</td>
</tr>
[%# Deadline %]
[% IF user.in_group(Param("timetrackinggroup")) %]
<tr>
<th align="right">
<label for="deadlinefrom" accesskey="l">Dead<u>l</u>ine</label>:
</th>
<td>
from&nbsp;
<input name="deadlinefrom" id="deadlinefrom" size="10" maxlength="10">&nbsp;
to&nbsp;
<input name="deadlineto" size="10" maxlength="10">
</td>
<td>
<small>(YYYY-MM-DD)</small>
</td>
</tr>
[% END %]
</table>
<table>
<tr>
<td>
<table cellspacing="0" cellpadding="0">
<tr>
<td>
Any one of:
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="bug_emailassigned_to[% n %]"
id="emailassigned_to[% n %]" value="1"
[% " checked" IF default.bug_emailassigned_to.$n %]>
<label for="emailassigned_to[% n %]">
the [% terms.bug %] assignee
</label>
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="bug_emailreporter[% n %]"
id="emailreporter[% n %]" value="1"
[% " checked" IF default.bug_emailreporter.$n %]>
<label for="emailreporter[% n %]">
the reporter
</label>
</td>
</tr>
[% IF Param('useqacontact') %]
<tr>
<td>
<input type="checkbox" name="bug_emailqa_contact[% n %]"
id="emailqa_contact[% n %]" value="1"
[% " checked" IF default.bug_emailqa_contact.$n %]>
<label for="emailqa_contact[% n %]">
the QA contact
</label>
</td>
</tr>
[% END %]
<tr>
<td>
<select name="bug_emailtype[% n %]">
[% FOREACH qv = [
{ name => "substring", description => "contains" },
{ name => "exact", description => "is" },
{ name => "regexp", description => "matches regexp" },
{ name => "notregexp", description => "doesn't match regexp" } ] %]
<option value="[% qv.name %]"
[% " selected" IF default.bug_emailtype.$n == qv.name %]>[% qv.description %]</option>
[% END %]
</select>
</td>
</tr>
<tr>
<td>
<input name="bug_email[% n %]" size="25" value="[% default.email.$n FILTER html %]">
</td>
</tr>
<tr><td>Where attached bugs are numbered: <input name="bug_id"></td></tr>
</table>
</td>
</tr>
</table>
</fieldset>
<fieldset>
<legend><strong>Associations (comma separated lists)</strong></legend>
<table>

View File

@@ -20,7 +20,7 @@
[% IF report %]
<form id="case_run_search_form" action="tr_caserun_reports.cgi" method="GET">
<form id="caserun_search_form" action="tr_caserun_reports.cgi" method="GET">
[% PROCESS "testopia/search/report-matrix.html.tmpl"
obj = caserun
%]
@@ -36,6 +36,9 @@
<th>Run Status</th>
<th>Priority</th>
<th>Automatic</th>
[% IF Param('useclassification') %]
<th>Classification</th>
[% END %]
<th>Product</th>
</tr>
<tr>
@@ -69,11 +72,31 @@
elements => 5,
mult => 1 } %]
</td>
[% IF Param('useclassification') %]
<td style="padding-right: 30px;">
[% PROCESS select sel = { name => 'classification',
accesskey => 'p',
list => user.get_selectable_classifications,
elements => 5,
byname => 1,
mult => 1
events => 'onChange="document.getElementById(\'component\').disabled=true;
document.getElementById(\'version\').disabled=true;
document.getElementById(\'milestone\').disabled=true;
document.getElementById(\'category\').disabled=true;
document.getElementById(\'build\').disabled=true;
document.getElementById(\'environment\').disabled=true;
document.getElementById(\'product\').disabled=true;
t.onProductSelection(this)"' } %]
</td>
[% END %]
<td colspan="3" align="center" >
[% PROCESS select sel = { name => 'product_id',
[% PROCESS select sel = { name => 'product',
accesskey => 'p',
list => user.get_selectable_products,
elements => 5,
byname => 1,
mult => 1
events => 'onChange="document.getElementById(\'component\').disabled=true;
document.getElementById(\'version\').disabled=true;
@@ -213,6 +236,288 @@
</td>
</tr>
</table>
<table>
<tr>
<th align="right">Environment Categories:</th>
<td>
[% PROCESS select sel = { name => 'env_category_type',
list => query_variants } %]</td>
<td><input name="env_category"></td>
</tr>
<tr>
<th align="right">Environment Elements:</th>
<td>
[% PROCESS select sel = { name => 'env_element_type',
list => query_variants } %]</td>
<td><input name="env_element"></td>
</tr>
<tr>
<th align="right">Environment Properties:</th>
<td>
[% PROCESS select sel = { name => 'env_property_type',
list => query_variants } %]</td>
<td><input name="env_property"></td>
</tr>
<tr>
<th align="right">Environment Value:</th>
<td>
[% PROCESS select sel = { name => 'env_value_type',
list => query_variants } %]</td>
<td><input name="env_value"></td>
</tr>
</table>
</fieldset>
<legend><strong>Linked Bug Attributes</strong></legend>
<table>
<tr>
<td>
<table>
<tr>
<th align="left">
<label for="bug_status" accesskey="a">St<u>a</u>tus</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_status',
list => bug_status,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="resolution" accesskey="r"><u>R</u>esolution</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_resolution',
list => resolution,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="bug_severity">Severity</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_severity',
list => bug_severity,
elements => 5,
mult => 1}%]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="priority" accesskey="i">Pr<u>i</u>ority</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_priority',
list => bug_priority,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="rep_platform" accesskey="h"><u>H</u>ardware</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_rep_platform',
list => rep_platform,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
<td>
<table>
<tr>
<th align="left">
<label for="op_sys" accesskey="o"><u>O</u>S</label>:
</th>
</tr>
<tr valign="top">
[% PROCESS select sel = { name => 'bug_op_sys',
list => op_sys,
elements => 5,
mult => 1 } %]
</tr>
</table>
</td>
</tr>
</table>
<table>
<tr>
<th align="right">
<label for="short_desc" accesskey="s"><u>S</u>ummary</label>:
</th>
<td>
[% PROCESS select sel = { name => 'bug_short_desc_type',
list => query_variants } %]
</td>
<td>
<input name="bug_short_desc" id="bug_short_desc" size="40"
value="[% default.bug_short_desc.0 FILTER html %]">
</td>
</tr>
[% FOREACH field = [
{ name => "bug_long_desc", description => "A&nbsp;<u>C</u>omment",
accesskey => 'c' },
{ name => "bug_file_loc", description => "The&nbsp;<u>U</u>RL",
accesskey => 'u' },
{ name => "bug_status_whiteboard", description => "<u>W</u>hiteboard",
accesskey => 'w' } ] %]
[% UNLESS field.name == 'status_whiteboard' AND NOT Param('usestatuswhiteboard') %]
<tr>
<th align="right">
<label for="[% field.name %]" accesskey="[% field.accesskey %]">[% field.description %]</label>:
</th>
<td>
<select name="[% field.name %]_type">
[% FOREACH qv = query_variants %]
[% type = "${field.name}_type" %]
<option value="[% qv.id %]"
[% " selected" IF default.$type.0 == qv.id %]>[% qv.name %]</option>
[% END %]
</select>
</td>
<td><input name="[% field.name %]" id="[% field.name %]" size="40"
value="[% default.${field.name}.0 FILTER html %]">
</td>
<td></td>
</tr>
[% END %]
[% END %]
<tr>
<th align="right">
<label for="keywords" accesskey="k"><a href="describekeywords.cgi"><u>K</u>eywords</a></label>:
</th>
<td>
<select name="keywords_type">
[% FOREACH qv = [
{ name => "allwords", description => "contains all of the keywords" },
{ name => "anywords", description => "contains any of the keywords" },
{ name => "nowords", description => "contains none of the keywords" } ] %]
<option value="[% qv.name %]"
[% " selected" IF default.keywords_type.0 == qv.name %]>
[% qv.description %]</option>
[% END %]
</select>
</td>
<td>
<input name="bug_keywords" id="bug_keywords" size="40"
value="[% default.bug_keywords.0 FILTER html %]">
</td>
</tr>
[%# Deadline %]
[% IF user.in_group(Param("timetrackinggroup")) %]
<tr>
<th align="right">
<label for="deadlinefrom" accesskey="l">Dead<u>l</u>ine</label>:
</th>
<td>
from&nbsp;
<input name="deadlinefrom" id="deadlinefrom" size="10" maxlength="10">&nbsp;
to&nbsp;
<input name="deadlineto" size="10" maxlength="10">
</td>
<td>
<small>(YYYY-MM-DD)</small>
</td>
</tr>
[% END %]
</table>
<table>
<tr>
<td>
<table cellspacing="0" cellpadding="0">
<tr>
<td>
Any one of:
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="bug_emailassigned_to[% n %]"
id="emailassigned_to[% n %]" value="1"
[% " checked" IF default.bug_emailassigned_to.$n %]>
<label for="emailassigned_to[% n %]">
the [% terms.bug %] assignee
</label>
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="bug_emailreporter[% n %]"
id="emailreporter[% n %]" value="1"
[% " checked" IF default.bug_emailreporter.$n %]>
<label for="emailreporter[% n %]">
the reporter
</label>
</td>
</tr>
[% IF Param('useqacontact') %]
<tr>
<td>
<input type="checkbox" name="bug_emailqa_contact[% n %]"
id="emailqa_contact[% n %]" value="1"
[% " checked" IF default.bug_emailqa_contact.$n %]>
<label for="emailqa_contact[% n %]">
the QA contact
</label>
</td>
</tr>
[% END %]
<tr>
<td>
<select name="bug_emailtype[% n %]">
[% FOREACH qv = [
{ name => "substring", description => "contains" },
{ name => "exact", description => "is" },
{ name => "regexp", description => "matches regexp" },
{ name => "notregexp", description => "doesn't match regexp" } ] %]
<option value="[% qv.name %]"
[% " selected" IF default.bug_emailtype.$n == qv.name %]>[% qv.description %]</option>
[% END %]
</select>
</td>
</tr>
<tr>
<td>
<input name="bug_email[% n %]" size="25" value="[% default.email.$n FILTER html %]">
</td>
</tr>
<tr><td>Where attached bugs are numbered: <input name="bug_id"></td></tr>
</table>
</td>
</tr>
</table>
</fieldset>
<p style="font-weight: bold;">

View File

@@ -31,16 +31,34 @@
<legend><strong>Product</strong></legend>
<table>
<tr class="bz_row_header">
[% IF Param('useclassification') %]
<th>Classification</th>
[% END %]
<th>Product</th>
<th>Product Version</th>
<th>Type</th>
</tr>
<tr>
[% IF Param('useclassification') %]
<td style="padding-right: 30px;">
[% PROCESS select sel = { name => 'product_id',
[% PROCESS select sel = { name => 'classification',
accesskey => 'p',
list => user.get_selectable_classifications,
elements => 5,
byname => 1,
mult => 1,
events => 'onChange="document.getElementById(\'version\').disabled=true;
document.getElementById(\'product\').disabled=true;
t.onProductSelection(this)"' } %]
</td>
[% END %]
<td style="padding-right: 30px;">
[% PROCESS select sel = { name => 'product',
accesskey => 'p',
list => user.get_selectable_products,
elements => 5,
byname => 1,
mult => 1
events => 'onChange="document.getElementById(\'version\').disabled=true;
t.onProductSelection(this)"' } %]
@@ -96,12 +114,24 @@
</tr>
</table>
</fieldset>
<!--
<fieldset>
<legend><strong>Permissions</strong></legend>
<table>
<tr><td>Where User <input name="permuser"> has at least
<select name="permission">
<option value="15">Admin</option>
<option value="7">Delete</option>
<option value="3">Write</option>
<option value="1">Read</option>
</select> permissions
</table>
</fieldset>
<fieldset>
<legend><strong>Plan Changes</strong></legend>
<dl class="bug_changes">
<dl>
<dt>Only plans changed between:</dt>
<dd>
<input name="chfieldfrom" size="10" value="[% default.chfieldfrom.0 FILTER html %]">
@@ -123,7 +153,7 @@
</dl>
</fieldset>
-->
<p style="font-weight: bold;">
<label for="plan_id">
Include plans numbered:

View File

@@ -33,6 +33,9 @@
<table>
<tr class="bz_row_header">
<th>Status</th>
[% IF Param('useclassification') %]
<th>Classification</th>
[% END %]
<th>Product</th>
<th>Version</th>
</tr>
@@ -44,11 +47,29 @@
elements => 5,
mult => 1 } %]
</td>
[% IF Param('useclassification') %]
<td style="padding-right: 30px;">
[% PROCESS select sel = { name => 'product_id',
[% PROCESS select sel = { name => 'classification',
accesskey => 'p',
list => user.get_selectable_classifications,
elements => 5,
byname => 1,
mult => 1
events => 'onChange="document.getElementById(\'product\').disabled=true;
document.getElementById(\'version\').disabled=true;
document.getElementById(\'milestone\').disabled=true;
document.getElementById(\'build\').disabled=true;
document.getElementById(\'environment\').disabled=true;
t.onProductSelection(this)"' } %]
</td>
[% END %]
<td style="padding-right: 30px;">
[% PROCESS select sel = { name => 'product',
accesskey => 'p',
list => user.get_selectable_products,
elements => 5,
byname => 1,
mult => 1
events => 'onChange="document.getElementById(\'version\').disabled=true;
document.getElementById(\'milestone\').disabled=true;
@@ -129,8 +150,37 @@
<td><input name="manager"></td>
</tr>
</table>
<table>
<tr>
<th align="right">Environment Categories:</th>
<td>
[% PROCESS select sel = { name => 'env_category_type',
list => query_variants } %]</td>
<td><input name="env_category"></td>
</tr>
<tr>
<th align="right">Environment Elements:</th>
<td>
[% PROCESS select sel = { name => 'env_element_type',
list => query_variants } %]</td>
<td><input name="env_element"></td>
</tr>
<tr>
<th align="right">Environment Properties:</th>
<td>
[% PROCESS select sel = { name => 'env_property_type',
list => query_variants } %]</td>
<td><input name="env_property"></td>
</tr>
<tr>
<th align="right">Environment Value:</th>
<td>
[% PROCESS select sel = { name => 'env_value_type',
list => query_variants } %]</td>
<td><input name="env_value"></td>
</tr>
</table>
</fieldset>
<!--
<fieldset>
<legend><strong>Run Changes</strong></legend>
@@ -157,7 +207,6 @@
</dl>
</fieldset>
-->
<p style="font-weight: bold;">
<label for="run_id">
Include runs numbered:

View File

@@ -1,5 +1,8 @@
"Product","Plans","Summary","Author","Default Tester","Status","Priority","Category","Components","Requirements","Estimated Time","Automated","Scripts","Arguments","Alias","Tags","Bugs","Depends On","Blocks","Runs","Setup","Breakdown","Action","Expected Results"
"Product*","Plans+","Summary*","Author*","Default Tester","Status*","Priority*","Category*","Components","Requirements","Estimated Time","Automated","Scripts","Arguments","Alias","Tags","Bugs","Depends On","Blocks","Runs","Setup","Breakdown","Action","Expected Results"
"Example Product","22, 33","Test the button for causing world destruction","admin@testopia.com","tester@testopia.com","CONFIRMED","P3","Destruction","buttons, widgets","REQ#00001",00:02:00,"NO",,,,"Explosions, Fried Fish","55,66",2,"8 ,9, 10","770, 857","Fill out last will and Testement","No Breakdown","1.Locate the big red button
2. Press the big red button
3. Wait for large explosion","1. Boom
2. Are you sure?"
"* Required field"
"+ Required if going to tr_importer.cgi directly (not from within the plan file menu)"
1 Product Product* Plans Plans+ Summary Summary* Author Author* Default Tester Status Status* Priority Priority* Category Category* Components Requirements Estimated Time Automated Scripts Arguments Alias Tags Bugs Depends On Blocks Runs Setup Breakdown Action Expected Results
2 Example Product Example Product 22, 33 22, 33 Test the button for causing world destruction Test the button for causing world destruction admin@testopia.com admin@testopia.com tester@testopia.com CONFIRMED CONFIRMED P3 P3 Destruction Destruction buttons, widgets REQ#00001 00:02:00 NO Explosions, Fried Fish 55,66 2 8 ,9, 10 770, 857 Fill out last will and Testement No Breakdown 1.Locate the big red button 2. Press the big red button 3. Wait for large explosion 1. Boom 2. Are you sure?
3 * Required field
4 + Required if going to tr_importer.cgi directly (not from within the plan file menu)
5
6
7
8

View File

@@ -20,6 +20,38 @@
* Daniel Parker <dparker1@novell.com>
*/
Testopia.Search = {};
Testopia.Search.fillInForm = function(type, params, name){
var f = document.getElementById(type + '_search_form');
for (var i=0; i < f.length; i++){
if (f[i].type == 'select-multiple'){
for (k=0; k < f[i].options.length; k++){
f[i].options[k].selected = false;
}
var list = params[f[i].name];
if(!list){
continue;
}
if (typeof list != 'object'){
list = new Array(list);
}
for (j=0; j < list.length; j++){
for (k=0; k < f[i].options.length; k++){
if(f[i].options[k].value == list[j]){
f[i].options[k].selected = true;
break;
}
}
}
}
else{
f[i].value = params[f[i].name] || '';
}
}
};
SearchPopup = function(tab, params){
var win = new Ext.Window({
id: 'search_win',
@@ -132,8 +164,8 @@ Ext.extend(PlanSearch, Ext.Panel,{
if (Ext.get('run_search_form')){
Ext.get('run_search_form').remove();
}
if (Ext.get('case_run_search_form')){
Ext.get('case_run_search_form').remove();
if (Ext.get('caserun_search_form')){
Ext.get('caserun_search_form').remove();
}
this.params.current_tab = 'plan';
@@ -141,7 +173,8 @@ Ext.extend(PlanSearch, Ext.Panel,{
url: 'tr_query.cgi',
params: this.params,
scripts: true,
text: 'Loading search form...'
text: 'Loading search form...',
callback: Testopia.Search.fillInForm.createDelegate(this,['plan',this.params])
});
}
});
@@ -221,8 +254,8 @@ Ext.extend(CaseSearch, Ext.Panel,{
if (Ext.get('plan_search_form')){
Ext.get('plan_search_form').remove();
}
if (Ext.get('case_run_search_form')){
Ext.get('case_run_search_form').remove();
if (Ext.get('caserun_search_form')){
Ext.get('caserun_search_form').remove();
}
this.params.current_tab = 'case';
@@ -230,7 +263,8 @@ Ext.extend(CaseSearch, Ext.Panel,{
url: 'tr_query.cgi',
params: this.params,
scripts: true,
text: 'Loading search form...'
text: 'Loading search form...',
callback: Testopia.Search.fillInForm.createDelegate(this,['case',this.params])
});
}
});
@@ -246,6 +280,8 @@ RunSearch = function(params){
handler: function(){
var form = new Ext.form.BasicForm('run_search_form');
var values = form.getValues();
if (params.qname)
values.qname = params.qname;
var searchnum = Math.round(Math.random()*100);
try {
// EXT BUG - Closing always causes an error:
@@ -310,8 +346,8 @@ Ext.extend(RunSearch, Ext.Panel,{
if (Ext.get('plan_search_form')){
Ext.get('plan_search_form').remove();
}
if (Ext.get('case_run_search_form')){
Ext.get('case_run_search_form').remove();
if (Ext.get('caserun_search_form')){
Ext.get('caserun_search_form').remove();
}
this.params.current_tab = 'run';
@@ -319,7 +355,8 @@ Ext.extend(RunSearch, Ext.Panel,{
url: 'tr_query.cgi',
params: this.params,
scripts: true,
text: 'Loading search form...'
text: 'Loading search form...',
callback: Testopia.Search.fillInForm.createDelegate(this,['run',this.params])
});
}
});
@@ -328,12 +365,12 @@ CaseRunSearch = function(params){
this.params = params;
CaseRunSearch.superclass.constructor.call(this,{
title: 'Case-Run Search',
id: 'case_run_search_panel',
id: 'caserun_search_panel',
layout:'fit',
buttons:[{
text: 'Submit',
handler: function(){
var form = new Ext.form.BasicForm('case_run_search_form');
var form = new Ext.form.BasicForm('caserun_search_form');
var values = form.getValues();
var searchnum = Math.round(Math.random()*100);
try {
@@ -407,7 +444,8 @@ Ext.extend(CaseRunSearch, Ext.Panel,{
url: 'tr_query.cgi',
params: this.params,
scripts: true,
text: 'Loading search form...'
text: 'Loading search form...',
callback: Testopia.Search.fillInForm.createDelegate(this,['caserun',this.params])
});
}
});
@@ -472,42 +510,54 @@ ReportGrid = function(cfg){
Ext.extend(ReportGrid, Ext.grid.GridPanel, {
onContextClick: function(grid, index, e){
if(!this.menu){ // create context menu on first right click
this.menu = new Ext.menu.Menu({
id:'run-ctx-menu',
items: [{
text: 'Open in a new tab',
handler: function(){
var r = grid.store.getAt(index);
if (r.get('type') == 0){
grid.loadPanel(r);
}
else{
var newTab = new Ext.Panel({
title: r.get('name'),
closable: true,
id: 'search' + r.get('name'),
autoScroll: true
});
Ext.getCmp('object_panel').add(newTab);
Ext.getCmp('object_panel').activate('search' + r.get('name'));
newTab.load({
url: r.get('query')
});
}
this.menu = new Ext.menu.Menu({
id:'run-ctx-menu',
items: [{
text: 'Open in a new tab',
handler: function(){
var r = grid.store.getAt(index);
if (r.get('type') == 0){
grid.loadPanel(r);
}
},{
text: 'Delete Saved Search',
handler: this.deleteSearch.createDelegate(this)
},{
text: 'Refresh List',
handler: function(){
grid.store.reload();
else{
var newTab = new Ext.Panel({
title: r.get('name'),
closable: true,
id: 'search' + r.get('name'),
autoScroll: true
});
Ext.getCmp('object_panel').add(newTab);
Ext.getCmp('object_panel').activate('search' + r.get('name'));
newTab.load({
url: r.get('query')
});
}
}]
});
}
}
},{
text: 'Edit',
icon: 'testopia/img/edit.png',
iconCls: 'img_button_16x',
handler: function(){
var r = grid.store.getAt(index);
var name = r.get('name');
var type = r.get('query').match(/tr_list_(run|case|plan|caserun)s/);
type = type[1]
var params = searchToJson(r.get('query'));
SearchPopup(type, params);
}
},{
text: 'Delete',
icon: 'testopia/img/delete.png',
iconCls: 'img_button_16x',
handler: this.deleteSearch.createDelegate(this)
},{
text: 'Refresh List',
handler: function(){
grid.store.reload();
}
}]
});
e.stopEvent();
this.menu.showAt(e.getXY());
},

View File

@@ -193,9 +193,10 @@ TestopiaUtil = function(){
}
}
var form = new Ext.form.BasicForm('testopia_helper_frm',{});
var type = prod.id == 'classification' ? 'classification' : 'product';
form.submit({
url: "tr_query.cgi",
params: { prod_ids: ids.join(","), action: "getversions" },
params: { value: ids.join(","), action: "getversions", type: type},
success: function(f,a){
fillSelects(a.result.objects);
},

View File

@@ -28,6 +28,7 @@ use Bugzilla;
use Bugzilla::Util;
use Bugzilla::Error;
use Bugzilla::Constants;
use Bugzilla::Field;
use Bugzilla::Testopia::Constants;
use Bugzilla::Testopia::Util;
use Bugzilla::Testopia::Classification;
@@ -48,6 +49,16 @@ local our $template = Bugzilla->template;
Bugzilla->login(LOGIN_REQUIRED);
Bugzilla->error_mode(ERROR_MODE_AJAX);
sub convert_bugzilla_fields {
my $field = shift;
my $values = get_legal_field_values($field);
my @vals;
foreach my $v (@$values){
push @vals, {name => $v, id => $v};
}
return \@vals;
}
sub get_searchable_objects{
my $object = shift;
my $dbh = Bugzilla->dbh;
@@ -114,36 +125,56 @@ my $action = $cgi->param('action') || '';
if ($action eq 'getversions'){
print $cgi->header;
my @prod_ids = split(",", $cgi->param('prod_ids'));
my $tab = $cgi->param('current_tab') || '';
my $plan = Bugzilla::Testopia::TestPlan->new({});
my @prod_ids;
my $products;
my @validated;
foreach my $p (@prod_ids){
detaint_natural($p);
validate_selection($p,'id','products');
my $prod = $plan->lookup_product($p);
push @validated, $p if Bugzilla->user->can_see_product($prod);
my $type = $cgi->param('type');
my @values = split(",",$cgi->param('value'));
my $obj;
my @products;
my $prodinfo;
my $selectTypes = [qw{version milestone component build category environment}];
foreach my $value (@values){
if ($type eq 'classification'){
$obj = Bugzilla::Testopia::Classification->new({name => $value});
next unless ($obj && scalar(grep {$_->name eq $obj->name} @{Bugzilla->user->get_selectable_classifications}));
push @products, @{$obj->user_visible_products()};
my @prod_names;
push @prod_names, $_->name foreach @products;
$prodinfo->{'product'} = \@prod_names;
unshift @$selectTypes, "product";
}
else {
trim($value);
$obj = Bugzilla::Product->new({name => $value});
next unless ($obj && Bugzilla->user->can_see_product($obj->name));
push @products, $obj;
}
}
unless (scalar @products > 0){
push @products, @{Bugzilla->user->get_selectable_products};
unshift @$selectTypes, "product";
my @prod_names;
push @prod_names, $_->name foreach @products;
$prodinfo->{'product'} = \@prod_names;
}
unless (scalar @validated > 0){
print "{}";
exit;
}
my $prod_ids = join(",", @validated);
push @prod_ids, $_->id foreach (@products);
my $prod_ids = join(",", @prod_ids);
my $dbh = Bugzilla->dbh;
$products->{'version'} = $dbh->selectcol_arrayref("SELECT DISTINCT value FROM versions WHERE product_id IN ($prod_ids)");
$products->{'milestone'} = $dbh->selectcol_arrayref("SELECT DISTINCT value FROM milestones WHERE product_id IN ($prod_ids)");
$products->{'component'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM components WHERE product_id IN ($prod_ids)");
$products->{'build'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM test_builds WHERE product_id IN ($prod_ids)");
$products->{'category'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM test_case_categories WHERE product_id IN ($prod_ids)");
$products->{'environment'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM test_environments WHERE product_id IN ($prod_ids)");
$prodinfo->{'version'} = $dbh->selectcol_arrayref("SELECT DISTINCT value FROM versions WHERE product_id IN ($prod_ids)");
$prodinfo->{'milestone'} = $dbh->selectcol_arrayref("SELECT DISTINCT value FROM milestones WHERE product_id IN ($prod_ids)");
$prodinfo->{'component'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM components WHERE product_id IN ($prod_ids)");
$prodinfo->{'build'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM test_builds WHERE product_id IN ($prod_ids)");
$prodinfo->{'category'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM test_case_categories WHERE product_id IN ($prod_ids)");
$prodinfo->{'environment'} = $dbh->selectcol_arrayref("SELECT DISTINCT name FROM test_environments WHERE product_id IN ($prod_ids)");
# This list must match the name of the select fields and the names above
$products->{'selectTypes'} = [qw{version milestone component build category environment}];
$prodinfo->{'selectTypes'} = $selectTypes;
my $json = new JSON;
print "{'success': true, objects: " . $json->encode($products) . "}";
print "{'success': true, objects: " . $json->encode($prodinfo) . "}";
}
elsif ($action eq 'get_products'){
@@ -353,14 +384,26 @@ else{
$vars->{'environments'} = get_searchable_objects('environments');
$vars->{'components'} = get_searchable_objects('components');
$vars->{'categories'} = get_searchable_objects('categories');
$vars->{'bug_status'} = convert_bugzilla_fields('bug_status');
$vars->{'rep_platform'} = convert_bugzilla_fields('rep_platform');
$vars->{'op_sys'} = convert_bugzilla_fields('op_sys');
$vars->{'bug_priority'} = convert_bugzilla_fields('priority');
$vars->{'bug_severity'} = convert_bugzilla_fields('bug_severity');
$vars->{'resolution'} = convert_bugzilla_fields('resolution');
}
elsif ($tab eq 'case') {
$tab = 'case';
my $case = Bugzilla::Testopia::TestCase->new({ 'case_id' => 0 });
$vars->{'title'} = "Search For Test Cases";
$vars->{'case'} = $case;
$vars->{'components'} = get_searchable_objects('components');
$vars->{'categories'} = get_searchable_objects('categories');
$vars->{'components'} = get_searchable_objects('components');
$vars->{'categories'} = get_searchable_objects('categories');
$vars->{'bug_status'} = convert_bugzilla_fields('bug_status');
$vars->{'rep_platform'} = convert_bugzilla_fields('rep_platform');
$vars->{'op_sys'} = convert_bugzilla_fields('op_sys');
$vars->{'bug_priority'} = convert_bugzilla_fields('priority');
$vars->{'bug_severity'} = convert_bugzilla_fields('bug_severity');
$vars->{'resolution'} = convert_bugzilla_fields('resolution');
}
else{
print "Location: tr_show_product.cgi?search=1 \n\n";