Commit 3281021e8b42ba4d0fff5be268f5c43dd6ab4ff8

Authored by Dmitriy Zaporozhets
1 parent 5b8cc95d

Rewrite issues/mr filtering logic

app/contexts/issues/list_context.rb
1 module Issues 1 module Issues
2 class ListContext < BaseContext 2 class ListContext < BaseContext
3 - include IssuesHelper  
4 -  
5 attr_accessor :issues 3 attr_accessor :issues
6 4
7 def execute 5 def execute
8 - @issues = case params[:status]  
9 - when issues_filter[:all] then @project.issues  
10 - when issues_filter[:closed] then @project.issues.closed  
11 - when issues_filter[:to_me] then @project.issues.assigned_to(current_user)  
12 - when issues_filter[:by_me] then @project.issues.authored(current_user)  
13 - else @project.issues.opened 6 + @issues = @project.issues
  7 +
  8 + @issues = case params[:state]
  9 + when 'all' then @issues
  10 + when 'closed' then @issues.closed
  11 + else @issues.opened
  12 + end
  13 +
  14 + @issues = case params[:scope]
  15 + when 'assigned-to-me' then @issues.assigned_to(current_user)
  16 + when 'created-by-me' then @issues.authored(current_user)
  17 + else @issues
14 end 18 end
15 19
16 @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present? 20 @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present?
app/contexts/merge_requests_load_context.rb
@@ -2,17 +2,21 @@ @@ -2,17 +2,21 @@
2 # based on filtering passed via params for @project 2 # based on filtering passed via params for @project
3 class MergeRequestsLoadContext < BaseContext 3 class MergeRequestsLoadContext < BaseContext
4 def execute 4 def execute
5 - type = params[:status] 5 + merge_requests = @project.merge_requests
6 6
7 - merge_requests = project.merge_requests  
8 -  
9 - merge_requests = case type 7 + merge_requests = case params[:state]
10 when 'all' then merge_requests 8 when 'all' then merge_requests
11 when 'closed' then merge_requests.closed 9 when 'closed' then merge_requests.closed
12 - when 'assigned-to-me' then merge_requests.opened.assigned_to(current_user)  
13 else merge_requests.opened 10 else merge_requests.opened
14 end 11 end
15 12
  13 + merge_requests = case params[:scope]
  14 + when 'assigned-to-me' then merge_requests.assigned_to(current_user)
  15 + when 'created-by-me' then merge_requests.authored(current_user)
  16 + else merge_requests
  17 + end
  18 +
  19 +
16 merge_requests = merge_requests.page(params[:page]).per(20) 20 merge_requests = merge_requests.page(params[:page]).per(20)
17 merge_requests = merge_requests.includes(:author, :source_project, :target_project).order("created_at desc") 21 merge_requests = merge_requests.includes(:author, :source_project, :target_project).order("created_at desc")
18 22
app/controllers/projects/issues_controller.rb
@@ -20,9 +20,7 @@ class Projects::IssuesController &lt; Projects::ApplicationController @@ -20,9 +20,7 @@ class Projects::IssuesController &lt; Projects::ApplicationController
20 @issues = @issues.where("title LIKE ?", "%#{terms}%") if terms.present? 20 @issues = @issues.where("title LIKE ?", "%#{terms}%") if terms.present?
21 @issues = @issues.page(params[:page]).per(20) 21 @issues = @issues.page(params[:page]).per(20)
22 22
23 -  
24 assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] 23 assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
25 -  
26 @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero? 24 @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
27 @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? 25 @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
28 26
app/controllers/projects/merge_requests_controller.rb
@@ -17,6 +17,9 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController @@ -17,6 +17,9 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
17 17
18 def index 18 def index
19 @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute 19 @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute
  20 + assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
  21 + @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
  22 + @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
20 end 23 end
21 24
22 def show 25 def show
app/helpers/issues_helper.rb
1 module IssuesHelper 1 module IssuesHelper
2 - def project_issues_filter_path project, params = {}  
3 - params[:f] ||= cookies['issue_filter']  
4 - project_issues_path project, params  
5 - end  
6 -  
7 def issue_css_classes issue 2 def issue_css_classes issue
8 classes = "issue" 3 classes = "issue"
9 classes << " closed" if issue.closed? 4 classes << " closed" if issue.closed?
@@ -18,25 +13,11 @@ module IssuesHelper @@ -18,25 +13,11 @@ module IssuesHelper
18 OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned') 13 OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned')
19 end 14 end
20 15
21 - def issues_filter  
22 - {  
23 - all: "all",  
24 - closed: "closed",  
25 - to_me: "assigned-to-me",  
26 - by_me: "created-by-me",  
27 - open: "open"  
28 - }  
29 - end  
30 -  
31 - def issues_active_milestones  
32 - @project.milestones.active.order("id desc").all  
33 - end  
34 -  
35 def url_for_project_issues 16 def url_for_project_issues
36 return "" if @project.nil? 17 return "" if @project.nil?
37 18
38 if @project.used_default_issues_tracker? 19 if @project.used_default_issues_tracker?
39 - project_issues_filter_path(@project) 20 + project_issues_path(@project)
40 else 21 else
41 url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"] 22 url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"]
42 url.gsub(':project_id', @project.id.to_s) 23 url.gsub(':project_id', @project.id.to_s)
@@ -78,15 +59,4 @@ module IssuesHelper @@ -78,15 +59,4 @@ module IssuesHelper
78 "" 59 ""
79 end 60 end
80 end 61 end
81 -  
82 - def project_issues_with_filter_path(project, opts)  
83 - default_opts = {  
84 - status: params[:status],  
85 - label_name: params[:label_name],  
86 - milestone_id: params[:milestone_id],  
87 - assignee_id: params[:assignee_id],  
88 - }  
89 -  
90 - project_issues_path(@project, default_opts.merge(opts))  
91 - end  
92 end 62 end
app/helpers/projects_helper.rb
@@ -61,6 +61,25 @@ module ProjectsHelper @@ -61,6 +61,25 @@ module ProjectsHelper
61 project_nav_tabs.include? name 61 project_nav_tabs.include? name
62 end 62 end
63 63
  64 + def project_filter_path(options={})
  65 + exist_opts = {
  66 + state: params[:state],
  67 + scope: params[:scope],
  68 + label_name: params[:label_name],
  69 + milestone_id: params[:milestone_id],
  70 + }
  71 +
  72 + options = exist_opts.merge(options)
  73 +
  74 + path = request.path
  75 + path << "?#{options.to_param}"
  76 + path
  77 + end
  78 +
  79 + def project_active_milestones
  80 + @project.milestones.active.order("id desc").all
  81 + end
  82 +
64 private 83 private
65 84
66 def get_project_nav_tabs(project, current_user) 85 def get_project_nav_tabs(project, current_user)
app/models/concerns/issuable.rb
@@ -17,6 +17,7 @@ module Issuable @@ -17,6 +17,7 @@ module Issuable
17 validates :author, presence: true 17 validates :author, presence: true
18 validates :title, presence: true, length: { within: 0..255 } 18 validates :title, presence: true, length: { within: 0..255 }
19 19
  20 + scope :authored, ->(user) { where(author_id: user) }
20 scope :assigned_to, ->(u) { where(assignee_id: u.id)} 21 scope :assigned_to, ->(u) { where(assignee_id: u.id)}
21 scope :recent, -> { order("created_at DESC") } 22 scope :recent, -> { order("created_at DESC") }
22 scope :assigned, -> { where("assignee_id IS NOT NULL") } 23 scope :assigned, -> { where("assignee_id IS NOT NULL") }
app/models/issue.rb
@@ -35,7 +35,6 @@ class Issue &lt; ActiveRecord::Base @@ -35,7 +35,6 @@ class Issue &lt; ActiveRecord::Base
35 acts_as_taggable_on :labels 35 acts_as_taggable_on :labels
36 36
37 scope :cared, ->(user) { where(assignee_id: user) } 37 scope :cared, ->(user) { where(assignee_id: user) }
38 - scope :authored, ->(user) { where(author_id: user) }  
39 scope :open_for, ->(user) { opened.assigned_to(user) } 38 scope :open_for, ->(user) { opened.assigned_to(user) }
40 39
41 state_machine :state, initial: :opened do 40 state_machine :state, initial: :opened do
app/views/projects/issues/_filter.html.haml
1 = form_tag project_issues_path(@project), method: 'get' do 1 = form_tag project_issues_path(@project), method: 'get' do
2 %fieldset 2 %fieldset
3 %ul.nav.nav-pills.nav-stacked 3 %ul.nav.nav-pills.nav-stacked
4 - %li{class: ("active" if !params[:status] || params[:status].blank?)}  
5 - = link_to project_issues_path(@project, status: nil) do  
6 - Open  
7 - %li{class: ("active" if params[:status] == 'assigned-to-me')}  
8 - = link_to project_issues_path(@project, status: 'assigned-to-me') do 4 + %li{class: ("active" if params[:scope].blank?)}
  5 + = link_to project_filter_path(scope: nil) do
  6 + Everyone's
  7 + %li{class: ("active" if params[:scope] == 'assigned-to-me')}
  8 + = link_to project_filter_path(scope: 'assigned-to-me') do
9 Assigned to me 9 Assigned to me
10 - %li{class: ("active" if params[:status] == 'created-by-me')}  
11 - = link_to project_issues_path(@project, status: 'created-by-me') do 10 + %li{class: ("active" if params[:scope] == 'created-by-me')}
  11 + = link_to project_filter_path(scope: 'created-by-me') do
12 Created by me 12 Created by me
13 - %li{class: ("active" if params[:status] == 'closed')}  
14 - = link_to project_issues_path(@project, status: 'closed') do 13 +
  14 + %ul.nav.nav-pills.nav-stacked
  15 + %li{class: ("active" if params[:state].blank?)}
  16 + = link_to project_filter_path(state: nil) do
  17 + Open
  18 + %li{class: ("active" if params[:state] == 'closed')}
  19 + = link_to project_filter_path(state: 'closed') do
15 Closed 20 Closed
16 - %li{class: ("active" if params[:status] == 'all')}  
17 - = link_to project_issues_path(@project, status: 'all') do 21 + %li{class: ("active" if params[:state] == 'all')}
  22 + = link_to project_filter_path(state: 'all') do
18 All 23 All
19 24
20 %fieldset 25 %fieldset
21 - - if %w(status milestone_id assignee_id label_name).select { |k| params[k].present? }.any? 26 + - if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any?
22 = link_to project_issues_path(@project), class: 'cgray pull-right' do 27 = link_to project_issues_path(@project), class: 'cgray pull-right' do
23 %i.icon-remove 28 %i.icon-remove
24 Clear filter 29 Clear filter
app/views/projects/issues/_issues.html.haml
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 %span Update selected issues with &nbsp; 7 %span Update selected issues with &nbsp;
8 = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") 8 = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
9 = select_tag('update[assignee_id]', options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]), prompt: "Assignee") 9 = select_tag('update[assignee_id]', options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]), prompt: "Assignee")
10 - = select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") 10 + = select_tag('update[milestone_id]', options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone")
11 = hidden_field_tag 'update[issues_ids]', [] 11 = hidden_field_tag 'update[issues_ids]', []
12 = hidden_field_tag :status, params[:status] 12 = hidden_field_tag :status, params[:status]
13 = button_tag "Save", class: "btn update_selected_issues btn-small btn-save" 13 = button_tag "Save", class: "btn update_selected_issues btn-small btn-save"
@@ -24,11 +24,11 @@ @@ -24,11 +24,11 @@
24 %b.caret 24 %b.caret
25 %ul.dropdown-menu 25 %ul.dropdown-menu
26 %li 26 %li
27 - = link_to project_issues_with_filter_path(@project, label_name: nil) do 27 + = link_to project_filter_path(label_name: nil) do
28 Any 28 Any
29 - issue_label_names.each do |label_name| 29 - issue_label_names.each do |label_name|
30 %li 30 %li
31 - = link_to project_issues_with_filter_path(@project, label_name: label_name) do 31 + = link_to project_filter_path(label_name: label_name) do
32 %span{class: "label #{label_css_class(label_name)}"} 32 %span{class: "label #{label_css_class(label_name)}"}
33 %i.icon-tag 33 %i.icon-tag
34 = label_name 34 = label_name
@@ -45,13 +45,13 @@ @@ -45,13 +45,13 @@
45 %b.caret 45 %b.caret
46 %ul.dropdown-menu 46 %ul.dropdown-menu
47 %li 47 %li
48 - = link_to project_issues_with_filter_path(@project, assignee_id: nil) do 48 + = link_to project_filter_path(assignee_id: nil) do
49 Any 49 Any
50 - = link_to project_issues_with_filter_path(@project, assignee_id: 0) do 50 + = link_to project_filter_path(assignee_id: 0) do
51 Unassigned 51 Unassigned
52 - @project.team.members.sort_by(&:name).each do |user| 52 - @project.team.members.sort_by(&:name).each do |user|
53 %li 53 %li
54 - = link_to project_issues_with_filter_path(@project, assignee_id: user.id) do 54 + = link_to project_filter_path(assignee_id: user.id) do
55 = image_tag gravatar_icon(user.email), class: "avatar s16", alt: '' 55 = image_tag gravatar_icon(user.email), class: "avatar s16", alt: ''
56 = user.name 56 = user.name
57 57
@@ -68,13 +68,13 @@ @@ -68,13 +68,13 @@
68 %b.caret 68 %b.caret
69 %ul.dropdown-menu 69 %ul.dropdown-menu
70 %li 70 %li
71 - = link_to project_issues_with_filter_path(@project, milestone_id: nil) do 71 + = link_to project_filter_path(milestone_id: nil) do
72 Any 72 Any
73 - = link_to project_issues_with_filter_path(@project, milestone_id: 0) do 73 + = link_to project_filter_path(milestone_id: 0) do
74 None (backlog) 74 None (backlog)
75 - - issues_active_milestones.each do |milestone| 75 + - project_active_milestones.each do |milestone|
76 %li 76 %li
77 - = link_to project_issues_with_filter_path(@project, milestone_id: milestone.id) do 77 + = link_to project_filter_path(milestone_id: milestone.id) do
78 %strong= milestone.title 78 %strong= milestone.title
79 %small.light= milestone.expires_at 79 %small.light= milestone.expires_at
80 80
app/views/projects/issues/index.html.haml
@@ -18,6 +18,6 @@ @@ -18,6 +18,6 @@
18 18
19 .row 19 .row
20 .span3 20 .span3
21 - = render 'filter', entity: 'issue' 21 + = render 'shared/project_filter', project_entities_path: project_issues_path(@project)
22 .span9.issues-holder 22 .span9.issues-holder
23 = render "issues" 23 = render "issues"
app/views/projects/merge_requests/index.html.haml
@@ -8,15 +8,57 @@ @@ -8,15 +8,57 @@
8 8
9 .row 9 .row
10 .span3 10 .span3
11 - = render 'filter' 11 + = render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project)
12 .span9 12 .span9
13 .ui-box 13 .ui-box
14 .title 14 .title
15 - = form_tag project_merge_requests_path(@project), id: "merge_requests_search_form", method: :get, class: :left do  
16 - = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee")  
17 - = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone")  
18 - = hidden_field_tag :f, params[:f]  
19 - .clearfix 15 + .mr-filters
  16 + %span Filter by
  17 + .dropdown.inline.prepend-left-10
  18 + %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
  19 + %i.icon-user
  20 + %span.light assignee:
  21 + - if @assignee.present?
  22 + %strong= @assignee.name
  23 + - elsif params[:assignee_id] == "0"
  24 + Unassigned
  25 + - else
  26 + Any
  27 + %b.caret
  28 + %ul.dropdown-menu
  29 + %li
  30 + = link_to project_filter_path(assignee_id: nil) do
  31 + Any
  32 + = link_to project_filter_path(assignee_id: 0) do
  33 + Unassigned
  34 + - @project.team.members.sort_by(&:name).each do |user|
  35 + %li
  36 + = link_to project_filter_path(assignee_id: user.id) do
  37 + = image_tag gravatar_icon(user.email), class: "avatar s16", alt: ''
  38 + = user.name
  39 +
  40 + .dropdown.inline.prepend-left-10
  41 + %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
  42 + %i.icon-time
  43 + %span.light milestone:
  44 + - if @milestone.present?
  45 + %strong= @milestone.title
  46 + - elsif params[:milestone_id] == "0"
  47 + None (backlog)
  48 + - else
  49 + Any
  50 + %b.caret
  51 + %ul.dropdown-menu
  52 + %li
  53 + = link_to project_filter_path(milestone_id: nil) do
  54 + Any
  55 + = link_to project_filter_path(milestone_id: 0) do
  56 + None (backlog)
  57 + - project_active_milestones.each do |milestone|
  58 + %li
  59 + = link_to project_filter_path(milestone_id: milestone.id) do
  60 + %strong= milestone.title
  61 + %small.light= milestone.expires_at
20 62
21 %ul.well-list.mr-list 63 %ul.well-list.mr-list
22 = render @merge_requests 64 = render @merge_requests
app/views/shared/_filter.html.haml
@@ -25,5 +25,5 @@ @@ -25,5 +25,5 @@
25 - if params[:status].present? || params[:project_id].present? 25 - if params[:status].present? || params[:project_id].present?
26 = link_to filter_path(entity, status: nil, project_id: nil), class: 'pull-right cgray' do 26 = link_to filter_path(entity, status: nil, project_id: nil), class: 'pull-right cgray' do
27 %i.icon-remove 27 %i.icon-remove
28 - Clear filter 28 + %strong Clear filter
29 29
app/views/shared/_project_filter.html.haml 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 += form_tag project_entities_path, method: 'get' do
  2 + %fieldset
  3 + %ul.nav.nav-pills.nav-stacked
  4 + %li{class: ("active" if params[:scope].blank?)}
  5 + = link_to project_filter_path(scope: nil) do
  6 + Everyone's
  7 + %li{class: ("active" if params[:scope] == 'assigned-to-me')}
  8 + = link_to project_filter_path(scope: 'assigned-to-me') do
  9 + Assigned to me
  10 + %li{class: ("active" if params[:scope] == 'created-by-me')}
  11 + = link_to project_filter_path(scope: 'created-by-me') do
  12 + Created by me
  13 +
  14 + %ul.nav.nav-pills.nav-stacked
  15 + %li{class: ("active" if params[:state].blank?)}
  16 + = link_to project_filter_path(state: nil) do
  17 + Open
  18 + %li{class: ("active" if params[:state] == 'closed')}
  19 + = link_to project_filter_path(state: 'closed') do
  20 + Closed
  21 + %li{class: ("active" if params[:state] == 'all')}
  22 + = link_to project_filter_path(state: 'all') do
  23 + All
  24 +
  25 + %fieldset
  26 + - if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any?
  27 + = link_to project_entities_path, class: 'cgray pull-right' do
  28 + %i.icon-remove
  29 + %strong Clear filter
  30 +
  31 +