diff options
Diffstat (limited to 'app/assets/javascripts/boards/stores/actions.js')
-rw-r--r-- | app/assets/javascripts/boards/stores/actions.js | 306 |
1 files changed, 215 insertions, 91 deletions
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index 19b31ee7291..8005414962c 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -1,16 +1,21 @@ +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, inactiveId, flashAnimationDuration, ISSUABLE, + titleQueries, + subscriptionQueries, } from '~/boards/constants'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import createGqClient, { fetchPolicies } from '~/lib/graphql'; import { convertObjectPropsToCamelCase, urlParamsToObject } from '~/lib/utils/common_utils'; +import { s__ } from '~/locale'; import { formatBoardLists, formatListIssues, @@ -20,18 +25,17 @@ 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'; -import issueSetSubscriptionMutation from '../graphql/issue_set_subscription.mutation.graphql'; -import issueSetTitleMutation from '../graphql/issue_set_title.mutation.graphql'; import listsIssuesQuery from '../graphql/lists_issues.query.graphql'; import * as types from './mutation_types'; @@ -68,6 +72,7 @@ export default { 'milestoneTitle', 'releaseTag', 'search', + 'myReactionEmoji', ]); filterParams.not = transformNotFilters(filters); commit(types.SET_FILTERS, filterParams); @@ -326,63 +331,155 @@ export default { commit(types.RESET_ISSUES); }, - moveItem: ({ dispatch }) => { - dispatch('moveIssue'); + moveItem: ({ dispatch }, payload) => { + 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('updateIssueOrder', { moveData }); + }, + + moveIssueCard: ({ commit }, moveData) => { + const { + reordering, + shouldClone, + itemNotInToList, + originalIndex, + 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) { + 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, + itemId, + fromListId, + toListId, + 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 }); + }, + + updateIssueOrder: 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 }); - } - }) - .catch(() => - commit(types.MOVE_ISSUE_FAILURE, { originalIssue, fromListId, toListId, originalIndex }), + }); + + if (data?.issueMoveList?.errors.length || !data.issueMoveList) { + throw new Error('issueMoveList empty'); + } + + 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) => { - commit('UPDATE_ISSUE_BY_ID', { - issueId: getters.activeIssue.id, + commit('UPDATE_BOARD_ITEM_BY_ID', { + itemId: getters.activeBoardItem.id, prop: 'assignees', value: assigneeUsernames, }); }, setActiveIssueMilestone: async ({ commit, getters }, input) => { - const { activeIssue } = getters; + const { activeBoardItem } = getters; const { data } = await gqlClient.mutate({ mutation: issueSetMilestoneMutation, variables: { input: { - iid: String(activeIssue.iid), + iid: String(activeBoardItem.iid), milestoneId: getIdFromGraphQLId(input.milestoneId), projectPath: input.projectPath, }, @@ -393,65 +490,71 @@ export default { throw new Error(data.updateIssue.errors); } - commit(types.UPDATE_ISSUE_BY_ID, { - issueId: activeIssue.id, + commit(types.UPDATE_BOARD_ITEM_BY_ID, { + itemId: activeBoardItem.id, prop: 'milestone', value: data.updateIssue.issue.milestone, }); }, - createNewIssue: ({ commit, state }, issueInput) => { - const { boardConfig } = state; + addListItem: ({ commit }, { list, item, position }) => { + commit(types.ADD_BOARD_ITEM_TO_LIST, { listId: list.id, itemId: item.id, atIndex: position }); + commit(types.UPDATE_BOARD_ITEM, item); + }, + + removeListItem: ({ commit }, { listId, itemId }) => { + commit(types.REMOVE_BOARD_ITEM_FROM_LIST, { listId, itemId }); + commit(types.REMOVE_BOARD_ITEM, itemId); + }, + addListNewIssue: ( + { state: { boardConfig, boardType, fullPath }, dispatch, commit }, + { issueInput, list, placeholderId = `tmp-${new Date().getTime()}` }, + ) => { const input = formatIssueInput(issueInput, boardConfig); - const { boardType, fullPath } = state; if (boardType === BoardType.project) { input.projectPath = fullPath; } - return gqlClient + const placeholderIssue = formatIssue({ ...issueInput, id: placeholderId }); + dispatch('addListItem', { list, item: placeholderIssue, position: 0 }); + + gqlClient .mutate({ mutation: issueCreateMutation, variables: { input }, }) .then(({ data }) => { if (data.createIssue.errors.length) { - commit(types.CREATE_ISSUE_FAILURE); - } else { - return data.createIssue?.issue; + throw new Error(); } - return null; - }) - .catch(() => commit(types.CREATE_ISSUE_FAILURE)); - }, - addListIssue: ({ commit }, { list, issue, position }) => { - commit(types.ADD_ISSUE_TO_LIST, { list, issue, position }); + const rawIssue = data.createIssue?.issue; + const formattedIssue = formatIssue({ ...rawIssue, id: getIdFromGraphQLId(rawIssue.id) }); + dispatch('removeListItem', { listId: list.id, itemId: placeholderId }); + dispatch('addListItem', { list, item: formattedIssue, position: 0 }); + }) + .catch(() => { + dispatch('removeListItem', { listId: list.id, itemId: placeholderId }); + commit( + types.SET_ERROR, + s__('Boards|An error occurred while creating the issue. Please try again.'), + ); + }); }, - addListNewIssue: ({ commit, dispatch }, { issueInput, list }) => { - const issue = formatIssue({ ...issueInput, id: 'tmp' }); - commit(types.ADD_ISSUE_TO_LIST, { list, issue, position: 0 }); - - dispatch('createNewIssue', issueInput) - .then((res) => { - commit(types.ADD_ISSUE_TO_LIST, { - list, - issue: formatIssue({ ...res, id: getIdFromGraphQLId(res.id) }), - }); - commit(types.REMOVE_ISSUE_FROM_LIST, { list, issue }); - }) - .catch(() => commit(types.ADD_ISSUE_TO_LIST_FAILURE, { list, issueId: issueInput.id })); + setActiveBoardItemLabels: ({ dispatch }, params) => { + dispatch('setActiveIssueLabels', params); }, setActiveIssueLabels: async ({ commit, getters }, input) => { - const { activeIssue } = getters; + const { activeBoardItem } = getters; const { data } = await gqlClient.mutate({ mutation: issueSetLabelsMutation, variables: { input: { - iid: String(activeIssue.iid), + iid: String(activeBoardItem.iid), addLabelIds: input.addLabelIds ?? [], removeLabelIds: input.removeLabelIds ?? [], projectPath: input.projectPath, @@ -463,20 +566,20 @@ export default { throw new Error(data.updateIssue.errors); } - commit(types.UPDATE_ISSUE_BY_ID, { - issueId: activeIssue.id, + commit(types.UPDATE_BOARD_ITEM_BY_ID, { + itemId: activeBoardItem.id, prop: 'labels', value: data.updateIssue.issue.labels.nodes, }); }, setActiveIssueDueDate: async ({ commit, getters }, input) => { - const { activeIssue } = getters; + const { activeBoardItem } = getters; const { data } = await gqlClient.mutate({ mutation: issueSetDueDateMutation, variables: { input: { - iid: String(activeIssue.iid), + iid: String(activeBoardItem.iid), projectPath: input.projectPath, dueDate: input.dueDate, }, @@ -487,57 +590,66 @@ export default { throw new Error(data.updateIssue.errors); } - commit(types.UPDATE_ISSUE_BY_ID, { - issueId: activeIssue.id, + commit(types.UPDATE_BOARD_ITEM_BY_ID, { + itemId: activeBoardItem.id, prop: 'dueDate', value: data.updateIssue.issue.dueDate, }); }, - setActiveIssueSubscribed: async ({ commit, getters }, input) => { + setActiveItemSubscribed: async ({ commit, getters, state }, input) => { + const { activeBoardItem, isEpicBoard } = getters; + const { fullPath, issuableType } = state; + const workspacePath = isEpicBoard + ? { groupPath: fullPath } + : { projectPath: input.projectPath }; const { data } = await gqlClient.mutate({ - mutation: issueSetSubscriptionMutation, + mutation: subscriptionQueries[issuableType].mutation, variables: { input: { - iid: String(getters.activeIssue.iid), - projectPath: input.projectPath, + ...workspacePath, + iid: String(activeBoardItem.iid), subscribedState: input.subscribed, }, }, }); - if (data.issueSetSubscription?.errors?.length > 0) { - throw new Error(data.issueSetSubscription.errors); + if (data.updateIssuableSubscription?.errors?.length > 0) { + throw new Error(data.updateIssuableSubscription[issuableType].errors); } - commit(types.UPDATE_ISSUE_BY_ID, { - issueId: getters.activeIssue.id, + commit(types.UPDATE_BOARD_ITEM_BY_ID, { + itemId: activeBoardItem.id, prop: 'subscribed', - value: data.issueSetSubscription.issue.subscribed, + value: data.updateIssuableSubscription[issuableType].subscribed, }); }, - setActiveIssueTitle: async ({ commit, getters }, input) => { - const { activeIssue } = getters; + setActiveItemTitle: async ({ commit, getters, state }, input) => { + const { activeBoardItem, isEpicBoard } = getters; + const { fullPath, issuableType } = state; + const workspacePath = isEpicBoard + ? { groupPath: fullPath } + : { projectPath: input.projectPath }; const { data } = await gqlClient.mutate({ - mutation: issueSetTitleMutation, + mutation: titleQueries[issuableType].mutation, variables: { input: { - iid: String(activeIssue.iid), - projectPath: input.projectPath, + ...workspacePath, + iid: String(activeBoardItem.iid), title: input.title, }, }, }); - if (data.updateIssue?.errors?.length > 0) { - throw new Error(data.updateIssue.errors); + if (data.updateIssuableTitle?.errors?.length > 0) { + throw new Error(data.updateIssuableTitle.errors); } - commit(types.UPDATE_ISSUE_BY_ID, { - issueId: activeIssue.id, + commit(types.UPDATE_BOARD_ITEM_BY_ID, { + itemId: activeBoardItem.id, prop: 'title', - value: data.updateIssue.issue.title, + value: data.updateIssuableTitle[issuableType].title, }); }, @@ -576,10 +688,10 @@ export default { const { selectedBoardItems } = state; const index = selectedBoardItems.indexOf(boardItem); - // If user already selected an item (activeIssue) without using mult-select, + // If user already selected an item (activeBoardItem) without using mult-select, // include that item in the selection and unset state.ActiveId to hide the sidebar. - if (getters.activeIssue) { - commit(types.ADD_BOARD_ITEM_TO_SELECTION, getters.activeIssue); + if (getters.activeBoardItem) { + commit(types.ADD_BOARD_ITEM_TO_SELECTION, getters.activeBoardItem); dispatch('unsetActiveId'); } @@ -608,6 +720,18 @@ export default { } }, + setError: ({ commit }, { message, error, captureError = false }) => { + commit(types.SET_ERROR, message); + + if (captureError) { + Sentry.captureException(error); + } + }, + + unsetError: ({ commit }) => { + commit(types.SET_ERROR, undefined); + }, + fetchBacklog: () => { notImplemented(); }, |