Bug 343007 - filter lists in management interfaces. Patch adds AJAX filter options to manage_*.cgi pages and exposes an interface for scripts to request a list of test ids, subgroup ids, testgroup ids, matching a given criteria.

This commit is contained in:
zach%zachlipton.com 2006-07-13 17:17:59 +00:00
parent 271440bb18
commit a169403b92
12 changed files with 345 additions and 27 deletions

View File

@ -68,6 +68,25 @@ __PACKAGE__->set_sql(EnabledBySubgroup => qq{
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(BySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE
tsg.subgroup_id=? AND
tsg.testcase_id=t.testcase_id
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(ByTestgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg, subgroup_testgroups sgtg
WHERE
tsg.testcase_id=t.testcase_id AND
tsg.subgroup_id=sgtg.subgroup_id AND
sgtg.testgroup_id = ?
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(CommunityEnabledBySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
@ -77,6 +96,9 @@ __PACKAGE__->set_sql(CommunityEnabledBySubgroup => qq{
Litmus::DB::Testcase->has_many(test_results => "Litmus::DB::Testresult", {order_by => 'submission_time DESC'});
Litmus::DB::Testcase->has_many(subgroups =>
["Litmus::DB::TestcaseSubgroup" => 'subgroup']);
#########################################################################
# is_completed($$$$$)
#

View File

@ -54,6 +54,8 @@ use base qw(Template);
my $template_include_path;
$Template::Directive::WHILE_MAX = 30000;
# Returns the path to the templates based on the Accept-Language
# settings of the user and of the available languages
# If no Accept-Language is present it uses the defined default
@ -137,6 +139,7 @@ sub create {
CONSTANTS => \%constants,
PRE_PROCESS => "variables.none.tmpl",
POST_CHOMP => 1,
EVAL_PERL => 1,
COMPILE_DIR => $Litmus::Config::datadir,

View File

@ -1,7 +1,7 @@
function selects_onload() {
load_products(getElementByClass("select_product"));
// load_testgroups(getElementByClass("select_testgroup"));
// load_subgroups(getElementByClass("select_subgroup"));
load_testgroups(getElementByClass("select_testgroup"));
load_subgroups(getElementByClass("select_subgroup"));
load_platforms(getElementByClass("select_platform"));
load_opsyses(getElementByClass("select_opsys"));
@ -184,8 +184,19 @@ function changePlatform(testid) {
}
function addNullEntry(select) {
// add a blank entry to the current select:
select.add(new Option("---", "---", false, false), null);
// add a blank entry to the current select
// if possible, try to make the null entry reflect the select's
// contents based on it's name:
if (select.className == 'select_product') {
select.add(new Option("-Product-", "---", false, false), null);
} else if (select.className == 'select_testgroup') {
select.add(new Option("-Testgroup-", "---", false, false), null);
} else if (select.className == 'select_subgroup') {
select.add(new Option("-Subgroup-", "---", false, false), null);
} else {
select.add(new Option("---", "---", false, false), null);
}
}
function clearSelect(select) {

View File

@ -42,15 +42,36 @@ use JSON;
my $c = Litmus->cgi();
# for the moment, you must be an admin to enter tests:
Litmus::Auth::requireAdmin('manage_subgroups.cgi');
my $vars;
my $subgroup_id;
my $message;
my $status;
my $rv;
if ($c->param("searchSubgroupList")) {
print $c->header('text/plain');
my $product_id = $c->param("product");
my $testgroup_id = $c->param("testgroup");
my $subgroups;
if ($testgroup_id) {
$subgroups = Litmus::DB::Subgroup->search_ByTestgroup($testgroup_id);
} elsif ($product_id) {
$subgroups = Litmus::DB::Subgroup->search(product => $product_id);
}
while (my $sg = $subgroups->next) {
print $sg->subgroup_id()."\n";
}
exit;
}
# anyone can use this script for its searching capabilities, but if we
# get here, then you need to be an admin:
Litmus::Auth::requireAdmin('manage_subgroups.cgi');
if ($c->param("subgroup_id")) {
$subgroup_id = $c->param("subgroup_id");
}

View File

@ -41,9 +41,6 @@ use Date::Manip;
my $c = Litmus->cgi();
# for the moment, you must be an admin to enter tests:
Litmus::Auth::requireAdmin('manage_testcases.cgi');
my $vars;
my $testcase_id;
@ -51,6 +48,32 @@ my $edit;
my $message;
my $status;
my $rv;
if ($c->param("searchTestcaseList")) {
print $c->header('text/plain');
my $product_id = $c->param("product");
my $testgroup_id = $c->param("testgroup");
my $subgroup_id = $c->param("subgroup");
my $tests;
if ($subgroup_id) {
$tests = Litmus::DB::Testcase->search_BySubgroup($subgroup_id);
} elsif ($testgroup_id) {
$tests = Litmus::DB::Testcase->search_ByTestgroup($testgroup_id);
} elsif ($product_id) {
$tests = Litmus::DB::Testcase->search(product => $product_id);
}
while (my $t = $tests->next) {
print $t->testcase_id()."\n";
}
exit;
}
# anyone can use this script for its searching capabilities, but if we
# get here, then you need to be an admin:
Litmus::Auth::requireAdmin('manage_testcases.cgi');
if ($c->param("testcase_id")) {
$testcase_id = $c->param("testcase_id");
if ($c->param("edit")) {
@ -172,7 +195,7 @@ if ($rebuild_cache) {
rebuildCache();
}
my $testcases = Litmus::FormWidget->getTestcases;
my $testcases = Litmus::FormWidget->getTestcases();
my $products = Litmus::FormWidget->getProducts();
my $authors = Litmus::FormWidget->getAuthors();
@ -190,5 +213,5 @@ $vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
print $c->header();
Litmus->template()->process("admin/manage_testcases.tmpl", $vars) ||
internalError("Error loading template.");
internalError("Error loading template: ".Litmus->template()->error());

View File

@ -42,15 +42,29 @@ use JSON;
my $c = Litmus->cgi();
# for the moment, you must be an admin to enter tests:
Litmus::Auth::requireAdmin('manage_testgroups.cgi');
my $vars;
my $testgroup_id;
my $message;
my $status;
my $rv;
if ($c->param("searchTestgroupList")) {
print $c->header('text/plain');
my $product_id = $c->param("product");
my $testgroups = Litmus::DB::Testgroup->search(product => $product_id);
while (my $tg = $testgroups->next) {
print $tg->testgroup_id()."\n";
}
exit;
}
# anyone can use this script for its searching capabilities, but if we
# get here, then you need to be an admin:
Litmus::Auth::requireAdmin('manage_testgroups.cgi');
if ($c->param("testgroup_id")) {
$testgroup_id = $c->param("testgroup_id");
}

View File

@ -34,6 +34,62 @@
<script type="text/javascript">
var subgroup;
var testcases=[% IF all_testcases %][% all_testcases %][% ELSE %]{}[% END %];
var filter_req;
var showAll = function(err) {
// if they cancelled, then just don't change anything:
if (err instanceof CancelledError) { return }
toggleMessage('none');
var testbox = document.getElementById("subgroup_id");
for (var i=0; i<testbox.options.length; i++) {
var option = testbox.options[i];
option.style.display = '';
}
};
var doFilterList = function(req) {
var subgroups = req.responseText.split("\n");
var subgroupbox = document.getElementById("subgroup_id");
for (var i=0; i<subgroupbox.options.length; i++) {
var subgroup = subgroupbox.options[i];
var hide = 0;
var id = subgroup.value;
if (subgroups.indexOf(id) == -1) { hide = 1; }
hide == 1 ? subgroup.style.display = 'none' : subgroup.style.display = '';
}
toggleMessage('none');
};
// filter the list by various criteria:
function filterList() {
// they just changed the selection, so cancel any pending filter actions:
if (filter_req instanceof Deferred && filter_req.fired == -1)
filter_req.cancel();
var productfilter = document.getElementById('product_filter');
var testgroupfilter = document.getElementById('testgroup_filter');
if (productfilter.options[productfilter.selectedIndex].value == '---' &&
testgroupfilter.options[testgroupfilter.selectedIndex].value == '---') {
// nothing to do here
showAll();
return;
}
toggleMessage('loading','Filtering subgroup list...');
filter_req = doSimpleXMLHttpRequest('manage_subgroups.cgi', {
searchSubgroupList: 1,
product: (productfilter.options[productfilter.selectedIndex].value == '---' ?
'' : productfilter.options[productfilter.selectedIndex].value),
testgroup: (testgroupfilter.options[testgroupfilter.selectedIndex].value == '---' ?
'' : testgroupfilter.options[testgroupfilter.selectedIndex].value)
});
// if something went wrong, just show all the tests:
filter_req.addErrback(showAll);
filter_req.addCallback(doFilterList);
}
function enableModeButtons() {
document.getElementById("edit_subgroup_button").disabled=false;
@ -218,11 +274,28 @@ function resetSubgroup() {
<h1 class="firstHeading">[% title %]</h1>
<div class="section-full">
<div class="section-header">Existing Subgroups</div>
<div class="section-header">Existing Subgroups</div> <br />
<div class="section-content">
<form id="select_subgroup_and_mode_form" name="select_subgroup_and_mode_form" method="post" action="manage_subgroups.cgi">
<div class="info">
<b>Filter:</b>
<table border="0">
<tr>
<td>Product:</td>
<td>Testgroup:</td>
</tr>
<tr>
<td>
[% INCLUDE productbox onchange="changeProduct('filter'); filterList();" nameextra="_filter" %]
</td>
<td>
[% INCLUDE testgroupbox onchange="changeTestgroup('filter'); filterList();" nameextra="_filter" %]
</td>
</tr>
</table>
</div>
<table border="0" cellspacing="0" cellpadding="5">
<tr>
<td>

View File

@ -33,6 +33,65 @@
<script type="text/javascript">
var testcase;
var filter_req;
var showAllTests = function(err) {
// if they cancelled, then just don't change anything:
if (err instanceof CancelledError) { return }
toggleMessage('none');
var testbox = document.getElementById("testcase_id");
for (var i=0; i<testbox.options.length; i++) {
var option = testbox.options[i];
option.style.display = '';
}
};
var doFilterList = function(req) {
var tests = req.responseText.split("\n");
var testbox = document.getElementById("testcase_id");
for (var i=0; i<testbox.options.length; i++) {
var test = testbox.options[i];
var hideTest = 0;
var id = test.value;
if (tests.indexOf(id) == -1) { hideTest = 1; }
hideTest == 1 ? test.style.display = 'none' : test.style.display = '';
}
toggleMessage('none');
};
// filter the list by various criteria:
function filterList() {
// they just changed the selection, so cancel any pending filter actions:
if (filter_req instanceof Deferred && filter_req.fired == -1)
filter_req.cancel();
var productfilter = document.getElementById('product_filter');
var testgroupfilter = document.getElementById('testgroup_filter');
var subgroupfilter = document.getElementById('subgroup_filter');
if (productfilter.options[productfilter.selectedIndex].value == '---' &&
testgroupfilter.options[testgroupfilter.selectedIndex].value == '---' &&
subgroupfilter.options[subgroupfilter.selectedIndex].value == '---') {
// nothing to do here
showAllTests();
return;
}
toggleMessage('loading','Filtering testcase list...');
filter_req = doSimpleXMLHttpRequest('manage_testcases.cgi', {
searchTestcaseList: 1,
product: (productfilter.options[productfilter.selectedIndex].value == '---' ?
'' : productfilter.options[productfilter.selectedIndex].value),
testgroup: (testgroupfilter.options[testgroupfilter.selectedIndex].value == '---' ?
'' : testgroupfilter.options[testgroupfilter.selectedIndex].value),
subgroup: (subgroupfilter.options[subgroupfilter.selectedIndex].value == '---' ?
'' : subgroupfilter.options[subgroupfilter.selectedIndex].value),
});
// if something went wrong, just show all the tests:
filter_req.addErrback(showAllTests);
filter_req.addCallback(doFilterList);
}
function setAuthor(user_id) {
changeSelectedValue('editform_author_id',user_id);;
@ -248,11 +307,32 @@ function resetTestcase() {
<h1 class="firstHeading">[% title %]</h1>
<div class="section-full">
<div class="section-header">Existing Testcases</div>
<div class="section-header">Existing Testcases</div> <br />
<div class="section-content" style="overflow:hidden;">
<form id="select_testcase_and_mode_form" name="select_testcase_and_mode_form" method="post" action="manage_testcases.cgi">
<div class="info">
<b>Filter:</b>
<table border="0">
<tr>
<td>Product:</td>
<td>Testgroup:</td>
<td>Subgroup:</td>
</tr>
<tr>
<td>
[% INCLUDE productbox onchange="changeProduct('filter'); filterList();" nameextra="_filter" %]
</td>
<td>
[% INCLUDE testgroupbox onchange="changeTestgroup('filter'); filterList();" nameextra="_filter" %]
</td>
<td>
[% INCLUDE subgroupbox onchange="filterList();" nameextra="_filter" %]
</td>
</tr>
</table>
</div>
<table border="0" cellspacing="0" cellpadding="5">
<tr>
<td>

View File

@ -34,6 +34,59 @@
<script type="text/javascript">
var testgroup;
var subgroups=[% IF all_subgroups %][% all_subgroups %][% ELSE %]{}[% END %];
var filter_req;
var showAll = function(err) {
// if they cancelled, then just don't change anything:
if (err instanceof CancelledError) { return }
toggleMessage('none');
var testgroupbox = document.getElementById("testgroup_id");
for (var i=0; i<testgroupbox.options.length; i++) {
var option = testgroupbox.options[i];
option.style.display = '';
}
};
var doFilterList = function(req) {
var testgroups = req.responseText.split("\n");
var testgroupbox = document.getElementById("testgroup_id");
for (var i=0; i<testgroupbox.options.length; i++) {
var testgroup = testgroupbox.options[i];
var hide = 0;
var id = testgroup.value;
if (testgroups.indexOf(id) == -1) { hide = 1; }
hide == 1 ? testgroup.style.display = 'none' : testgroup.style.display = '';
}
toggleMessage('none');
};
// filter the list by various criteria:
function filterList() {
// they just changed the selection, so cancel any pending filter actions:
if (filter_req instanceof Deferred && filter_req.fired == -1)
filter_req.cancel();
var productfilter = document.getElementById('product_filter');
if (productfilter.options[productfilter.selectedIndex].value == '---') {
// nothing to do here
showAll();
return;
}
toggleMessage('loading','Filtering testgroup list...');
filter_req = doSimpleXMLHttpRequest('manage_testgroups.cgi', {
searchTestgroupList: 1,
product: (productfilter.options[productfilter.selectedIndex].value == '---' ?
'' : productfilter.options[productfilter.selectedIndex].value)
});
// if something went wrong, just show all the tests:
filter_req.addErrback(showAll);
filter_req.addCallback(doFilterList);
}
function enableModeButtons() {
document.getElementById("edit_testgroup_button").disabled=false;
@ -185,11 +238,24 @@ function resetTestgroup() {
<h1 class="firstHeading">[% title %]</h1>
<div class="section-full">
<div class="section-header">Existing Testgroups</div>
<div class="section-header">Existing Testgroups</div> <br />
<div class="section-content">
<form id="select_testgroup_and_mode_form" name="select_testgroup_and_mode_form" method="post" action="manage_testgroups.cgi">
<div class="info">
<b>Filter:</b>
<table border="0">
<tr>
<td>Product:</td>
</tr>
<tr>
<td>
[% INCLUDE productbox onchange="changeProduct('filter'); filterList();" nameextra="_filter" %]
</td>
</tr>
</table>
</div>
<table border="0" cellspacing="0" cellpadding="5">
<tr>
<td>

View File

@ -2,9 +2,11 @@
[% IF placeholder %]<option value="">-Testcase ID#[% IF show_summary %]: Summary[% END %]-</option>[% END %]
[% IF testcases %]
[% FOREACH testcase=testcases %]
<option[% IF defaults.testcase_id==testcase.testcase_id %] selected[% END %]
value="[% testcase.testcase_id | html %]">
value="[% testcase.testcase_id | html %]"
id="[%name%]_testcase_[%testcase.testcase_id | html %]">
[% testcase.testcase_id | html%][% IF show_summary %]: [% testcase.summary %][% END %]</option>
[% END %]
[% END %]
</select>
</select>
[% END %]

View File

@ -121,6 +121,7 @@
# (can be either a single object or a list)
# testcase_id (optional) - the current testcase_id. If given,
# the selname will be testgroup_testcase_id
# onchange (optional) - optional js code to run for the onChange event
%]
[% BLOCK testgroupbox %]
[% IF testcase %] [% testidflag = "_$testcase.testcase_id" %]
@ -132,8 +133,8 @@
type="hidden"
value="[%default FILTER html%]">
[% END %]
<select name="testgroup[%testidflag FILTER html%]" id="testgroup[%testidflag FILTER html%]"
onchange="changeTestgroup([%testcase.testcase_id FILTER js%])"
<select name="testgroup[%testidflag FILTER html%][%nameextra%]" id="testgroup[%testidflag FILTER html%][%nameextra%]"
onchange="[% IF onchange %][% onchange %][% ELSE %]changeTestgroup([%testcase.testcase_id FILTER js%])[%END%]"
class="select_testgroup">
</select>
[% END %]
@ -143,6 +144,7 @@
# (can be either a single object or a list)
# testcase_id (optional) - the current testcase_id. If given,
# the selname will be subgroup_testcase_id
# onchange (optional) - optional js code to run for the onChange event
%]
[% BLOCK subgroupbox %]
[% IF testcase %] [% testidflag = "_$testcase.testcase_id" %]
@ -154,8 +156,9 @@
type="hidden"
value="[%valuelist FILTER html%]">
[% END %]
<select name="subgroup[%testidflag FILTER html%]" id="subgroup[%testidflag FILTER html%]"
class="select_subgroup">
<select name="subgroup[%testidflag FILTER html%][%nameextra%]" id="subgroup[%testidflag FILTER html%][%nameextra%]"
class="select_subgroup"
[%IF onchange %]onchange="[%onchange%]"[%END%]>
</select>
[% END %]
@ -177,7 +180,7 @@
type="hidden"
value="[%valuelist FILTER html%]">
[% END %]
<select name="product[%testidflag FILTER html%]" id="product[%testidflag FILTER html%]"
<select name="product[%testidflag FILTER html%][%nameextra%]" id="product[%testidflag FILTER html%][%nameextra%]"
onchange="[% IF onchange %][% onchange %][% ELSE %]changeProduct([%testcase.testcase_id FILTER js%])[% END %]"
class="select_product"[% IF disabled %] disabled[% END %]>
</select>

View File

@ -3,7 +3,7 @@
<div>
<h3>Admin</h3>
<ul>
<li>Manange Test Runs</li>
<li>Manage Test Runs</li>
<hr/>
<li><a href="manage_testcases.cgi">Manage Testcases</a></li>
<li><a href="manage_subgroups.cgi">Manage Subgroups</a></li>