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 |