Commit 15c06897 authored by Coung Ngo's avatar Coung Ngo

Add milestone wildcard filters to issues page refactor

Add ability to filter issues by milestone None, Any, Upcoming,
and Started values on the issues page refactor.

Also adds merge request count on issues card
parent b6216e88
......@@ -306,7 +306,6 @@ export default {
icon: 'clock',
token: MilestoneToken,
unique: true,
defaultMilestones: [],
fetchMilestones: this.fetchMilestones,
},
{
......
......@@ -5,6 +5,8 @@ import {
FILTER_ANY,
FILTER_CURRENT,
FILTER_NONE,
FILTER_STARTED,
FILTER_UPCOMING,
OPERATOR_IS,
OPERATOR_IS_NOT,
} from '~/vue_shared/components/filtered_search_bar/constants';
......@@ -186,7 +188,13 @@ export const URL_PARAM = 'urlParam';
export const NORMAL_FILTER = 'normalFilter';
export const SPECIAL_FILTER = 'specialFilter';
export const ALTERNATIVE_FILTER = 'alternativeFilter';
export const SPECIAL_FILTER_VALUES = [FILTER_NONE, FILTER_ANY, FILTER_CURRENT];
export const SPECIAL_FILTER_VALUES = [
FILTER_NONE,
FILTER_ANY,
FILTER_CURRENT,
FILTER_UPCOMING,
FILTER_STARTED,
];
export const TOKEN_TYPE_AUTHOR = 'author_username';
export const TOKEN_TYPE_ASSIGNEE = 'assignee_username';
......@@ -231,10 +239,12 @@ export const filters = {
[TOKEN_TYPE_MILESTONE]: {
[API_PARAM]: {
[NORMAL_FILTER]: 'milestoneTitle',
[SPECIAL_FILTER]: 'milestoneWildcardId',
},
[URL_PARAM]: {
[OPERATOR_IS]: {
[NORMAL_FILTER]: 'milestone_title',
[SPECIAL_FILTER]: 'milestone_title',
},
[OPERATOR_IS_NOT]: {
[NORMAL_FILTER]: 'not[milestone_title]',
......
......@@ -12,6 +12,7 @@ query getProjectIssues(
$authorUsername: String
$labelName: [String]
$milestoneTitle: [String]
$milestoneWildcardId: MilestoneWildcardId
$not: NegatedIssueFilterInput
$beforeCursor: String
$afterCursor: String
......@@ -28,6 +29,7 @@ query getProjectIssues(
authorUsername: $authorUsername
labelName: $labelName
milestoneTitle: $milestoneTitle
milestoneWildcardId: $milestoneWildcardId
not: $not
before: $beforeCursor
after: $afterCursor
......
......@@ -7,6 +7,7 @@ query getProjectIssuesCount(
$authorUsername: String
$labelName: [String]
$milestoneTitle: [String]
$milestoneWildcardId: MilestoneWildcardId
$not: NegatedIssueFilterInput
) {
project(fullPath: $projectPath) {
......@@ -18,6 +19,7 @@ query getProjectIssuesCount(
authorUsername: $authorUsername
labelName: $labelName
milestoneTitle: $milestoneTitle
milestoneWildcardId: $milestoneWildcardId
not: $not
) {
count
......
......@@ -7,6 +7,7 @@ fragment IssueFragment on Issue {
downvotes
dueDate
humanTimeEstimate
mergeRequestsCount
moved
title
updatedAt
......
......@@ -21,6 +21,7 @@ import {
SPECIAL_FILTER_VALUES,
TOKEN_TYPE_ASSIGNEE,
TOKEN_TYPE_ITERATION,
TOKEN_TYPE_MILESTONE,
UPDATED_ASC,
UPDATED_DESC,
URL_PARAM,
......@@ -186,8 +187,14 @@ const getFilterType = (data, tokenType = '') =>
? SPECIAL_FILTER
: NORMAL_FILTER;
const isIterationSpecialValue = (tokenType, value) =>
tokenType === TOKEN_TYPE_ITERATION && SPECIAL_FILTER_VALUES.includes(value);
const requiresUpperCaseValue = (tokenType, value) =>
(tokenType === TOKEN_TYPE_ITERATION || tokenType === TOKEN_TYPE_MILESTONE) &&
SPECIAL_FILTER_VALUES.includes(value);
const formatData = (token) =>
requiresUpperCaseValue(token.type, token.value.data)
? token.value.data.toUpperCase()
: token.value.data;
export const convertToApiParams = (filterTokens) => {
const params = {};
......@@ -199,9 +206,7 @@ export const convertToApiParams = (filterTokens) => {
const filterType = getFilterType(token.value.data, token.type);
const field = filters[token.type][API_PARAM][filterType];
const obj = token.value.operator === OPERATOR_IS_NOT ? not : params;
const data = isIterationSpecialValue(token.type, token.value.data)
? token.value.data.toUpperCase()
: token.value.data;
const data = formatData(token);
Object.assign(obj, {
[field]: obj[field] ? [obj[field], data].flat() : data,
});
......
......@@ -7,6 +7,8 @@ export const WEIGHT_TOKEN_SUGGESTIONS_SIZE = 21;
export const FILTER_NONE = 'None';
export const FILTER_ANY = 'Any';
export const FILTER_CURRENT = 'Current';
export const FILTER_UPCOMING = 'Upcoming';
export const FILTER_STARTED = 'Started';
export const OPERATOR_IS = '=';
export const OPERATOR_IS_TEXT = __('is');
......@@ -28,8 +30,8 @@ export const DEFAULT_ITERATIONS = DEFAULT_NONE_ANY.concat([
export const DEFAULT_LABELS = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY];
export const DEFAULT_MILESTONES = DEFAULT_NONE_ANY.concat([
{ value: 'Upcoming', text: __('Upcoming') }, // eslint-disable-line @gitlab/require-i18n-strings
{ value: 'Started', text: __('Started') }, // eslint-disable-line @gitlab/require-i18n-strings
{ value: FILTER_UPCOMING, text: __(FILTER_UPCOMING) },
{ value: FILTER_STARTED, text: __(FILTER_STARTED) },
]);
export const SortDirection = {
......
......@@ -12,6 +12,7 @@ query getProjectIssues(
$authorUsername: String
$labelName: [String]
$milestoneTitle: [String]
$milestoneWildcardId: MilestoneWildcardId
$epicId: String
$iterationId: [ID]
$iterationWildcardId: IterationWildcardId
......@@ -32,6 +33,7 @@ query getProjectIssues(
authorUsername: $authorUsername
labelName: $labelName
milestoneTitle: $milestoneTitle
milestoneWildcardId: $milestoneWildcardId
epicId: $epicId
iterationId: $iterationId
iterationWildcardId: $iterationWildcardId
......
......@@ -7,6 +7,7 @@ query getProjectIssuesCount(
$authorUsername: String
$labelName: [String]
$milestoneTitle: [String]
$milestoneWildcardId: MilestoneWildcardId
$epicId: String
$iterationId: [ID]
$iterationWildcardId: IterationWildcardId
......@@ -22,6 +23,7 @@ query getProjectIssuesCount(
authorUsername: $authorUsername
labelName: $labelName
milestoneTitle: $milestoneTitle
milestoneWildcardId: $milestoneWildcardId
epicId: $epicId
iterationId: $iterationId
iterationWildcardId: $iterationWildcardId
......
......@@ -23,6 +23,7 @@ export const getIssuesQueryResponse = {
downvotes: 2,
dueDate: '2021-05-29',
humanTimeEstimate: null,
mergeRequestsCount: false,
moved: false,
title: 'Issue title',
updatedAt: '2021-05-22T04:08:01Z',
......@@ -108,6 +109,7 @@ export const locationSearchWithSpecialValues = [
'assignee_username=bart',
'my_reaction_emoji=None',
'iteration_id=Current',
'milestone_title=Upcoming',
'epic_id=None',
'weight=None',
].join('&');
......@@ -142,6 +144,7 @@ export const filteredTokensWithSpecialValues = [
{ type: 'assignee_username', value: { data: 'bart', operator: OPERATOR_IS } },
{ type: 'my_reaction_emoji', value: { data: 'None', operator: OPERATOR_IS } },
{ type: 'iteration', value: { data: 'Current', operator: OPERATOR_IS } },
{ type: 'milestone', value: { data: 'Upcoming', operator: OPERATOR_IS } },
{ type: 'epic_id', value: { data: 'None', operator: OPERATOR_IS } },
{ type: 'weight', value: { data: 'None', operator: OPERATOR_IS } },
];
......@@ -172,6 +175,7 @@ export const apiParamsWithSpecialValues = {
assigneeUsernames: 'bart',
myReactionEmoji: 'None',
iterationWildcardId: 'CURRENT',
milestoneWildcardId: 'UPCOMING',
epicId: 'None',
weight: 'None',
};
......@@ -200,6 +204,7 @@ export const urlParamsWithSpecialValues = {
'assignee_username[]': 'bart',
my_reaction_emoji: 'None',
iteration_id: 'Current',
milestone_title: 'Upcoming',
epic_id: 'None',
weight: 'None',
};
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