diff --git a/CHANGELOG b/CHANGELOG index 760d3c0e2de303703f75d42594d89328dd6b3020..a0a7fe59e86f8c209059528f9870184c725651e7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.12.0 (unreleased) + - Filter tags by name !6121 - Make push events have equal vertical spacing. - Add two-factor recovery endpoint to internal API !5510 - Remove vendor prefixes for linear-gradient CSS (ClemMakesApps) diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 8592579abbd18a6174f6401e637fc6c135fabd23..6ea8ee62bc59e57fc1248347dbf0938b69272556 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -1,4 +1,6 @@ class Projects::TagsController < Projects::ApplicationController + include SortingHelper + # Authorize before_action :require_non_empty_project before_action :authorize_download_code! @@ -6,8 +8,10 @@ class Projects::TagsController < Projects::ApplicationController before_action :authorize_admin_project!, only: [:destroy] def index - @sort = params[:sort] || 'name' - @tags = @repository.tags_sorted_by(@sort) + params[:sort] = params[:sort].presence || 'name' + + @sort = params[:sort] + @tags = TagsFinder.new(@repository, params).execute @tags = Kaminari.paginate_array(@tags).page(params[:page]) @releases = project.releases.where(tag: @tags.map(&:name)) diff --git a/app/finders/tags_finder.rb b/app/finders/tags_finder.rb new file mode 100644 index 0000000000000000000000000000000000000000..b474f0805dcdddd9c15f060819e0b8dfbabcfeff --- /dev/null +++ b/app/finders/tags_finder.rb @@ -0,0 +1,29 @@ +class TagsFinder + def initialize(repository, params) + @repository = repository + @params = params + end + + def execute + tags = @repository.tags_sorted_by(sort) + filter_by_name(tags) + end + + private + + def sort + @params[:sort].presence + end + + def search + @params[:search].presence + end + + def filter_by_name(tags) + if search + tags.select { |tag| tag.name.include?(search) } + else + tags + end + end +end diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb index fb85544df2d7a9da130de651631bf962562cfd6a..c0ec1634cdb83b5cb004afcd8e06886892e430e1 100644 --- a/app/helpers/tags_helper.rb +++ b/app/helpers/tags_helper.rb @@ -3,6 +3,16 @@ module TagsHelper "/tags/#{tag}" end + def filter_tags_path(options = {}) + exist_opts = { + search: params[:search], + sort: params[:sort] + } + + options = exist_opts.merge(options) + namespace_project_tags_path(@project.namespace, @project, @id, options) + end + def tag_list(project) html = '' project.tag_list.each do |tag| diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml index 368231e73fe6cae1daa6c85b64badebad0b2aa99..6adbe9351dcec5d3c7b3734c08c990d7139dd98e 100644 --- a/app/views/projects/tags/index.html.haml +++ b/app/views/projects/tags/index.html.haml @@ -8,21 +8,24 @@ Tags give the ability to mark specific points in history as being important .nav-controls - - if can? current_user, :push_code, @project - = link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do - New tag + = form_tag(filter_tags_path, method: :get) do + = search_field_tag :search, params[:search], { placeholder: 'Filter by tag name', id: 'tag-search', class: 'form-control search-text-input input-short', spellcheck: false } .dropdown.inline %button.dropdown-toggle.btn{ type: 'button', data: { toggle: 'dropdown'} } - %span.light= @sort.humanize + %span.light + = @sort.humanize %b.caret %ul.dropdown-menu.dropdown-menu-align-right %li - = link_to namespace_project_tags_path(sort: nil) do + = link_to filter_tags_path(sort: nil) do Name - = link_to namespace_project_tags_path(sort: sort_value_recently_updated) do + = link_to filter_tags_path(sort: sort_value_recently_updated) do = sort_title_recently_updated - = link_to namespace_project_tags_path(sort: sort_value_oldest_updated) do + = link_to filter_tags_path(sort: sort_value_oldest_updated) do = sort_title_oldest_updated + - if can?(current_user, :push_code, @project) + = link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do + New tag .tags - if @tags.any? diff --git a/spec/finders/tags_finder_spec.rb b/spec/finders/tags_finder_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..2ac810e478ae7de82fbbb925f0882a887d4d8be2 --- /dev/null +++ b/spec/finders/tags_finder_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper' + +describe TagsFinder do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:repository) { project.repository } + + describe '#execute' do + context 'sort only' do + it 'sorts by name' do + tags_finder = described_class.new(repository, {}) + + result = tags_finder.execute + + expect(result.first.name).to eq("v1.0.0") + end + + it 'sorts by recently_updated' do + tags_finder = described_class.new(repository, { sort: 'updated_desc' }) + + result = tags_finder.execute + recently_updated_tag = repository.tags.max do |a, b| + repository.commit(a.target).committed_date <=> repository.commit(b.target).committed_date + end + + expect(result.first.name).to eq(recently_updated_tag.name) + end + + it 'sorts by last_updated' do + tags_finder = described_class.new(repository, { sort: 'updated_asc' }) + + result = tags_finder.execute + + expect(result.first.name).to eq('v1.0.0') + end + end + + context 'filter only' do + it 'filters tags by name' do + tags_finder = described_class.new(repository, { search: '1.0.0' }) + + result = tags_finder.execute + + expect(result.first.name).to eq('v1.0.0') + expect(result.count).to eq(1) + end + + it 'does not find any tags with that name' do + tags_finder = described_class.new(repository, { search: 'hey' }) + + result = tags_finder.execute + + expect(result.count).to eq(0) + end + end + + context 'filter and sort' do + it 'filters tags by name and sorts by recently_updated' do + params = { sort: 'updated_desc', search: 'v1' } + tags_finder = described_class.new(repository, params) + + result = tags_finder.execute + + expect(result.first.name).to eq('v1.1.0') + expect(result.count).to eq(2) + end + + it 'filters tags by name and sorts by last_updated' do + params = { sort: 'updated_asc', search: 'v1' } + tags_finder = described_class.new(repository, params) + + result = tags_finder.execute + + expect(result.first.name).to eq('v1.0.0') + expect(result.count).to eq(2) + end + end + end +end