Commit 1e990c8c authored by Eulyeon Ko's avatar Eulyeon Ko

Clone issue card on move when needed

Also resolves duplicate key error by
checking if issue card already exists
in the destination list
parent f028aff4
import { sortBy } from 'lodash';
import { sortBy, cloneDeep } from 'lodash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { ListType, NOT_FILTER } from './constants';
......@@ -113,6 +113,37 @@ export function formatIssueInput(issueInput, boardConfig) {
};
}
export function shouldCloneCard(fromListType, toListType) {
const involvesClosed = fromListType === ListType.closed || toListType === ListType.closed;
const involvesBacklog = fromListType === ListType.backlog || toListType === ListType.backlog;
if (involvesClosed || involvesBacklog) {
return false;
}
if (fromListType !== toListType) {
return true;
}
return false;
}
export function getMoveData(state, params) {
const { boardItems, boardItemsByListId, boardLists } = state;
const { itemId, fromListId, toListId } = params;
const fromListType = boardLists[fromListId].listType;
const toListType = boardLists[toListId].listType;
return {
reordering: fromListId === toListId,
shouldClone: shouldCloneCard(fromListType, toListType),
itemNotInToList: !boardItemsByListId[toListId].includes(itemId),
originalIssue: cloneDeep(boardItems[itemId]),
originalIndex: boardItemsByListId[fromListId].indexOf(itemId),
...params,
};
}
export function moveItemListHelper(item, fromList, toList) {
const updatedItem = item;
if (
......
......@@ -190,7 +190,7 @@ export default {
}
this.moveItem({
itemId,
itemId: Number(itemId),
itemIid,
itemPath,
fromListId: from.dataset.listId,
......
......@@ -2,6 +2,7 @@ import * as Sentry from '@sentry/browser';
import { pick } from 'lodash';
import createBoardListMutation from 'ee_else_ce/boards/graphql/board_list_create.mutation.graphql';
import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql';
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
import {
BoardType,
ListType,
......@@ -23,13 +24,14 @@ import {
formatIssueInput,
updateListPosition,
transformNotFilters,
moveItemListHelper,
getMoveData,
} from '../boards_util';
import boardLabelsQuery from '../graphql/board_labels.query.graphql';
import destroyBoardListMutation from '../graphql/board_list_destroy.mutation.graphql';
import updateBoardListMutation from '../graphql/board_list_update.mutation.graphql';
import groupProjectsQuery from '../graphql/group_projects.query.graphql';
import issueCreateMutation from '../graphql/issue_create.mutation.graphql';
import issueMoveListMutation from '../graphql/issue_move_list.mutation.graphql';
import issueSetDueDateMutation from '../graphql/issue_set_due_date.mutation.graphql';
import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql';
import issueSetMilestoneMutation from '../graphql/issue_set_milestone.mutation.graphql';
......@@ -333,42 +335,123 @@ export default {
dispatch('moveIssue', payload);
},
moveIssue: (
{ state, commit },
{ itemId, itemIid, itemPath, fromListId, toListId, moveBeforeId, moveAfterId },
moveIssue: ({ dispatch, state }, params) => {
const moveData = getMoveData(state, params);
dispatch('moveIssueCard', moveData);
dispatch('updateMovedIssue', moveData);
dispatch('requestIssueMoveListMutation', { moveData });
},
moveIssueCard: ({ commit }, moveData) => {
const { reordering, shouldClone, itemNotInToList } = moveData;
const { itemId, fromListId, toListId, moveBeforeId, moveAfterId } = moveData;
commit(types.REMOVE_BOARD_ITEM_FROM_LIST, { itemId, listId: fromListId });
if (reordering) {
commit(types.ADD_BOARD_ITEM_TO_LIST, {
itemId,
listId: toListId,
moveBeforeId,
moveAfterId,
});
return;
}
if (itemNotInToList) {
commit(types.ADD_BOARD_ITEM_TO_LIST, {
itemId,
listId: toListId,
moveBeforeId,
moveAfterId,
});
}
if (shouldClone) {
const { originalIndex } = moveData;
commit(types.ADD_BOARD_ITEM_TO_LIST, { itemId, listId: fromListId, atIndex: originalIndex });
}
},
updateMovedIssue: (
{ commit, state: { boardItems, boardLists } },
{ itemId, fromListId, toListId },
) => {
const originalIssue = state.boardItems[itemId];
const fromList = state.boardItemsByListId[fromListId];
const originalIndex = fromList.indexOf(Number(itemId));
commit(types.MOVE_ISSUE, { originalIssue, fromListId, toListId, moveBeforeId, moveAfterId });
const updatedIssue = moveItemListHelper(
boardItems[itemId],
boardLists[fromListId],
boardLists[toListId],
);
const { boardId } = state;
const [fullProjectPath] = itemPath.split(/[#]/);
commit(types.UPDATE_BOARD_ITEM, updatedIssue);
},
gqlClient
.mutate({
undoMoveIssueCard: ({ commit }, moveData) => {
const { reordering, shouldClone, itemNotInToList } = moveData;
const { itemId, fromListId, toListId } = moveData;
const { originalIssue, originalIndex } = moveData;
commit(types.UPDATE_BOARD_ITEM, originalIssue);
if (reordering) {
commit(types.REMOVE_BOARD_ITEM_FROM_LIST, { itemId, listId: fromListId });
commit(types.ADD_BOARD_ITEM_TO_LIST, { itemId, listId: fromListId, atIndex: originalIndex });
return;
}
if (shouldClone) {
commit(types.REMOVE_BOARD_ITEM_FROM_LIST, { itemId, listId: fromListId });
}
if (itemNotInToList) {
commit(types.REMOVE_BOARD_ITEM_FROM_LIST, { itemId, listId: toListId });
}
commit(types.ADD_BOARD_ITEM_TO_LIST, { itemId, listId: fromListId, atIndex: originalIndex });
},
requestIssueMoveListMutation: async (
{ commit, dispatch, state },
{ moveData, mutationVariables = {} },
) => {
try {
const { itemId, fromListId, toListId, moveBeforeId, moveAfterId } = moveData;
const {
boardId,
boardItems: {
[itemId]: { iid, referencePath },
},
} = state;
const { data } = await gqlClient.mutate({
mutation: issueMoveListMutation,
variables: {
projectPath: fullProjectPath,
iid,
projectPath: referencePath.split(/[#]/)[0],
boardId: fullBoardId(boardId),
iid: itemIid,
fromListId: getIdFromGraphQLId(fromListId),
toListId: getIdFromGraphQLId(toListId),
moveBeforeId,
moveAfterId,
// 'mutationVariables' allows EE code to pass in extra parameters.
...mutationVariables,
},
})
.then(({ data }) => {
if (data?.issueMoveList?.errors.length) {
throw new Error();
} else {
const issue = data.issueMoveList?.issue;
commit(types.MOVE_ISSUE_SUCCESS, { issue });
});
if (data?.issueMoveList?.errors.length || !data.issueMoveList) {
throw new Error('issueMoveList empty');
}
})
.catch(() =>
commit(types.MOVE_ISSUE_FAILURE, { originalIssue, fromListId, toListId, originalIndex }),
commit(types.MUTATE_ISSUE_SUCCESS, { issue: data.issueMoveList.issue });
} catch {
commit(
types.SET_ERROR,
s__('Boards|An error occurred while moving the issue. Please try again.'),
);
dispatch('undoMoveIssueCard', moveData);
}
},
setAssignees: ({ commit, getters }, assigneeUsernames) => {
......
......@@ -23,12 +23,10 @@ export const RECEIVE_ITEMS_FOR_LIST_SUCCESS = 'RECEIVE_ITEMS_FOR_LIST_SUCCESS';
export const REQUEST_ADD_ISSUE = 'REQUEST_ADD_ISSUE';
export const RECEIVE_ADD_ISSUE_SUCCESS = 'RECEIVE_ADD_ISSUE_SUCCESS';
export const RECEIVE_ADD_ISSUE_ERROR = 'RECEIVE_ADD_ISSUE_ERROR';
export const MOVE_ISSUE = 'MOVE_ISSUE';
export const MOVE_ISSUE_SUCCESS = 'MOVE_ISSUE_SUCCESS';
export const MOVE_ISSUE_FAILURE = 'MOVE_ISSUE_FAILURE';
export const UPDATE_BOARD_ITEM = 'UPDATE_BOARD_ITEM';
export const REMOVE_BOARD_ITEM = 'REMOVE_BOARD_ITEM';
export const REQUEST_UPDATE_ISSUE = 'REQUEST_UPDATE_ISSUE';
export const MUTATE_ISSUE_SUCCESS = 'MUTATE_ISSUE_SUCCESS';
export const RECEIVE_UPDATE_ISSUE_SUCCESS = 'RECEIVE_UPDATE_ISSUE_SUCCESS';
export const RECEIVE_UPDATE_ISSUE_ERROR = 'RECEIVE_UPDATE_ISSUE_ERROR';
export const ADD_BOARD_ITEM_TO_LIST = 'ADD_BOARD_ITEM_TO_LIST';
......
......@@ -2,7 +2,7 @@ import { pull, union } from 'lodash';
import Vue from 'vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { s__ } from '~/locale';
import { formatIssue, moveItemListHelper } from '../boards_util';
import { formatIssue } from '../boards_util';
import { issuableTypes } from '../constants';
import * as mutationTypes from './mutation_types';
......@@ -183,40 +183,11 @@ export default {
notImplemented();
},
[mutationTypes.MOVE_ISSUE]: (
state,
{ originalIssue, fromListId, toListId, moveBeforeId, moveAfterId },
) => {
const fromList = state.boardLists[fromListId];
const toList = state.boardLists[toListId];
const issue = moveItemListHelper(originalIssue, fromList, toList);
Vue.set(state.boardItems, issue.id, issue);
removeItemFromList({ state, listId: fromListId, itemId: issue.id });
addItemToList({ state, listId: toListId, itemId: issue.id, moveBeforeId, moveAfterId });
},
[mutationTypes.MOVE_ISSUE_SUCCESS]: (state, { issue }) => {
[mutationTypes.MUTATE_ISSUE_SUCCESS]: (state, { issue }) => {
const issueId = getIdFromGraphQLId(issue.id);
Vue.set(state.boardItems, issueId, formatIssue({ ...issue, id: issueId }));
},
[mutationTypes.MOVE_ISSUE_FAILURE]: (
state,
{ originalIssue, fromListId, toListId, originalIndex },
) => {
state.error = s__('Boards|An error occurred while moving the issue. Please try again.');
Vue.set(state.boardItems, originalIssue.id, originalIssue);
removeItemFromList({ state, listId: toListId, itemId: originalIssue.id });
addItemToList({
state,
listId: fromListId,
itemId: originalIssue.id,
atIndex: originalIndex,
});
},
[mutationTypes.REQUEST_UPDATE_ISSUE]: () => {
notImplemented();
},
......
......@@ -147,7 +147,7 @@ export default {
}
this.moveIssue({
itemId,
itemId: Number(itemId),
itemIid,
itemPath,
fromListId: from.dataset.listId,
......
......@@ -5,6 +5,7 @@ import {
formatListsPageInfo,
fullBoardId,
transformNotFilters,
getMoveData,
} from '~/boards/boards_util';
import { BoardType } from '~/boards/constants';
import eventHub from '~/boards/eventhub';
......@@ -12,7 +13,6 @@ import listsIssuesQuery from '~/boards/graphql/lists_issues.query.graphql';
import actionsCE from '~/boards/stores/actions';
import boardsStore from '~/boards/stores/boards_store';
import * as typesCE from '~/boards/stores/mutation_types';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
import axios from '~/lib/utils/axios_utils';
import {
......@@ -37,7 +37,6 @@ import epicsSwimlanesQuery from '../graphql/epics_swimlanes.query.graphql';
import groupBoardAssigneesQuery from '../graphql/group_board_assignees.query.graphql';
import groupBoardIterationsQuery from '../graphql/group_board_iterations.query.graphql';
import groupBoardMilestonesQuery from '../graphql/group_board_milestones.query.graphql';
import issueMoveListMutation from '../graphql/issue_move_list.mutation.graphql';
import issueSetEpicMutation from '../graphql/issue_set_epic.mutation.graphql';
import issueSetWeightMutation from '../graphql/issue_set_weight.mutation.graphql';
import listUpdateLimitMetricsMutation from '../graphql/list_update_limit_metrics.mutation.graphql';
......@@ -482,50 +481,35 @@ export default {
}
},
moveIssue: (
{ state, commit },
{ itemId, itemIid, itemPath, fromListId, toListId, moveBeforeId, moveAfterId, epicId },
) => {
const originalIssue = state.boardItems[itemId];
const fromList = state.boardItemsByListId[fromListId];
const originalIndex = fromList.indexOf(Number(itemId));
commit(types.MOVE_ISSUE, {
originalIssue,
fromListId,
toListId,
moveBeforeId,
moveAfterId,
epicId,
moveIssue: ({ dispatch, state }, params) => {
const { itemId, epicId } = params;
const moveData = getMoveData(state, params);
dispatch('moveIssueCard', moveData);
dispatch('updateMovedIssue', moveData);
dispatch('updateEpicForIssue', { itemId, epicId });
dispatch('requestIssueMoveListMutation', {
moveData,
mutationVariables: { epicId },
});
},
const { boardId } = state;
const [fullProjectPath] = itemPath.split(/[#]/);
updateEpicForIssue: ({ commit, state: { boardItems } }, { itemId, epicId }) => {
const issue = boardItems[itemId];
gqlClient
.mutate({
mutation: issueMoveListMutation,
variables: {
projectPath: fullProjectPath,
boardId: fullBoardId(boardId),
iid: itemIid,
fromListId: getIdFromGraphQLId(fromListId),
toListId: getIdFromGraphQLId(toListId),
moveBeforeId,
moveAfterId,
epicId,
},
})
.then(({ data }) => {
if (data?.issueMoveList?.errors.length) {
throw new Error();
} else {
const issue = data.issueMoveList?.issue;
commit(types.MOVE_ISSUE_SUCCESS, { issue });
if (epicId === null) {
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: issue.id,
prop: 'epic',
value: null,
});
} else if (epicId !== undefined) {
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: issue.id,
prop: 'epic',
value: { id: epicId },
});
}
})
.catch(() =>
commit(types.MOVE_ISSUE_FAILURE, { originalIssue, fromListId, toListId, originalIndex }),
);
},
moveEpic: ({ state, commit }, { itemId, fromListId, toListId, moveBeforeId, moveAfterId }) => {
......
......@@ -150,25 +150,6 @@ export default {
Vue.set(state, 'epics', []);
},
[mutationTypes.MOVE_ISSUE]: (
state,
{ originalIssue, fromListId, toListId, moveBeforeId, moveAfterId, epicId },
) => {
const fromList = state.boardLists[fromListId];
const toList = state.boardLists[toListId];
const issue = moveItemListHelper(originalIssue, fromList, toList);
if (epicId === null) {
Vue.set(state.boardItems, issue.id, { ...issue, epic: null });
} else if (epicId !== undefined) {
Vue.set(state.boardItems, issue.id, { ...issue, epic: { id: epicId } });
}
removeItemFromList({ state, listId: fromListId, itemId: issue.id });
addItemToList({ state, listId: toListId, itemId: issue.id, moveBeforeId, moveAfterId });
},
[mutationTypes.MOVE_EPIC]: (
state,
{ originalEpic, fromListId, toListId, moveBeforeId, moveAfterId },
......
---
title: Clone issue card on move when necessary in epic swimlanes
merge_request: 58644
author:
type: fixed
......@@ -9,6 +9,7 @@ import * as types from 'ee/boards/stores/mutation_types';
import mutations from 'ee/boards/stores/mutations';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
import { mockMoveIssueParams, mockMoveData, mockMoveState } from 'jest/boards/mock_data';
import { formatBoardLists, formatListIssues } from '~/boards/boards_util';
import { issuableTypes } from '~/boards/constants';
import listsIssuesQuery from '~/boards/graphql/lists_issues.query.graphql';
......@@ -19,13 +20,10 @@ import {
labels,
mockLists,
mockIssue,
mockIssue2,
mockIssues,
mockEpic,
rawIssue,
mockMilestones,
mockAssignees,
mockEpics,
} from '../mock_data';
Vue.use(Vuex);
......@@ -903,204 +901,89 @@ describe.each`
});
describe('moveIssue', () => {
const epicId = 'gid://gitlab/Epic/1';
it('should dispatch a correct set of actions with epic id', () => {
const params = mockMoveIssueParams;
const listIssues = {
'gid://gitlab/List/1': [436, 437],
'gid://gitlab/List/2': [],
const moveData = {
...mockMoveData,
epicId: 'some-epic-id',
};
const issues = {
436: mockIssue,
437: mockIssue2,
};
const state = {
fullPath: 'gitlab-org',
boardId: 1,
boardType: 'group',
disabled: false,
boardLists: mockLists,
boardItemsByListId: listIssues,
boardItems: issues,
};
it('should commit MOVE_ISSUE mutation and MOVE_ISSUE_SUCCESS mutation when successful', (done) => {
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: {
issueMoveList: {
issue: rawIssue,
errors: [],
},
},
});
testAction(
actions.moveIssue,
{
itemId: '436',
itemIid: mockIssue.iid,
itemPath: mockIssue.referencePath,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
epicId,
},
state,
[
{
type: types.MOVE_ISSUE,
testAction({
action: actions.moveIssue,
payload: {
originalIssue: mockIssue,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
epicId,
},
...params,
epicId: 'some-epic-id',
},
state: mockMoveState,
expectedActions: [
{ type: 'moveIssueCard', payload: moveData },
{ type: 'updateMovedIssue', payload: moveData },
{ type: 'updateEpicForIssue', payload: { itemId: params.itemId, epicId: 'some-epic-id' } },
{
type: types.MOVE_ISSUE_SUCCESS,
payload: { issue: rawIssue },
},
],
[],
done,
);
});
it('should commit MOVE_ISSUE mutation and MOVE_ISSUE_FAILURE mutation when unsuccessful', (done) => {
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: {
issueMoveList: {
issue: {},
errors: [{ foo: 'bar' }],
},
},
});
testAction(
actions.moveIssue,
{
itemId: '436',
itemIid: mockIssue.iid,
itemPath: mockIssue.referencePath,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
epicId,
},
state,
[
{
type: types.MOVE_ISSUE,
type: 'requestIssueMoveListMutation',
payload: {
originalIssue: mockIssue,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
epicId,
},
moveData,
mutationVariables: {
epicId: 'some-epic-id',
},
{
type: types.MOVE_ISSUE_FAILURE,
payload: {
originalIssue: mockIssue,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
originalIndex: 0,
},
},
],
[],
done,
);
});
});
});
describe('moveEpic', () => {
const listEpics = {
'gid://gitlab/List/1': [41, 40],
'gid://gitlab/List/2': [],
};
const epics = {
41: mockEpic,
40: mockEpics[1],
};
describe('updateEpicForIssue', () => {
let commonState;
const state = {
fullPath: 'gitlab-org',
boardId: 1,
boardType: 'group',
disabled: false,
boardLists: mockLists,
boardItemsByListId: listEpics,
boardItems: epics,
issuableType: 'epic',
};
it('should commit MOVE_EPIC mutation mutation when successful', async () => {
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: {
epicMoveList: {
errors: [],
beforeEach(() => {
commonState = {
boardItems: {
itemId: {
id: 'issueId',
},
},
};
});
await testAction({
action: actions.moveEpic,
it.each([
[
'with epic id',
{
payload: {
itemId: '41',
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
itemId: 'itemId',
epicId: 'epicId',
},
state,
expectedMutations: [
{
type: types.MOVE_EPIC,
payload: {
originalEpic: mockEpic,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
},
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload: { itemId: 'issueId', prop: 'epic', value: { id: 'epicId' } },
},
],
});
});
it('should commit MOVE_EPIC mutation and MOVE_EPIC_FAILURE mutation when unsuccessful', async () => {
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: {
epicMoveList: {
errors: [{ foo: 'bar' }],
},
},
});
await testAction({
action: actions.moveEpic,
payload: {
itemId: '41',
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
},
state,
expectedMutations: [
],
[
'with null as epic id',
{
type: types.MOVE_EPIC,
payload: {
originalEpic: mockEpic,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
},
itemId: 'itemId',
epicId: null,
},
expectedMutations: [
{
type: types.MOVE_EPIC_FAILURE,
payload: {
originalEpic: mockEpic,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
originalIndex: 0,
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload: { itemId: 'issueId', prop: 'epic', value: null },
},
],
},
],
])(`commits UPDATE_BOARD_ITEM_BY_ID mutation %s`, (_, { payload, expectedMutations }) => {
testAction({
action: actions.updateEpicForIssue,
payload,
state: commonState,
expectedMutations,
});
});
});
......
import mutations from 'ee/boards/stores/mutations';
import { mockIssue, mockIssue2, mockEpics, mockEpic, mockLists } from '../mock_data';
import { mockEpics, mockEpic, mockLists } from '../mock_data';
const expectNotImplemented = (action) => {
it('is not implemented', () => {
......@@ -7,8 +7,6 @@ const expectNotImplemented = (action) => {
});
};
const epicId = mockEpic.id;
const initialBoardListsState = {
'gid://gitlab/List/1': mockLists[0],
'gid://gitlab/List/2': mockLists[1],
......@@ -222,64 +220,6 @@ describe('RESET_EPICS', () => {
});
});
describe('MOVE_ISSUE', () => {
beforeEach(() => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
'gid://gitlab/List/2': [],
};
const issues = {
436: mockIssue,
437: mockIssue2,
};
state = {
...state,
boardItemsByListId: listIssues,
boardItems: issues,
};
});
it('updates boardItemsByListId, moving issue between lists and updating epic id on issue', () => {
expect(state.boardItems['437'].epic.id).toEqual('gid://gitlab/Epic/40');
mutations.MOVE_ISSUE(state, {
originalIssue: mockIssue2,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
epicId,
});
const updatedListIssues = {
'gid://gitlab/List/1': [mockIssue.id],
'gid://gitlab/List/2': [mockIssue2.id],
};
expect(state.boardItemsByListId).toEqual(updatedListIssues);
expect(state.boardItems['437'].epic.id).toEqual(epicId);
});
it('removes epic id from issue when epicId is null', () => {
expect(state.boardItems['437'].epic.id).toEqual('gid://gitlab/Epic/40');
mutations.MOVE_ISSUE(state, {
originalIssue: mockIssue2,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
epicId: null,
});
const updatedListIssues = {
'gid://gitlab/List/1': [mockIssue.id],
'gid://gitlab/List/2': [mockIssue2.id],
};
expect(state.boardItemsByListId).toEqual(updatedListIssues);
expect(state.boardItems['437'].epic).toEqual(null);
});
});
describe('MOVE_EPIC', () => {
it('updates boardItemsByListId, moving epic between lists', () => {
const listIssues = {
......
......@@ -3,6 +3,7 @@
import { keyBy } from 'lodash';
import Vue from 'vue';
import '~/boards/models/list';
import { ListType } from '~/boards/constants';
import boardsStore from '~/boards/stores/boards_store';
export const boardObj = {
......@@ -488,3 +489,38 @@ export const mockBlockedIssue2 = {
blockedByCount: 4,
webUrl: 'http://gdk.test:3000/gitlab-org/my-project-1/-/issues/0',
};
export const mockMoveIssueParams = {
itemId: 1,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
moveBeforeId: undefined,
moveAfterId: undefined,
};
export const mockMoveState = {
boardLists: {
'gid://gitlab/List/1': {
listType: ListType.backlog,
},
'gid://gitlab/List/2': {
listType: ListType.closed,
},
},
boardItems: {
[mockMoveIssueParams.itemId]: { foo: 'bar' },
},
boardItemsByListId: {
[mockMoveIssueParams.fromListId]: [mockMoveIssueParams.itemId],
[mockMoveIssueParams.toListId]: [],
},
};
export const mockMoveData = {
reordering: false,
shouldClone: false,
itemNotInToList: true,
originalIndex: 0,
originalIssue: { foo: 'bar' },
...mockMoveIssueParams,
};
This diff is collapsed.
......@@ -394,41 +394,7 @@ describe('Board Store Mutations', () => {
expectNotImplemented(mutations.RECEIVE_ADD_ISSUE_ERROR);
});
describe('MOVE_ISSUE', () => {
it('updates boardItemsByListId, moving issue between lists', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
'gid://gitlab/List/2': [],
};
const issues = {
1: mockIssue,
2: mockIssue2,
};
state = {
...state,
boardItemsByListId: listIssues,
boardLists: initialBoardListsState,
boardItems: issues,
};
mutations.MOVE_ISSUE(state, {
originalIssue: mockIssue2,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
});
const updatedListIssues = {
'gid://gitlab/List/1': [mockIssue.id],
'gid://gitlab/List/2': [mockIssue2.id],
};
expect(state.boardItemsByListId).toEqual(updatedListIssues);
});
});
describe('MOVE_ISSUE_SUCCESS', () => {
describe('MUTATE_ISSUE_SUCCESS', () => {
it('updates issue in issues state', () => {
const issues = {
436: { id: rawIssue.id },
......@@ -439,7 +405,7 @@ describe('Board Store Mutations', () => {
boardItems: issues,
};
mutations.MOVE_ISSUE_SUCCESS(state, {
mutations.MUTATE_ISSUE_SUCCESS(state, {
issue: rawIssue,
});
......@@ -447,36 +413,6 @@ describe('Board Store Mutations', () => {
});
});
describe('MOVE_ISSUE_FAILURE', () => {
it('updates boardItemsByListId, reverting moving issue between lists, and sets error message', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id],
'gid://gitlab/List/2': [mockIssue2.id],
};
state = {
...state,
boardItemsByListId: listIssues,
boardLists: initialBoardListsState,
};
mutations.MOVE_ISSUE_FAILURE(state, {
originalIssue: mockIssue2,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
originalIndex: 1,
});
const updatedListIssues = {
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
'gid://gitlab/List/2': [],
};
expect(state.boardItemsByListId).toEqual(updatedListIssues);
expect(state.error).toEqual('An error occurred while moving the issue. Please try again.');
});
});
describe('UPDATE_BOARD_ITEM', () => {
it('updates the given issue in state.boardItems', () => {
const updatedIssue = { id: 'some_gid', foo: 'bar' };
......
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