Commit 25741c97a2ae1446fe03b86cc5e0bd5f49b41cf6
Exists in
spb-stable
and in
3 other branches
Merge pull request #6350 from tudorpavel/filter-by-multiple-labels
Add feature to filter issues by multiple labels
Showing
6 changed files
with
134 additions
and
19 deletions
Show diff stats
app/assets/stylesheets/main/variables.scss
@@ -5,6 +5,7 @@ $primary_color: #2FA0BB; | @@ -5,6 +5,7 @@ $primary_color: #2FA0BB; | ||
5 | $link_color: #3A89A3; | 5 | $link_color: #3A89A3; |
6 | $style_color: #474D57; | 6 | $style_color: #474D57; |
7 | $bg_style_color: #2299BB; | 7 | $bg_style_color: #2299BB; |
8 | +$list-group-active-bg: $bg_style_color; | ||
8 | $hover: #D9EDF7; | 9 | $hover: #D9EDF7; |
9 | 10 | ||
10 | /** | 11 | /** |
app/helpers/projects_helper.rb
@@ -64,6 +64,31 @@ module ProjectsHelper | @@ -64,6 +64,31 @@ module ProjectsHelper | ||
64 | project_nav_tabs.include? name | 64 | project_nav_tabs.include? name |
65 | end | 65 | end |
66 | 66 | ||
67 | + def selected_label?(label_name) | ||
68 | + params[:label_name].to_s.split(',').include?(label_name) | ||
69 | + end | ||
70 | + | ||
71 | + def labels_filter_path(label_name) | ||
72 | + label_name = | ||
73 | + if selected_label?(label_name) | ||
74 | + params[:label_name].split(',').reject { |l| l == label_name }.join(',') | ||
75 | + elsif params[:label_name].present? | ||
76 | + "#{params[:label_name]},#{label_name}" | ||
77 | + else | ||
78 | + label_name | ||
79 | + end | ||
80 | + | ||
81 | + project_filter_path(label_name: label_name) | ||
82 | + end | ||
83 | + | ||
84 | + def label_filter_class(label_name) | ||
85 | + if selected_label?(label_name) | ||
86 | + 'list-group-item active' | ||
87 | + else | ||
88 | + 'list-group-item' | ||
89 | + end | ||
90 | + end | ||
91 | + | ||
67 | def project_filter_path(options={}) | 92 | def project_filter_path(options={}) |
68 | exist_opts = { | 93 | exist_opts = { |
69 | state: params[:state], | 94 | state: params[:state], |
app/views/projects/issues/_issues.html.haml
@@ -2,25 +2,6 @@ | @@ -2,25 +2,6 @@ | ||
2 | .check-all-holder | 2 | .check-all-holder |
3 | = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" | 3 | = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" |
4 | .issues-filters | 4 | .issues-filters |
5 | - .dropdown.inline | ||
6 | - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} | ||
7 | - %i.icon-tags | ||
8 | - %span.light labels: | ||
9 | - - if params[:label_name].present? | ||
10 | - %strong= params[:label_name] | ||
11 | - - else | ||
12 | - Any | ||
13 | - %b.caret | ||
14 | - %ul.dropdown-menu | ||
15 | - %li | ||
16 | - = link_to project_filter_path(label_name: nil) do | ||
17 | - Any | ||
18 | - - issue_label_names.each do |label_name| | ||
19 | - %li | ||
20 | - = link_to project_filter_path(label_name: label_name) do | ||
21 | - %span{class: "label #{label_css_class(label_name)}"} | ||
22 | - %i.icon-tag | ||
23 | - = label_name | ||
24 | .dropdown.inline.prepend-left-10 | 5 | .dropdown.inline.prepend-left-10 |
25 | %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} | 6 | %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} |
26 | %i.icon-user | 7 | %i.icon-user |
app/views/shared/_project_filter.html.haml
@@ -27,6 +27,18 @@ | @@ -27,6 +27,18 @@ | ||
27 | All | 27 | All |
28 | 28 | ||
29 | %fieldset | 29 | %fieldset |
30 | + %legend Labels | ||
31 | + %ul.list-group | ||
32 | + - issue_label_names.each do |label_name| | ||
33 | + = link_to labels_filter_path(label_name), class: label_filter_class(label_name) do | ||
34 | + %span{class: "label #{label_css_class(label_name)}"} | ||
35 | + %i.icon-tag | ||
36 | + = label_name | ||
37 | + - if selected_label?(label_name) | ||
38 | + .pull-right | ||
39 | + %i.icon-remove | ||
40 | + | ||
41 | + %fieldset | ||
30 | - if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any? | 42 | - if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any? |
31 | = link_to project_entities_path, class: 'cgray pull-right' do | 43 | = link_to project_entities_path, class: 'cgray pull-right' do |
32 | %i.icon-remove | 44 | %i.icon-remove |
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +Feature: Project Filter Labels | ||
2 | + Background: | ||
3 | + Given I sign in as a user | ||
4 | + And I own project "Shop" | ||
5 | + And project "Shop" has issue "Bugfix1" with tags: "bug", "feature" | ||
6 | + And project "Shop" has issue "Bugfix2" with tags: "bug", "enhancement" | ||
7 | + And project "Shop" has issue "Feature1" with tags: "feature" | ||
8 | + Given I visit project "Shop" issues page | ||
9 | + | ||
10 | + Scenario: I should see project issues | ||
11 | + Then I should see "bug" in labels filter | ||
12 | + And I should see "feature" in labels filter | ||
13 | + And I should see "enhancement" in labels filter | ||
14 | + | ||
15 | + Scenario: I filter by one label | ||
16 | + Given I click link "bug" | ||
17 | + Then I should see "Bugfix1" in issues list | ||
18 | + And I should see "Bugfix2" in issues list | ||
19 | + And I should not see "Feature1" in issues list | ||
20 | + | ||
21 | + Scenario: I filter by two labels | ||
22 | + Given I click link "bug" | ||
23 | + And I click link "feature" | ||
24 | + Then I should see "Bugfix1" in issues list | ||
25 | + And I should not see "Bugfix2" in issues list | ||
26 | + And I should not see "Feature1" in issues list |
@@ -0,0 +1,70 @@ | @@ -0,0 +1,70 @@ | ||
1 | +class ProjectFilterLabels < Spinach::FeatureSteps | ||
2 | + include SharedAuthentication | ||
3 | + include SharedProject | ||
4 | + include SharedPaths | ||
5 | + | ||
6 | + Then 'I should see "bug" in labels filter' do | ||
7 | + within ".list-group" do | ||
8 | + page.should have_content "bug" | ||
9 | + end | ||
10 | + end | ||
11 | + | ||
12 | + And 'I should see "feature" in labels filter' do | ||
13 | + within ".list-group" do | ||
14 | + page.should have_content "feature" | ||
15 | + end | ||
16 | + end | ||
17 | + | ||
18 | + And 'I should see "enhancement" in labels filter' do | ||
19 | + within ".list-group" do | ||
20 | + page.should have_content "enhancement" | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | + Then 'I should see "Bugfix1" in issues list' do | ||
25 | + within ".issues-list" do | ||
26 | + page.should have_content "Bugfix1" | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + And 'I should see "Bugfix2" in issues list' do | ||
31 | + within ".issues-list" do | ||
32 | + page.should have_content "Bugfix2" | ||
33 | + end | ||
34 | + end | ||
35 | + | ||
36 | + And 'I should not see "Bugfix2" in issues list' do | ||
37 | + within ".issues-list" do | ||
38 | + page.should_not have_content "Bugfix2" | ||
39 | + end | ||
40 | + end | ||
41 | + | ||
42 | + And 'I should not see "Feature1" in issues list' do | ||
43 | + within ".issues-list" do | ||
44 | + page.should_not have_content "Feature1" | ||
45 | + end | ||
46 | + end | ||
47 | + | ||
48 | + Given 'I click link "bug"' do | ||
49 | + click_link "bug" | ||
50 | + end | ||
51 | + | ||
52 | + Given 'I click link "feature"' do | ||
53 | + click_link "feature" | ||
54 | + end | ||
55 | + | ||
56 | + And 'project "Shop" has issue "Bugfix1" with tags: "bug", "feature"' do | ||
57 | + project = Project.find_by(name: "Shop") | ||
58 | + create(:issue, title: "Bugfix1", project: project, label_list: ['bug', 'feature']) | ||
59 | + end | ||
60 | + | ||
61 | + And 'project "Shop" has issue "Bugfix2" with tags: "bug", "enhancement"' do | ||
62 | + project = Project.find_by(name: "Shop") | ||
63 | + create(:issue, title: "Bugfix2", project: project, label_list: ['bug', 'enhancement']) | ||
64 | + end | ||
65 | + | ||
66 | + And 'project "Shop" has issue "Feature1" with tags: "feature"' do | ||
67 | + project = Project.find_by(name: "Shop") | ||
68 | + create(:issue, title: "Feature1", project: project, label_list: 'feature') | ||
69 | + end | ||
70 | +end |