Commit 89bea703 authored by Florie Guibert's avatar Florie Guibert

Swimlanes - Paginate epics

Chain fetch epics by chunks of 20
parent 83dede41
...@@ -155,7 +155,13 @@ export default () => { ...@@ -155,7 +155,13 @@ export default () => {
} }
}, },
methods: { methods: {
...mapActions(['setInitialBoardData', 'setFilters', 'fetchEpicsSwimlanes', 'resetIssues']), ...mapActions([
'setInitialBoardData',
'setFilters',
'fetchEpicsSwimlanes',
'resetIssues',
'resetEpics',
]),
initialBoardLoad() { initialBoardLoad() {
boardsStore boardsStore
.all() .all()
...@@ -176,7 +182,8 @@ export default () => { ...@@ -176,7 +182,8 @@ export default () => {
performSearch() { performSearch() {
this.setFilters(convertObjectPropsToCamelCase(urlParamsToObject(window.location.search))); this.setFilters(convertObjectPropsToCamelCase(urlParamsToObject(window.location.search)));
if (gon.features.boardsWithSwimlanes && this.isShowingEpicsSwimlanes) { if (gon.features.boardsWithSwimlanes && this.isShowingEpicsSwimlanes) {
this.fetchEpicsSwimlanes(false); this.resetEpics();
this.fetchEpicsSwimlanes({ withLists: false });
this.resetIssues(); this.resetIssues();
} }
}, },
......
...@@ -8,6 +8,7 @@ query BoardEE( ...@@ -8,6 +8,7 @@ query BoardEE(
$withLists: Boolean = true $withLists: Boolean = true
$isGroup: Boolean = false $isGroup: Boolean = false
$isProject: Boolean = false $isProject: Boolean = false
$after: String
) { ) {
group(fullPath: $fullPath) @include(if: $isGroup) { group(fullPath: $fullPath) @include(if: $isGroup) {
board(id: $boardId) { board(id: $boardId) {
...@@ -16,9 +17,15 @@ query BoardEE( ...@@ -16,9 +17,15 @@ query BoardEE(
...BoardListFragment ...BoardListFragment
} }
} }
epics(issueFilters: $issueFilters) { epics(first: 2, issueFilters: $issueFilters, after: $after) {
nodes { edges {
...BoardEpicNode node {
...BoardEpicNode
}
}
pageInfo {
endCursor
hasNextPage
} }
} }
} }
...@@ -30,9 +37,15 @@ query BoardEE( ...@@ -30,9 +37,15 @@ query BoardEE(
...BoardListFragment ...BoardListFragment
} }
} }
epics(issueFilters: $issueFilters) { epics(first: 20, issueFilters: $issueFilters, after: $after) {
nodes { edges {
...BoardEpicNode node {
...BoardEpicNode
}
}
pageInfo {
endCursor
hasNextPage
} }
} }
} }
......
...@@ -75,7 +75,7 @@ export default { ...@@ -75,7 +75,7 @@ export default {
commit(types.SET_FILTERS, filterParams); commit(types.SET_FILTERS, filterParams);
}, },
fetchEpicsSwimlanes({ state, commit }, withLists = true) { fetchEpicsSwimlanes({ state, commit, dispatch }, { withLists = true, endCursor = null }) {
const { endpoints, boardType, filterParams } = state; const { endpoints, boardType, filterParams } = state;
const { fullPath, boardId } = endpoints; const { fullPath, boardId } = endpoints;
...@@ -86,6 +86,7 @@ export default { ...@@ -86,6 +86,7 @@ export default {
withLists, withLists,
isGroup: boardType === BoardType.group, isGroup: boardType === BoardType.group,
isProject: boardType === BoardType.project, isProject: boardType === BoardType.project,
after: endCursor,
}; };
return gqlClient return gqlClient
...@@ -95,24 +96,27 @@ export default { ...@@ -95,24 +96,27 @@ export default {
}) })
.then(({ data }) => { .then(({ data }) => {
const { epics, lists } = data[boardType]?.board; const { epics, lists } = data[boardType]?.board;
const epicsFormatted = epics.nodes.map(e => ({ const epicsFormatted = epics.edges.map(e => ({
...e, ...e.node,
issues: (e?.issues?.nodes || []).map(i => ({
...i,
labels: i.labels?.nodes || [],
assignees: i.assignees?.nodes || [],
})),
})); }));
if (!withLists) { if (!withLists) {
commit(types.RECEIVE_EPICS_SUCCESS, epicsFormatted); commit(types.RECEIVE_EPICS_SUCCESS, epicsFormatted);
} }
if (epics.pageInfo?.hasNextPage) {
dispatch('fetchEpicsSwimlanes', {
withLists: false,
endCursor: epics.pageInfo.endCursor,
});
}
return { return {
epics: epicsFormatted, epics: epicsFormatted,
lists: lists?.nodes, lists: lists?.nodes,
}; };
}); })
.catch(() => commit(types.RECEIVE_SWIMLANES_FAILURE));
}, },
setShowLabels({ commit }, val) { setShowLabels({ commit }, val) {
...@@ -206,7 +210,7 @@ export default { ...@@ -206,7 +210,7 @@ export default {
commit(types.TOGGLE_EPICS_SWIMLANES); commit(types.TOGGLE_EPICS_SWIMLANES);
if (state.isShowingEpicsSwimlanes) { if (state.isShowingEpicsSwimlanes) {
dispatch('fetchEpicsSwimlanes') dispatch('fetchEpicsSwimlanes', {})
.then(({ lists, epics }) => { .then(({ lists, epics }) => {
if (lists) { if (lists) {
let boardLists = lists.map(list => let boardLists = lists.map(list =>
...@@ -226,4 +230,8 @@ export default { ...@@ -226,4 +230,8 @@ export default {
eventHub.$emit('initialBoardLoad'); eventHub.$emit('initialBoardLoad');
} }
}, },
resetEpics: ({ commit }) => {
commit(types.RESET_EPICS);
},
}; };
...@@ -20,5 +20,6 @@ export const TOGGLE_EPICS_SWIMLANES = 'TOGGLE_EPICS_SWIMLANES'; ...@@ -20,5 +20,6 @@ export const TOGGLE_EPICS_SWIMLANES = 'TOGGLE_EPICS_SWIMLANES';
export const RECEIVE_BOARD_LISTS_SUCCESS = 'RECEIVE_BOARD_LISTS_SUCCESS'; export const RECEIVE_BOARD_LISTS_SUCCESS = 'RECEIVE_BOARD_LISTS_SUCCESS';
export const RECEIVE_SWIMLANES_FAILURE = 'RECEIVE_SWIMLANES_FAILURE'; export const RECEIVE_SWIMLANES_FAILURE = 'RECEIVE_SWIMLANES_FAILURE';
export const RECEIVE_EPICS_SUCCESS = 'RECEIVE_EPICS_SUCCESS'; export const RECEIVE_EPICS_SUCCESS = 'RECEIVE_EPICS_SUCCESS';
export const RESET_EPICS = 'RESET_EPICS';
export const SET_SHOW_LABELS = 'SET_SHOW_LABELS'; export const SET_SHOW_LABELS = 'SET_SHOW_LABELS';
export const SET_FILTERS = 'SET_FILTERS'; export const SET_FILTERS = 'SET_FILTERS';
...@@ -103,6 +103,10 @@ export default { ...@@ -103,6 +103,10 @@ export default {
}, },
[mutationTypes.RECEIVE_EPICS_SUCCESS]: (state, epics) => { [mutationTypes.RECEIVE_EPICS_SUCCESS]: (state, epics) => {
state.epics = epics; Vue.set(state, 'epics', union(state.epics || [], epics));
},
[mutationTypes.RESET_EPICS]: state => {
Vue.set(state, 'epics', []);
}, },
}; };
...@@ -5,6 +5,6 @@ export default () => ({ ...@@ -5,6 +5,6 @@ export default () => ({
isShowingEpicsSwimlanes: false, isShowingEpicsSwimlanes: false,
epicsSwimlanesFetchInProgress: false, epicsSwimlanesFetchInProgress: false,
epics: {}, epics: [],
epicsFlags: {}, epicsFlags: {},
}); });
...@@ -63,6 +63,99 @@ describe('setFilters', () => { ...@@ -63,6 +63,99 @@ describe('setFilters', () => {
}); });
}); });
describe('fetchEpicsSwimlanes', () => {
const state = {
endpoints: {
fullPath: 'gitlab-org',
boardId: 1,
},
filterParams: {},
boardType: 'group',
};
const queryResponse = {
data: {
group: {
board: {
epics: {
edges: [{ node: mockEpic }],
pageInfo: {},
},
},
},
},
};
it('should commit mutation RECEIVE_EPICS_SUCCESS on success without lists', done => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
actions.fetchEpicsSwimlanes,
{ withLists: false },
state,
[
{
type: types.RECEIVE_EPICS_SUCCESS,
payload: [mockEpic],
},
],
[],
done,
);
});
it('should commit mutation RECEIVE_SWIMLANES_FAILURE on failure', done => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(Promise.reject());
testAction(
actions.fetchEpicsSwimlanes,
{},
state,
[{ type: types.RECEIVE_SWIMLANES_FAILURE }],
[],
done,
);
});
it('should dispatch fetchEpicsSwimlanes when page info hasNextPage', done => {
const queryResponseWithNextPage = {
data: {
group: {
board: {
epics: {
edges: [{ node: mockEpic }],
pageInfo: {
hasNextPage: true,
endCursor: 'ENDCURSOR',
},
},
},
},
},
};
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponseWithNextPage);
testAction(
actions.fetchEpicsSwimlanes,
{ withLists: false },
state,
[
{
type: types.RECEIVE_EPICS_SUCCESS,
payload: [mockEpic],
},
],
[
{
type: 'fetchEpicsSwimlanes',
payload: { withLists: false, endCursor: 'ENDCURSOR' },
},
],
done,
);
});
});
describe('setShowLabels', () => { describe('setShowLabels', () => {
it('should commit mutation SET_SHOW_LABELS', done => { it('should commit mutation SET_SHOW_LABELS', done => {
const state = { const state = {
...@@ -251,3 +344,9 @@ describe('toggleEpicSwimlanes', () => { ...@@ -251,3 +344,9 @@ describe('toggleEpicSwimlanes', () => {
); );
}); });
}); });
describe('resetEpics', () => {
it('commits RESET_EPICS mutation', () => {
return testAction(actions.resetEpics, {}, {}, [{ type: types.RESET_EPICS }], []);
});
});
...@@ -205,7 +205,7 @@ describe('RECEIVE_SWIMLANES_FAILURE', () => { ...@@ -205,7 +205,7 @@ describe('RECEIVE_SWIMLANES_FAILURE', () => {
}); });
describe('RECEIVE_EPICS_SUCCESS', () => { describe('RECEIVE_EPICS_SUCCESS', () => {
it('populates epics with payload and set epicsFlags loading to true', () => { it('populates epics with payload', () => {
state = { state = {
...state, ...state,
epics: {}, epics: {},
...@@ -216,3 +216,16 @@ describe('RECEIVE_EPICS_SUCCESS', () => { ...@@ -216,3 +216,16 @@ describe('RECEIVE_EPICS_SUCCESS', () => {
expect(state.epics).toEqual(mockEpics); expect(state.epics).toEqual(mockEpics);
}); });
}); });
describe('RESET_EPICS', () => {
it('should remove issues from issuesByListId state', () => {
state = {
...state,
epics: mockEpics,
};
mutations.RESET_EPICS(state);
expect(state.epics).toEqual([]);
});
});
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