Commit f9542582 authored by Mark Florian's avatar Mark Florian

Merge branch 'ss/mv-fetch-milestones-to-ce' into 'master'

Move fetchMilestones in boards to ce [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!66976
parents ef0f0d7e 74bfd729
...@@ -36,10 +36,13 @@ import { ...@@ -36,10 +36,13 @@ import {
filterVariables, filterVariables,
} from '../boards_util'; } from '../boards_util';
import boardLabelsQuery from '../graphql/board_labels.query.graphql'; import boardLabelsQuery from '../graphql/board_labels.query.graphql';
import groupBoardMilestonesQuery from '../graphql/group_board_milestones.query.graphql';
import groupProjectsQuery from '../graphql/group_projects.query.graphql'; import groupProjectsQuery from '../graphql/group_projects.query.graphql';
import issueCreateMutation from '../graphql/issue_create.mutation.graphql'; import issueCreateMutation from '../graphql/issue_create.mutation.graphql';
import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql'; import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql';
import listsIssuesQuery from '../graphql/lists_issues.query.graphql'; import listsIssuesQuery from '../graphql/lists_issues.query.graphql';
import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql';
import * as types from './mutation_types'; import * as types from './mutation_types';
export const gqlClient = createGqClient( export const gqlClient = createGqClient(
...@@ -216,6 +219,52 @@ export default { ...@@ -216,6 +219,52 @@ export default {
}); });
}, },
fetchMilestones({ state, commit }, searchTerm) {
commit(types.RECEIVE_MILESTONES_REQUEST);
const { fullPath, boardType } = state;
const variables = {
fullPath,
searchTerm,
};
let query;
if (boardType === BoardType.project) {
query = projectBoardMilestonesQuery;
}
if (boardType === BoardType.group) {
query = groupBoardMilestonesQuery;
}
if (!query) {
// eslint-disable-next-line @gitlab/require-i18n-strings
throw new Error('Unknown board type');
}
return gqlClient
.query({
query,
variables,
})
.then(({ data }) => {
const errors = data[boardType]?.errors;
const milestones = data[boardType]?.milestones.nodes;
if (errors?.[0]) {
throw new Error(errors[0]);
}
commit(types.RECEIVE_MILESTONES_SUCCESS, milestones);
return milestones;
})
.catch((e) => {
commit(types.RECEIVE_MILESTONES_FAILURE);
throw e;
});
},
moveList: ( moveList: (
{ state: { boardLists }, commit, dispatch }, { state: { boardLists }, commit, dispatch },
{ {
......
...@@ -18,6 +18,9 @@ export const RESET_ITEMS_FOR_LIST = 'RESET_ITEMS_FOR_LIST'; ...@@ -18,6 +18,9 @@ export const RESET_ITEMS_FOR_LIST = 'RESET_ITEMS_FOR_LIST';
export const REQUEST_ITEMS_FOR_LIST = 'REQUEST_ITEMS_FOR_LIST'; export const REQUEST_ITEMS_FOR_LIST = 'REQUEST_ITEMS_FOR_LIST';
export const RECEIVE_ITEMS_FOR_LIST_FAILURE = 'RECEIVE_ITEMS_FOR_LIST_FAILURE'; export const RECEIVE_ITEMS_FOR_LIST_FAILURE = 'RECEIVE_ITEMS_FOR_LIST_FAILURE';
export const RECEIVE_ITEMS_FOR_LIST_SUCCESS = 'RECEIVE_ITEMS_FOR_LIST_SUCCESS'; export const RECEIVE_ITEMS_FOR_LIST_SUCCESS = 'RECEIVE_ITEMS_FOR_LIST_SUCCESS';
export const RECEIVE_MILESTONES_REQUEST = 'RECEIVE_MILESTONES_REQUEST';
export const RECEIVE_MILESTONES_SUCCESS = 'RECEIVE_MILESTONES_SUCCESS';
export const RECEIVE_MILESTONES_FAILURE = 'RECEIVE_MILESTONES_FAILURE';
export const UPDATE_BOARD_ITEM = 'UPDATE_BOARD_ITEM'; export const UPDATE_BOARD_ITEM = 'UPDATE_BOARD_ITEM';
export const REMOVE_BOARD_ITEM = 'REMOVE_BOARD_ITEM'; export const REMOVE_BOARD_ITEM = 'REMOVE_BOARD_ITEM';
export const MUTATE_ISSUE_SUCCESS = 'MUTATE_ISSUE_SUCCESS'; export const MUTATE_ISSUE_SUCCESS = 'MUTATE_ISSUE_SUCCESS';
......
import { cloneDeep, pull, union } from 'lodash'; import { cloneDeep, pull, union } from 'lodash';
import Vue from 'vue'; import Vue from 'vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { s__ } from '~/locale'; import { s__, __ } from '~/locale';
import { formatIssue } from '../boards_util'; import { formatIssue } from '../boards_util';
import { issuableTypes } from '../constants'; import { issuableTypes } from '../constants';
import * as mutationTypes from './mutation_types'; import * as mutationTypes from './mutation_types';
...@@ -133,6 +133,20 @@ export default { ...@@ -133,6 +133,20 @@ export default {
Vue.set(state.listsFlags, listId, { [fetchNext ? 'isLoadingMore' : 'isLoading']: true }); Vue.set(state.listsFlags, listId, { [fetchNext ? 'isLoadingMore' : 'isLoading']: true });
}, },
[mutationTypes.RECEIVE_MILESTONES_SUCCESS](state, milestones) {
state.milestones = milestones;
state.milestonesLoading = false;
},
[mutationTypes.RECEIVE_MILESTONES_REQUEST](state) {
state.milestonesLoading = true;
},
[mutationTypes.RECEIVE_MILESTONES_FAILURE](state) {
state.milestonesLoading = false;
state.error = __('Failed to load milestones.');
},
[mutationTypes.RECEIVE_ITEMS_FOR_LIST_SUCCESS]: (state, { listItems, listPageInfo, listId }) => { [mutationTypes.RECEIVE_ITEMS_FOR_LIST_SUCCESS]: (state, { listItems, listPageInfo, listId }) => {
const { listData, boardItems } = listItems; const { listData, boardItems } = listItems;
Vue.set(state, 'boardItems', { ...state.boardItems, ...boardItems }); Vue.set(state, 'boardItems', { ...state.boardItems, ...boardItems });
......
...@@ -19,6 +19,8 @@ export default () => ({ ...@@ -19,6 +19,8 @@ export default () => ({
boardConfig: {}, boardConfig: {},
labelsLoading: false, labelsLoading: false,
labels: [], labels: [],
milestones: [],
milestonesLoading: false,
highlightedLists: [], highlightedLists: [],
selectedBoardItems: [], selectedBoardItems: [],
groupProjects: [], groupProjects: [],
......
...@@ -34,11 +34,9 @@ import epicCreateMutation from '../graphql/epic_create.mutation.graphql'; ...@@ -34,11 +34,9 @@ import epicCreateMutation from '../graphql/epic_create.mutation.graphql';
import epicMoveListMutation from '../graphql/epic_move_list.mutation.graphql'; import epicMoveListMutation from '../graphql/epic_move_list.mutation.graphql';
import epicsSwimlanesQuery from '../graphql/epics_swimlanes.query.graphql'; import epicsSwimlanesQuery from '../graphql/epics_swimlanes.query.graphql';
import groupBoardIterationsQuery from '../graphql/group_board_iterations.query.graphql'; import groupBoardIterationsQuery from '../graphql/group_board_iterations.query.graphql';
import groupBoardMilestonesQuery from '../graphql/group_board_milestones.query.graphql';
import listUpdateLimitMetricsMutation from '../graphql/list_update_limit_metrics.mutation.graphql'; import listUpdateLimitMetricsMutation from '../graphql/list_update_limit_metrics.mutation.graphql';
import listsEpicsQuery from '../graphql/lists_epics.query.graphql'; import listsEpicsQuery from '../graphql/lists_epics.query.graphql';
import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql'; import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql';
import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql';
import updateBoardEpicUserPreferencesMutation from '../graphql/update_board_epic_user_preferences.mutation.graphql'; import updateBoardEpicUserPreferencesMutation from '../graphql/update_board_epic_user_preferences.mutation.graphql';
import updateEpicLabelsMutation from '../graphql/update_epic_labels.mutation.graphql'; import updateEpicLabelsMutation from '../graphql/update_epic_labels.mutation.graphql';
...@@ -424,50 +422,6 @@ export default { ...@@ -424,50 +422,6 @@ export default {
); );
}, },
fetchMilestones({ state, commit }, searchTerm) {
commit(types.RECEIVE_MILESTONES_REQUEST);
const { fullPath, boardType } = state;
const variables = {
fullPath,
searchTerm,
};
let query;
if (boardType === BoardType.project) {
query = projectBoardMilestonesQuery;
}
if (boardType === BoardType.group) {
query = groupBoardMilestonesQuery;
}
if (!query) {
// eslint-disable-next-line @gitlab/require-i18n-strings
throw new Error('Unknown board type');
}
return gqlClient
.query({
query,
variables,
})
.then(({ data }) => {
const errors = data[boardType]?.errors;
const milestones = data[boardType]?.milestones.nodes;
if (errors?.[0]) {
throw new Error(errors[0]);
}
commit(types.RECEIVE_MILESTONES_SUCCESS, milestones);
})
.catch((e) => {
commit(types.RECEIVE_MILESTONES_FAILURE);
throw e;
});
},
fetchIterations({ state, commit }, title) { fetchIterations({ state, commit }, title) {
commit(types.RECEIVE_ITERATIONS_REQUEST); commit(types.RECEIVE_ITERATIONS_REQUEST);
......
...@@ -15,9 +15,6 @@ export const SET_SHOW_LABELS = 'SET_SHOW_LABELS'; ...@@ -15,9 +15,6 @@ export const SET_SHOW_LABELS = 'SET_SHOW_LABELS';
export const MOVE_EPIC = 'MOVE_EPIC'; export const MOVE_EPIC = 'MOVE_EPIC';
export const MOVE_EPIC_FAILURE = 'MOVE_EPIC_FAILURE'; export const MOVE_EPIC_FAILURE = 'MOVE_EPIC_FAILURE';
export const SET_BOARD_EPIC_USER_PREFERENCES = 'SET_BOARD_EPIC_USER_PREFERENCES'; export const SET_BOARD_EPIC_USER_PREFERENCES = 'SET_BOARD_EPIC_USER_PREFERENCES';
export const RECEIVE_MILESTONES_REQUEST = 'RECEIVE_MILESTONES_REQUEST';
export const RECEIVE_MILESTONES_SUCCESS = 'RECEIVE_MILESTONES_SUCCESS';
export const RECEIVE_MILESTONES_FAILURE = 'RECEIVE_MILESTONES_FAILURE';
export const RECEIVE_ITERATIONS_REQUEST = 'RECEIVE_ITERATIONS_REQUEST'; export const RECEIVE_ITERATIONS_REQUEST = 'RECEIVE_ITERATIONS_REQUEST';
export const RECEIVE_ITERATIONS_SUCCESS = 'RECEIVE_ITERATIONS_SUCCESS'; export const RECEIVE_ITERATIONS_SUCCESS = 'RECEIVE_ITERATIONS_SUCCESS';
export const RECEIVE_ITERATIONS_FAILURE = 'RECEIVE_ITERATIONS_FAILURE'; export const RECEIVE_ITERATIONS_FAILURE = 'RECEIVE_ITERATIONS_FAILURE';
......
...@@ -171,20 +171,6 @@ export default { ...@@ -171,20 +171,6 @@ export default {
} }
}, },
[mutationTypes.RECEIVE_MILESTONES_REQUEST](state) {
state.milestonesLoading = true;
},
[mutationTypes.RECEIVE_MILESTONES_SUCCESS](state, milestones) {
state.milestones = milestones;
state.milestonesLoading = false;
},
[mutationTypes.RECEIVE_MILESTONES_FAILURE](state) {
state.milestonesLoading = false;
state.error = __('Failed to load milestones.');
},
[mutationTypes.RECEIVE_ITERATIONS_REQUEST](state) { [mutationTypes.RECEIVE_ITERATIONS_REQUEST](state) {
state.iterationsLoading = true; state.iterationsLoading = true;
}, },
......
...@@ -15,8 +15,6 @@ export default () => ({ ...@@ -15,8 +15,6 @@ export default () => ({
epicsEndCursor: null, epicsEndCursor: null,
epics: [], epics: [],
epicsFlags: {}, epicsFlags: {},
milestones: [],
milestonesLoading: false,
iterations: [], iterations: [],
iterationsLoading: false, iterationsLoading: false,
assignees: [], assignees: [],
......
...@@ -1120,87 +1120,6 @@ describe('addListNewEpic', () => { ...@@ -1120,87 +1120,6 @@ describe('addListNewEpic', () => {
}); });
}); });
describe('fetchMilestones', () => {
const queryResponse = {
data: {
project: {
milestones: {
nodes: mockMilestones,
},
},
},
};
const queryErrors = {
data: {
project: {
errors: ['You cannot view these milestones'],
milestones: {},
},
},
};
function createStore({
state = {
boardType: 'project',
fullPath: 'gitlab-org/gitlab',
milestones: [],
milestonesLoading: false,
},
} = {}) {
return new Vuex.Store({
state,
mutations,
});
}
it('throws error if state.boardType is not group or project', () => {
const store = createStore({
state: {
boardType: 'invalid',
},
});
expect(() => actions.fetchMilestones(store)).toThrow(new Error('Unknown board type'));
});
it('sets milestonesLoading to true', async () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
const store = createStore();
actions.fetchMilestones(store);
expect(store.state.milestonesLoading).toBe(true);
});
describe('success', () => {
it('sets state.milestones from query result', async () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
const store = createStore();
await actions.fetchMilestones(store);
expect(store.state.milestonesLoading).toBe(false);
expect(store.state.milestones).toBe(mockMilestones);
});
});
describe('failure', () => {
it('sets state.milestones from query result', async () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryErrors);
const store = createStore();
await expect(actions.fetchMilestones(store)).rejects.toThrow();
expect(store.state.milestonesLoading).toBe(false);
expect(store.state.error).toBe('Failed to load milestones.');
});
});
});
describe('fetchIterations', () => { describe('fetchIterations', () => {
const queryResponse = { const queryResponse = {
data: { data: {
......
...@@ -101,6 +101,17 @@ export const mockMilestone = { ...@@ -101,6 +101,17 @@ export const mockMilestone = {
due_date: '2019-12-31', due_date: '2019-12-31',
}; };
export const mockMilestones = [
{
id: 'gid://gitlab/Milestone/1',
title: 'Milestone 1',
},
{
id: 'gid://gitlab/Milestone/2',
title: 'Milestone 2',
},
];
export const assignees = [ export const assignees = [
{ {
id: 'gid://gitlab/User/2', id: 'gid://gitlab/User/2',
......
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import Vue from 'vue';
import Vuex from 'vuex';
import { import {
inactiveId, inactiveId,
ISSUABLE, ISSUABLE,
...@@ -22,6 +24,7 @@ import destroyBoardListMutation from '~/boards/graphql/board_list_destroy.mutati ...@@ -22,6 +24,7 @@ import destroyBoardListMutation from '~/boards/graphql/board_list_destroy.mutati
import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql'; import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql';
import actions, { gqlClient } from '~/boards/stores/actions'; import actions, { gqlClient } from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types'; import * as types from '~/boards/stores/mutation_types';
import mutations from '~/boards/stores/mutations';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { import {
...@@ -38,6 +41,7 @@ import { ...@@ -38,6 +41,7 @@ import {
mockMoveState, mockMoveState,
mockMoveData, mockMoveData,
mockList, mockList,
mockMilestones,
} from '../mock_data'; } from '../mock_data';
jest.mock('~/flash'); jest.mock('~/flash');
...@@ -46,6 +50,8 @@ jest.mock('~/flash'); ...@@ -46,6 +50,8 @@ jest.mock('~/flash');
// subgroups when the movIssue action is called. // subgroups when the movIssue action is called.
const getProjectPath = (path) => path.split('#')[0]; const getProjectPath = (path) => path.split('#')[0];
Vue.use(Vuex);
beforeEach(() => { beforeEach(() => {
window.gon = { features: {} }; window.gon = { features: {} };
}); });
...@@ -261,6 +267,87 @@ describe('fetchLists', () => { ...@@ -261,6 +267,87 @@ describe('fetchLists', () => {
); );
}); });
describe('fetchMilestones', () => {
const queryResponse = {
data: {
project: {
milestones: {
nodes: mockMilestones,
},
},
},
};
const queryErrors = {
data: {
project: {
errors: ['You cannot view these milestones'],
milestones: {},
},
},
};
function createStore({
state = {
boardType: 'project',
fullPath: 'gitlab-org/gitlab',
milestones: [],
milestonesLoading: false,
},
} = {}) {
return new Vuex.Store({
state,
mutations,
});
}
it('throws error if state.boardType is not group or project', () => {
const store = createStore({
state: {
boardType: 'invalid',
},
});
expect(() => actions.fetchMilestones(store)).toThrow(new Error('Unknown board type'));
});
it('sets milestonesLoading to true', async () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
const store = createStore();
actions.fetchMilestones(store);
expect(store.state.milestonesLoading).toBe(true);
});
describe('success', () => {
it('sets state.milestones from query result', async () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
const store = createStore();
await actions.fetchMilestones(store);
expect(store.state.milestonesLoading).toBe(false);
expect(store.state.milestones).toBe(mockMilestones);
});
});
describe('failure', () => {
it('sets state.milestones from query result', async () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryErrors);
const store = createStore();
await expect(actions.fetchMilestones(store)).rejects.toThrow();
expect(store.state.milestonesLoading).toBe(false);
expect(store.state.error).toBe('Failed to load milestones.');
});
});
});
describe('createList', () => { describe('createList', () => {
it('should dispatch createIssueList action', () => { it('should dispatch createIssueList action', () => {
testAction({ testAction({
......
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