diff options
Diffstat (limited to 'app/assets/javascripts/boards/stores')
7 files changed, 78 insertions, 914 deletions
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index 970d00841bd..dc06b62cebb 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -36,11 +36,13 @@ import { filterVariables, } from '../boards_util'; import boardLabelsQuery from '../graphql/board_labels.query.graphql'; +import groupBoardIterationsQuery from '../graphql/group_board_iterations.query.graphql'; import groupBoardMilestonesQuery from '../graphql/group_board_milestones.query.graphql'; import groupProjectsQuery from '../graphql/group_projects.query.graphql'; import issueCreateMutation from '../graphql/issue_create.mutation.graphql'; import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql'; import listsIssuesQuery from '../graphql/lists_issues.query.graphql'; +import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql'; import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql'; import * as types from './mutation_types'; @@ -82,11 +84,8 @@ export default { 'setFilters', convertObjectPropsToCamelCase(queryToObject(window.location.search, { gatherArrays: true })), ); - - if (gon.features.graphqlBoardLists) { - dispatch('fetchLists'); - dispatch('resetIssues'); - } + dispatch('fetchLists'); + dispatch('resetIssues'); }, fetchLists: ({ commit, state, dispatch }) => { @@ -182,7 +181,7 @@ export default { }); }, - fetchLabels: ({ state, commit, getters }, searchTerm) => { + fetchLabels: ({ state, commit }, searchTerm) => { const { fullPath, boardType } = state; const variables = { @@ -200,14 +199,7 @@ export default { variables, }) .then(({ data }) => { - let labels = data[boardType]?.labels.nodes; - - if (!getters.shouldUseGraphQL && !getters.isEpicBoard) { - labels = labels.map((label) => ({ - ...label, - id: getIdFromGraphQLId(label.id), - })); - } + const labels = data[boardType]?.labels.nodes; commit(types.RECEIVE_LABELS_SUCCESS, labels); return labels; @@ -218,6 +210,52 @@ export default { }); }, + fetchIterations({ state, commit }, title) { + commit(types.RECEIVE_ITERATIONS_REQUEST); + + const { fullPath, boardType } = state; + + const variables = { + fullPath, + title, + }; + + let query; + if (boardType === BoardType.project) { + query = projectBoardIterationsQuery; + } + if (boardType === BoardType.group) { + query = groupBoardIterationsQuery; + } + + 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 iterations = data[boardType]?.iterations.nodes; + + if (errors?.[0]) { + throw new Error(errors[0]); + } + + commit(types.RECEIVE_ITERATIONS_SUCCESS, iterations); + + return iterations; + }) + .catch((e) => { + commit(types.RECEIVE_ITERATIONS_FAILURE); + throw e; + }); + }, + fetchMilestones({ state, commit }, searchTerm) { commit(types.RECEIVE_MILESTONES_REQUEST); @@ -536,8 +574,8 @@ export default { boardId: fullBoardId, fromListId: getIdFromGraphQLId(fromListId), toListId: getIdFromGraphQLId(toListId), - moveBeforeId, - moveAfterId, + moveBeforeId: moveBeforeId ? getIdFromGraphQLId(moveBeforeId) : undefined, + moveAfterId: moveAfterId ? getIdFromGraphQLId(moveAfterId) : undefined, // 'mutationVariables' allows EE code to pass in extra parameters. ...mutationVariables, }, @@ -604,7 +642,7 @@ export default { } const rawIssue = data.createIssue?.issue; - const formattedIssue = formatIssue({ ...rawIssue, id: getIdFromGraphQLId(rawIssue.id) }); + const formattedIssue = formatIssue(rawIssue); dispatch('removeListItem', { listId: list.id, itemId: placeholderId }); dispatch('addListItem', { list, item: formattedIssue, position: 0 }); }) @@ -640,7 +678,7 @@ export default { } commit(types.UPDATE_BOARD_ITEM_BY_ID, { - itemId: getIdFromGraphQLId(data.updateIssue?.issue?.id) || activeBoardItem.id, + itemId: data.updateIssue?.issue?.id || activeBoardItem.id, prop: 'labels', value: data.updateIssue.issue.labels.nodes, }); diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js deleted file mode 100644 index 857b0912c57..00000000000 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ /dev/null @@ -1,883 +0,0 @@ -/* eslint-disable no-shadow, no-param-reassign,consistent-return */ -/* global List */ -/* global ListIssue */ -import { sortBy } from 'lodash'; -import Vue from 'vue'; -import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee'; -import { getIdFromGraphQLId } from '~/graphql_shared/utils'; -import createDefaultClient from '~/lib/graphql'; -import axios from '~/lib/utils/axios_utils'; -import { parseBoolean, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; -import { mergeUrlParams, queryToObject, getUrlParamsArray } from '~/lib/utils/url_utility'; -import { ListType, flashAnimationDuration } from '../constants'; -import eventHub from '../eventhub'; -import ListAssignee from '../models/assignee'; -import ListLabel from '../models/label'; -import ListMilestone from '../models/milestone'; -import IssueProject from '../models/project'; - -const PER_PAGE = 20; -export const gqlClient = createDefaultClient(); - -const boardsStore = { - disabled: false, - timeTracking: { - limitToHours: false, - }, - scopedLabels: { - enabled: false, - }, - filter: { - path: '', - }, - state: { - currentBoard: { - labels: [], - }, - currentPage: '', - endpoints: {}, - }, - detail: { - issue: {}, - list: {}, - }, - moving: { - issue: {}, - list: {}, - }, - multiSelect: { list: [] }, - - setEndpoints({ - boardsEndpoint, - listsEndpoint, - bulkUpdatePath, - boardId, - recentBoardsEndpoint, - fullPath, - }) { - const listsEndpointGenerate = `${listsEndpoint}/generate.json`; - this.state.endpoints = { - boardsEndpoint, - boardId, - listsEndpoint, - listsEndpointGenerate, - bulkUpdatePath, - fullPath, - recentBoardsEndpoint: `${recentBoardsEndpoint}.json`, - }; - }, - create() { - this.state.lists = []; - this.filter.path = getUrlParamsArray().join('&'); - this.detail = { - issue: {}, - list: {}, - }; - }, - showPage(page) { - this.state.currentPage = page; - }, - updateListPosition(listObj) { - const listType = listObj.listType || listObj.list_type; - let { position } = listObj; - if (listType === ListType.closed) { - position = Infinity; - } else if (listType === ListType.backlog) { - position = -1; - } - - const list = new List({ ...listObj, position }); - return list; - }, - addList(listObj) { - const list = this.updateListPosition(listObj); - this.state.lists = sortBy([...this.state.lists, list], 'position'); - return list; - }, - new(listObj) { - const list = this.addList(listObj); - const backlogList = this.findList('type', 'backlog'); - - list - .save() - .then(() => { - list.highlighted = true; - setTimeout(() => { - list.highlighted = false; - }, flashAnimationDuration); - - // Remove any new issues from the backlog - // as they will be visible in the new list - list.issues.forEach(backlogList.removeIssue.bind(backlogList)); - this.state.lists = sortBy(this.state.lists, 'position'); - }) - .catch(() => { - // https://gitlab.com/gitlab-org/gitlab-foss/issues/30821 - }); - }, - - updateNewListDropdown(listId) { - document - .querySelector(`.js-board-list-${getIdFromGraphQLId(listId)}`) - ?.classList.remove('is-active'); - }, - - findIssueLabel(issue, findLabel) { - return issue.labels.find((label) => label.id === findLabel.id); - }, - - goToNextPage(list) { - if (list.issuesSize > list.issues.length) { - if (list.issues.length / PER_PAGE >= 1) { - list.page += 1; - } - - return list.getIssues(false); - } - }, - - addListIssue(list, issue, listFrom, newIndex) { - let moveBeforeId = null; - let moveAfterId = null; - - if (!list.findIssue(issue.id)) { - if (newIndex !== undefined) { - list.issues.splice(newIndex, 0, issue); - - if (list.issues[newIndex - 1]) { - moveBeforeId = list.issues[newIndex - 1].id; - } - - if (list.issues[newIndex + 1]) { - moveAfterId = list.issues[newIndex + 1].id; - } - } else { - list.issues.push(issue); - } - - if (list.label) { - issue.addLabel(list.label); - } - - if (list.assignee) { - if (listFrom && listFrom.type === 'assignee') { - issue.removeAssignee(listFrom.assignee); - } - issue.addAssignee(list.assignee); - } - - if (IS_EE && list.milestone) { - if (listFrom && listFrom.type === 'milestone') { - issue.removeMilestone(listFrom.milestone); - } - issue.addMilestone(list.milestone); - } - - if (listFrom) { - list.issuesSize += 1; - - list.updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId); - } - } - }, - findListIssue(list, id) { - return list.issues.find((issue) => issue.id === id); - }, - - removeList(id) { - const list = this.findList('id', id); - - if (!list) return; - - this.state.lists = this.state.lists.filter((list) => list.id !== id); - }, - moveList(listFrom, orderLists) { - orderLists.forEach((id, i) => { - const list = this.findList('id', parseInt(id, 10)); - - list.position = i; - }); - listFrom.update(); - }, - - addMultipleListIssues(list, issues, listFrom, newIndex) { - let moveBeforeId = null; - let moveAfterId = null; - - const listHasIssues = issues.every((issue) => list.findIssue(issue.id)); - - if (!listHasIssues) { - if (newIndex !== undefined) { - if (list.issues[newIndex - 1]) { - moveBeforeId = list.issues[newIndex - 1].id; - } - - if (list.issues[newIndex]) { - moveAfterId = list.issues[newIndex].id; - } - - list.issues.splice(newIndex, 0, ...issues); - } else { - list.issues.push(...issues); - } - - if (list.label) { - issues.forEach((issue) => issue.addLabel(list.label)); - } - - if (list.assignee) { - if (listFrom && listFrom.type === 'assignee') { - issues.forEach((issue) => issue.removeAssignee(listFrom.assignee)); - } - issues.forEach((issue) => issue.addAssignee(list.assignee)); - } - - if (IS_EE && list.milestone) { - if (listFrom && listFrom.type === 'milestone') { - issues.forEach((issue) => issue.removeMilestone(listFrom.milestone)); - } - issues.forEach((issue) => issue.addMilestone(list.milestone)); - } - - if (listFrom) { - list.issuesSize += issues.length; - - list.updateMultipleIssues(issues, listFrom, moveBeforeId, moveAfterId); - } - } - }, - - removeListIssues(list, removeIssue) { - list.issues = list.issues.filter((issue) => { - const matchesRemove = removeIssue.id === issue.id; - - if (matchesRemove) { - list.issuesSize -= 1; - issue.removeLabel(list.label); - } - - return !matchesRemove; - }); - }, - removeListMultipleIssues(list, removeIssues) { - const ids = removeIssues.map((issue) => issue.id); - - list.issues = list.issues.filter((issue) => { - const matchesRemove = ids.includes(issue.id); - - if (matchesRemove) { - list.issuesSize -= 1; - issue.removeLabel(list.label); - } - - return !matchesRemove; - }); - }, - - startMoving(list, issue) { - Object.assign(this.moving, { list, issue }); - }, - - onNewListIssueResponse(list, issue, data) { - issue.refreshData(data); - - if (list.issues.length > 1) { - const moveBeforeId = list.issues[1].id; - this.moveIssue(issue.id, null, null, null, moveBeforeId); - } - }, - - moveMultipleIssuesToList({ listFrom, listTo, issues, newIndex }) { - const issueTo = issues.map((issue) => listTo.findIssue(issue.id)); - const issueLists = issues.map((issue) => issue.getLists()).flat(); - const listLabels = issueLists.map((list) => list.label); - const hasMoveableIssues = issueTo.filter(Boolean).length > 0; - - if (!hasMoveableIssues) { - // Check if target list assignee is already present in this issue - if ( - listTo.type === ListType.assignee && - listFrom.type === ListType.assignee && - issues.some((issue) => issue.findAssignee(listTo.assignee)) - ) { - const targetIssues = issues.map((issue) => listTo.findIssue(issue.id)); - targetIssues.forEach((targetIssue) => targetIssue.removeAssignee(listFrom.assignee)); - } else if (listTo.type === 'milestone') { - const currentMilestones = issues.map((issue) => issue.milestone); - const currentLists = this.state.lists - .filter((list) => list.type === 'milestone' && list.id !== listTo.id) - .filter((list) => - list.issues.some((listIssue) => issues.some((issue) => listIssue.id === issue.id)), - ); - - issues.forEach((issue) => { - currentMilestones.forEach((milestone) => { - issue.removeMilestone(milestone); - }); - }); - - issues.forEach((issue) => { - issue.addMilestone(listTo.milestone); - }); - - currentLists.forEach((currentList) => { - issues.forEach((issue) => { - currentList.removeIssue(issue); - }); - }); - - listTo.addMultipleIssues(issues, listFrom, newIndex); - } else { - // Add to new lists issues if it doesn't already exist - listTo.addMultipleIssues(issues, listFrom, newIndex); - } - } else { - listTo.updateMultipleIssues(issues, listFrom); - issues.forEach((issue) => { - issue.removeLabel(listFrom.label); - }); - } - - if (listTo.type === ListType.closed && listFrom.type !== ListType.backlog) { - issueLists.forEach((list) => { - issues.forEach((issue) => { - list.removeIssue(issue); - }); - }); - - issues.forEach((issue) => { - issue.removeLabels(listLabels); - }); - } else if (listTo.type === ListType.backlog && listFrom.type === ListType.assignee) { - issues.forEach((issue) => { - issue.removeAssignee(listFrom.assignee); - }); - issueLists.forEach((list) => { - issues.forEach((issue) => { - list.removeIssue(issue); - }); - }); - } else if (listTo.type === ListType.backlog && listFrom.type === ListType.milestone) { - issues.forEach((issue) => { - issue.removeMilestone(listFrom.milestone); - }); - issueLists.forEach((list) => { - issues.forEach((issue) => { - list.removeIssue(issue); - }); - }); - } else if ( - this.shouldRemoveIssue(listFrom, listTo) && - this.issuesAreContiguous(listFrom, issues) - ) { - listFrom.removeMultipleIssues(issues); - } - }, - - issuesAreContiguous(list, issues) { - // When there's only 1 issue selected, we can return early. - if (issues.length === 1) return true; - - // Create list of ids for issues involved. - const listIssueIds = list.issues.map((issue) => issue.id); - const movedIssueIds = issues.map((issue) => issue.id); - - // Check if moved issue IDs is sub-array - // of source list issue IDs (i.e. contiguous selection). - return listIssueIds.join('|').includes(movedIssueIds.join('|')); - }, - - moveIssueToList(listFrom, listTo, issue, newIndex) { - const issueTo = listTo.findIssue(issue.id); - const issueLists = issue.getLists(); - const listLabels = issueLists.map((listIssue) => listIssue.label); - - if (!issueTo) { - // Check if target list assignee is already present in this issue - if ( - listTo.type === 'assignee' && - listFrom.type === 'assignee' && - issue.findAssignee(listTo.assignee) - ) { - const targetIssue = listTo.findIssue(issue.id); - targetIssue.removeAssignee(listFrom.assignee); - } else if (listTo.type === 'milestone') { - const currentMilestone = issue.milestone; - const currentLists = this.state.lists - .filter((list) => list.type === 'milestone' && list.id !== listTo.id) - .filter((list) => list.issues.some((listIssue) => issue.id === listIssue.id)); - - issue.removeMilestone(currentMilestone); - issue.addMilestone(listTo.milestone); - currentLists.forEach((currentList) => currentList.removeIssue(issue)); - listTo.addIssue(issue, listFrom, newIndex); - } else { - // Add to new lists issues if it doesn't already exist - listTo.addIssue(issue, listFrom, newIndex); - } - } else { - listTo.updateIssueLabel(issue, listFrom); - issueTo.removeLabel(listFrom.label); - } - - if (listTo.type === 'closed' && listFrom.type !== 'backlog') { - issueLists.forEach((list) => { - list.removeIssue(issue); - }); - issue.removeLabels(listLabels); - } else if (listTo.type === 'backlog' && listFrom.type === 'assignee') { - issue.removeAssignee(listFrom.assignee); - listFrom.removeIssue(issue); - } else if (listTo.type === 'backlog' && listFrom.type === 'milestone') { - issue.removeMilestone(listFrom.milestone); - listFrom.removeIssue(issue); - } else if (this.shouldRemoveIssue(listFrom, listTo)) { - listFrom.removeIssue(issue); - } - }, - shouldRemoveIssue(listFrom, listTo) { - return ( - (listTo.type !== 'label' && listFrom.type === 'assignee') || - (listTo.type !== 'assignee' && listFrom.type === 'label') || - listFrom.type === 'backlog' || - listFrom.type === 'closed' - ); - }, - moveIssueInList(list, issue, oldIndex, newIndex, idArray) { - const beforeId = parseInt(idArray[newIndex - 1], 10) || null; - const afterId = parseInt(idArray[newIndex + 1], 10) || null; - - list.moveIssue(issue, oldIndex, newIndex, beforeId, afterId); - }, - moveMultipleIssuesInList({ list, issues, oldIndicies, newIndex, idArray }) { - const beforeId = parseInt(idArray[newIndex - 1], 10) || null; - const afterId = parseInt(idArray[newIndex + issues.length], 10) || null; - list.moveMultipleIssues({ - issues, - oldIndicies, - newIndex, - moveBeforeId: beforeId, - moveAfterId: afterId, - }); - }, - findList(key, val) { - return this.state.lists.find((list) => list[key] === val); - }, - findListByLabelId(id) { - return this.state.lists.find((list) => list.type === 'label' && list.label.id === id); - }, - - toggleFilter(filter) { - const filterPath = this.filter.path.split('&'); - const filterIndex = filterPath.indexOf(filter); - - if (filterIndex === -1) { - filterPath.push(filter); - } else { - filterPath.splice(filterIndex, 1); - } - - this.filter.path = filterPath.join('&'); - - this.updateFiltersUrl(); - - eventHub.$emit('updateTokens'); - }, - - setListDetail(newList) { - this.detail.list = newList; - }, - - updateFiltersUrl() { - window.history.pushState(null, null, `?${this.filter.path}`); - }, - - clearDetailIssue() { - this.setIssueDetail({}); - }, - - setIssueDetail(issueDetail) { - this.detail.issue = issueDetail; - }, - - setTimeTrackingLimitToHours(limitToHours) { - this.timeTracking.limitToHours = parseBoolean(limitToHours); - }, - - generateBoardGid(boardId) { - return `gid://gitlab/Board/${boardId}`; - }, - - generateBoardsPath(id) { - return `${this.state.endpoints.boardsEndpoint}${id ? `/${id}` : ''}.json`; - }, - - generateIssuesPath(id) { - return `${this.state.endpoints.listsEndpoint}${id ? `/${id}` : ''}/issues`; - }, - - generateIssuePath(boardId, id) { - return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues${ - id ? `/${id}` : '' - }`; - }, - - generateMultiDragPath(boardId) { - return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues/bulk_move`; - }, - - all() { - return axios.get(this.state.endpoints.listsEndpoint); - }, - - createList(entityId, entityType) { - const list = { - [entityType]: entityId, - }; - - return axios.post(this.state.endpoints.listsEndpoint, { - list, - }); - }, - - updateList(id, position, collapsed) { - return axios.put(`${this.state.endpoints.listsEndpoint}/${id}`, { - list: { - position, - collapsed, - }, - }); - }, - - updateListFunc(list) { - const collapsed = !list.isExpanded; - return this.updateList(list.id, list.position, collapsed).catch(() => { - // TODO: handle request error - }); - }, - - destroyList(id) { - return axios.delete(`${this.state.endpoints.listsEndpoint}/${id}`); - }, - destroy(list) { - const index = this.state.lists.indexOf(list); - this.state.lists.splice(index, 1); - this.updateNewListDropdown(list.id); - - this.destroyList(list.id).catch(() => { - // TODO: handle request error - }); - }, - - saveList(list) { - const entity = list.label || list.assignee || list.milestone || list.iteration; - let entityType = ''; - if (list.label) { - entityType = 'label_id'; - } else if (list.assignee) { - entityType = 'assignee_id'; - } else if (IS_EE && list.milestone) { - entityType = 'milestone_id'; - } else if (IS_EE && list.iteration) { - entityType = 'iteration_id'; - } - - return this.createList(entity.id, entityType) - .then((res) => res.data) - .then((data) => { - list.id = data.id; - list.type = data.list_type; - list.position = data.position; - list.label = data.label; - - return list.getIssues(); - }); - }, - - getListIssues(list, emptyIssues = true) { - const data = { - ...queryToObject(this.filter.path, { gatherArrays: true }), - page: list.page, - }; - - if (list.label && data.label_name) { - data.label_name = data.label_name.filter((label) => label !== list.label.title); - } - - if (emptyIssues) { - list.loading = true; - } - - return this.getIssuesForList(list.id, data) - .then((res) => res.data) - .then((data) => { - list.loading = false; - list.issuesSize = data.size; - - if (emptyIssues) { - list.issues = []; - } - - data.issues.forEach((issueObj) => { - list.addIssue(new ListIssue(issueObj)); - }); - - return data; - }); - }, - - getIssuesForList(id, filter = {}) { - const data = { id }; - Object.keys(filter).forEach((key) => { - data[key] = filter[key]; - }); - - return axios.get(mergeUrlParams(data, this.generateIssuesPath(id))); - }, - - moveIssue(id, fromListId = null, toListId = null, moveBeforeId = null, moveAfterId = null) { - return axios.put(this.generateIssuePath(this.state.endpoints.boardId, id), { - from_list_id: fromListId, - to_list_id: toListId, - move_before_id: moveBeforeId, - move_after_id: moveAfterId, - }); - }, - - moveListIssues(list, issue, oldIndex, newIndex, moveBeforeId, moveAfterId) { - list.issues.splice(oldIndex, 1); - list.issues.splice(newIndex, 0, issue); - - this.moveIssue(issue.id, null, null, moveBeforeId, moveAfterId).catch(() => { - // TODO: handle request error - }); - }, - - moveMultipleIssues({ ids, fromListId, toListId, moveBeforeId, moveAfterId }) { - return axios.put(this.generateMultiDragPath(this.state.endpoints.boardId), { - from_list_id: fromListId, - to_list_id: toListId, - move_before_id: moveBeforeId, - move_after_id: moveAfterId, - ids, - }); - }, - - moveListMultipleIssues({ list, issues, oldIndicies, newIndex, moveBeforeId, moveAfterId }) { - oldIndicies.reverse().forEach((index) => { - list.issues.splice(index, 1); - }); - list.issues.splice(newIndex, 0, ...issues); - - return this.moveMultipleIssues({ - ids: issues.map((issue) => issue.id), - fromListId: null, - toListId: null, - moveBeforeId, - moveAfterId, - }); - }, - - newIssue(id, issue) { - if (typeof id === 'string') { - id = getIdFromGraphQLId(id); - } - - return axios.post(this.generateIssuesPath(id), { - issue, - }); - }, - - newListIssue(list, issue) { - list.addIssue(issue, null, 0); - list.issuesSize += 1; - let listId = list.id; - if (typeof listId === 'string') { - listId = getIdFromGraphQLId(listId); - } - - return this.newIssue(list.id, issue) - .then((res) => res.data) - .then((data) => list.onNewIssueResponse(issue, data)); - }, - - getBacklog(data) { - return axios.get( - mergeUrlParams( - data, - `${gon.relative_url_root}/-/boards/${this.state.endpoints.boardId}/issues.json`, - ), - ); - }, - removeIssueLabel(issue, removeLabel) { - if (removeLabel) { - issue.labels = issue.labels.filter((label) => removeLabel.id !== label.id); - } - }, - - addIssueAssignee(issue, assignee) { - if (!issue.findAssignee(assignee)) { - issue.assignees.push(new ListAssignee(assignee)); - } - }, - - setIssueAssignees(issue, assignees) { - issue.assignees = [...assignees]; - }, - - removeIssueLabels(issue, labels) { - labels.forEach(issue.removeLabel.bind(issue)); - }, - - bulkUpdate(issueIds, extraData = {}) { - const data = { - update: Object.assign(extraData, { - issuable_ids: issueIds.join(','), - }), - }; - - return axios.post(this.state.endpoints.bulkUpdatePath, data); - }, - - getIssueInfo(endpoint) { - return axios.get(endpoint); - }, - - toggleIssueSubscription(endpoint) { - return axios.post(endpoint); - }, - - recentBoards() { - return axios.get(this.state.endpoints.recentBoardsEndpoint); - }, - - setCurrentBoard(board) { - this.state.currentBoard = board; - }, - - toggleMultiSelect(issue) { - const selectedIssueIds = this.multiSelect.list.map((issue) => issue.id); - const index = selectedIssueIds.indexOf(issue.id); - - if (index === -1) { - this.multiSelect.list.push(issue); - return; - } - - this.multiSelect.list = [ - ...this.multiSelect.list.slice(0, index), - ...this.multiSelect.list.slice(index + 1), - ]; - }, - removeIssueAssignee(issue, removeAssignee) { - if (removeAssignee) { - issue.assignees = issue.assignees.filter((assignee) => assignee.id !== removeAssignee.id); - } - }, - - findIssueAssignee(issue, findAssignee) { - return issue.assignees.find((assignee) => assignee.id === findAssignee.id); - }, - - clearMultiSelect() { - this.multiSelect.list = []; - }, - - removeAllIssueAssignees(issue) { - issue.assignees = []; - }, - - addIssueMilestone(issue, milestone) { - const miletoneId = issue.milestone ? issue.milestone.id : null; - if (IS_EE && milestone.id !== miletoneId) { - issue.milestone = new ListMilestone(milestone); - } - }, - - setIssueLoadingState(issue, key, value) { - issue.isLoading[key] = value; - }, - - updateIssueData(issue, newData) { - Object.assign(issue, newData); - }, - - setIssueFetchingState(issue, key, value) { - issue.isFetching[key] = value; - }, - - removeIssueMilestone(issue, removeMilestone) { - if (IS_EE && removeMilestone && removeMilestone.id === issue.milestone.id) { - issue.milestone = {}; - } - }, - - refreshIssueData(issue, obj) { - const convertedObj = convertObjectPropsToCamelCase(obj, { - dropKeys: ['issue_sidebar_endpoint', 'real_path', 'webUrl'], - }); - convertedObj.sidebarInfoEndpoint = obj.issue_sidebar_endpoint; - issue.path = obj.real_path || obj.webUrl; - issue.project_id = obj.project_id; - Object.assign(issue, convertedObj); - - if (obj.project) { - issue.project = new IssueProject(obj.project); - } - - if (obj.milestone) { - issue.milestone = new ListMilestone(obj.milestone); - issue.milestone_id = obj.milestone.id; - } - - if (obj.labels) { - issue.labels = obj.labels.map((label) => new ListLabel(label)); - } - - if (obj.assignees) { - issue.assignees = obj.assignees.map((a) => new ListAssignee(a)); - } - }, - addIssueLabel(issue, label) { - if (!issue.findLabel(label)) { - issue.labels.push(new ListLabel(label)); - } - }, - updateIssue(issue) { - const data = { - issue: { - milestone_id: issue.milestone ? issue.milestone.id : null, - due_date: issue.dueDate, - assignee_ids: issue.assignees.length > 0 ? issue.assignees.map(({ id }) => id) : [0], - label_ids: issue.labels.length > 0 ? issue.labels.map(({ id }) => id) : [''], - }, - }; - - return axios.patch(`${issue.path}.json`, data).then(({ data: body = {} } = {}) => { - /** - * Since post implementation of Scoped labels, server can reject - * same key-ed labels. To keep the UI and server Model consistent, - * we're just assigning labels that server echo's back to us when we - * PATCH the said object. - */ - if (body) { - issue.labels = convertObjectPropsToCamelCase(body.labels, { deep: true }); - } - }); - }, -}; - -BoardsStoreEE.initEESpecific(boardsStore); - -// hacks added in order to allow milestone_select to function properly -// TODO: remove these - -export function boardStoreIssueSet(...args) { - Vue.set(boardsStore.detail.issue, ...args); -} - -export function boardStoreIssueDelete(...args) { - Vue.delete(boardsStore.detail.issue, ...args); -} - -export default boardsStore; diff --git a/app/assets/javascripts/boards/stores/boards_store_ee.js b/app/assets/javascripts/boards/stores/boards_store_ee.js deleted file mode 100644 index 2a289ce5d0a..00000000000 --- a/app/assets/javascripts/boards/stores/boards_store_ee.js +++ /dev/null @@ -1,5 +0,0 @@ -// this is just to make ee_else_ce happy and will be cleaned up in https://gitlab.com/gitlab-org/gitlab-foss/issues/59807 - -export default { - initEESpecific() {}, -}; diff --git a/app/assets/javascripts/boards/stores/getters.js b/app/assets/javascripts/boards/stores/getters.js index 140c9ef7ac4..cb31eb4b008 100644 --- a/app/assets/javascripts/boards/stores/getters.js +++ b/app/assets/javascripts/boards/stores/getters.js @@ -16,7 +16,7 @@ export default { }, activeBoardItem: (state) => { - return state.boardItems[state.activeId] || { iid: '', id: '', fullId: '' }; + return state.boardItems[state.activeId] || { iid: '', id: '' }; }, groupPathForActiveIssue: (_, getters) => { @@ -51,8 +51,4 @@ export default { isEpicBoard: () => { return false; }, - - shouldUseGraphQL: () => { - return gon?.features?.graphqlBoardLists; - }, }; diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js index 31b78014525..928cece19f7 100644 --- a/app/assets/javascripts/boards/stores/mutation_types.js +++ b/app/assets/javascripts/boards/stores/mutation_types.js @@ -41,3 +41,7 @@ export const ADD_LIST_TO_HIGHLIGHTED_LISTS = 'ADD_LIST_TO_HIGHLIGHTED_LISTS'; export const REMOVE_LIST_FROM_HIGHLIGHTED_LISTS = 'REMOVE_LIST_FROM_HIGHLIGHTED_LISTS'; export const RESET_BOARD_ITEM_SELECTION = 'RESET_BOARD_ITEM_SELECTION'; export const SET_ERROR = 'SET_ERROR'; + +export const RECEIVE_ITERATIONS_REQUEST = 'RECEIVE_ITERATIONS_REQUEST'; +export const RECEIVE_ITERATIONS_SUCCESS = 'RECEIVE_ITERATIONS_SUCCESS'; +export const RECEIVE_ITERATIONS_FAILURE = 'RECEIVE_ITERATIONS_FAILURE'; diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js index 668a3dbaa7e..ef5b84b4575 100644 --- a/app/assets/javascripts/boards/stores/mutations.js +++ b/app/assets/javascripts/boards/stores/mutations.js @@ -1,6 +1,5 @@ import { cloneDeep, pull, union } from 'lodash'; import Vue from 'vue'; -import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { s__, __ } from '~/locale'; import { formatIssue } from '../boards_util'; import { issuableTypes } from '../constants'; @@ -65,6 +64,20 @@ export default { ); }, + [mutationTypes.RECEIVE_ITERATIONS_REQUEST](state) { + state.iterationsLoading = true; + }, + + [mutationTypes.RECEIVE_ITERATIONS_SUCCESS](state, iterations) { + state.iterations = iterations; + state.iterationsLoading = false; + }, + + [mutationTypes.RECEIVE_ITERATIONS_FAILURE](state) { + state.iterationsLoading = false; + state.error = __('Failed to load iterations.'); + }, + [mutationTypes.SET_ACTIVE_ID](state, { id, sidebarType }) { state.activeId = id; state.sidebarType = sidebarType; @@ -187,8 +200,7 @@ export default { }, [mutationTypes.MUTATE_ISSUE_SUCCESS]: (state, { issue }) => { - const issueId = getIdFromGraphQLId(issue.id); - Vue.set(state.boardItems, issueId, formatIssue({ ...issue, id: issueId })); + Vue.set(state.boardItems, issue.id, formatIssue(issue)); }, [mutationTypes.ADD_BOARD_ITEM_TO_LIST]: ( diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js index 264a03ff39d..80c51c966d2 100644 --- a/app/assets/javascripts/boards/stores/state.js +++ b/app/assets/javascripts/boards/stores/state.js @@ -31,6 +31,8 @@ export default () => ({ }, selectedProject: {}, error: undefined, + iterations: [], + iterationsLoading: false, addColumnForm: { visible: false, columnType: ListType.label, |