Commit f0b2eabb authored by Simon Knox's avatar Simon Knox Committed by Natalia Tepluhina

Fetch board lists with GraphQL

FE parts only, depends on https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24812
parent 632ce4dd
export const BoardType = {
project: 'project',
group: 'group',
};
export const ListType = {
assignee: 'assignee',
milestone: 'milestone',
......@@ -11,5 +16,6 @@ export const ListType = {
export const inactiveListId = 0;
export default {
BoardType,
ListType,
};
......@@ -16,10 +16,13 @@ import {
getBoardsModalData,
} from 'ee_else_ce/boards/ee_functions';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import Flash from '~/flash';
import { __ } from '~/locale';
import './models/label';
import './models/assignee';
import { BoardType } from './constants';
import FilteredSearchBoards from '~/boards/filtered_search_boards';
import eventHub from '~/boards/eventhub';
......@@ -37,7 +40,16 @@ import {
convertObjectPropsToCamelCase,
parseBoolean,
} from '~/lib/utils/common_utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher';
import projectBoardQuery from './queries/project_board.query.graphql';
import groupQuery from './queries/group_board.query.graphql';
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
let issueBoardsApp;
......@@ -79,18 +91,22 @@ export default () => {
import('ee_component/boards/components/board_settings_sidebar.vue'),
},
store,
data: {
state: boardsStore.state,
loading: true,
boardsEndpoint: $boardApp.dataset.boardsEndpoint,
recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint,
listsEndpoint: $boardApp.dataset.listsEndpoint,
boardId: $boardApp.dataset.boardId,
disabled: parseBoolean($boardApp.dataset.disabled),
issueLinkBase: $boardApp.dataset.issueLinkBase,
rootPath: $boardApp.dataset.rootPath,
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
detailIssue: boardsStore.detail,
apolloProvider,
data() {
return {
state: boardsStore.state,
loading: 0,
boardsEndpoint: $boardApp.dataset.boardsEndpoint,
recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint,
listsEndpoint: $boardApp.dataset.listsEndpoint,
boardId: $boardApp.dataset.boardId,
disabled: parseBoolean($boardApp.dataset.disabled),
issueLinkBase: $boardApp.dataset.issueLinkBase,
rootPath: $boardApp.dataset.rootPath,
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
detailIssue: boardsStore.detail,
parent: $boardApp.dataset.parent,
};
},
computed: {
detailIssueVisible() {
......@@ -124,31 +140,56 @@ export default () => {
this.filterManager.setup();
boardsStore.disabled = this.disabled;
boardsStore
.all()
.then(res => res.data)
.then(lists => {
lists.forEach(listObj => {
let { position } = listObj;
if (listObj.list_type === 'closed') {
position = Infinity;
} else if (listObj.list_type === 'backlog') {
position = -1;
if (gon.features.graphqlBoardLists) {
this.$apollo.addSmartQuery('lists', {
query() {
return this.parent === BoardType.group ? groupQuery : projectBoardQuery;
},
variables() {
return {
fullPath: this.state.endpoints.fullPath,
boardId: `gid://gitlab/Board/${this.boardId}`,
};
},
update(data) {
return this.getNodes(data);
},
result({ data, error }) {
if (error) {
throw error;
}
boardsStore.addList({
...listObj,
position,
});
});
const lists = this.getNodes(data);
lists.forEach(list =>
boardsStore.addList({
...list,
id: getIdFromGraphQLId(list.id),
}),
);
boardsStore.addBlankState();
setPromotionState(boardsStore);
this.loading = false;
})
.catch(() => {
Flash(__('An error occurred while fetching the board lists. Please try again.'));
boardsStore.addBlankState();
setPromotionState(boardsStore);
},
error() {
Flash(__('An error occurred while fetching the board lists. Please try again.'));
},
});
} else {
boardsStore
.all()
.then(res => res.data)
.then(lists => {
lists.forEach(list => boardsStore.addList(list));
boardsStore.addBlankState();
setPromotionState(boardsStore);
this.loading = false;
})
.catch(() => {
Flash(__('An error occurred while fetching the board lists. Please try again.'));
});
}
},
methods: {
updateTokens() {
......@@ -233,6 +274,9 @@ export default () => {
});
}
},
getNodes(data) {
return data[this.parent]?.board?.lists.nodes;
},
},
});
......
......@@ -3,7 +3,7 @@ export default class ListAssignee {
this.id = obj.id;
this.name = obj.name;
this.username = obj.username;
this.avatar = obj.avatar_url || obj.avatar || gon.default_avatar_url;
this.avatar = obj.avatarUrl || obj.avatar_url || obj.avatar || gon.default_avatar_url;
this.path = obj.path;
this.state = obj.state;
this.webUrl = obj.web_url || obj.webUrl;
......
......@@ -15,7 +15,7 @@ class ListIssue {
this.labels = [];
this.assignees = [];
this.selected = false;
this.position = obj.relative_position || Infinity;
this.position = obj.position || obj.relative_position || Infinity;
this.isFetching = {
subscriptions: true,
};
......
......@@ -39,8 +39,8 @@ class List {
this.id = obj.id;
this._uid = this.guid();
this.position = obj.position;
this.title = obj.list_type === 'backlog' ? __('Open') : obj.title;
this.type = obj.list_type;
this.title = (obj.list_type || obj.listType) === 'backlog' ? __('Open') : obj.title;
this.type = obj.list_type || obj.listType;
const typeInfo = this.getTypeInfo(this.type);
this.preset = Boolean(typeInfo.isPreset);
......@@ -51,14 +51,12 @@ class List {
this.loadingMore = false;
this.issues = obj.issues || [];
this.issuesSize = obj.issuesSize ? obj.issuesSize : 0;
this.maxIssueCount = Object.hasOwnProperty.call(obj, 'max_issue_count')
? obj.max_issue_count
: 0;
this.maxIssueCount = obj.maxIssueCount || obj.max_issue_count || 0;
if (obj.label) {
this.label = new ListLabel(obj.label);
} else if (obj.user) {
this.assignee = new ListAssignee(obj.user);
} else if (obj.user || obj.assignee) {
this.assignee = new ListAssignee(obj.user || obj.assignee);
this.title = this.assignee.name;
} else if (IS_EE && obj.milestone) {
this.milestone = new ListMilestone(obj.milestone);
......
#import "./board_list_shared.fragment.graphql"
fragment BoardListFragment on BoardList {
...BoardListShared
}
fragment BoardListShared on BoardList {
id,
title,
position,
listType,
collapsed,
label {
id,
title,
color,
textColor,
description,
descriptionHtml
}
}
#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
query GroupBoard($fullPath: ID!, $boardId: ID!) {
group(fullPath: $fullPath) {
board(id: $boardId) {
lists {
nodes {
...BoardListFragment
}
}
}
}
}
#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
query ProjectBoard($fullPath: ID!, $boardId: ID!) {
project(fullPath: $fullPath) {
board(id: $boardId) {
lists {
nodes {
...BoardListFragment
}
}
}
}
}
......@@ -80,7 +80,15 @@ const boardsStore = {
this.state.currentPage = page;
},
addList(listObj) {
const list = new List(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 });
this.state.lists = sortBy([...this.state.lists, list], 'position');
return list;
},
......
......@@ -16,7 +16,8 @@ module BoardsHelper
full_path: full_path,
bulk_update_path: @bulk_issues_path,
time_tracking_limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s,
recent_boards_endpoint: recent_boards_path
recent_boards_endpoint: recent_boards_path,
parent: current_board_parent.model_name.param_key
}
end
......
#import "~/boards/queries/board_list_shared.fragment.graphql"
fragment BoardListFragment on BoardList {
...BoardListShared,
maxIssueCount,
assignee {
id,
name,
username,
avatarUrl,
webUrl
},
milestone {
id,
title,
webPath,
description
}
}
......@@ -48,6 +48,10 @@ describe BoardsHelper do
it 'returns a board_lists_path as lists_endpoint' do
expect(helper.board_data[:lists_endpoint]).to eq(board_lists_path(board))
end
it 'returns board type as parent' do
expect(helper.board_data[:parent]).to eq('project')
end
end
describe '#current_board_json' do
......
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