import { cloneDeep, pull, union } from 'lodash'; import Vue from 'vue'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { TYPE_EPIC } from '~/issues/constants'; import { s__, __ } from '~/locale'; import { formatIssue } from '../boards_util'; import * as mutationTypes from './mutation_types'; const updateListItemsCount = ({ state, listId, value }) => { const list = state.boardLists[listId]; if (state.issuableType === TYPE_EPIC) { const listItem = cloneDeep(state.boardLists[listId]); listItem.metadataepicsCount += value; Vue.set(state.boardLists[listId], listId, listItem); } Vue.set(state.boardLists, listId, { ...list }); }; export const removeItemFromList = ({ state, listId, itemId, reordering = false }) => { Vue.set(state.boardItemsByListId, listId, pull(state.boardItemsByListId[listId], itemId)); if (!reordering) { updateListItemsCount({ state, listId, value: -1 }); } }; export const addItemToList = ({ state, listId, itemId, moveBeforeId, moveAfterId, atIndex, positionInList, reordering = false, }) => { const listIssues = state.boardItemsByListId[listId]; let newIndex = atIndex || 0; const moveToStartOrLast = positionInList !== undefined; if (moveBeforeId) { newIndex = listIssues.indexOf(moveBeforeId) + 1; } else if (moveAfterId) { newIndex = listIssues.indexOf(moveAfterId); } else if (moveToStartOrLast) { newIndex = positionInList === -1 ? listIssues.length : 0; } listIssues.splice(newIndex, 0, itemId); Vue.set(state.boardItemsByListId, listId, listIssues); if (!reordering) { updateListItemsCount({ state, listId, value: moveToStartOrLast ? 0 : 1 }); } }; export default { [mutationTypes.REQUEST_CURRENT_BOARD]: (state) => { state.isBoardLoading = true; }, [mutationTypes.RECEIVE_BOARD_SUCCESS]: (state, board) => { state.board = { ...board, labels: board?.labels?.nodes || [], }; state.fullBoardId = board.id; state.boardId = getIdFromGraphQLId(board.id); state.isBoardLoading = false; }, [mutationTypes.RECEIVE_BOARD_FAILURE]: (state) => { state.error = s__('Boards|An error occurred while fetching the board. Please reload the page.'); state.isBoardLoading = false; }, [mutationTypes.SET_INITIAL_BOARD_DATA](state, data) { const { allowSubEpics, boardId, boardType, disabled, fullBoardId, fullPath, issuableType, } = data; state.allowSubEpics = allowSubEpics; state.boardId = boardId; state.boardType = boardType; state.disabled = disabled; state.fullBoardId = fullBoardId; state.fullPath = fullPath; state.issuableType = issuableType; }, [mutationTypes.SET_BOARD_CONFIG](state, boardConfig) { state.boardConfig = boardConfig; }, [mutationTypes.RECEIVE_BOARD_LISTS_SUCCESS]: (state, lists) => { state.boardLists = lists; }, [mutationTypes.RECEIVE_BOARD_LISTS_FAILURE]: (state) => { state.error = s__( 'Boards|An error occurred while fetching the board lists. Please reload the page.', ); }, [mutationTypes.SET_ACTIVE_ID](state, { id, sidebarType }) { state.activeId = id; state.sidebarType = sidebarType; }, [mutationTypes.SET_FILTERS](state, filterParams) { state.filterParams = filterParams; }, [mutationTypes.CREATE_LIST_FAILURE]: ( state, error = s__('Boards|An error occurred while creating the list. Please try again.'), ) => { state.error = error; }, [mutationTypes.RECEIVE_LABELS_REQUEST]: (state) => { state.labelsLoading = true; }, [mutationTypes.RECEIVE_LABELS_SUCCESS]: (state, labels) => { state.labels = labels; state.labelsLoading = false; }, [mutationTypes.RECEIVE_LABELS_FAILURE]: (state) => { state.error = s__('Boards|An error occurred while fetching labels. Please reload the page.'); state.labelsLoading = false; }, [mutationTypes.GENERATE_DEFAULT_LISTS_FAILURE]: (state) => { state.error = s__('Boards|An error occurred while generating lists. Please reload the page.'); }, [mutationTypes.RECEIVE_ADD_LIST_SUCCESS]: (state, list) => { Vue.set(state.boardLists, list.id, list); }, [mutationTypes.MOVE_LISTS]: (state, movedLists) => { const updatedBoardList = movedLists.reduce((acc, { listId, position }) => { acc[listId].position = position; return acc; }, cloneDeep(state.boardLists)); Vue.set(state, 'boardLists', updatedBoardList); }, [mutationTypes.TOGGLE_LIST_COLLAPSED]: (state, { listId, collapsed }) => { Vue.set(state.boardLists[listId], 'collapsed', collapsed); }, [mutationTypes.REMOVE_LIST]: (state, listId) => { Vue.delete(state.boardLists, listId); }, [mutationTypes.REMOVE_LIST_FAILURE](state, listsBackup) { state.error = s__('Boards|An error occurred while removing the list. Please try again.'); state.boardLists = listsBackup; }, [mutationTypes.REQUEST_ITEMS_FOR_LIST]: (state, { listId, fetchNext }) => { 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 }) => { const { listData, boardItems } = listItems; Vue.set(state, 'boardItems', { ...state.boardItems, ...boardItems }); Vue.set( state.boardItemsByListId, listId, union(state.boardItemsByListId[listId] || [], listData[listId]), ); Vue.set(state.pageInfoByListId, listId, listPageInfo[listId]); Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false }); }, [mutationTypes.RECEIVE_ITEMS_FOR_LIST_FAILURE]: (state, listId) => { state.error = s__( 'Boards|An error occurred while fetching the board issues. Please reload the page.', ); Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false }); }, [mutationTypes.RESET_ISSUES]: (state) => { Object.keys(state.boardItemsByListId).forEach((listId) => { Vue.set(state.boardItemsByListId, listId, []); }); }, [mutationTypes.UPDATE_BOARD_ITEM_BY_ID]: (state, { itemId, prop, value }) => { if (!state.boardItems[itemId]) { /* eslint-disable-next-line @gitlab/require-i18n-strings */ throw new Error('No issue found.'); } Vue.set(state.boardItems[itemId], prop, value); }, [mutationTypes.SET_ASSIGNEE_LOADING](state, isLoading) { state.isSettingAssignees = isLoading; }, [mutationTypes.MUTATE_ISSUE_SUCCESS]: (state, { issue }) => { Vue.set(state.boardItems, issue.id, formatIssue(issue)); }, [mutationTypes.MUTATE_ISSUE_IN_PROGRESS](state, isLoading) { state.isUpdateIssueOrderInProgress = isLoading; }, [mutationTypes.ADD_BOARD_ITEM_TO_LIST]: ( state, { itemId, listId, moveBeforeId, moveAfterId, atIndex, positionInList, allItemsLoadedInList, inProgress = false, }, ) => { Vue.set(state.listsFlags, listId, { ...state.listsFlags, addItemToListInProgress: inProgress }); addItemToList({ state, listId, itemId, moveBeforeId, moveAfterId, atIndex, positionInList, allItemsLoadedInList, }); }, [mutationTypes.REMOVE_BOARD_ITEM_FROM_LIST]: (state, { itemId, listId }) => { removeItemFromList({ state, listId, itemId }); }, [mutationTypes.UPDATE_BOARD_ITEM]: (state, item) => { Vue.set(state.boardItems, item.id, item); }, [mutationTypes.REMOVE_BOARD_ITEM]: (state, itemId) => { Vue.delete(state.boardItems, itemId); }, [mutationTypes.REQUEST_GROUP_PROJECTS]: (state, fetchNext) => { Vue.set(state, 'groupProjectsFlags', { [fetchNext ? 'isLoadingMore' : 'isLoading']: true, pageInfo: state.groupProjectsFlags.pageInfo, }); }, [mutationTypes.RECEIVE_GROUP_PROJECTS_SUCCESS]: (state, { projects, pageInfo, fetchNext }) => { Vue.set(state, 'groupProjects', fetchNext ? [...state.groupProjects, ...projects] : projects); Vue.set(state, 'groupProjectsFlags', { isLoading: false, isLoadingMore: false, pageInfo }); }, [mutationTypes.RECEIVE_GROUP_PROJECTS_FAILURE]: (state) => { state.error = s__('Boards|An error occurred while fetching group projects. Please try again.'); Vue.set(state, 'groupProjectsFlags', { isLoading: false, isLoadingMore: false }); }, [mutationTypes.SET_SELECTED_PROJECT]: (state, project) => { state.selectedProject = project; }, [mutationTypes.ADD_BOARD_ITEM_TO_SELECTION]: (state, boardItem) => { state.selectedBoardItems = [...state.selectedBoardItems, boardItem]; }, [mutationTypes.REMOVE_BOARD_ITEM_FROM_SELECTION]: (state, boardItem) => { Vue.set( state, 'selectedBoardItems', state.selectedBoardItems.filter((obj) => obj !== boardItem), ); }, [mutationTypes.SET_ADD_COLUMN_FORM_VISIBLE]: (state, visible) => { Vue.set(state.addColumnForm, 'visible', visible); }, [mutationTypes.ADD_LIST_TO_HIGHLIGHTED_LISTS]: (state, listId) => { state.highlightedLists.push(listId); }, [mutationTypes.REMOVE_LIST_FROM_HIGHLIGHTED_LISTS]: (state, listId) => { state.highlightedLists = state.highlightedLists.filter((id) => id !== listId); }, [mutationTypes.RESET_BOARD_ITEM_SELECTION]: (state) => { state.selectedBoardItems = []; }, [mutationTypes.SET_ERROR]: (state, error) => { state.error = error; }, };