Commit c2fbc4a9 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch...

Merge branch '337045-add-the-ability-to-filter-epic-boards-and-issue-boards-by-my-reaction-emoji-in-graphql' into 'master'

Allow filtering by user reaction on issue boards

See merge request gitlab-org/gitlab!74261
parents 35d156b9 da5b059e
......@@ -42,6 +42,7 @@ export default {
types,
weight,
epicId,
myReactionEmoji,
} = this.filterParams;
const filteredSearchValue = [];
......@@ -89,6 +90,13 @@ export default {
});
}
if (myReactionEmoji) {
filteredSearchValue.push({
type: 'my_reaction_emoji',
value: { data: myReactionEmoji, operator: '=' },
});
}
if (epicId) {
filteredSearchValue.push({
type: 'epic_id',
......@@ -147,6 +155,13 @@ export default {
});
}
if (this.filterParams['not[myReactionEmoji]']) {
filteredSearchValue.push({
type: 'my_reaction_emoji',
value: { data: this.filterParams['not[myReactionEmoji]'], operator: '!=' },
});
}
if (search) {
filteredSearchValue.push(search);
}
......@@ -163,6 +178,7 @@ export default {
types,
weight,
epicId,
myReactionEmoji,
} = this.filterParams;
let notParams = {};
......@@ -177,6 +193,7 @@ export default {
'not[milestone_title]': this.filterParams.not.milestoneTitle,
'not[weight]': this.filterParams.not.weight,
'not[epic_id]': this.filterParams.not.epicId,
'not[my_reaction_emoji]': this.filterParams.not.myReactionEmoji,
},
undefined,
);
......@@ -192,6 +209,7 @@ export default {
types,
weight,
epic_id: getIdFromGraphQLId(epicId),
my_reaction_emoji: myReactionEmoji,
};
},
},
......@@ -249,6 +267,9 @@ export default {
case 'epic_id':
filterParams.epicId = filter.value.data;
break;
case 'my_reaction_emoji':
filterParams.myReactionEmoji = filter.value.data;
break;
case 'filtered-search-term':
if (filter.value.data) plainText.push(filter.value.data);
break;
......
<script>
import { GlFilteredSearchToken } from '@gitlab/ui';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { mapActions } from 'vuex';
import BoardFilteredSearch from 'ee_else_ce/boards/components/board_filtered_search.vue';
import { BoardType } from '~/boards/constants';
import axios from '~/lib/utils/axios_utils';
import issueBoardFilters from '~/boards/issue_board_filters';
import { TYPE_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import { DEFAULT_MILESTONES_GRAPHQL } from '~/vue_shared/components/filtered_search_bar/constants';
import {
DEFAULT_MILESTONES_GRAPHQL,
TOKEN_TITLE_MY_REACTION,
} 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';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
......@@ -33,6 +39,7 @@ export default {
isNot: __('is not'),
},
components: { BoardFilteredSearch },
inject: ['isSignedIn'],
props: {
fullPath: {
type: String,
......@@ -113,6 +120,32 @@ export default {
symbol: '~',
fetchLabels,
},
...(this.isSignedIn
? [
{
type: 'my_reaction_emoji',
title: TOKEN_TITLE_MY_REACTION,
icon: 'thumb-up',
token: EmojiToken,
unique: true,
fetchEmojis: (search = '') => {
// TODO: Switch to GraphQL query when backend is ready: https://gitlab.com/gitlab-org/gitlab/-/issues/339694
return axios
.get(`${gon.relative_url_root || ''}/-/autocomplete/award_emojis`)
.then(({ data }) => {
if (search) {
return {
data: fuzzaldrinPlus.filter(data, search, {
key: ['name'],
}),
};
}
return { data };
});
},
},
]
: []),
{
type: 'milestone_title',
title: milestone,
......
......@@ -13,7 +13,7 @@ import FilteredSearchBoards from '~/boards/filtered_search_boards';
import initBoardsFilteredSearch from '~/boards/mount_filtered_search_issue_boards';
import store from '~/boards/stores';
import toggleFocusMode from '~/boards/toggle_focus';
import { NavigationType, parseBoolean } from '~/lib/utils/common_utils';
import { NavigationType, isLoggedIn, parseBoolean } from '~/lib/utils/common_utils';
import { fullBoardId } from './boards_util';
import boardConfigToggle from './config_toggle';
import initNewBoard from './new_board';
......@@ -110,7 +110,7 @@ export default () => {
});
if (gon?.features?.issueBoardsFilteredSearch) {
initBoardsFilteredSearch(apolloProvider, parseBoolean($boardApp.dataset.epicFeatureAvailable));
initBoardsFilteredSearch(apolloProvider, isLoggedIn());
}
mountBoardApp($boardApp);
......
......@@ -4,7 +4,7 @@ import store from '~/boards/stores';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { queryToObject } from '~/lib/utils/url_utility';
export default (apolloProvider) => {
export default (apolloProvider, isSignedIn) => {
const el = document.getElementById('js-issue-board-filtered-search');
const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true });
......@@ -20,6 +20,7 @@ export default (apolloProvider) => {
el,
provide: {
initialFilterParams,
isSignedIn,
},
store, // TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/324094
apolloProvider,
......
......@@ -12,6 +12,7 @@ describe('IssueBoardFilter', () => {
const createComponent = () => {
wrapper = shallowMount(IssueBoardFilteredSpec, {
propsData: { fullPath: 'gitlab-org', boardType: 'group' },
provide: { isSignedIn: true },
});
};
......
......@@ -3,6 +3,7 @@ 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 EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_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';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
......@@ -438,6 +439,14 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
symbol: '~',
fetchLabels,
},
{
type: 'my_reaction_emoji',
icon: 'thumb-up',
title: 'My-Reaction',
unique: true,
token: EmojiToken,
fetchEmojis: expect.any(Function),
},
{
icon: 'clock',
title: __('Milestone'),
......
......@@ -11,11 +11,11 @@ describe('IssueBoardFilter', () => {
const findBoardsFilteredSearch = () => wrapper.findComponent(BoardFilteredSearch);
const createComponent = ({ epicFeatureAvailable = false } = {}) => {
const createComponent = ({ isSignedIn = false } = {}) => {
wrapper = shallowMount(IssueBoardFilteredSpec, {
propsData: { fullPath: 'gitlab-org', boardType: 'group' },
provide: {
epicFeatureAvailable,
isSignedIn,
},
});
};
......@@ -45,10 +45,24 @@ describe('IssueBoardFilter', () => {
expect(findBoardsFilteredSearch().exists()).toBe(true);
});
it('passes the correct tokens to BoardFilteredSearch', () => {
const tokens = mockTokens(fetchLabelsSpy, fetchAuthorsSpy, wrapper.vm.fetchMilestones);
it.each`
isSignedIn
${true}
${false}
`(
'passes the correct tokens to BoardFilteredSearch when user sign in is $isSignedIn',
({ isSignedIn }) => {
createComponent({ isSignedIn });
expect(findBoardsFilteredSearch().props('tokens')).toEqual(tokens);
});
const tokens = mockTokens(
fetchLabelsSpy,
fetchAuthorsSpy,
wrapper.vm.fetchMilestones,
isSignedIn,
);
expect(findBoardsFilteredSearch().props('tokens')).toEqual(tokens);
},
);
});
});
......@@ -4,6 +4,7 @@ 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';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
......@@ -549,7 +550,16 @@ export const mockMoveData = {
...mockMoveIssueParams,
};
export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
export const mockEmojiToken = {
type: 'my_reaction_emoji',
icon: 'thumb-up',
title: 'My-Reaction',
unique: true,
token: EmojiToken,
fetchEmojis: expect.any(Function),
};
export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, hasEmoji) => [
{
icon: 'user',
title: __('Assignee'),
......@@ -590,6 +600,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
symbol: '~',
fetchLabels,
},
...(hasEmoji ? [mockEmojiToken] : []),
{
icon: 'clock',
title: __('Milestone'),
......
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