Commit 9c5d8585 authored by Douwe Maan's avatar Douwe Maan Committed by Rémy Coutable

Merge branch 'filter-branch-by-name' into 'master'

Users can filter branches by name on project branches page

This MR aims to solve #18674 by adding the possibility to filter project branches by name

![Screen_Shot_2016-07-07_at_17.21.25](/uploads/b674765d2b1cb8a121c2101715a4568b/Screen_Shot_2016-07-07_at_17.21.25.png)

See merge request !5144
Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 7ee7567a
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.10.2 (unreleased) v 8.10.2 (unreleased)
- User can now search branches by name. !5144
- Don't show comment button in gutter of diffs on MR discussion tab - Don't show comment button in gutter of diffs on MR discussion tab
v 8.10.1 v 8.10.1
......
...@@ -6,8 +6,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -6,8 +6,7 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :authorize_push_code!, only: [:new, :create, :destroy] before_action :authorize_push_code!, only: [:new, :create, :destroy]
def index def index
@sort = params[:sort] || 'name' @branches = BranchesFinder.new(@repository, params).execute
@branches = @repository.branches_sorted_by(@sort)
@branches = Kaminari.paginate_array(@branches).page(params[:page]) @branches = Kaminari.paginate_array(@branches).page(params[:page])
@max_commits = @branches.reduce(0) do |memo, branch| @max_commits = @branches.reduce(0) do |memo, branch|
......
class BranchesFinder
def initialize(repository, params)
@repository = repository
@params = params
end
def execute
branches = @repository.branches_sorted_by(sort)
filter_by_name(branches)
end
private
attr_reader :repository, :params
def search
@params[:search].presence
end
def sort
@params[:sort].presence || 'name'
end
def filter_by_name(branches)
if search
branches.select { |branch| branch.name.include?(search) }
else
branches
end
end
end
...@@ -9,6 +9,17 @@ module BranchesHelper ...@@ -9,6 +9,17 @@ module BranchesHelper
end end
end end
def filter_branches_path(options = {})
exist_opts = {
search: params[:search],
sort: params[:sort]
}
options = exist_opts.merge(options)
namespace_project_branches_path(@project.namespace, @project, @id, options)
end
def can_push_branch?(project, branch_name) def can_push_branch?(project, branch_name)
return false unless project.repository.branch_exists?(branch_name) return false unless project.repository.branch_exists?(branch_name)
......
...@@ -610,6 +610,8 @@ class Repository ...@@ -610,6 +610,8 @@ class Repository
# Remove archives older than 2 hours # Remove archives older than 2 hours
def branches_sorted_by(value) def branches_sorted_by(value)
case value case value
when 'name'
branches.sort_by(&:name)
when 'recently_updated' when 'recently_updated'
branches.sort do |a, b| branches.sort do |a, b|
commit(b.target).committed_date <=> commit(a.target).committed_date commit(b.target).committed_date <=> commit(a.target).committed_date
......
...@@ -9,26 +9,30 @@ ...@@ -9,26 +9,30 @@
- if can? current_user, :push_code, @project - if can? current_user, :push_code, @project
.nav-controls .nav-controls
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do = form_tag(filter_branches_path, method: :get) do
New branch = search_field_tag :search, params[:search], { placeholder: 'Filter by branch name', id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
.dropdown.inline .dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light %span.light
- if @sort.present? - if params[:sort].present?
= @sort.humanize = params[:sort].humanize
- else - else
Name Name
%b.caret %b.caret
%ul.dropdown-menu.dropdown-menu-align-right %ul.dropdown-menu.dropdown-menu-align-right
%li %li
= link_to namespace_project_branches_path(sort: nil) do = link_to filter_branches_path(sort: nil) do
Name = sort_title_name
= link_to namespace_project_branches_path(sort: 'recently_updated') do = link_to filter_branches_path(sort: 'recently_updated') do
= sort_title_recently_updated = sort_title_recently_updated
= link_to namespace_project_branches_path(sort: 'last_updated') do = link_to filter_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated = sort_title_oldest_updated
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
New branch
- if @branches.any? - if @branches.any?
%ul.content-list.all-branches %ul.content-list.all-branches
- @branches.each do |branch| - @branches.each do |branch|
= render "projects/branches/branch", branch: branch = render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab' = paginate @branches, theme: 'gitlab'
- else
.nothing-here-block No branches to show
...@@ -84,7 +84,7 @@ ActiveRecord::Schema.define(version: 20160721081015) do ...@@ -84,7 +84,7 @@ ActiveRecord::Schema.define(version: 20160721081015) do
t.string "health_check_access_token" t.string "health_check_access_token"
t.boolean "send_user_confirmation_email", default: false t.boolean "send_user_confirmation_email", default: false
t.integer "container_registry_token_expire_delay", default: 5 t.integer "container_registry_token_expire_delay", default: 5
t.boolean "user_default_external", default: false, null: false t.boolean "user_default_external", default: false, null: false
t.text "after_sign_up_text" t.text "after_sign_up_text"
t.string "repository_storage", default: "default" t.string "repository_storage", default: "default"
t.string "enabled_git_access_protocol" t.string "enabled_git_access_protocol"
...@@ -607,9 +607,9 @@ ActiveRecord::Schema.define(version: 20160721081015) do ...@@ -607,9 +607,9 @@ ActiveRecord::Schema.define(version: 20160721081015) do
add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree
create_table "merge_requests", force: :cascade do |t| create_table "merge_requests", force: :cascade do |t|
t.string "target_branch", null: false t.string "target_branch", null: false
t.string "source_branch", null: false t.string "source_branch", null: false
t.integer "source_project_id", null: false t.integer "source_project_id", null: false
t.integer "author_id" t.integer "author_id"
t.integer "assignee_id" t.integer "assignee_id"
t.string "title" t.string "title"
...@@ -618,20 +618,21 @@ ActiveRecord::Schema.define(version: 20160721081015) do ...@@ -618,20 +618,21 @@ ActiveRecord::Schema.define(version: 20160721081015) do
t.integer "milestone_id" t.integer "milestone_id"
t.string "state" t.string "state"
t.string "merge_status" t.string "merge_status"
t.integer "target_project_id", null: false t.integer "target_project_id", null: false
t.integer "iid" t.integer "iid"
t.text "description" t.text "description"
t.integer "position", default: 0 t.integer "position", default: 0
t.datetime "locked_at" t.datetime "locked_at"
t.integer "updated_by_id" t.integer "updated_by_id"
t.string "merge_error" t.string "merge_error"
t.text "merge_params" t.text "merge_params"
t.boolean "merge_when_build_succeeds", default: false, null: false t.boolean "merge_when_build_succeeds", default: false, null: false
t.integer "merge_user_id" t.integer "merge_user_id"
t.string "merge_commit_sha" t.string "merge_commit_sha"
t.datetime "deleted_at" t.datetime "deleted_at"
t.string "in_progress_merge_commit_sha" t.string "in_progress_merge_commit_sha"
end end
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
add_index "merge_requests", ["created_at", "id"], name: "index_merge_requests_on_created_at_and_id", using: :btree add_index "merge_requests", ["created_at", "id"], name: "index_merge_requests_on_created_at_and_id", using: :btree
......
require 'spec_helper'
describe 'Branches', feature: true do
let(:project) { create(:project) }
let(:repository) { project.repository }
before do
login_as :user
project.team << [@user, :developer]
end
describe 'Initial branches page' do
it 'shows all the branches' do
visit namespace_project_branches_path(project.namespace, project)
repository.branches { |branch| expect(page).to have_content("#{branch.name}") }
expect(page).to have_content("Protected branches can be managed in project settings")
end
end
describe 'Find branches' do
it 'shows filtered branches', js: true do
visit namespace_project_branches_path(project.namespace, project, project.id)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
expect(page).to have_content('fix')
expect(find('.all-branches')).to have_selector('li', count: 1)
end
end
end
require 'spec_helper'
describe 'Branches', feature: true do
let(:project) { create(:project) }
let(:repository) { project.repository }
before do
login_as :user
project.team << [@user, :developer]
end
describe 'Initial branches page' do
it 'shows all the branches' do
visit namespace_project_branches_path(project.namespace, project)
repository.branches { |branch| expect(page).to have_content("#{branch.name}") }
expect(page).to have_content("Protected branches can be managed in project settings")
end
end
describe 'Find branches' do
it 'shows filtered branches', js: true do
visit namespace_project_branches_path(project.namespace, project, project.id)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
expect(page).to have_content('fix')
expect(find('.all-branches')).to have_selector('li', count: 1)
end
end
end
require 'spec_helper'
describe BranchesFinder 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
branches_finder = described_class.new(repository, {})
result = branches_finder.execute
expect(result.first.name).to eq("'test'")
end
it 'sorts by recently_updated' do
branches_finder = described_class.new(repository, { sort: 'recently_updated' })
result = branches_finder.execute
expect(result.first.name).to eq('expand-collapse-lines')
end
it 'sorts by last_updated' do
branches_finder = described_class.new(repository, { sort: 'last_updated' })
result = branches_finder.execute
expect(result.first.name).to eq('feature')
end
end
context 'filter only' do
it 'filters branches by name' do
branches_finder = described_class.new(repository, { search: 'fix' })
result = branches_finder.execute
expect(result.first.name).to eq('fix')
expect(result.count).to eq(1)
end
it 'does not find any branch with that name' do
branches_finder = described_class.new(repository, { search: 'random' })
result = branches_finder.execute
expect(result.count).to eq(0)
end
end
context 'filter and sort' do
it 'filters branches by name and sorts by recently_updated' do
params = { sort: 'recently_updated', search: 'feature' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature_conflict')
expect(result.count).to eq(2)
end
it 'filters branches by name and sorts by last_updated' do
params = { sort: 'last_updated', search: 'feature' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature')
expect(result.count).to eq(2)
end
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