Commit 3d2a5fa2 authored by Florie Guibert's avatar Florie Guibert

Delete Epic Board

Add ability to delete an epic board from boards selector dropdown
parent c39d19e9
...@@ -163,6 +163,9 @@ export default { ...@@ -163,6 +163,9 @@ export default {
currentMutation() { currentMutation() {
return this.board.id ? updateBoardMutation : createBoardMutation; return this.board.id ? updateBoardMutation : createBoardMutation;
}, },
deleteMutation() {
return destroyBoardMutation;
},
baseMutationVariables() { baseMutationVariables() {
const { board } = this; const { board } = this;
const variables = { const variables = {
...@@ -244,17 +247,20 @@ export default { ...@@ -244,17 +247,20 @@ export default {
return this.boardUpdateResponse(response.data); return this.boardUpdateResponse(response.data);
}, },
async deleteBoard() {
await this.$apollo.mutate({
mutation: this.deleteMutation,
variables: {
id: fullBoardId(this.board.id),
},
});
},
async submit() { async submit() {
if (this.board.name.length === 0) return; if (this.board.name.length === 0) return;
this.isLoading = true; this.isLoading = true;
if (this.isDeleteForm) { if (this.isDeleteForm) {
try { try {
await this.$apollo.mutate({ await this.deleteBoard();
mutation: destroyBoardMutation,
variables: {
id: fullBoardId(this.board.id),
},
});
visitUrl(this.rootPath); visitUrl(this.rootPath);
} catch { } catch {
Flash(this.$options.i18n.deleteErrorMessage); Flash(this.$options.i18n.deleteErrorMessage);
......
...@@ -3,18 +3,17 @@ ...@@ -3,18 +3,17 @@
// extends a valid Vue single file component. // extends a valid Vue single file component.
/* eslint-disable @gitlab/no-runtime-template-compiler */ /* eslint-disable @gitlab/no-runtime-template-compiler */
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { fullBoardId } from '~/boards/boards_util';
import BoardFormFoss from '~/boards/components/board_form.vue'; import BoardFormFoss from '~/boards/components/board_form.vue';
import { fullEpicBoardId } from '../boards_util'; import { fullEpicBoardId } from '../boards_util';
import createEpicBoardMutation from '../graphql/epic_board_create.mutation.graphql'; import createEpicBoardMutation from '../graphql/epic_board_create.mutation.graphql';
import destroyEpicBoardMutation from '../graphql/epic_board_destroy.mutation.graphql';
import updateEpicBoardMutation from '../graphql/epic_board_update.mutation.graphql'; import updateEpicBoardMutation from '../graphql/epic_board_update.mutation.graphql';
export default { export default {
extends: BoardFormFoss, extends: BoardFormFoss,
computed: { computed: {
...mapGetters(['isEpicBoard']), ...mapGetters(['isEpicBoard']),
epicBoardCreateQuery() {
return createEpicBoardMutation;
},
currentEpicBoardMutation() { currentEpicBoardMutation() {
return this.board.id ? updateEpicBoardMutation : createEpicBoardMutation; return this.board.id ? updateEpicBoardMutation : createEpicBoardMutation;
}, },
...@@ -53,6 +52,14 @@ export default { ...@@ -53,6 +52,14 @@ export default {
? this.epicBoardUpdateResponse(response.data) ? this.epicBoardUpdateResponse(response.data)
: this.boardUpdateResponse(response.data); : this.boardUpdateResponse(response.data);
}, },
async deleteBoard() {
await this.$apollo.mutate({
mutation: this.isEpicBoard ? destroyEpicBoardMutation : this.deleteMutation,
variables: {
id: this.isEpicBoard ? fullEpicBoardId(this.board.id) : fullBoardId(this.board.id),
},
});
},
}, },
}; };
</script> </script>
...@@ -15,7 +15,7 @@ export default { ...@@ -15,7 +15,7 @@ export default {
return this.isEpicBoard || this.multipleIssueBoardsAvailable; return this.isEpicBoard || this.multipleIssueBoardsAvailable;
}, },
showDelete() { showDelete() {
return this.boards.length > 1 && !this.isEpicBoard; return this.boards.length > 1;
}, },
}, },
methods: { methods: {
......
mutation destroyEpicBoard($id: BoardsEpicBoardID!) {
destroyEpicBoard(input: { id: $id }) {
epicBoard {
id
}
}
}
...@@ -54,6 +54,22 @@ RSpec.describe 'epic boards', :js do ...@@ -54,6 +54,22 @@ RSpec.describe 'epic boards', :js do
expect(page).to have_button('This is a new board') expect(page).to have_button('This is a new board')
end end
it 'deletes an epic board' do
in_boards_switcher_dropdown do
expect(page).to have_content(epic_board.name)
expect(page).to have_content(epic_board2.name)
click_button 'Delete board'
end
click_button 'Delete'
wait_for_requests
in_boards_switcher_dropdown do
expect(page).not_to have_content(epic_board.name)
expect(page).to have_content(epic_board2.name)
end
end
end end
def visit_epic_boards_page def visit_epic_boards_page
......
import { GlModal } from '@gitlab/ui'; import { GlModal } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import BoardForm from 'ee/boards/components/board_form.vue'; import BoardForm from 'ee/boards/components/board_form.vue';
import createEpicBoardMutation from 'ee/boards/graphql/epic_board_create.mutation.graphql'; import createEpicBoardMutation from 'ee/boards/graphql/epic_board_create.mutation.graphql';
import destroyEpicBoardMutation from 'ee/boards/graphql/epic_board_destroy.mutation.graphql';
import updateEpicBoardMutation from 'ee/boards/graphql/epic_board_update.mutation.graphql'; import updateEpicBoardMutation from 'ee/boards/graphql/epic_board_update.mutation.graphql';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
...@@ -19,8 +21,7 @@ jest.mock('~/lib/utils/url_utility', () => ({ ...@@ -19,8 +21,7 @@ jest.mock('~/lib/utils/url_utility', () => ({
})); }));
jest.mock('~/flash'); jest.mock('~/flash');
const localVue = createLocalVue(); Vue.use(Vuex);
localVue.use(Vuex);
const currentBoard = { const currentBoard = {
id: 1, id: 1,
...@@ -68,7 +69,6 @@ describe('BoardForm', () => { ...@@ -68,7 +69,6 @@ describe('BoardForm', () => {
const createComponent = (props) => { const createComponent = (props) => {
wrapper = shallowMount(BoardForm, { wrapper = shallowMount(BoardForm, {
localVue,
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
provide: { provide: {
rootPath: 'root', rootPath: 'root',
...@@ -227,4 +227,49 @@ describe('BoardForm', () => { ...@@ -227,4 +227,49 @@ describe('BoardForm', () => {
expect(createFlash).toHaveBeenCalled(); expect(createFlash).toHaveBeenCalled();
}); });
}); });
describe('when deleting an epic board', () => {
it('passes correct primary action text and variant', () => {
createComponent({ canAdminBoard: true, currentPage: formType.delete });
expect(findModalActionPrimary().text).toBe('Delete');
expect(findModalActionPrimary().attributes[0].variant).toBe('danger');
});
it('renders delete confirmation message', () => {
createComponent({ canAdminBoard: true, currentPage: formType.delete });
expect(findDeleteConfirmation().exists()).toBe(true);
});
it('calls a correct GraphQL mutation and redirects to correct page after deleting board', async () => {
mutate = jest.fn().mockResolvedValue({});
createComponent({ canAdminBoard: true, currentPage: formType.delete });
findModal().vm.$emit('primary');
await waitForPromises();
expect(mutate).toHaveBeenCalledWith({
mutation: destroyEpicBoardMutation,
variables: {
id: 'gid://gitlab/Boards::EpicBoard/1',
},
});
await waitForPromises();
expect(visitUrl).toHaveBeenCalledWith('root');
});
it('shows an error flash if GraphQL mutation fails', async () => {
mutate = jest.fn().mockRejectedValue('Houston, we have a problem');
createComponent({ canAdminBoard: true, currentPage: formType.delete });
findModal().vm.$emit('primary');
await waitForPromises();
expect(mutate).toHaveBeenCalled();
await waitForPromises();
expect(visitUrl).not.toHaveBeenCalled();
expect(createFlash).toHaveBeenCalled();
});
});
}); });
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