Commit 0fad7aa7 authored by Alexis Reigel's avatar Alexis Reigel

add tag filter to admin runners page

parent d3accd36
......@@ -17,6 +17,14 @@ const tokenKeys = [
icon: 'cube',
tag: 'type',
},
{
key: 'tag',
type: 'array',
param: 'name[]',
symbol: '~',
icon: 'tag',
tag: '~tag',
},
];
const AdminRunnersFilteredSearchTokenKeys = new FilteredSearchTokenKeys(tokenKeys);
......
......@@ -111,6 +111,15 @@ export default class FilteredSearchDropdownManager {
gl: NullDropdown,
element: this.container.querySelector('#js-dropdown-admin-runner-type'),
},
tag: {
reference: null,
gl: DropdownNonUser,
extraArguments: {
endpoint: this.getRunnerTagsEndpoint(),
symbol: '~',
},
element: this.container.querySelector('#js-dropdown-runner-tag'),
},
};
supportedTokens.forEach(type => {
......@@ -146,6 +155,10 @@ export default class FilteredSearchDropdownManager {
return endpoint;
}
getRunnerTagsEndpoint() {
return `${this.baseEndpoint}/admin/runners/tag_list.json`;
}
static addWordToInput(tokenName, tokenValue = '', clicked = false, options = {}) {
const { uppercaseTokenName = false, capitalizeTokenValue = false } = options;
const input = FilteredSearchContainer.container.querySelector('.filtered-search');
......
# frozen_string_literal: true
class Admin::RunnersController < Admin::ApplicationController
before_action :runner, except: :index
before_action :runner, except: [:index, :tag_list]
def index
finder = Admin::RunnersFinder.new(params: params)
......@@ -48,6 +48,10 @@ class Admin::RunnersController < Admin::ApplicationController
end
end
def tag_list
render json: AutocompleteTagsService.new(Ci::Runner).run
end
private
def runner
......
......@@ -11,6 +11,7 @@ class Admin::RunnersFinder < UnionFinder
search!
filter_by_status!
filter_by_runner_type!
filter_by_tag_list!
sort!
paginate!
......@@ -44,6 +45,14 @@ class Admin::RunnersFinder < UnionFinder
filter_by!(:type_type, Ci::Runner::AVAILABLE_TYPES)
end
def filter_by_tag_list!
tag_list = @params[:tag_name].presence
if tag_list
@runners = @runners.tagged_with(tag_list)
end
end
def sort!
@runners = @runners.order_by(sort_key)
end
......
# frozen_string_literal: true
class AutocompleteTagsService
def initialize(taggable_type)
@taggable_type = taggable_type
end
# rubocop: disable CodeReuse/ActiveRecord
def run
@taggable_type
.all_tags
.pluck(:id, :name).map do |id, name|
{ id: id, title: name }
end
end
# rubocop: enable CodeReuse/ActiveRecord
end
......@@ -92,6 +92,24 @@
= button_tag class: %w[btn btn-link] do
= runner_type.titleize
#js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
- Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
%li.filter-dropdown-item{ data: { value: runner_type } }
= button_tag class: %w[btn btn-link] do
= runner_type.titleize
#js-dropdown-runner-tag.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'none' } }
%button.btn.btn-link
= _('No Tag')
%li.divider.droplab-item-ignore
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
%button.btn.btn-link.js-data-value
{{title}}
= button_tag class: %w[clear-search hidden] do
= icon('times')
.filter-dropdown-container
......
......@@ -120,6 +120,10 @@ namespace :admin do
get :resume
get :pause
end
collection do
get :tag_list, format: :json
end
end
resources :jobs, only: :index do
......
......@@ -4943,6 +4943,9 @@ msgstr ""
msgid "No %{providerTitle} repositories available to import"
msgstr ""
msgid "No Tag"
msgstr ""
msgid "No activities found"
msgstr ""
......
......@@ -141,6 +141,56 @@ describe "Admin Runners" do
end
end
describe 'filter by tag', :js do
it 'shows correct runner when tag matches' do
create :ci_runner, description: 'runner-blue', tag_list: ['blue']
create :ci_runner, description: 'runner-red', tag_list: ['red']
visit admin_runners_path
expect(page).to have_content 'runner-blue'
expect(page).to have_content 'runner-red'
input_filtered_search_keys('tag:blue')
expect(page).to have_content 'runner-blue'
expect(page).not_to have_content 'runner-red'
end
it 'shows no runner when tag does not match' do
create :ci_runner, description: 'runner-blue', tag_list: ['blue']
create :ci_runner, description: 'runner-red', tag_list: ['blue']
visit admin_runners_path
input_filtered_search_keys('tag:red')
expect(page).not_to have_content 'runner-blue'
expect(page).not_to have_content 'runner-blue'
expect(page).to have_text 'No runners found'
end
it 'shows correct runner when tag is selected and search term is entered' do
create :ci_runner, description: 'runner-a-1', tag_list: ['blue']
create :ci_runner, description: 'runner-a-2', tag_list: ['red']
create :ci_runner, description: 'runner-b-1', tag_list: ['blue']
visit admin_runners_path
input_filtered_search_keys('tag:blue')
expect(page).to have_content 'runner-a-1'
expect(page).to have_content 'runner-b-1'
expect(page).not_to have_content 'runner-a-2'
input_filtered_search_keys('tag:blue runner-a')
expect(page).to have_content 'runner-a-1'
expect(page).not_to have_content 'runner-b-1'
expect(page).not_to have_content 'runner-a-2'
end
end
it 'sorts by last contact date', :js do
create(:ci_runner, description: 'runner-1', created_at: '2018-07-12 15:37', contacted_at: '2018-07-12 15:37')
create(:ci_runner, description: 'runner-2', created_at: '2018-07-12 16:37', contacted_at: '2018-07-12 16:37')
......
......@@ -37,6 +37,14 @@ describe Admin::RunnersFinder do
end
end
context 'filter by tag_name' do
it 'calls the corresponding scope on Ci::Runner' do
expect(Ci::Runner).to receive(:tagged_with).with(%w[tag1 tag2]).and_call_original
described_class.new(params: { tag_name: %w[tag1 tag2] }).execute
end
end
context 'sort' do
context 'without sort param' do
it 'sorts by created_at' do
......
require 'rails_helper'
RSpec.describe AutocompleteTagsService do
describe '#run' do
it 'returns a hash of all tags' do
create(:ci_runner, tag_list: %w[tag1 tag2])
create(:ci_runner, tag_list: %w[tag1 tag3])
create(:project, tag_list: %w[tag4])
expect(described_class.new(Ci::Runner).run).to match_array [
{ id: kind_of(Integer), title: 'tag1' },
{ id: kind_of(Integer), title: 'tag2' },
{ id: kind_of(Integer), title: 'tag3' }
]
end
end
end
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