Commit b76948e6c92ce445249116ef86dbbd4d0b57573a
1 parent
983bf359
Exists in
master
and in
4 other branches
Added sorting to project issues page
Showing
7 changed files
with
206 additions
and
0 deletions
Show diff stats
CHANGELOG
app/contexts/issues/list_context.rb
... | ... | @@ -29,8 +29,26 @@ module Issues |
29 | 29 | if params[:milestone_id].present? |
30 | 30 | @issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id])) |
31 | 31 | end |
32 | + | |
33 | + # Sort by :sort param | |
34 | + @issues = sort(@issues, params[:sort]) | |
32 | 35 | |
33 | 36 | @issues |
34 | 37 | end |
38 | + | |
39 | + private | |
40 | + | |
41 | + def sort(issues, condition) | |
42 | + case condition | |
43 | + when 'newest' then issues.except(:order).order('created_at DESC') | |
44 | + when 'oldest' then issues.except(:order).order('created_at ASC') | |
45 | + when 'recently_updated' then issues.except(:order).order('updated_at DESC') | |
46 | + when 'last_updated' then issues.except(:order).order('updated_at ASC') | |
47 | + when 'milestone_due_soon' then issues.except(:order).joins(:milestone).order("milestones.due_date ASC") | |
48 | + when 'milestone_due_later' then issues.except(:order).joins(:milestone).order("milestones.due_date DESC") | |
49 | + else issues | |
50 | + end | |
51 | + end | |
52 | + | |
35 | 53 | end |
36 | 54 | end | ... | ... |
app/controllers/projects/issues_controller.rb
... | ... | @@ -23,6 +23,9 @@ class Projects::IssuesController < Projects::ApplicationController |
23 | 23 | assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] |
24 | 24 | @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero? |
25 | 25 | @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? |
26 | + sort_param = params[:sort] || 'newest' | |
27 | + @sort = sort_param.humanize unless sort_param.empty? | |
28 | + | |
26 | 29 | |
27 | 30 | respond_to do |format| |
28 | 31 | format.html # index.html.erb | ... | ... |
app/helpers/projects_helper.rb
app/views/projects/issues/_issues.html.haml
... | ... | @@ -78,6 +78,26 @@ |
78 | 78 | %strong= milestone.title |
79 | 79 | %small.light= milestone.expires_at |
80 | 80 | |
81 | + .dropdown.inline.prepend-left-10 | |
82 | + %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"} | |
83 | + %span.light sort: | |
84 | + = @sort | |
85 | + %b.caret | |
86 | + %ul.dropdown-menu | |
87 | + %li | |
88 | + = link_to project_filter_path(sort: 'newest') do | |
89 | + Newest | |
90 | + = link_to project_filter_path(sort: 'oldest') do | |
91 | + Oldest | |
92 | + = link_to project_filter_path(sort: 'recently_updated') do | |
93 | + Recently updated | |
94 | + = link_to project_filter_path(sort: 'last_updated') do | |
95 | + Last updated | |
96 | + = link_to project_filter_path(sort: 'milestone_due_soon') do | |
97 | + Milestone due soon | |
98 | + = link_to project_filter_path(sort: 'milestone_due_later') do | |
99 | + Milestone due later | |
100 | + | |
81 | 101 | |
82 | 102 | %ul.well-list.issues-list |
83 | 103 | = render @issues | ... | ... |
... | ... | @@ -0,0 +1,77 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe Issues::ListContext do | |
4 | + | |
5 | + let(:user) { create(:user) } | |
6 | + let(:project) { create(:project, creator: user) } | |
7 | + | |
8 | + titles = ['foo','bar','baz'] | |
9 | + titles.each_with_index do |title, index| | |
10 | + let!(title.to_sym) { create(:issue, title: title, project: project, created_at: Time.now - (index * 60)) } | |
11 | + end | |
12 | + | |
13 | + describe 'sorting' do | |
14 | + | |
15 | + it 'sorts by newest' do | |
16 | + params = {:sort => 'newest'} | |
17 | + | |
18 | + issues = Issues::ListContext.new(project, user, params).execute | |
19 | + issues.first.should eq foo | |
20 | + end | |
21 | + | |
22 | + it 'sorts by oldest' do | |
23 | + params = {:sort => 'oldest'} | |
24 | + | |
25 | + issues = Issues::ListContext.new(project, user, params).execute | |
26 | + issues.first.should eq baz | |
27 | + end | |
28 | + | |
29 | + it 'sorts by recently updated' do | |
30 | + params = {:sort => 'recently_updated'} | |
31 | + baz.updated_at = Time.now + 10 | |
32 | + baz.save | |
33 | + | |
34 | + issues = Issues::ListContext.new(project, user, params).execute | |
35 | + issues.first.should eq baz | |
36 | + end | |
37 | + | |
38 | + it 'sorts by least recently updated' do | |
39 | + params = {:sort => 'last_updated'} | |
40 | + bar.updated_at = Time.now - 10 | |
41 | + bar.save | |
42 | + | |
43 | + issues = Issues::ListContext.new(project, user, params).execute | |
44 | + issues.first.should eq bar | |
45 | + end | |
46 | + | |
47 | + describe 'sorting by milestone' do | |
48 | + | |
49 | + let(:newer_due_milestone) { create(:milestone, :due_date => '2013-12-11') } | |
50 | + let(:later_due_milestone) { create(:milestone, :due_date => '2013-12-12') } | |
51 | + | |
52 | + before :each do | |
53 | + foo.milestone = newer_due_milestone | |
54 | + foo.save | |
55 | + bar.milestone = later_due_milestone | |
56 | + bar.save | |
57 | + end | |
58 | + | |
59 | + it 'sorts by most recently due milestone' do | |
60 | + params = {:sort => 'milestone_due_soon'} | |
61 | + | |
62 | + issues = Issues::ListContext.new(project, user, params).execute | |
63 | + issues.first.should eq foo | |
64 | + | |
65 | + end | |
66 | + | |
67 | + it 'sorts by least recently due milestone' do | |
68 | + params = {:sort => 'milestone_due_later'} | |
69 | + | |
70 | + issues = Issues::ListContext.new(project, user, params).execute | |
71 | + issues.first.should eq bar | |
72 | + end | |
73 | + | |
74 | + end | |
75 | + end | |
76 | + | |
77 | +end | ... | ... |
spec/features/issues_spec.rb
... | ... | @@ -95,4 +95,87 @@ describe "Issues" do |
95 | 95 | page.should have_content 'gitlab' |
96 | 96 | end |
97 | 97 | end |
98 | + | |
99 | + describe 'filter issue' do | |
100 | + titles = ['foo','bar','baz'] | |
101 | + titles.each_with_index do |title, index| | |
102 | + let!(title.to_sym) { create(:issue, title: title, project: project, created_at: Time.now - (index * 60)) } | |
103 | + end | |
104 | + let(:newer_due_milestone) { create(:milestone, :due_date => '2013-12-11') } | |
105 | + let(:later_due_milestone) { create(:milestone, :due_date => '2013-12-12') } | |
106 | + | |
107 | + it 'sorts by newest' do | |
108 | + visit project_issues_path(project, sort: 'newest') | |
109 | + | |
110 | + page.should have_selector("ul.issues-list li:first-child", :text => 'foo') | |
111 | + page.should have_selector("ul.issues-list li:last-child", :text => 'baz') | |
112 | + end | |
113 | + | |
114 | + it 'sorts by oldest' do | |
115 | + visit project_issues_path(project, sort: 'oldest') | |
116 | + | |
117 | + page.should have_selector("ul.issues-list li:first-child", :text => 'baz') | |
118 | + page.should have_selector("ul.issues-list li:last-child", :text => 'foo') | |
119 | + end | |
120 | + | |
121 | + it 'sorts by most recently updated' do | |
122 | + baz.updated_at = Time.now + 100 | |
123 | + baz.save | |
124 | + visit project_issues_path(project, sort: 'recently_updated') | |
125 | + | |
126 | + page.should have_selector("ul.issues-list li:first-child", :text => 'baz') | |
127 | + end | |
128 | + | |
129 | + it 'sorts by least recently updated' do | |
130 | + baz.updated_at = Time.now - 100 | |
131 | + baz.save | |
132 | + visit project_issues_path(project, sort: 'last_updated') | |
133 | + | |
134 | + page.should have_selector("ul.issues-list li:first-child", :text => 'baz') | |
135 | + end | |
136 | + | |
137 | + describe 'sorting by milestone' do | |
138 | + | |
139 | + before :each do | |
140 | + foo.milestone = newer_due_milestone | |
141 | + foo.save | |
142 | + bar.milestone = later_due_milestone | |
143 | + bar.save | |
144 | + end | |
145 | + | |
146 | + it 'sorts by recently due milestone' do | |
147 | + visit project_issues_path(project, sort: 'milestone_due_soon') | |
148 | + | |
149 | + page.should have_selector("ul.issues-list li:first-child", :text => 'foo') | |
150 | + end | |
151 | + | |
152 | + it 'sorts by least recently due milestone' do | |
153 | + visit project_issues_path(project, sort: 'milestone_due_later') | |
154 | + | |
155 | + page.should have_selector("ul.issues-list li:first-child", :text => 'bar') | |
156 | + end | |
157 | + end | |
158 | + | |
159 | + describe 'combine filter and sort' do | |
160 | + | |
161 | + let(:user2) { create(:user) } | |
162 | + | |
163 | + before :each do | |
164 | + foo.assignee = user2 | |
165 | + foo.save | |
166 | + bar.assignee = user2 | |
167 | + bar.save | |
168 | + end | |
169 | + | |
170 | + it 'sorts with a filter applied' do | |
171 | + visit project_issues_path(project, sort: 'oldest', assignee_id: user2.id) | |
172 | + | |
173 | + page.should have_selector("ul.issues-list li:first-child", :text => 'bar') | |
174 | + page.should have_selector("ul.issues-list li:last-child", :text => 'foo') | |
175 | + page.should_not have_content 'baz' | |
176 | + | |
177 | + end | |
178 | + end | |
179 | + end | |
180 | + | |
98 | 181 | end | ... | ... |