diff --git a/app/assets/javascripts/boards/components/board_column.vue b/app/assets/javascripts/boards/components/board_column.vue index dae24338e45..23e4edea40f 100644 --- a/app/assets/javascripts/boards/components/board_column.vue +++ b/app/assets/javascripts/boards/components/board_column.vue @@ -1,9 +1,11 @@ + + diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index f421faeb52d..fff89832bf0 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -27,7 +27,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager { updateObject(path) { this.store.path = path.substr(1); - if (gon.features.boardsWithSwimlanes) { + if (gon.features.boardsWithSwimlanes || gon.features.graphqlBoardLists) { boardsStore.updateFiltersUrl(); boardsStore.performSearch(); } diff --git a/app/assets/javascripts/boards/queries/issue.fragment.graphql b/app/assets/javascripts/boards/queries/issue.fragment.graphql index 21b52766190..4b429f875a6 100644 --- a/app/assets/javascripts/boards/queries/issue.fragment.graphql +++ b/app/assets/javascripts/boards/queries/issue.fragment.graphql @@ -7,15 +7,10 @@ fragment IssueNode on Issue { referencePath: reference(full: true) dueDate timeEstimate - weight confidential webUrl subscribed - blocked relativePosition - epic { - id - } assignees { nodes { ...User diff --git a/app/assets/javascripts/boards/queries/lists_issues.query.graphql b/app/assets/javascripts/boards/queries/lists_issues.query.graphql index a9fc99fd916..c66cdf68cf4 100644 --- a/app/assets/javascripts/boards/queries/lists_issues.query.graphql +++ b/app/assets/javascripts/boards/queries/lists_issues.query.graphql @@ -1,15 +1,16 @@ -#import "./issue.fragment.graphql" +#import "ee_else_ce/boards/queries/issue.fragment.graphql" query ListIssues( $fullPath: ID! $boardId: ID! + $id: ID $filters: BoardIssueInput $isGroup: Boolean = false $isProject: Boolean = false ) { group(fullPath: $fullPath) @include(if: $isGroup) { board(id: $boardId) { - lists { + lists(id: $id) { nodes { id issues(filters: $filters) { @@ -23,7 +24,7 @@ query ListIssues( } project(fullPath: $fullPath) @include(if: $isProject) { board(id: $boardId) { - lists { + lists(id: $id) { nodes { id issues(filters: $filters) { diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index f8767211abd..248e06ba264 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -79,10 +79,10 @@ export default { lists = lists.nodes.map(list => boardStore.updateListPosition({ ...list, - id: getIdFromGraphQLId(list.id), + doNotFetchIssues: true, }), ); - commit(types.RECEIVE_LISTS, sortBy(lists, 'position')); + commit(types.RECEIVE_BOARD_LISTS_SUCCESS, sortBy(lists, 'position')); // Backlog list needs to be created if it doesn't exist if (!lists.find(l => l.type === ListType.backlog)) { dispatch('createList', { backlog: true }); @@ -113,7 +113,7 @@ export default { commit(types.CREATE_LIST_FAILURE); } else { const list = data.boardListCreate?.list; - dispatch('addList', { ...list, id: getIdFromGraphQLId(list.id) }); + dispatch('addList', list); } }) .catch(() => { @@ -124,8 +124,8 @@ export default { addList: ({ state, commit }, list) => { const lists = state.boardLists; // Temporarily using positioning logic from boardStore - lists.push(boardStore.updateListPosition(list)); - commit(types.RECEIVE_LISTS, sortBy(lists, 'position')); + lists.push(boardStore.updateListPosition({ ...list, doNotFetchIssues: true })); + commit(types.RECEIVE_BOARD_LISTS_SUCCESS, sortBy(lists, 'position')); }, showWelcomeList: ({ state, dispatch }) => { @@ -197,8 +197,33 @@ export default { notImplemented(); }, - fetchIssuesForList: () => { - notImplemented(); + fetchIssuesForList: ({ state, commit }, listId) => { + const { endpoints, boardType, filterParams } = state; + const { fullPath, boardId } = endpoints; + + const variables = { + fullPath, + boardId: fullBoardId(boardId), + id: listId, + filters: filterParams, + isGroup: boardType === BoardType.group, + isProject: boardType === BoardType.project, + }; + + return gqlClient + .query({ + query: listsIssuesQuery, + context: { + isSingleRequest: true, + }, + variables, + }) + .then(({ data }) => { + const { lists } = data[boardType]?.board; + const listIssues = formatListIssues(lists); + commit(types.RECEIVE_ISSUES_FOR_LIST_SUCCESS, { listIssues, listId }); + }) + .catch(() => commit(types.RECEIVE_ISSUES_FOR_LIST_FAILURE, listId)); }, fetchIssuesForAllLists: ({ state, commit }) => { diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index 4fdbfbc36c5..faf4f9ebfd3 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -304,7 +304,11 @@ const boardsStore = { onNewListIssueResponse(list, issue, data) { issue.refreshData(data); - if (!gon.features.boardsWithSwimlanes && list.issuesSize > 1) { + if ( + !gon.features.boardsWithSwimlanes && + !gon.features.graphqlBoardLists && + list.issues.length > 1 + ) { const moveBeforeId = list.issues[1].id; this.moveIssue(issue.id, null, null, null, moveBeforeId); } @@ -723,6 +727,10 @@ const boardsStore = { 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) diff --git a/app/assets/javascripts/boards/stores/getters.js b/app/assets/javascripts/boards/stores/getters.js index 80acf8e66cc..3688476dc5f 100644 --- a/app/assets/javascripts/boards/stores/getters.js +++ b/app/assets/javascripts/boards/stores/getters.js @@ -14,6 +14,11 @@ export default { return state.issues[id] || {}; }, + getIssues: (state, getters) => listId => { + const listIssueIds = state.issuesByListId[listId] || []; + return listIssueIds.map(id => getters.getIssueById(id)); + }, + getActiveIssue: state => { return state.issues[state.activeId] || {}; }, diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js index 5a3d62dc703..f0a283f6161 100644 --- a/app/assets/javascripts/boards/stores/mutation_types.js +++ b/app/assets/javascripts/boards/stores/mutation_types.js @@ -2,7 +2,7 @@ export const SET_INITIAL_BOARD_DATA = 'SET_INITIAL_BOARD_DATA'; export const SET_FILTERS = 'SET_FILTERS'; export const CREATE_LIST_SUCCESS = 'CREATE_LIST_SUCCESS'; export const CREATE_LIST_FAILURE = 'CREATE_LIST_FAILURE'; -export const RECEIVE_LISTS = 'RECEIVE_LISTS'; +export const RECEIVE_BOARD_LISTS_SUCCESS = 'RECEIVE_BOARD_LISTS_SUCCESS'; export const SHOW_PROMOTION_LIST = 'SHOW_PROMOTION_LIST'; export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST'; export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS'; @@ -13,6 +13,8 @@ export const REQUEST_REMOVE_LIST = 'REQUEST_REMOVE_LIST'; export const RECEIVE_REMOVE_LIST_SUCCESS = 'RECEIVE_REMOVE_LIST_SUCCESS'; export const RECEIVE_REMOVE_LIST_ERROR = 'RECEIVE_REMOVE_LIST_ERROR'; export const REQUEST_ISSUES_FOR_ALL_LISTS = 'REQUEST_ISSUES_FOR_ALL_LISTS'; +export const RECEIVE_ISSUES_FOR_LIST_FAILURE = 'RECEIVE_ISSUES_FOR_LIST_FAILURE'; +export const RECEIVE_ISSUES_FOR_LIST_SUCCESS = 'RECEIVE_ISSUES_FOR_LIST_SUCCESS'; export const RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS = 'RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS'; export const RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE = 'RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE'; export const REQUEST_ADD_ISSUE = 'REQUEST_ADD_ISSUE'; diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js index a03c541ada5..faeb3e25a71 100644 --- a/app/assets/javascripts/boards/stores/mutations.js +++ b/app/assets/javascripts/boards/stores/mutations.js @@ -35,7 +35,7 @@ export default { state.showPromotion = showPromotion; }, - [mutationTypes.RECEIVE_LISTS]: (state, lists) => { + [mutationTypes.RECEIVE_BOARD_LISTS_SUCCESS]: (state, lists) => { state.boardLists = lists; }, @@ -89,6 +89,20 @@ export default { notImplemented(); }, + [mutationTypes.RECEIVE_ISSUES_FOR_LIST_SUCCESS]: (state, { listIssues, listId }) => { + const { listData, issues } = listIssues; + Vue.set(state, 'issues', { ...state.issues, ...issues }); + Vue.set(state.issuesByListId, listId, listData[listId]); + const listIndex = state.boardLists.findIndex(l => l.id === listId); + Vue.set(state.boardLists[listIndex], 'loading', false); + }, + + [mutationTypes.RECEIVE_ISSUES_FOR_LIST_FAILURE]: (state, listId) => { + state.error = __('An error occurred while fetching the board issues. Please reload the page.'); + const listIndex = state.boardLists.findIndex(l => l.id === listId); + Vue.set(state.boardLists[listIndex], 'loading', false); + }, + [mutationTypes.REQUEST_ISSUES_FOR_ALL_LISTS]: state => { state.isLoadingIssues = true; }, diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index c8b7168dce1..02396a4ba1b 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -1,32 +1,26 @@