diff --git a/assets/javascripts/openqa.js b/assets/javascripts/openqa.js index 635649c5f181..4d5b11994b0d 100644 --- a/assets/javascripts/openqa.js +++ b/assets/javascripts/openqa.js @@ -290,28 +290,45 @@ function renderSearchResults(query, url) { } spinner.style.display = 'none'; var heading = document.getElementById('results-heading'); - heading.appendChild(document.createTextNode(': ' + json.data.length + ' matches found')); + heading.appendChild(document.createTextNode(': ' + json.data.total_count + ' matches found')); var results = document.createElement('div'); results.id = 'results'; results.className = 'list-group'; - json.data.forEach(function (value, index) { - var item = document.createElement('div'); - item.className = 'list-group-item'; - var header = document.createElement('div'); - header.className = 'd-flex w-100 justify-content-between'; - var title = document.createElement('h5'); - title.className = 'occurrence mb-1'; - title.appendChild(document.createTextNode(value.occurrence)); - header.appendChild(title); - item.appendChild(header); - if (value.contents) { - var contents = document.createElement('pre'); - contents.className = 'contents mb-1'; - contents.appendChild(document.createTextNode(value.contents)); - item.appendChild(contents); + const types = ['code', 'modules', 'templates']; + + for (var i = 0; i < types.length; i++) { + var searchtype = types[i]; + var searchresults = json.data.results[searchtype]; + if (searchresults.length > 0) { + var header = document.createElement('div'); + header.id = searchtype; + var bold = document.createElement('strong'); + var textnode = document.createTextNode(searchtype + ': ' + searchresults.length); + bold.appendChild(textnode); + + header.className = 'list-group-item'; + header.appendChild(bold); + results.append(header); } - results.append(item); - }); + searchresults.forEach(function (value, index) { + var item = document.createElement('div'); + item.className = 'list-group-item'; + var header = document.createElement('div'); + header.className = 'd-flex w-100 justify-content-between'; + var title = document.createElement('h5'); + title.className = 'occurrence mb-1'; + title.appendChild(document.createTextNode(value.occurrence)); + header.appendChild(title); + item.appendChild(header); + if (value.contents) { + var contents = document.createElement('pre'); + contents.className = 'contents mb-1'; + contents.appendChild(document.createTextNode(value.contents)); + item.appendChild(contents); + } + results.append(item); + }); + } const oldResults = document.getElementById('results'); oldResults.parentElement.replaceChild(results, oldResults); }; diff --git a/lib/OpenQA/WebAPI/Controller/API/V1/Search.pm b/lib/OpenQA/WebAPI/Controller/API/V1/Search.pm index 1df04a48775d..14ac66dd09b7 100644 --- a/lib/OpenQA/WebAPI/Controller/API/V1/Search.pm +++ b/lib/OpenQA/WebAPI/Controller/API/V1/Search.pm @@ -176,22 +176,27 @@ sub query { unless $self->app->minion->lock($lockname, 60, {limit => $self->app->config->{'rate_limits'}->{'search'}}); my $cap = $self->app->config->{'global'}->{'search_results_limit'}; - my @results; + my %results; my $keywords = $validation->param('q'); + my %json = (total_count => 0, results => \%results); my $perl_module_results = $self->_search_perl_modules($keywords, $cap); - $cap -= scalar @{$perl_module_results}; - push @results, @{$perl_module_results}; - return $self->render(json => {data => \@results}) unless $cap > 0; + $json{total_count} += @{$perl_module_results}; + $cap -= @{$perl_module_results}; + $results{code} = $perl_module_results; + return $self->render(json => {data => \%json}) unless $cap > 0; my $job_module_results = $self->_search_job_modules($keywords, $cap); - $cap -= scalar @{$job_module_results}; - push @results, @{$job_module_results}; - return $self->render(json => {data => \@results}) unless $cap > 0; + $json{total_count} += @{$job_module_results}; + $cap -= @{$job_module_results}; + $results{modules} = $job_module_results; + return $self->render(json => {data => \%json}) unless $cap > 0; - push @results, @{$self->_search_job_templates($keywords, $cap)}; + my $job_template_resuts = $self->_search_job_templates($keywords, $cap); + $json{total_count} += @{$job_template_resuts}; + $results{templates} = $job_template_resuts; - $self->render(json => {data => \@results}); + $self->render(json => {data => \%json}); } 1; diff --git a/t/api/15-search.t b/t/api/15-search.t index 582cee69deb0..a644d8a75e4c 100644 --- a/t/api/15-search.t +++ b/t/api/15-search.t @@ -17,9 +17,12 @@ $t->app->config->{rate_limits}->{search} = 10; subtest 'Perl modules' => sub { $t->get_ok('/api/v1/experimental/search?q=timezone', 'search successful'); $t->json_is('/error' => undef, 'no errors'); - $t->json_is('/data/0' => {occurrence => 'opensuse/tests/installation/installer_timezone.pm'}, 'module found'); $t->json_is( - '/data/1' => { + '/data/results/code/0' => {occurrence => 'opensuse/tests/installation/installer_timezone.pm'}, + 'module found' + ); + $t->json_is( + '/data/results/code/1' => { occurrence => 'opensuse/tests/installation/installer_timezone.pm', contents => qq{ 3 # Summary: Verify timezone settings page\n} . qq{ 10 assert_screen "inst-timezone", 125 || die 'no timezone';} @@ -31,9 +34,9 @@ subtest 'Perl modules' => sub { subtest 'Python modules' => sub { $t->get_ok('/api/v1/experimental/search?q=search', 'search successful'); $t->json_is('/error' => undef, 'no errors'); - $t->json_is('/data/0' => {occurrence => 'opensuse/tests/openQA/search.py'}, 'module found'); + $t->json_is('/data/results/code/0' => {occurrence => 'opensuse/tests/openQA/search.py'}, 'module found'); $t->json_is( - '/data/1' => { + '/data/results/code/1' => { occurrence => 'opensuse/tests/openQA/search.py', contents => qq{ 6 assert_and_click('openqa-search')\n} . qq{ 9 assert_screen('openqa-search-results')} @@ -64,14 +67,14 @@ subtest 'Job modules' => sub { $t->get_ok('/api/v1/experimental/search?q=ipsum', 'search successful'); $t->json_is('/error' => undef, 'no errors'); $t->json_is( - '/data/0' => { + '/data/results/modules/0' => { occurrence => 'lorem', contents => "tests/lorem/ipsum.pm\n" . "tests/lorem/ipsum_dolor.py" }, 'job module found' ); $t->json_is( - '/data/1' => undef, + '/data/total_count' => 1, 'no additional job module found' ); }; @@ -97,11 +100,11 @@ subtest 'Job templates' => sub { $t->get_ok('/api/v1/experimental/search?q=fancy', 'search successful'); $t->json_is('/error' => undef, 'no errors'); $t->json_is( - '/data/0' => {occurrence => 'Cool Group', contents => "fancy-example\nVery posh"}, + '/data/results/templates/0' => {occurrence => 'Cool Group', contents => "fancy-example\nVery posh"}, 'job template found' ); $t->json_is( - '/data/1' => undef, + '/data/total_count' => 1, 'no additional job template found' ); @@ -116,7 +119,7 @@ subtest 'Job templates' => sub { $t->get_ok('/api/v1/experimental/search?q=apple', 'search successful'); $t->json_is('/error' => undef, 'no errors'); $t->json_is( - '/data/0' => {occurrence => 'Cool Group', contents => "apple\n"}, + '/data/results/templates/0' => {occurrence => 'Cool Group', contents => "apple\n"}, 'job template was found by using test suite name' ); }; @@ -124,7 +127,7 @@ subtest 'Job templates' => sub { subtest 'Limits' => sub { $t->app->config->{global}->{search_results_limit} = 1; $t->get_ok('/api/v1/experimental/search?q=test', 'Extensive search with limit')->status_is(200); - $t->json_is('/data/1' => undef, 'capped at one match'); + $t->json_is('/data/results/templates/1' => undef, 'capped at one match'); }; subtest 'Errors' => sub { @@ -133,7 +136,7 @@ subtest 'Errors' => sub { $t->get_ok('/api/v1/experimental/search?q=*', 'wildcard is interpreted literally'); $t->json_is( - '/data/0' => { + '/data/results/code/0' => { occurrence => "opensuse\/tests\/openQA\/search.py", contents => " 1 from testapi import *", }, diff --git a/t/ui/15-search.t b/t/ui/15-search.t index f943777d7546..a2a44035dc45 100644 --- a/t/ui/15-search.t +++ b/t/ui/15-search.t @@ -36,9 +36,10 @@ subtest 'Perl modules' => sub { my $header = $driver->find_element_by_id('results-heading'); my $results = $driver->find_element_by_id('results'); my @entries = $results->children('.list-group-item'); - is $header->get_text(), 'Search results: ' . scalar @entries . ' matches found', 'number of results in header'; - is scalar @entries, 2, '2 elements' or return; + is $header->get_text(), 'Search results: ' . (@entries - 1) . ' matches found', 'number of results in header'; + is scalar @entries, 3, '3 elements' or return; + shift @entries; my $first = $entries[0]; is $first->child('.occurrence')->get_text(), 'opensuse/tests/installation/installer_timezone.pm', 'expected occurrence'; diff --git a/templates/webapi/search/search.html.ep b/templates/webapi/search/search.html.ep index 51f8c6cbc34e..751a253e2e06 100644 --- a/templates/webapi/search/search.html.ep +++ b/templates/webapi/search/search.html.ep @@ -7,9 +7,9 @@

Search results

-

The search currently finds job templates by name or description, - job modules by filename, - or test modules within the test distributions, +

The search currently finds job templates by name or description, + job modules by filename, + or test modules within the test distributions, either by filename or source code.