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