Commit 78b867a8 authored by Coung Ngo's avatar Coung Ngo Committed by Andrew Fontaine

Split issues list refactor into CE and EE

parent 63d7b0b1
......@@ -18,7 +18,6 @@ import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/auth
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';
export default {
types: {
......@@ -35,7 +34,6 @@ export default {
incident: __('Incident'),
issue: __('Issue'),
milestone: __('Milestone'),
weight: __('Weight'),
},
components: { BoardFilteredSearch },
inject: ['isSignedIn'],
......@@ -59,16 +57,7 @@ export default {
: this.fullPath.slice(0, this.fullPath.lastIndexOf('/'));
},
tokensCE() {
const {
label,
author,
assignee,
issue,
incident,
type,
milestone,
weight,
} = this.$options.i18n;
const { label, author, assignee, issue, incident, type, milestone } = this.$options.i18n;
const { types } = this.$options;
const { fetchAuthors, fetchLabels } = issueBoardFilters(
this.$apollo,
......@@ -155,13 +144,6 @@ export default {
{ icon: 'issue-type-incident', value: types.INCIDENT, title: incident },
],
},
{
type: 'weight',
title: weight,
icon: 'weight',
token: WeightToken,
unique: true,
},
];
},
tokens() {
......
......@@ -7,25 +7,16 @@ import {
isInPast,
isToday,
} from '~/lib/utils/datetime_utility';
import { convertToCamelCase } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
export default {
components: {
GlLink,
GlIcon,
IssueHealthStatus: () =>
import('ee_component/related_items_tree/components/issue_health_status.vue'),
WeightCount: () => import('ee_component/issues/components/weight_count.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
},
inject: {
hasIssuableHealthStatusFeature: {
default: false,
},
},
props: {
issue: {
type: Object,
......@@ -54,12 +45,6 @@ export default {
timeEstimate() {
return this.issue.humanTimeEstimate || this.issue.timeStats?.humanTimeEstimate;
},
showHealthStatus() {
return this.hasIssuableHealthStatusFeature && this.issue.healthStatus;
},
healthStatus() {
return convertToCamelCase(this.issue.healthStatus);
},
},
methods: {
milestoneRemainingTime(dueDate, startDate) {
......@@ -114,7 +99,6 @@ export default {
<gl-icon name="timer" />
{{ timeEstimate }}
</span>
<weight-count class="issuable-weight gl-mr-3" :weight="issue.weight" />
<issue-health-status v-if="showHealthStatus" :health-status="healthStatus" />
<slot></slot>
</span>
</template>
......@@ -11,6 +11,7 @@ import {
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import getIssuesQuery from 'ee_else_ce/issues_list/queries/get_issues.query.graphql';
import getIssuesCountsQuery from 'ee_else_ce/issues_list/queries/get_issues_counts.query.graphql';
import IssueCardTimeInfo from 'ee_else_ce/issues_list/components/issue_card_time_info.vue';
import createFlash, { FLASH_TYPES } from '~/flash';
import { TYPE_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
......@@ -31,14 +32,11 @@ import {
TOKEN_TYPE_ASSIGNEE,
TOKEN_TYPE_AUTHOR,
TOKEN_TYPE_CONFIDENTIAL,
TOKEN_TYPE_EPIC,
TOKEN_TYPE_ITERATION,
TOKEN_TYPE_LABEL,
TOKEN_TYPE_MILESTONE,
TOKEN_TYPE_MY_REACTION,
TOKEN_TYPE_RELEASE,
TOKEN_TYPE_TYPE,
TOKEN_TYPE_WEIGHT,
UPDATED_DESC,
urlSortParams,
} from '~/issues_list/constants';
......@@ -61,39 +59,29 @@ import {
TOKEN_TITLE_ASSIGNEE,
TOKEN_TITLE_AUTHOR,
TOKEN_TITLE_CONFIDENTIAL,
TOKEN_TITLE_EPIC,
TOKEN_TITLE_ITERATION,
TOKEN_TITLE_LABEL,
TOKEN_TITLE_MILESTONE,
TOKEN_TITLE_MY_REACTION,
TOKEN_TITLE_RELEASE,
TOKEN_TITLE_TYPE,
TOKEN_TITLE_WEIGHT,
} from '~/vue_shared/components/filtered_search_bar/constants';
import eventHub from '../eventhub';
import reorderIssuesMutation from '../queries/reorder_issues.mutation.graphql';
import searchIterationsQuery from '../queries/search_iterations.query.graphql';
import searchLabelsQuery from '../queries/search_labels.query.graphql';
import searchMilestonesQuery from '../queries/search_milestones.query.graphql';
import searchUsersQuery from '../queries/search_users.query.graphql';
import IssueCardTimeInfo from './issue_card_time_info.vue';
import NewIssueDropdown from './new_issue_dropdown.vue';
const AuthorToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/author_token.vue');
const EmojiToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue');
const EpicToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue');
const IterationToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue');
const LabelToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/label_token.vue');
const MilestoneToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue');
const ReleaseToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/release_token.vue');
const WeightToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue');
export default {
i18n,
......@@ -109,7 +97,6 @@ export default {
IssuableList,
IssueCardTimeInfo,
NewIssueDropdown,
BlockingIssuesCount: () => import('ee_component/issues/components/blocking_issues_count.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -133,9 +120,6 @@ export default {
fullPath: {
default: '',
},
groupPath: {
default: '',
},
hasAnyIssues: {
default: false,
},
......@@ -148,9 +132,6 @@ export default {
hasIssueWeightsFeature: {
default: false,
},
hasIterationsFeature: {
default: false,
},
hasMultipleIssueAssigneesFeature: {
default: false,
},
......@@ -185,6 +166,13 @@ export default {
default: '',
},
},
props: {
eeSearchTokens: {
type: Array,
required: false,
default: () => [],
},
},
data() {
const state = getParameterByName(PARAM_STATE);
const defaultSortKey = state === IssuableStates.Closed ? UPDATED_DESC : CREATED_DESC;
......@@ -389,39 +377,8 @@ export default {
});
}
if (this.hasIterationsFeature) {
tokens.push({
type: TOKEN_TYPE_ITERATION,
title: TOKEN_TITLE_ITERATION,
icon: 'iteration',
token: IterationToken,
fetchIterations: this.fetchIterations,
});
}
if (this.groupPath) {
tokens.push({
type: TOKEN_TYPE_EPIC,
title: TOKEN_TITLE_EPIC,
icon: 'epic',
token: EpicToken,
unique: true,
symbol: '&',
idProperty: 'id',
useIdValue: true,
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-epic_id`,
fullPath: this.groupPath,
});
}
if (this.hasIssueWeightsFeature) {
tokens.push({
type: TOKEN_TYPE_WEIGHT,
title: TOKEN_TITLE_WEIGHT,
icon: 'weight',
token: WeightToken,
unique: true,
});
if (this.eeSearchTokens.length) {
tokens.push(...this.eeSearchTokens);
}
return tokens;
......@@ -499,20 +456,6 @@ export default {
})
.then(({ data }) => data[this.namespace]?.milestones.nodes);
},
fetchIterations(search) {
const id = Number(search);
const variables =
!search || Number.isNaN(id)
? { fullPath: this.fullPath, search, isProject: this.isProject }
: { fullPath: this.fullPath, id, isProject: this.isProject };
return this.$apollo
.query({
query: searchIterationsQuery,
variables,
})
.then(({ data }) => data[this.namespace]?.iterations.nodes);
},
fetchUsers(search) {
return this.$apollo
.query({
......@@ -746,12 +689,7 @@ export default {
<gl-icon name="thumb-down" />
{{ issuable.downvotes }}
</li>
<blocking-issues-count
class="blocking-issues gl-display-none gl-sm-display-block"
:blocking-issues-count="issuable.blockingCount"
:is-list-item="true"
data-testid="blocking-issues"
/>
<slot :issuable="issuable"></slot>
</template>
<template #empty-state>
......
......@@ -2,7 +2,7 @@ import produce from 'immer';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import getIssuesQuery from 'ee_else_ce/issues_list/queries/get_issues.query.graphql';
import IssuesListApp from '~/issues_list/components/issues_list_app.vue';
import IssuesListApp from 'ee_else_ce/issues_list/components/issues_list_app.vue';
import createDefaultClient from '~/lib/graphql';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import IssuablesListApp from './components/issuables_list_app.vue';
......
......@@ -2,7 +2,6 @@ import { __ } from '~/locale';
export const DEBOUNCE_DELAY = 200;
export const MAX_RECENT_TOKENS_SIZE = 3;
export const WEIGHT_TOKEN_SUGGESTIONS_SIZE = 21;
export const FILTER_NONE = 'None';
export const FILTER_ANY = 'Any';
......@@ -24,10 +23,6 @@ export const DEFAULT_LABEL_NONE = { value: FILTER_NONE, text: __('None'), title:
export const DEFAULT_LABEL_ANY = { value: FILTER_ANY, text: __('Any'), title: __('Any') };
export const DEFAULT_NONE_ANY = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY];
export const DEFAULT_ITERATIONS = DEFAULT_NONE_ANY.concat([
{ value: FILTER_CURRENT, text: __('Current') },
]);
export const DEFAULT_MILESTONES = DEFAULT_NONE_ANY.concat([
{ value: FILTER_UPCOMING, text: __('Upcoming'), title: __('Upcoming') },
{ value: FILTER_STARTED, text: __('Started'), title: __('Started') },
......@@ -56,6 +51,3 @@ export const TOKEN_TITLE_TYPE = __('Type');
export const TOKEN_TITLE_RELEASE = __('Release');
export const TOKEN_TITLE_MY_REACTION = __('My-Reaction');
export const TOKEN_TITLE_CONFIDENTIAL = __('Confidential');
export const TOKEN_TITLE_ITERATION = __('Iteration');
export const TOKEN_TITLE_EPIC = __('Epic');
export const TOKEN_TITLE_WEIGHT = __('Weight');
......@@ -7,9 +7,10 @@ import IssueBoardFilteredSearchFoss from '~/boards/components/issue_board_filter
import { BoardType } from '~/boards/constants';
import { __ } from '~/locale';
import { OPERATOR_IS_AND_IS_NOT } from '~/vue_shared/components/filtered_search_bar/constants';
import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import EpicToken from 'ee/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
import IterationToken from 'ee/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import WeightToken from 'ee/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
export default {
extends: IssueBoardFilteredSearchFoss,
......@@ -17,6 +18,7 @@ export default {
...IssueBoardFilteredSearchFoss.i18n,
epic: __('Epic'),
iteration: __('Iteration'),
weight: __('Weight'),
},
mixins: [glFeatureFlagMixin()],
computed: {
......@@ -29,7 +31,7 @@ export default {
: this.fullPath.slice(0, this.fullPath.lastIndexOf('/'));
},
tokens() {
const { epic, iteration } = this.$options.i18n;
const { epic, iteration, weight } = this.$options.i18n;
return [
...this.tokensCE,
......@@ -57,6 +59,13 @@ export default {
},
]
: []),
{
type: 'weight',
title: weight,
icon: 'weight',
token: WeightToken,
unique: true,
},
];
},
},
......
<script>
import IssueCardTimeInfo from '~/issues_list/components/issue_card_time_info.vue';
import WeightCount from 'ee/issues/components/weight_count.vue';
import IssueHealthStatus from 'ee/related_items_tree/components/issue_health_status.vue';
export default {
components: {
IssueCardTimeInfo,
IssueHealthStatus,
WeightCount,
},
inject: ['hasIssuableHealthStatusFeature'],
props: {
issue: {
type: Object,
required: true,
},
},
computed: {
showHealthStatus() {
return this.hasIssuableHealthStatusFeature && this.issue.healthStatus;
},
},
};
</script>
<template>
<issue-card-time-info :issue="issue">
<weight-count class="issuable-weight gl-mr-3" :weight="issue.weight" />
<issue-health-status v-if="showHealthStatus" :health-status="issue.healthStatus" />
</issue-card-time-info>
</template>
<script>
import { ITEM_TYPE } from '~/groups/constants';
import IssuesListApp from '~/issues_list/components/issues_list_app.vue';
import { TOKEN_TYPE_EPIC, TOKEN_TYPE_ITERATION, TOKEN_TYPE_WEIGHT } from '~/issues_list/constants';
import {
TOKEN_TITLE_EPIC,
TOKEN_TITLE_ITERATION,
TOKEN_TITLE_WEIGHT,
} from 'ee/vue_shared/components/filtered_search_bar/constants';
import BlockingIssuesCount from 'ee/issues/components/blocking_issues_count.vue';
import searchIterationsQuery from '../queries/search_iterations.query.graphql';
const EpicToken = () =>
import('ee/vue_shared/components/filtered_search_bar/tokens/epic_token.vue');
const IterationToken = () =>
import('ee/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue');
const WeightToken = () =>
import('ee/vue_shared/components/filtered_search_bar/tokens/weight_token.vue');
export default {
components: {
BlockingIssuesCount,
IssuesListApp,
},
inject: {
fullPath: {
default: '',
},
groupPath: {
default: '',
},
hasIssueWeightsFeature: {
default: false,
},
hasIterationsFeature: {
default: false,
},
isProject: {
default: false,
},
},
computed: {
namespace() {
return this.isProject ? ITEM_TYPE.PROJECT : ITEM_TYPE.GROUP;
},
searchTokens() {
const tokens = [];
if (this.hasIterationsFeature) {
tokens.push({
type: TOKEN_TYPE_ITERATION,
title: TOKEN_TITLE_ITERATION,
icon: 'iteration',
token: IterationToken,
fetchIterations: this.fetchIterations,
});
}
if (this.groupPath) {
tokens.push({
type: TOKEN_TYPE_EPIC,
title: TOKEN_TITLE_EPIC,
icon: 'epic',
token: EpicToken,
unique: true,
symbol: '&',
idProperty: 'id',
useIdValue: true,
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-epic_id`,
fullPath: this.groupPath,
});
}
if (this.hasIssueWeightsFeature) {
tokens.push({
type: TOKEN_TYPE_WEIGHT,
title: TOKEN_TITLE_WEIGHT,
icon: 'weight',
token: WeightToken,
unique: true,
});
}
return tokens;
},
},
methods: {
fetchIterations(search) {
const id = Number(search);
const variables =
!search || Number.isNaN(id)
? { fullPath: this.fullPath, search, isProject: this.isProject }
: { fullPath: this.fullPath, id, isProject: this.isProject };
return this.$apollo
.query({
query: searchIterationsQuery,
variables,
})
.then(({ data }) => data[this.namespace]?.iterations.nodes);
},
},
};
</script>
<template>
<issues-list-app #default="{ issuable }" :ee-search-tokens="searchTokens">
<blocking-issues-count
class="blocking-issues gl-display-none gl-sm-display-block"
:blocking-issues-count="issuable.blockingCount"
is-list-item
data-testid="blocking-issues"
/>
</issues-list-app>
</template>
......@@ -12,9 +12,9 @@ import {
} 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 EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_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 EpicToken from 'ee/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
export default {
inject: ['groupFullPath', 'groupMilestonesPath', 'listEpicsPath'],
......
import { __ } from '~/locale';
import {
DEFAULT_NONE_ANY,
FILTER_CURRENT,
} from '~/vue_shared/components/filtered_search_bar/constants';
export * from '~/vue_shared/components/filtered_search_bar/constants';
export const WEIGHT_TOKEN_SUGGESTIONS_SIZE = 21;
export const DEFAULT_ITERATIONS = DEFAULT_NONE_ANY.concat([
{ value: FILTER_CURRENT, text: __('Current') },
]);
export const TOKEN_TITLE_ITERATION = __('Iteration');
export const TOKEN_TITLE_EPIC = __('Epic');
export const TOKEN_TITLE_WEIGHT = __('Weight');
......@@ -3,11 +3,10 @@ import { GlFilteredSearchSuggestion } from '@gitlab/ui';
import createFlash from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { DEFAULT_NONE_ANY, FILTER_NONE_ANY, OPERATOR_IS_NOT } from '../constants';
import searchEpicsQuery from '../queries/search_epics.query.graphql';
import BaseToken from './base_token.vue';
export default {
prefix: '&',
separator: '::',
......
......@@ -2,12 +2,12 @@ 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 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';
import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import EpicToken from 'ee/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
import IterationToken from 'ee/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import WeightToken from 'ee/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
export const mockEpicBoardResponse = {
data: {
......@@ -469,13 +469,6 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, fetchIter
{ icon: 'issue-type-incident', value: 'INCIDENT', title: 'Incident' },
],
},
{
icon: 'weight',
title: __('Weight'),
type: 'weight',
token: WeightToken,
unique: true,
},
{
type: 'epic_id',
icon: 'epic',
......@@ -499,4 +492,11 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, fetchIter
fetchIterations,
token: IterationToken,
},
{
type: 'weight',
icon: 'weight',
title: __('Weight'),
token: WeightToken,
unique: true,
},
];
import { shallowMount } from '@vue/test-utils';
import IssueCardTimeInfo from 'ee/issues_list/components/issue_card_time_info.vue';
import WeightCount from 'ee/issues/components/weight_count.vue';
import IssueHealthStatus from 'ee/related_items_tree/components/issue_health_status.vue';
describe('EE IssueCardTimeInfo component', () => {
let wrapper;
const issue = {
weight: 2,
healthStatus: 'onTrack',
};
const findWeightCount = () => wrapper.findComponent(WeightCount);
const findIssueHealthStatus = () => wrapper.findComponent(IssueHealthStatus);
const mountComponent = ({ hasIssuableHealthStatusFeature = false } = {}) =>
shallowMount(IssueCardTimeInfo, {
provide: { hasIssuableHealthStatusFeature },
propsData: { issue },
});
afterEach(() => {
wrapper.destroy();
});
describe('weight', () => {
it('renders', () => {
wrapper = mountComponent();
expect(findWeightCount().props('weight')).toBe(issue.weight);
});
});
describe('health status', () => {
describe('when hasIssuableHealthStatusFeature=true', () => {
it('renders', () => {
wrapper = mountComponent({ hasIssuableHealthStatusFeature: true });
expect(findIssueHealthStatus().props('healthStatus')).toBe(issue.healthStatus);
});
});
describe('when hasIssuableHealthStatusFeature=false', () => {
it('does not render', () => {
wrapper = mountComponent({ hasIssuableHealthStatusFeature: false });
expect(findIssueHealthStatus().exists()).toBe(false);
});
});
});
});
import { mount } from '@vue/test-utils';
import { cloneDeep } from 'lodash';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import getIssuesQuery from 'ee_else_ce/issues_list/queries/get_issues.query.graphql';
import getIssuesCountsQuery from 'ee_else_ce/issues_list/queries/get_issues_counts.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import { getIssuesCountsQueryResponse, getIssuesQueryResponse } from 'jest/issues_list/mock_data';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import IssuableList from '~/issuable_list/components/issuable_list_root.vue';
import {
TOKEN_TYPE_ASSIGNEE,
TOKEN_TYPE_AUTHOR,
TOKEN_TYPE_CONFIDENTIAL,
TOKEN_TYPE_EPIC,
TOKEN_TYPE_ITERATION,
TOKEN_TYPE_LABEL,
TOKEN_TYPE_MILESTONE,
TOKEN_TYPE_MY_REACTION,
TOKEN_TYPE_RELEASE,
TOKEN_TYPE_TYPE,
TOKEN_TYPE_WEIGHT,
} from '~/issues_list/constants';
import BlockingIssuesCount from 'ee/issues/components/blocking_issues_count.vue';
import IssuesListApp from 'ee/issues_list/components/issues_list_app.vue';
describe('EE IssuesListApp component', () => {
let wrapper;
Vue.use(VueApollo);
const defaultQueryResponse = cloneDeep(getIssuesQueryResponse);
defaultQueryResponse.data.project.issues.nodes[0].blockingCount = 1;
defaultQueryResponse.data.project.issues.nodes[0].healthStatus = null;
defaultQueryResponse.data.project.issues.nodes[0].weight = 5;
const findIssuableList = () => wrapper.findComponent(IssuableList);
const mountComponent = ({
provide = {},
issuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse),
issuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse),
} = {}) => {
const requestHandlers = [
[getIssuesQuery, issuesQueryResponse],
[getIssuesCountsQuery, issuesCountsQueryResponse],
];
const apolloProvider = createMockApollo(requestHandlers);
return mount(IssuesListApp, {
apolloProvider,
provide: {
hasAnyIssues: true,
hasIssuableHealthStatusFeature: true,
isProject: true,
...provide,
},
});
};
afterEach(() => {
wrapper.destroy();
});
describe('template', () => {
beforeEach(() => {
wrapper = mountComponent();
jest.runOnlyPendingTimers();
});
it('shows blocking issues count', () => {
expect(wrapper.findComponent(BlockingIssuesCount).props('blockingIssuesCount')).toBe(
defaultQueryResponse.data.project.issues.nodes[0].blockingCount,
);
});
});
describe('tokens', () => {
const mockCurrentUser = {
id: 1,
name: 'Administrator',
username: 'root',
avatar_url: 'avatar/url',
};
describe.each`
feature | property | tokenName | type
${'iterations'} | ${'hasIterationsFeature'} | ${'Iteration'} | ${TOKEN_TYPE_ITERATION}
${'epics'} | ${'groupPath'} | ${'Epic'} | ${TOKEN_TYPE_EPIC}
${'weights'} | ${'hasIssueWeightsFeature'} | ${'Weight'} | ${TOKEN_TYPE_WEIGHT}
`('when $feature are not available', ({ property, tokenName, type }) => {
beforeEach(() => {
wrapper = mountComponent({ provide: { [property]: '' } });
});
it(`does not render ${tokenName} token`, () => {
expect(findIssuableList().props('searchTokens')).not.toMatchObject([{ type }]);
});
});
describe('when all tokens are available', () => {
const originalGon = window.gon;
beforeEach(() => {
window.gon = {
...originalGon,
current_user_id: mockCurrentUser.id,
current_user_fullname: mockCurrentUser.name,
current_username: mockCurrentUser.username,
current_user_avatar_url: mockCurrentUser.avatar_url,
};
wrapper = mountComponent({
provide: {
groupPath: 'group/path',
hasIssueWeightsFeature: true,
hasIterationsFeature: true,
isSignedIn: true,
},
});
});
afterEach(() => {
window.gon = originalGon;
});
it('renders all tokens', () => {
const preloadedAuthors = [
{ ...mockCurrentUser, id: convertToGraphQLId('User', mockCurrentUser.id) },
];
expect(findIssuableList().props('searchTokens')).toMatchObject([
{ type: TOKEN_TYPE_AUTHOR, preloadedAuthors },
{ type: TOKEN_TYPE_ASSIGNEE, preloadedAuthors },
{ type: TOKEN_TYPE_MILESTONE },
{ type: TOKEN_TYPE_LABEL },
{ type: TOKEN_TYPE_TYPE },
{ type: TOKEN_TYPE_RELEASE },
{ type: TOKEN_TYPE_MY_REACTION },
{ type: TOKEN_TYPE_CONFIDENTIAL },
{ type: TOKEN_TYPE_ITERATION },
{ type: TOKEN_TYPE_EPIC },
{ type: TOKEN_TYPE_WEIGHT },
]);
});
});
});
});
......@@ -10,9 +10,9 @@ import {
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 EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_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 EpicToken from 'ee/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
export const mockScrollBarSize = 15;
......
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
import EpicToken from 'ee/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
import IterationToken from 'ee/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import WeightToken from 'ee/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
export const mockEpics = [
{ iid: 1, id: 1, title: 'Foo', group_full_path: 'gitlab-org' },
{ iid: 2, id: 2, title: 'Bar', group_full_path: 'gitlab-org/design' },
];
export const mockIterationToken = {
type: 'iteration',
icon: 'iteration',
title: 'Iteration',
unique: true,
token: IterationToken,
fetchIterations: () => Promise.resolve(),
};
export const mockIterations = [
{
id: 1,
title: 'Iteration 1',
startDate: '2021-11-05',
dueDate: '2021-11-10',
iterationCadence: {
title: 'Cadence 1',
},
},
];
export const mockEpicToken = {
type: 'epic_iid',
icon: 'clock',
title: 'Epic',
unique: true,
symbol: '&',
token: EpicToken,
operators: OPERATOR_IS_ONLY,
idProperty: 'iid',
fullPath: 'gitlab-org',
};
const mockEpicNode1 = {
__typename: 'Epic',
parent: null,
id: 'gid://gitlab/Epic/40',
iid: '2',
title: 'Marketing epic',
description: 'Mock epic description',
state: 'opened',
startDate: '2017-12-25',
dueDate: '2018-02-15',
webUrl: 'http://gdk.test:3000/groups/gitlab-org/marketing/-/epics/1',
hasChildren: false,
hasParent: false,
confidential: false,
};
const mockEpicNode2 = {
__typename: 'Epic',
parent: null,
id: 'gid://gitlab/Epic/41',
iid: '3',
title: 'Another marketing',
startDate: '2017-12-26',
dueDate: '2018-03-10',
state: 'opened',
webUrl: 'http://gdk.test:3000/groups/gitlab-org/marketing/-/epics/2',
};
export const mockGroupEpicsQueryResponse = {
data: {
group: {
id: 'gid://gitlab/Group/1',
name: 'Gitlab Org',
epics: {
edges: [
{
node: {
...mockEpicNode1,
},
__typename: 'EpicEdge',
},
{
node: {
...mockEpicNode2,
},
__typename: 'EpicEdge',
},
],
__typename: 'EpicConnection',
},
__typename: 'Group',
},
},
};
export const mockWeightToken = {
type: 'weight',
icon: 'weight',
title: 'Weight',
unique: true,
token: WeightToken,
};
......@@ -8,9 +8,9 @@ import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import searchEpicsQuery from '~/vue_shared/components/filtered_search_bar/queries/search_epics.query.graphql';
import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import searchEpicsQuery from 'ee/vue_shared/components/filtered_search_bar/queries/search_epics.query.graphql';
import EpicToken from 'ee/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
import { mockEpicToken, mockEpics, mockGroupEpicsQueryResponse } from '../mock_data';
......
......@@ -6,7 +6,7 @@ import {
import { mount } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import IterationToken from 'ee/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import { mockIterationToken, mockIterations } from '../mock_data';
jest.mock('~/flash');
......
import { GlFilteredSearchTokenSegment } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
import WeightToken from 'ee/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
import { mockWeightToken } from '../mock_data';
jest.mock('~/flash');
......
......@@ -7,7 +7,6 @@ import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/auth
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';
export const boardObj = {
id: 1,
......@@ -21,7 +20,6 @@ export const listObj = {
position: 0,
title: 'Test',
list_type: 'label',
weight: 3,
label: {
id: 5000,
title: 'Test',
......@@ -154,7 +152,6 @@ export const rawIssue = {
iid: '27',
dueDate: null,
timeEstimate: 0,
weight: null,
confidential: false,
referencePath: 'gitlab-org/test-subgroup/gitlab-test#27',
path: '/gitlab-org/test-subgroup/gitlab-test/-/issues/27',
......@@ -184,7 +181,6 @@ export const mockIssue = {
title: 'Issue 1',
dueDate: null,
timeEstimate: 0,
weight: null,
confidential: false,
referencePath: `${mockIssueFullPath}#27`,
path: `/${mockIssueFullPath}/-/issues/27`,
......@@ -216,7 +212,6 @@ export const mockIssue2 = {
title: 'Issue 2',
dueDate: null,
timeEstimate: 0,
weight: null,
confidential: false,
referencePath: 'gitlab-org/test-subgroup/gitlab-test#28',
path: '/gitlab-org/test-subgroup/gitlab-test/-/issues/28',
......@@ -234,7 +229,6 @@ export const mockIssue3 = {
referencePath: '#29',
dueDate: null,
timeEstimate: 0,
weight: null,
confidential: false,
path: '/gitlab-org/gitlab-test/-/issues/28',
assignees,
......@@ -249,7 +243,6 @@ export const mockIssue4 = {
referencePath: '#30',
dueDate: null,
timeEstimate: 0,
weight: null,
confidential: false,
path: '/gitlab-org/gitlab-test/-/issues/28',
assignees,
......@@ -622,13 +615,6 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, hasEmoji)
{ icon: 'issue-type-incident', value: 'INCIDENT', title: 'Incident' },
],
},
{
icon: 'weight',
title: __('Weight'),
type: 'weight',
token: WeightToken,
unique: true,
},
];
export const mockLabel1 = {
......
......@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import { useFakeDate } from 'helpers/fake_date';
import IssueCardTimeInfo from '~/issues_list/components/issue_card_time_info.vue';
describe('IssuesListApp component', () => {
describe('CE IssueCardTimeInfo component', () => {
useFakeDate(2020, 11, 11);
let wrapper;
......
import { GlButton, GlEmptyState, GlLink } from '@gitlab/ui';
import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
import { mount, shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
import { cloneDeep } from 'lodash';
import { nextTick } from 'vue';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import getIssuesQuery from 'ee_else_ce/issues_list/queries/get_issues.query.graphql';
import getIssuesCountsQuery from 'ee_else_ce/issues_list/queries/get_issues_counts.query.graphql';
......@@ -34,14 +34,11 @@ import {
TOKEN_TYPE_ASSIGNEE,
TOKEN_TYPE_AUTHOR,
TOKEN_TYPE_CONFIDENTIAL,
TOKEN_TYPE_EPIC,
TOKEN_TYPE_ITERATION,
TOKEN_TYPE_LABEL,
TOKEN_TYPE_MILESTONE,
TOKEN_TYPE_MY_REACTION,
TOKEN_TYPE_RELEASE,
TOKEN_TYPE_TYPE,
TOKEN_TYPE_WEIGHT,
urlSortParams,
} from '~/issues_list/constants';
import eventHub from '~/issues_list/eventhub';
......@@ -55,12 +52,11 @@ jest.mock('~/lib/utils/scroll_utils', () => ({
scrollUp: jest.fn().mockName('scrollUpMock'),
}));
describe('IssuesListApp component', () => {
describe('CE IssuesListApp component', () => {
let axiosMock;
let wrapper;
const localVue = createLocalVue();
localVue.use(VueApollo);
Vue.use(VueApollo);
const defaultProvide = {
calendarPath: 'calendar/path',
......@@ -71,6 +67,7 @@ describe('IssuesListApp component', () => {
hasAnyIssues: true,
hasAnyProjects: true,
hasBlockedIssuesFeature: true,
hasIssuableHealthStatusFeature: true,
hasIssueWeightsFeature: true,
hasIterationsFeature: true,
isProject: true,
......@@ -113,7 +110,6 @@ describe('IssuesListApp component', () => {
const apolloProvider = createMockApollo(requestHandlers);
return mountFn(IssuesListApp, {
localVue,
apolloProvider,
provide: {
...defaultProvide,
......@@ -526,54 +522,6 @@ describe('IssuesListApp component', () => {
});
});
describe('when iterations are not available', () => {
beforeEach(() => {
wrapper = mountComponent({
provide: {
projectIterationsPath: '',
},
});
});
it('does not render Iteration token', () => {
expect(findIssuableList().props('searchTokens')).not.toMatchObject([
{ type: TOKEN_TYPE_ITERATION },
]);
});
});
describe('when epics are not available', () => {
beforeEach(() => {
wrapper = mountComponent({
provide: {
groupPath: '',
},
});
});
it('does not render Epic token', () => {
expect(findIssuableList().props('searchTokens')).not.toMatchObject([
{ type: TOKEN_TYPE_EPIC },
]);
});
});
describe('when weights are not available', () => {
beforeEach(() => {
wrapper = mountComponent({
provide: {
groupPath: '',
},
});
});
it('does not render Weight token', () => {
expect(findIssuableList().props('searchTokens')).not.toMatchObject([
{ type: TOKEN_TYPE_WEIGHT },
]);
});
});
describe('when all tokens are available', () => {
const originalGon = window.gon;
......@@ -586,14 +534,11 @@ describe('IssuesListApp component', () => {
current_user_avatar_url: mockCurrentUser.avatar_url,
};
wrapper = mountComponent({
provide: {
isSignedIn: true,
projectIterationsPath: 'project/iterations/path',
groupPath: 'group/path',
hasIssueWeightsFeature: true,
},
});
wrapper = mountComponent({ provide: { isSignedIn: true } });
});
afterEach(() => {
window.gon = originalGon;
});
it('renders all tokens', () => {
......@@ -610,9 +555,6 @@ describe('IssuesListApp component', () => {
{ type: TOKEN_TYPE_RELEASE },
{ type: TOKEN_TYPE_MY_REACTION },
{ type: TOKEN_TYPE_CONFIDENTIAL },
{ type: TOKEN_TYPE_ITERATION },
{ type: TOKEN_TYPE_EPIC },
{ type: TOKEN_TYPE_WEIGHT },
]);
});
});
......
......@@ -5,12 +5,9 @@ import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/co
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import BranchToken from '~/vue_shared/components/filtered_search_bar/tokens/branch_token.vue';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_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 ReleaseToken from '~/vue_shared/components/filtered_search_bar/tokens/release_token.vue';
import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
export const mockAuthor1 = {
id: 1,
......@@ -65,11 +62,6 @@ export const mockMilestones = [
mockEscapedMilestone,
];
export const mockEpics = [
{ iid: 1, id: 1, title: 'Foo', group_full_path: 'gitlab-org' },
{ iid: 2, id: 2, title: 'Bar', group_full_path: 'gitlab-org/design' },
];
export const mockEmoji1 = {
name: 'thumbsup',
};
......@@ -102,27 +94,6 @@ export const mockAuthorToken = {
fetchAuthors: Api.projectUsers.bind(Api),
};
export const mockIterationToken = {
type: 'iteration',
icon: 'iteration',
title: 'Iteration',
unique: true,
token: IterationToken,
fetchIterations: () => Promise.resolve(),
};
export const mockIterations = [
{
id: 1,
title: 'Iteration 1',
startDate: '2021-11-05',
dueDate: '2021-11-10',
iterationCadence: {
title: 'Cadence 1',
},
},
];
export const mockLabelToken = {
type: 'label_name',
icon: 'labels',
......@@ -153,73 +124,6 @@ export const mockReleaseToken = {
fetchReleases: () => Promise.resolve(),
};
export const mockEpicToken = {
type: 'epic_iid',
icon: 'clock',
title: 'Epic',
unique: true,
symbol: '&',
token: EpicToken,
operators: OPERATOR_IS_ONLY,
idProperty: 'iid',
fullPath: 'gitlab-org',
};
export const mockEpicNode1 = {
__typename: 'Epic',
parent: null,
id: 'gid://gitlab/Epic/40',
iid: '2',
title: 'Marketing epic',
description: 'Mock epic description',
state: 'opened',
startDate: '2017-12-25',
dueDate: '2018-02-15',
webUrl: 'http://gdk.test:3000/groups/gitlab-org/marketing/-/epics/1',
hasChildren: false,
hasParent: false,
confidential: false,
};
export const mockEpicNode2 = {
__typename: 'Epic',
parent: null,
id: 'gid://gitlab/Epic/41',
iid: '3',
title: 'Another marketing',
startDate: '2017-12-26',
dueDate: '2018-03-10',
state: 'opened',
webUrl: 'http://gdk.test:3000/groups/gitlab-org/marketing/-/epics/2',
};
export const mockGroupEpicsQueryResponse = {
data: {
group: {
id: 'gid://gitlab/Group/1',
name: 'Gitlab Org',
epics: {
edges: [
{
node: {
...mockEpicNode1,
},
__typename: 'EpicEdge',
},
{
node: {
...mockEpicNode2,
},
__typename: 'EpicEdge',
},
],
__typename: 'EpicConnection',
},
__typename: 'Group',
},
},
};
export const mockReactionEmojiToken = {
type: 'my_reaction_emoji',
icon: 'thumb-up',
......@@ -243,14 +147,6 @@ export const mockMembershipToken = {
],
};
export const mockWeightToken = {
type: 'weight',
icon: 'weight',
title: 'Weight',
unique: true,
token: WeightToken,
};
export const mockMembershipTokenOptionsWithoutTitles = {
...mockMembershipToken,
options: [{ value: 'exclude' }, { value: 'only' }],
......
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