Commit 7e242b28 authored by Phil Hughes's avatar Phil Hughes

Merge branch '337688-on-graphql-boards-add-support-for-milestone-wildcard-search' into 'master'

Add support for milestoneWildCardId for boards

See merge request gitlab-org/gitlab!74573
parents 574144e1 8ee44515
import { sortBy, cloneDeep } from 'lodash';
import { isGid } from '~/graphql_shared/utils';
import { ListType, MilestoneIDs } from './constants';
import { ListType, MilestoneIDs, AssigneeFilterType, MilestoneFilterType } from './constants';
export function getMilestone() {
return null;
......@@ -186,6 +186,7 @@ export function isListDraggable(list) {
export const FiltersInfo = {
assigneeUsername: {
negatedSupport: true,
remap: (k, v) => (v === AssigneeFilterType.any ? 'assigneeWildcardId' : k),
},
assigneeId: {
// assigneeId should be renamed to assigneeWildcardId.
......@@ -204,6 +205,11 @@ export const FiltersInfo = {
},
milestoneTitle: {
negatedSupport: true,
remap: (k, v) => (Object.values(MilestoneFilterType).includes(v) ? 'milestoneWildcardId' : k),
},
milestoneWildcardId: {
negatedSupport: true,
transform: (val) => val.toUpperCase(),
},
myReactionEmoji: {
negatedSupport: true,
......
<script>
import { pickBy, isEmpty } from 'lodash';
import { mapActions } from 'vuex';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
......@@ -80,7 +80,7 @@ export default {
if (milestoneTitle) {
filteredSearchValue.push({
type: 'milestone_title',
type: 'milestone',
value: { data: milestoneTitle, operator: '=' },
});
}
......@@ -129,7 +129,7 @@ export default {
if (this.filterParams['not[milestoneTitle]']) {
filteredSearchValue.push({
type: 'milestone_title',
type: 'milestone',
value: { data: this.filterParams['not[milestoneTitle]'], operator: '!=' },
});
}
......@@ -242,7 +242,7 @@ export default {
search,
types,
weight,
epic_id: getIdFromGraphQLId(epicId),
epic_id: isGid(epicId) ? getIdFromGraphQLId(epicId) : epicId,
my_reaction_emoji: myReactionEmoji,
release_tag: releaseTag,
};
......@@ -293,7 +293,7 @@ export default {
case 'label_name':
labels.push(filter.value.data);
break;
case 'milestone_title':
case 'milestone':
filterParams.milestoneTitle = filter.value.data;
break;
case 'iteration':
......@@ -326,6 +326,7 @@ export default {
if (plainText.length) {
filterParams.search = plainText.join(' ');
}
return filterParams;
},
},
......
......@@ -11,7 +11,6 @@ import { TYPE_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import {
DEFAULT_MILESTONES_GRAPHQL,
TOKEN_TITLE_MY_REACTION,
OPERATOR_IS_AND_IS_NOT,
} from '~/vue_shared/components/filtered_search_bar/constants';
......@@ -136,13 +135,12 @@ export default {
]
: []),
{
type: 'milestone_title',
type: 'milestone',
title: milestone,
icon: 'clock',
symbol: '%',
token: MilestoneToken,
unique: true,
defaultMilestones: DEFAULT_MILESTONES_GRAPHQL,
fetchMilestones: this.fetchMilestones,
},
{
......
......@@ -106,6 +106,7 @@ export const FilterFields = {
'authorUsername',
'labelName',
'milestoneTitle',
'milestoneWildcardId',
'myReactionEmoji',
'releaseTag',
'search',
......@@ -114,6 +115,18 @@ export const FilterFields = {
],
};
/* eslint-disable @gitlab/require-i18n-strings */
export const AssigneeFilterType = {
any: 'Any',
};
export const MilestoneFilterType = {
any: 'Any',
none: 'None',
started: 'Started',
upcoming: 'Upcoming',
};
export const DraggableItemTypes = {
card: 'card',
list: 'list',
......
......@@ -28,13 +28,6 @@ export const DEFAULT_MILESTONES = DEFAULT_NONE_ANY.concat([
{ value: FILTER_STARTED, text: __('Started'), title: __('Started') },
]);
export const DEFAULT_MILESTONES_GRAPHQL = [
{ value: 'any', text: __('Any'), title: __('Any') },
{ value: 'none', text: __('None'), title: __('None') },
{ value: '#upcoming', text: __('Upcoming'), title: __('Upcoming') },
{ value: '#started', text: __('Started'), title: __('Started') },
];
export const SortDirection = {
descending: 'descending',
ascending: 'ascending',
......
import { GlFilteredSearchToken } from '@gitlab/ui';
import { __ } from '~/locale';
import { DEFAULT_MILESTONES_GRAPHQL } from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
......@@ -453,10 +452,9 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, fetchIter
icon: 'clock',
title: __('Milestone'),
symbol: '%',
type: 'milestone_title',
type: 'milestone',
token: MilestoneToken,
unique: true,
defaultMilestones: DEFAULT_MILESTONES_GRAPHQL,
fetchMilestones,
},
{
......
......@@ -30,9 +30,7 @@ RSpec.describe 'Issue board filters', :js do
describe 'filters by releases' do
before do
filter_input.click
filter_input.set('release:')
filter_first_suggestion.click # Select `=` operator
set_filter('release')
end
it 'loads all the releases when opened and submit one as filter', :aggregate_failures do
......@@ -47,6 +45,35 @@ RSpec.describe 'Issue board filters', :js do
end
end
describe 'filters by milestone' do
before do
set_filter('milestone')
end
it 'loads all the milestones when opened and submit one as filter', :aggregate_failures do
expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
expect_filtered_search_dropdown_results(filter_dropdown, 6)
expect(filter_dropdown).to have_content('None')
expect(filter_dropdown).to have_content('Any')
expect(filter_dropdown).to have_content('Started')
expect(filter_dropdown).to have_content('Upcoming')
expect(filter_dropdown).to have_content(milestone_1.title)
expect(filter_dropdown).to have_content(milestone_2.title)
click_on milestone_1.title
filter_submit.click
expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
end
end
def set_filter(filter)
filter_input.click
filter_input.set("#{filter}:")
filter_first_suggestion.click # Select `=` operator
end
def expect_filtered_search_dropdown_results(filter_dropdown, count)
expect(filter_dropdown).to have_selector('.gl-new-dropdown-item', count: count)
end
......
......@@ -120,7 +120,7 @@ describe('BoardFilteredSearch', () => {
{ type: 'author_username', value: { data: 'root', operator: '=' } },
{ type: 'label_name', value: { data: 'label', operator: '=' } },
{ type: 'label_name', value: { data: 'label2', operator: '=' } },
{ type: 'milestone_title', value: { data: 'New Milestone', operator: '=' } },
{ type: 'milestone', value: { data: 'New Milestone', operator: '=' } },
{ type: 'types', value: { data: 'INCIDENT', operator: '=' } },
{ type: 'weight', value: { data: '2', operator: '=' } },
{ type: 'iteration', value: { data: '3341', operator: '=' } },
......
......@@ -2,7 +2,6 @@ import { GlFilteredSearchToken } from '@gitlab/ui';
import { keyBy } from 'lodash';
import { ListType } from '~/boards/constants';
import { __ } from '~/locale';
import { DEFAULT_MILESTONES_GRAPHQL } from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
......@@ -599,10 +598,9 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, hasEmoji)
icon: 'clock',
title: __('Milestone'),
symbol: '%',
type: 'milestone_title',
type: 'milestone',
token: MilestoneToken,
unique: true,
defaultMilestones: DEFAULT_MILESTONES_GRAPHQL,
fetchMilestones,
},
{
......
......@@ -11,10 +11,7 @@ import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { sortMilestonesByDueDate } from '~/milestones/milestone_utils';
import {
DEFAULT_MILESTONES,
DEFAULT_MILESTONES_GRAPHQL,
} from '~/vue_shared/components/filtered_search_bar/constants';
import { DEFAULT_MILESTONES } from '~/vue_shared/components/filtered_search_bar/constants';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import { mockMilestoneToken, mockMilestones, mockRegularMilestone } from '../mock_data';
......@@ -199,12 +196,12 @@ describe('MilestoneToken', () => {
beforeEach(() => {
wrapper = createComponent({
active: true,
config: { ...mockMilestoneToken, defaultMilestones: DEFAULT_MILESTONES_GRAPHQL },
config: { ...mockMilestoneToken, defaultMilestones: DEFAULT_MILESTONES },
});
});
it('finds the correct value from the activeToken', () => {
DEFAULT_MILESTONES_GRAPHQL.forEach(({ value, title }) => {
DEFAULT_MILESTONES.forEach(({ value, title }) => {
const activeToken = wrapper.vm.getActiveMilestone([], value);
expect(activeToken.title).toEqual(title);
......
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