Commit b8993fd5 authored by Alex Kalderimis's avatar Alex Kalderimis

Merge branch 'issue_322686-negated_filters' into 'master'

Support epic board lists negated filters on GraphQL

See merge request gitlab-org/gitlab!57001
parents 47d8b264 0896cb7d
......@@ -129,6 +129,8 @@ class EpicsFinder < IssuableFinder
# API endpoints send in `nil` values so we test if there are any non-nil
return items unless not_params&.values&.any?
items = by_negated_my_reaction_emoji(items)
by_negated_label(items)
end
......
......@@ -5,6 +5,13 @@ module Types
class BoardEpicInputType < BoardIssuableInputBaseType
graphql_name 'EpicFilters'
class NegatedEpicBoardIssueInputType < BoardIssuableInputBaseType
end
argument :not, NegatedEpicBoardIssueInputType,
required: false,
description: 'List of epic negated params. Warning: this argument is experimental and a subject to change in the future.'
argument :search, GraphQL::STRING_TYPE,
required: false,
description: 'Search query for epic title or description.'
......
---
title: Support epic board list negated filter params
merge_request: 57001
author:
type: added
......@@ -673,6 +673,25 @@ RSpec.describe EpicsFinder do
end
end
end
context 'with negated reaction emoji' do
let_it_be(:awarded_emoji) { create(:award_emoji, name: 'thumbsup', awardable: epic3, user: search_user) }
let_it_be(:params) { { not: { my_reaction_emoji: awarded_emoji.name } } }
it 'returns all epics without given emoji name' do
expect(epics(params)).to contain_exactly(epic1, epic2)
end
context 'when not_issuable_queries is disabled' do
before do
stub_feature_flags(not_issuable_queries: false)
end
it 'returns epics that include negated params' do
expect(epics(params)).to contain_exactly(epic1, epic2, epic3)
end
end
end
end
end
end
......
......@@ -41,43 +41,56 @@ RSpec.describe Resolvers::Boards::BoardListEpicsResolver do
expect(result.to_a).to eq([list1_epic2, list1_epic1])
end
context 'with filters' do
context 'when filtering' do
let_it_be(:production_label) { create(:group_label, group: group, name: 'production') }
let_it_be(:list1_epic3) { create(:labeled_epic, group: group, labels: [development, production_label], title: 'filter_this 1') }
let_it_be(:list1_epic4) { create(:labeled_epic, group: group, labels: [development], description: 'filter_this 2') }
let_it_be(:awarded_emoji) { create(:award_emoji, name: 'thumbsup', awardable: list1_epic1, user: user) }
it 'filters epics by label' do
args = { filters: { label_name: [production_label.title] } }
subject(:results) { resolve(described_class, ctx: { current_user: user }, obj: list1, args: args) }
result = resolve_board_list_epics(args: args)
context 'by label' do
let(:args) { { filters: { label_name: [production_label.title] } } }
expect(result).to contain_exactly(list1_epic3)
it { is_expected.to contain_exactly(list1_epic3) }
end
it 'filters epics by author' do
args = { filters: { author_username: list1_epic4.author.username } }
context 'by author' do
let(:args) { { filters: { author_username: list1_epic4.author.username } } }
result = resolve_board_list_epics(args: args)
expect(result).to contain_exactly(list1_epic4)
it { is_expected.to contain_exactly(list1_epic4) }
end
it 'filters epics by reaction emoji' do
emoji_name = 'thumbsup'
create(:award_emoji, name: emoji_name, awardable: list1_epic1, user: user)
args = { filters: { my_reaction_emoji: emoji_name } }
context 'by reaction emoji' do
let(:args) { { filters: { my_reaction_emoji: awarded_emoji.name } } }
it { is_expected.to contain_exactly(list1_epic1) }
end
result = resolve_board_list_epics(args: args)
context 'by title and description' do
let(:args) { { filters: { search: 'filter_this' } } }
expect(result).to contain_exactly(list1_epic1)
it { is_expected.to contain_exactly(list1_epic3, list1_epic4) }
end
it 'filters epics by title and description' do
args = { filters: { search: 'filter_this' } }
context 'with negated filters' do
context 'by label' do
let(:args) { { filters: { not: { label_name: [production_label.title] } } } }
it { is_expected.to contain_exactly(list1_epic1, list1_epic2, list1_epic4) }
end
context 'by author' do
let(:args) { { filters: { not: { author_username: list1_epic2.author.username } } } }
it { is_expected.to contain_exactly(list1_epic1, list1_epic3, list1_epic4) }
end
result = resolve_board_list_epics(args: args)
context 'by emoji' do
let(:args) { { filters: { not: { my_reaction_emoji: awarded_emoji.name } } } }
expect(result).to contain_exactly(list1_epic3, list1_epic4)
it { is_expected.to contain_exactly(list1_epic2, list1_epic3, list1_epic4) }
end
end
end
end
......
......@@ -56,7 +56,7 @@ RSpec.describe 'get list of epics for an epic board list' do
end
end
context 'filters' do
context 'with filters' do
let(:epic_fields) { 'id' }
it 'finds only epics matching the filter' do
......@@ -68,5 +68,17 @@ RSpec.describe 'get list of epics for an epic board list' do
boards = graphql_data_at(*data_path, :nodes, :id)
expect(boards).to contain_exactly(global_id_of(epic3))
end
context 'when negated' do
it 'finds only epics matching the negated filter' do
filter_params = { filters: { not: { label_name: [staging.title] } } }
query = pagination_query(filter_params)
post_graphql(query, current_user: current_user)
boards = graphql_data_at(*data_path, :nodes, :id)
expect(boards).to contain_exactly(global_id_of(epic1), global_id_of(epic2))
end
end
end
end
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