Commit dfbbc806 authored by Stan Hu's avatar Stan Hu

Support filtering by "Any" milestone or issue and fix "No Milestone" and "No Label" filters

Closes #2619

Closes https://github.com/gitlabhq/gitlabhq/issues/9631
parent cc8c91a1
...@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.1.0 (unreleased) v 8.1.0 (unreleased)
- Add support for creating directories from Files page (Stan Hu) - Add support for creating directories from Files page (Stan Hu)
- Support filtering by "Any" milestone or issue and fix "No Milestone" and "No Label" filters (Stan Hu)
- Fix bug where transferring a project would result in stale commit links (Stan Hu) - Fix bug where transferring a project would result in stale commit links (Stan Hu)
- Include full path of source and target branch names in New Merge Request page (Stan Hu) - Include full path of source and target branch names in New Merge Request page (Stan Hu)
- Add user preference to view activities as default dashboard (Stan Hu) - Add user preference to view activities as default dashboard (Stan Hu)
......
...@@ -72,11 +72,15 @@ class IssuableFinder ...@@ -72,11 +72,15 @@ class IssuableFinder
params[:milestone_title].present? params[:milestone_title].present?
end end
def no_milestones?
milestones? && params[:milestone_title] == Milestone::None.title
end
def milestones def milestones
return @milestones if defined?(@milestones) return @milestones if defined?(@milestones)
@milestones = @milestones =
if milestones? && params[:milestone_title] != Milestone::None.title if milestones?
Milestone.where(title: params[:milestone_title]) Milestone.where(title: params[:milestone_title])
else else
nil nil
...@@ -183,8 +187,12 @@ class IssuableFinder ...@@ -183,8 +187,12 @@ class IssuableFinder
def by_milestone(items) def by_milestone(items)
if milestones? if milestones?
if no_milestones?
items = items.where(milestone_id: [-1, nil])
else
items = items.where(milestone_id: milestones.try(:pluck, :id)) items = items.where(milestone_id: milestones.try(:pluck, :id))
end end
end
items items
end end
...@@ -207,6 +215,11 @@ class IssuableFinder ...@@ -207,6 +215,11 @@ class IssuableFinder
def by_label(items) def by_label(items)
if params[:label_name].present? if params[:label_name].present?
if params[:label_name] == Label::None.title
item_ids = LabelLink.where(target_type: klass.name).pluck(:target_id)
items = items.where('id NOT IN (?)', item_ids)
else
label_names = params[:label_name].split(",") label_names = params[:label_name].split(",")
item_ids = LabelLink.joins(:label). item_ids = LabelLink.joins(:label).
...@@ -215,6 +228,7 @@ class IssuableFinder ...@@ -215,6 +228,7 @@ class IssuableFinder
items = items.where(id: item_ids) items = items.where(id: item_ids)
end end
end
items items
end end
......
...@@ -93,7 +93,9 @@ module LabelsHelper ...@@ -93,7 +93,9 @@ module LabelsHelper
end end
def project_labels_options(project) def project_labels_options(project)
options_from_collection_for_select(project.labels, 'name', 'name', params[:label_name]) labels = project.labels.to_a
labels.unshift(Label::None)
options_from_collection_for_select(labels, 'name', 'name', params[:label_name])
end end
# Required for Gitlab::Markdown::LabelReferenceFilter # Required for Gitlab::Markdown::LabelReferenceFilter
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
class Label < ActiveRecord::Base class Label < ActiveRecord::Base
include Referable include Referable
# Represents a "No Label" state used for filtering Issues and Merge
# Requests that have no label assigned.
None = Struct.new(:title, :name).new('No Label', 'No Label')
DEFAULT_COLOR = '#428BCA' DEFAULT_COLOR = '#428BCA'
......
...@@ -39,13 +39,13 @@ ...@@ -39,13 +39,13 @@
.filter-item.inline.milestone-filter .filter-item.inline.milestone-filter
= select_tag('milestone_title', projects_milestones_options, = select_tag('milestone_title', projects_milestones_options,
class: 'select2 trigger-submit', include_blank: true, class: 'select2 trigger-submit', include_blank: 'Any',
data: {placeholder: 'Milestone'}) data: {placeholder: 'Milestone'})
- if @project - if @project
.filter-item.inline.labels-filter .filter-item.inline.labels-filter
= select_tag('label_name', project_labels_options(@project), = select_tag('label_name', project_labels_options(@project),
class: 'select2 trigger-submit', include_blank: true, class: 'select2 trigger-submit', include_blank: 'Any',
data: {placeholder: 'Label'}) data: {placeholder: 'Label'})
.pull-right .pull-right
......
...@@ -6,9 +6,11 @@ describe IssuesFinder do ...@@ -6,9 +6,11 @@ describe IssuesFinder do
let(:project1) { create(:project) } let(:project1) { create(:project) }
let(:project2) { create(:project) } let(:project2) { create(:project) }
let(:milestone) { create(:milestone, project: project1) } let(:milestone) { create(:milestone, project: project1) }
let(:label) { create(:label, project: project2) }
let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone) } let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone) }
let(:issue2) { create(:issue, author: user, assignee: user, project: project2) } let(:issue2) { create(:issue, author: user, assignee: user, project: project2) }
let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) } let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) }
let!(:label_link) { create(:label_link, label: label, target: issue2) }
before do before do
project1.team << [user, :master] project1.team << [user, :master]
...@@ -48,6 +50,24 @@ describe IssuesFinder do ...@@ -48,6 +50,24 @@ describe IssuesFinder do
expect(issues).to eq([issue1]) expect(issues).to eq([issue1])
end end
it 'should filter by no milestone id' do
params = { scope: "all", milestone_title: Milestone::None.title, state: 'opened' }
issues = IssuesFinder.new(user, params).execute
expect(issues).to match_array([issue2, issue3])
end
it 'should filter by label name' do
params = { scope: "all", label_name: label.title, state: 'opened' }
issues = IssuesFinder.new(user, params).execute
expect(issues).to eq([issue2])
end
it 'should filter by no label name' do
params = { scope: "all", label_name: Label::None.title, state: 'opened' }
issues = IssuesFinder.new(user, params).execute
expect(issues).to match_array([issue1, issue3])
end
it 'should be empty for unauthorized user' do it 'should be empty for unauthorized user' do
params = { scope: "all", state: 'opened' } params = { scope: "all", state: 'opened' }
issues = IssuesFinder.new(nil, params).execute issues = IssuesFinder.new(nil, params).execute
......
...@@ -14,6 +14,11 @@ describe LabelsHelper do ...@@ -14,6 +14,11 @@ describe LabelsHelper do
expect(label).not_to receive(:project) expect(label).not_to receive(:project)
link_to_label(label) link_to_label(label)
end end
it 'includes option for "No Label"' do
result = project_labels_options(project)
expect(result).to include('No Label')
end
end end
context 'without @project set' do context 'without @project set' do
......
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