Commit 1d4c7478 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'psi-gql-board-lists' into 'master'

Load board lists with GraphQL (feature flag disabled)

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