Commit 52f42de7 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '229418-boards-move-fetching-of-board-and-lists-to-vuex-action' into 'master'

Board refactor - Move fetch lists GraphQL to VueX

See merge request gitlab-org/gitlab!37905
parents 0705c6eb 39474ce8
...@@ -22,6 +22,10 @@ export function formatListIssues(listIssues) { ...@@ -22,6 +22,10 @@ export function formatListIssues(listIssues) {
}, {}); }, {});
} }
export function fullBoardId(boardId) {
return `gid://gitlab/Board/${boardId}`;
}
export default { export default {
getMilestone, getMilestone,
formatListIssues, formatListIssues,
......
<script> <script>
import { mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { GlAlert } from '@gitlab/ui'; import { GlAlert } from '@gitlab/ui';
import BoardColumn from 'ee_else_ce/boards/components/board_column.vue'; import BoardColumn from 'ee_else_ce/boards/components/board_column.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
...@@ -47,6 +47,18 @@ export default { ...@@ -47,6 +47,18 @@ export default {
isSwimlanesOn() { isSwimlanesOn() {
return this.glFeatures.boardsWithSwimlanes && this.isShowingEpicsSwimlanes; return this.glFeatures.boardsWithSwimlanes && this.isShowingEpicsSwimlanes;
}, },
boardListsToUse() {
return this.glFeatures.graphqlBoardLists ? this.boardLists : this.lists;
},
},
mounted() {
if (this.glFeatures.graphqlBoardLists) {
this.fetchLists();
this.showPromotionList();
}
},
methods: {
...mapActions(['fetchLists', 'showPromotionList']),
}, },
}; };
</script> </script>
...@@ -62,7 +74,7 @@ export default { ...@@ -62,7 +74,7 @@ export default {
data-qa-selector="boards_list" data-qa-selector="boards_list"
> >
<board-column <board-column
v-for="list in lists" v-for="list in boardListsToUse"
:key="list.id" :key="list.id"
ref="board" ref="board"
:can-admin-list="canAdminList" :can-admin-list="canAdminList"
...@@ -77,7 +89,7 @@ export default { ...@@ -77,7 +89,7 @@ export default {
<epics-swimlanes <epics-swimlanes
v-else v-else
ref="swimlanes" ref="swimlanes"
:lists="boardLists" :lists="boardListsToUse"
:can-admin-list="canAdminList" :can-admin-list="canAdminList"
:disabled="disabled" :disabled="disabled"
:board-id="boardId" :board-id="boardId"
......
...@@ -6,6 +6,7 @@ import boardsStore from '~/boards/stores/boards_store'; ...@@ -6,6 +6,7 @@ import boardsStore from '~/boards/stores/boards_store';
import eventHub from '~/sidebar/event_hub'; import eventHub from '~/sidebar/event_hub';
import { isScopedLabel } from '~/lib/utils/common_utils'; import { isScopedLabel } from '~/lib/utils/common_utils';
import { inactiveId } from '~/boards/constants'; import { inactiveId } from '~/boards/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
// NOTE: need to revisit how we handle headerHeight, because we have so many different header and footer options. // NOTE: need to revisit how we handle headerHeight, because we have so many different header and footer options.
export default { export default {
...@@ -23,13 +24,17 @@ export default { ...@@ -23,13 +24,17 @@ export default {
BoardSettingsListTypes: () => BoardSettingsListTypes: () =>
import('ee_component/boards/components/board_settings_list_types.vue'), import('ee_component/boards/components/board_settings_list_types.vue'),
}, },
mixins: [glFeatureFlagMixin()],
computed: { computed: {
...mapState(['activeId']), ...mapState(['activeId', 'boardLists']),
activeList() { activeList() {
/* /*
Warning: Though a computed property it is not reactive because we are Warning: Though a computed property it is not reactive because we are
referencing a List Model class. Reactivity only applies to plain JS objects referencing a List Model class. Reactivity only applies to plain JS objects
*/ */
if (this.glFeatures.graphqlBoardLists) {
return this.boardLists.find(({ id }) => id === this.activeId);
}
return boardsStore.state.lists.find(({ id }) => id === this.activeId); return boardsStore.state.lists.find(({ id }) => id === this.activeId);
}, },
isSidebarOpen() { isSidebarOpen() {
......
...@@ -24,7 +24,6 @@ import { deprecatedCreateFlash as Flash } from '~/flash'; ...@@ -24,7 +24,6 @@ import { deprecatedCreateFlash as 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 toggleFocusMode from '~/boards/toggle_focus'; import toggleFocusMode from '~/boards/toggle_focus';
import FilteredSearchBoards from '~/boards/filtered_search_boards'; import FilteredSearchBoards from '~/boards/filtered_search_boards';
...@@ -44,10 +43,7 @@ import { ...@@ -44,10 +43,7 @@ import {
parseBoolean, parseBoolean,
urlParamsToObject, urlParamsToObject,
} 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); Vue.use(VueApollo);
...@@ -119,7 +115,12 @@ export default () => { ...@@ -119,7 +115,12 @@ export default () => {
boardId: this.boardId, boardId: this.boardId,
fullPath: $boardApp.dataset.fullPath, fullPath: $boardApp.dataset.fullPath,
}; };
this.setInitialBoardData({ ...endpoints, boardType: this.parent }); this.setInitialBoardData({
...endpoints,
boardType: this.parent,
disabled: this.disabled,
showPromotion: parseBoolean($boardApp.getAttribute('data-show-promotion')),
});
boardsStore.setEndpoints(endpoints); boardsStore.setEndpoints(endpoints);
boardsStore.rootPath = this.boardsEndpoint; boardsStore.rootPath = this.boardsEndpoint;
...@@ -144,42 +145,7 @@ export default () => { ...@@ -144,42 +145,7 @@ export default () => {
boardsStore.disabled = this.disabled; boardsStore.disabled = this.disabled;
if (gon.features.graphqlBoardLists) { 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;
}
const lists = this.getNodes(data);
lists.forEach(list =>
boardsStore.addList({
...list,
id: getIdFromGraphQLId(list.id),
}),
);
boardsStore.addBlankState();
setPromotionState(boardsStore);
},
error() {
Flash(__('An error occurred while fetching the board lists. Please try again.'));
},
});
} else {
boardsStore boardsStore
.all() .all()
.then(res => res.data) .then(res => res.data)
......
#import "./board_list.fragment.graphql"
mutation CreateBoardList($boardId: BoardID!, $backlog: Boolean) {
boardListCreate(input: { boardId: $boardId, backlog: $backlog }) {
list {
...BoardListFragment
}
errors
}
}
...@@ -4,7 +4,6 @@ fragment BoardListShared on BoardList { ...@@ -4,7 +4,6 @@ fragment BoardListShared on BoardList {
position position
listType listType
collapsed collapsed
maxIssueCount
label { label {
id id
title title
......
import * as types from './mutation_types'; import Cookies from 'js-cookie';
import { sortBy } from 'lodash';
import createFlash from '~/flash';
import { __ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import { BoardType } from '~/boards/constants'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { formatListIssues } from '../boards_util'; import { BoardType, ListType } from '~/boards/constants';
import * as types from './mutation_types';
import { formatListIssues, fullBoardId } from '../boards_util';
import boardStore from '~/boards/stores/boards_store';
import groupListsIssuesQuery from '../queries/group_lists_issues.query.graphql'; import groupListsIssuesQuery from '../queries/group_lists_issues.query.graphql';
import projectListsIssuesQuery from '../queries/project_lists_issues.query.graphql'; import projectListsIssuesQuery from '../queries/project_lists_issues.query.graphql';
import projectBoardQuery from '../queries/project_board.query.graphql';
const gqlClient = createDefaultClient(); import groupBoardQuery from '../queries/group_board.query.graphql';
import createBoardListMutation from '../queries/board_list_create.mutation.graphql';
const notImplemented = () => { const notImplemented = () => {
/* eslint-disable-next-line @gitlab/require-i18n-strings */ /* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('Not implemented!'); throw new Error('Not implemented!');
}; };
export const gqlClient = createDefaultClient();
export default { export default {
setInitialBoardData: ({ commit }, data) => { setInitialBoardData: ({ commit }, data) => {
commit(types.SET_INITIAL_BOARD_DATA, data); commit(types.SET_INITIAL_BOARD_DATA, data);
...@@ -26,15 +37,109 @@ export default { ...@@ -26,15 +37,109 @@ export default {
commit(types.SET_FILTERS, filterParams); commit(types.SET_FILTERS, filterParams);
}, },
fetchLists: () => { fetchLists: ({ commit, state, dispatch }) => {
notImplemented(); const { endpoints, boardType } = state;
const { fullPath, boardId } = endpoints;
let query;
if (boardType === BoardType.group) {
query = groupBoardQuery;
} else if (boardType === BoardType.project) {
query = projectBoardQuery;
} else {
createFlash(__('Invalid board'));
return Promise.reject();
}
const variables = {
fullPath,
boardId: fullBoardId(boardId),
};
return gqlClient
.query({
query,
variables,
})
.then(({ data }) => {
let { lists } = data[boardType]?.board;
// Temporarily using positioning logic from boardStore
lists = lists.nodes.map(list =>
boardStore.updateListPosition({
...list,
id: getIdFromGraphQLId(list.id),
}),
);
commit(types.RECEIVE_LISTS, 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 });
}
dispatch('showWelcomeList');
})
.catch(() => {
createFlash(
__('An error occurred while fetching the board lists. Please reload the page.'),
);
});
},
// This action only supports backlog list creation at this stage
// Future iterations will add the ability to create other list types
createList: ({ state, commit, dispatch }, { backlog = false }) => {
const { boardId } = state.endpoints;
gqlClient
.mutate({
mutation: createBoardListMutation,
variables: {
boardId: fullBoardId(boardId),
backlog,
},
})
.then(({ data }) => {
if (data?.boardListCreate?.errors.length) {
commit(types.CREATE_LIST_FAILURE);
} else {
const list = data.boardListCreate?.list;
dispatch('addList', { ...list, id: getIdFromGraphQLId(list.id) });
}
})
.catch(() => {
commit(types.CREATE_LIST_FAILURE);
});
}, },
generateDefaultLists: () => { addList: ({ state, commit }, list) => {
notImplemented(); const lists = state.boardLists;
// Temporarily using positioning logic from boardStore
lists.push(boardStore.updateListPosition(list));
commit(types.RECEIVE_LISTS, sortBy(lists, 'position'));
}, },
createList: () => { showWelcomeList: ({ state, dispatch }) => {
if (state.disabled) {
return;
}
if (
state.boardLists.find(list => list.type !== ListType.backlog && list.type !== ListType.closed)
) {
return;
}
if (parseBoolean(Cookies.get('issue_board_welcome_hidden'))) {
return;
}
dispatch('addList', {
id: 'blank',
listType: ListType.blank,
title: __('Welcome to your issue board!'),
position: 0,
});
},
showPromotionList: () => {},
generateDefaultLists: () => {
notImplemented(); notImplemented();
}, },
...@@ -60,7 +165,7 @@ export default { ...@@ -60,7 +165,7 @@ export default {
const variables = { const variables = {
fullPath, fullPath,
boardId: `gid://gitlab/Board/${boardId}`, boardId: fullBoardId(boardId),
}; };
return gqlClient return gqlClient
......
export const SET_INITIAL_BOARD_DATA = 'SET_INITIAL_BOARD_DATA'; export const SET_INITIAL_BOARD_DATA = 'SET_INITIAL_BOARD_DATA';
export const SET_FILTERS = 'SET_FILTERS'; 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 SHOW_PROMOTION_LIST = 'SHOW_PROMOTION_LIST';
export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST'; export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST';
export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS'; export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS';
export const RECEIVE_ADD_LIST_ERROR = 'RECEIVE_ADD_LIST_ERROR'; export const RECEIVE_ADD_LIST_ERROR = 'RECEIVE_ADD_LIST_ERROR';
......
...@@ -7,10 +7,16 @@ const notImplemented = () => { ...@@ -7,10 +7,16 @@ const notImplemented = () => {
}; };
export default { export default {
[mutationTypes.SET_INITIAL_BOARD_DATA]: (state, data) => { [mutationTypes.SET_INITIAL_BOARD_DATA](state, data) {
const { boardType, ...endpoints } = data; const { boardType, disabled, showPromotion, ...endpoints } = data;
state.endpoints = endpoints; state.endpoints = endpoints;
state.boardType = boardType; state.boardType = boardType;
state.disabled = disabled;
state.showPromotion = showPromotion;
},
[mutationTypes.RECEIVE_LISTS]: (state, lists) => {
state.boardLists = lists;
}, },
[mutationTypes.SET_ACTIVE_ID](state, id) { [mutationTypes.SET_ACTIVE_ID](state, id) {
...@@ -21,6 +27,10 @@ export default { ...@@ -21,6 +27,10 @@ export default {
state.filterParams = filterParams; state.filterParams = filterParams;
}, },
[mutationTypes.CREATE_LIST_FAILURE]: state => {
state.error = __('An error occurred while creating the list. Please try again.');
},
[mutationTypes.REQUEST_ADD_LIST]: () => { [mutationTypes.REQUEST_ADD_LIST]: () => {
notImplemented(); notImplemented();
}, },
......
...@@ -3,6 +3,8 @@ import { inactiveId } from '~/boards/constants'; ...@@ -3,6 +3,8 @@ import { inactiveId } from '~/boards/constants';
export default () => ({ export default () => ({
endpoints: {}, endpoints: {},
boardType: null, boardType: null,
disabled: false,
showPromotion: false,
isShowingLabels: true, isShowingLabels: true,
activeId: inactiveId, activeId: inactiveId,
boardLists: [], boardLists: [],
......
...@@ -8,6 +8,7 @@ class Groups::BoardsController < Groups::ApplicationController ...@@ -8,6 +8,7 @@ class Groups::BoardsController < Groups::ApplicationController
before_action :assign_endpoint_vars before_action :assign_endpoint_vars
before_action do before_action do
push_frontend_feature_flag(:multi_select_board, default_enabled: true) push_frontend_feature_flag(:multi_select_board, default_enabled: true)
push_frontend_feature_flag(:graphql_board_lists, group, default_enabled: false)
push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: false) push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: false)
end end
......
import { sortBy } from 'lodash'; import { sortBy } from 'lodash';
import Cookies from 'js-cookie';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import boardsStore from '~/boards/stores/boards_store'; import boardsStore from '~/boards/stores/boards_store';
import { __ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
import actionsCE from '~/boards/stores/actions'; import actionsCE from '~/boards/stores/actions';
import { BoardType, ListType } from '~/boards/constants';
import boardsStoreEE from './boards_store_ee'; import boardsStoreEE from './boards_store_ee';
import * as types from './mutation_types'; import * as types from './mutation_types';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import { BoardType } from '~/boards/constants';
import groupEpicsSwimlanesQuery from '../queries/group_epics_swimlanes.query.graphql'; import groupEpicsSwimlanesQuery from '../queries/group_epics_swimlanes.query.graphql';
const notImplemented = () => { const notImplemented = () => {
...@@ -73,6 +76,22 @@ export default { ...@@ -73,6 +76,22 @@ export default {
}); });
}, },
showPromotionList: ({ state, dispatch }) => {
if (
!state.showPromotion ||
parseBoolean(Cookies.get('promotion_issue_board_hidden')) ||
state.disabled
) {
return;
}
dispatch('addList', {
id: 'promotion',
listType: ListType.promotion,
title: __('Improve Issue Boards'),
position: 0,
});
},
fetchAllBoards: () => { fetchAllBoards: () => {
notImplemented(); notImplemented();
}, },
......
...@@ -57,6 +57,7 @@ RSpec.describe 'Multiple Issue Boards', :js do ...@@ -57,6 +57,7 @@ RSpec.describe 'Multiple Issue Boards', :js do
before do before do
stub_licensed_features(multiple_group_issue_boards: true) stub_licensed_features(multiple_group_issue_boards: true)
stub_feature_flags(graphql_board_lists: false)
end end
it_behaves_like 'multiple issue boards' it_behaves_like 'multiple issue boards'
......
...@@ -3,6 +3,7 @@ import boardsStoreEE from 'ee/boards/stores/boards_store_ee'; ...@@ -3,6 +3,7 @@ import boardsStoreEE from 'ee/boards/stores/boards_store_ee';
import actions from 'ee/boards/stores/actions'; import actions from 'ee/boards/stores/actions';
import * as types from 'ee/boards/stores/mutation_types'; import * as types from 'ee/boards/stores/mutation_types';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import { ListType } from '~/boards/constants';
jest.mock('axios'); jest.mock('axios');
...@@ -56,6 +57,34 @@ describe('updateListWipLimit', () => { ...@@ -56,6 +57,34 @@ describe('updateListWipLimit', () => {
}); });
}); });
describe('showPromotionList', () => {
it('should dispatch addList action when conditions showPromotion is true', done => {
const state = {
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
boardType: 'group',
disabled: false,
boardLists: [{ type: 'backlog' }, { type: 'closed' }],
showPromotion: true,
};
const promotionList = {
id: 'promotion',
listType: ListType.promotion,
title: 'Improve Issue Boards',
position: 0,
};
testAction(
actions.showPromotionList,
{},
state,
[],
[{ type: 'addList', payload: promotionList }],
done,
);
});
});
describe('fetchAllBoards', () => { describe('fetchAllBoards', () => {
expectNotImplemented(actions.fetchAllBoards); expectNotImplemented(actions.fetchAllBoards);
}); });
......
...@@ -2597,6 +2597,9 @@ msgstr "" ...@@ -2597,6 +2597,9 @@ msgstr ""
msgid "An error occurred while committing your changes." msgid "An error occurred while committing your changes."
msgstr "" msgstr ""
msgid "An error occurred while creating the list. Please try again."
msgstr ""
msgid "An error occurred while decoding the file." msgid "An error occurred while decoding the file."
msgstr "" msgstr ""
...@@ -2672,6 +2675,9 @@ msgstr "" ...@@ -2672,6 +2675,9 @@ msgstr ""
msgid "An error occurred while fetching the board issues. Please reload the page." msgid "An error occurred while fetching the board issues. Please reload the page."
msgstr "" msgstr ""
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again." msgid "An error occurred while fetching the board lists. Please try again."
msgstr "" msgstr ""
...@@ -12971,6 +12977,9 @@ msgstr "" ...@@ -12971,6 +12977,9 @@ msgstr ""
msgid "ImportProjects|Update of imported projects with realtime changes failed" msgid "ImportProjects|Update of imported projects with realtime changes failed"
msgstr "" msgstr ""
msgid "Improve Issue Boards"
msgstr ""
msgid "Improve Issue boards" msgid "Improve Issue boards"
msgstr "" msgstr ""
...@@ -13300,6 +13309,9 @@ msgstr "" ...@@ -13300,6 +13309,9 @@ msgstr ""
msgid "Invalid URL" msgid "Invalid URL"
msgstr "" msgstr ""
msgid "Invalid board"
msgstr ""
msgid "Invalid container_name" msgid "Invalid container_name"
msgstr "" msgstr ""
...@@ -27595,6 +27607,9 @@ msgstr "" ...@@ -27595,6 +27607,9 @@ msgstr ""
msgid "Welcome to your Issue Board!" msgid "Welcome to your Issue Board!"
msgstr "" msgstr ""
msgid "Welcome to your issue board!"
msgstr ""
msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience." msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
msgstr "" msgstr ""
......
...@@ -130,24 +130,43 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -130,24 +130,43 @@ RSpec.describe 'Issue Boards new issue', :js do
context 'group boards' do context 'group boards' do
let_it_be(:group) { create(:group, :public) } let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, namespace: group) } let_it_be(:project) { create(:project, :public, namespace: group) }
let_it_be(:group_board) { create(:board, group: group) } let_it_be(:group_board) { create(:board, group: group) }
let_it_be(:list) { create(:list, board: group_board, position: 0) } let_it_be(:project_label) { create(:label, project: project, name: 'label') }
let_it_be(:list) { create(:list, board: group_board, label: project_label, position: 0) }
context 'for unauthorized users' do context 'for unauthorized users' do
before do context 'when backlog does not exist' do
sign_in(user) before do
visit group_board_path(group, group_board) sign_in(user)
wait_for_requests visit group_board_path(group, group_board)
end wait_for_requests
end
it 'displays new issue button in open list' do it 'does not display new issue button in label list' do
expect(first('.board')).to have_selector('.issue-count-badge-add-button', count: 1) page.within('.board.is-draggable') do
expect(page).not_to have_selector('.issue-count-badge-add-button')
end
end
end end
it 'does not display new issue button in label list' do context 'when backlog list already exists' do
page.within('.board.is-draggable') do let!(:backlog_list) { create(:backlog_list, board: group_board) }
expect(page).not_to have_selector('.issue-count-badge-add-button')
before do
sign_in(user)
visit group_board_path(group, group_board)
wait_for_requests
end
it 'displays new issue button in open list' do
expect(first('.board')).to have_selector('.issue-count-badge-add-button', count: 1)
end
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
expect(page).not_to have_selector('.issue-count-badge-add-button')
end
end end
end end
end end
......
...@@ -296,6 +296,7 @@ RSpec.describe 'Labels Hierarchy', :js do ...@@ -296,6 +296,7 @@ RSpec.describe 'Labels Hierarchy', :js do
let(:board) { create(:board, group: parent) } let(:board) { create(:board, group: parent) }
before do before do
stub_feature_flags(graphql_board_lists: false)
parent.add_developer(user) parent.add_developer(user)
visit group_board_path(parent, board) visit group_board_path(parent, board)
find('.js-new-board-list').click find('.js-new-board-list').click
......
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import actions from '~/boards/stores/actions'; import actions, { gqlClient } from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types'; import * as types from '~/boards/stores/mutation_types';
import { inactiveId } from '~/boards/constants'; import { inactiveId, ListType } from '~/boards/constants';
const expectNotImplemented = action => { const expectNotImplemented = action => {
it('is not implemented', () => { it('is not implemented', () => {
...@@ -62,8 +62,31 @@ describe('setActiveId', () => { ...@@ -62,8 +62,31 @@ describe('setActiveId', () => {
}); });
}); });
describe('fetchLists', () => { describe('showWelcomeList', () => {
expectNotImplemented(actions.fetchLists); it('should dispatch addList action', done => {
const state = {
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
boardType: 'group',
disabled: false,
boardLists: [{ type: 'backlog' }, { type: 'closed' }],
};
const blankList = {
id: 'blank',
listType: ListType.blank,
title: 'Welcome to your issue board!',
position: 0,
};
testAction(
actions.showWelcomeList,
{},
state,
[],
[{ type: 'addList', payload: blankList }],
done,
);
});
}); });
describe('generateDefaultLists', () => { describe('generateDefaultLists', () => {
...@@ -71,7 +94,70 @@ describe('generateDefaultLists', () => { ...@@ -71,7 +94,70 @@ describe('generateDefaultLists', () => {
}); });
describe('createList', () => { describe('createList', () => {
expectNotImplemented(actions.createList); it('should dispatch addList action when creating backlog list', done => {
const backlogList = {
id: 'gid://gitlab/List/1',
listType: 'backlog',
title: 'Open',
position: 0,
};
jest.spyOn(gqlClient, 'mutate').mockReturnValue(
Promise.resolve({
data: {
boardListCreate: {
list: backlogList,
errors: [],
},
},
}),
);
const state = {
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
boardType: 'group',
disabled: false,
boardLists: [{ type: 'closed' }],
};
testAction(
actions.createList,
{ backlog: true },
state,
[],
[{ type: 'addList', payload: { ...backlogList, id: 1 } }],
done,
);
});
it('should commit CREATE_LIST_FAILURE mutation when API returns an error', done => {
jest.spyOn(gqlClient, 'mutate').mockReturnValue(
Promise.resolve({
data: {
boardListCreate: {
list: {},
errors: [{ foo: 'bar' }],
},
},
}),
);
const state = {
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
boardType: 'group',
disabled: false,
boardLists: [{ type: 'closed' }],
};
testAction(
actions.createList,
{ backlog: true },
state,
[{ type: types.CREATE_LIST_FAILURE }],
[],
done,
);
});
}); });
describe('updateList', () => { describe('updateList', () => {
......
import mutations from '~/boards/stores/mutations'; import mutations from '~/boards/stores/mutations';
import * as types from '~/boards/stores/mutation_types';
import defaultState from '~/boards/stores/state'; import defaultState from '~/boards/stores/state';
import { mockIssue } from '../mock_data'; import { listObj, listObjDuplicate, mockIssue } from '../mock_data';
const expectNotImplemented = action => { const expectNotImplemented = action => {
it('is not implemented', () => { it('is not implemented', () => {
...@@ -26,11 +27,30 @@ describe('Board Store Mutations', () => { ...@@ -26,11 +27,30 @@ describe('Board Store Mutations', () => {
fullPath: 'gitlab-org', fullPath: 'gitlab-org',
}; };
const boardType = 'group'; const boardType = 'group';
const disabled = false;
const showPromotion = false;
mutations.SET_INITIAL_BOARD_DATA(state, { ...endpoints, boardType }); mutations[types.SET_INITIAL_BOARD_DATA](state, {
...endpoints,
boardType,
disabled,
showPromotion,
});
expect(state.endpoints).toEqual(endpoints); expect(state.endpoints).toEqual(endpoints);
expect(state.boardType).toEqual(boardType); expect(state.boardType).toEqual(boardType);
expect(state.disabled).toEqual(disabled);
expect(state.showPromotion).toEqual(showPromotion);
});
});
describe('RECEIVE_LISTS', () => {
it('Should set boardLists to state', () => {
const lists = [listObj, listObjDuplicate];
mutations[types.RECEIVE_LISTS](state, lists);
expect(state.boardLists).toEqual(lists);
}); });
}); });
......
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