Commit 5d696a75 authored by Brandon Labuschagne's avatar Brandon Labuschagne

Refactor to use a single modal

Prevent the modal from being rendered
for each button, instead render a single
modal and add an event handler to the buttons
which transfer data via attributes.
parent d53b89b4
<script>
import { uniqueId } from 'lodash';
import { GlButton, GlModal, GlModalDirective, GlSprintf } from '@gitlab/ui';
import { GlModal, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
import csrf from '~/lib/utils/csrf';
export default {
components: {
GlButton,
GlModal,
GlSprintf,
},
directives: {
GlModal: GlModalDirective,
},
inject: {
name: {
default: '',
},
path: {
default: '',
},
},
data() {
return {
modalId: uniqueId('application-delete-button-'),
name: '',
path: '',
};
},
mounted() {
document.querySelectorAll('.js-application-delete-button').forEach((button) => {
button.addEventListener('click', (e) => {
e.preventDefault();
this.show(button.dataset);
});
});
},
methods: {
show(dataset) {
const { name, path } = dataset;
this.name = name;
this.path = path;
this.$refs.deleteModal.show();
},
deleteApplication() {
this.$refs.deleteForm.submit();
},
......@@ -54,24 +58,22 @@ export default {
};
</script>
<template>
<div>
<gl-button v-gl-modal="modalId" variant="danger">{{ $options.i18n.destroy }}</gl-button>
<gl-modal
:title="$options.i18n.title"
:action-primary="$options.modal.actionPrimary"
:action-secondary="$options.modal.actionSecondary"
:modal-id="modalId"
size="sm"
@primary="deleteApplication"
><gl-sprintf :message="$options.i18n.body">
<template #application>
<strong>{{ name }}</strong>
</template></gl-sprintf
>
<form ref="deleteForm" method="post" :action="path">
<input type="hidden" name="_method" value="delete" />
<input type="hidden" name="authenticity_token" :value="$options.csrf.token" />
</form>
</gl-modal>
</div>
<gl-modal
ref="deleteModal"
:title="$options.i18n.title"
:action-primary="$options.modal.actionPrimary"
:action-secondary="$options.modal.actionSecondary"
modal-id="delete-application-modal"
size="sm"
@primary="deleteApplication"
><gl-sprintf :message="$options.i18n.body">
<template #application>
<strong>{{ name }}</strong>
</template></gl-sprintf
>
<form ref="deleteForm" method="post" :action="path">
<input type="hidden" name="_method" value="delete" />
<input type="hidden" name="authenticity_token" :value="$options.csrf.token" />
</form>
</gl-modal>
</template>
......@@ -2,24 +2,14 @@ import Vue from 'vue';
import DeleteApplication from './components/delete_application.vue';
export default () => {
const elements = document.querySelectorAll('.js-application-delete-button');
const el = document.querySelector('.js-application-delete-modal');
if (!elements) {
return false;
}
if (!el) return false;
return elements.forEach((el) => {
const { path, name } = el.dataset;
return new Vue({
el,
provide: {
path,
name,
},
render(h) {
return h(DeleteApplication);
},
});
return new Vue({
el,
render(h) {
return h(DeleteApplication);
},
});
};
.js-application-delete-button{ data: { path: admin_application_path(application), name: application.name } }
- submit_btn_css ||= 'gl-button btn btn-danger btn-sm js-application-delete-button'
%button{ class: submit_btn_css, data: { path: admin_application_path(application), name: application.name } }
= _('Destroy')
......@@ -33,3 +33,5 @@
%td= render 'delete_form', application: application
= paginate @applications, theme: 'gitlab'
.js-application-delete-modal
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DeleteApplication the modal component form renders with action and method 1`] = `
exports[`DeleteApplication the modal component form matches the snapshot 1`] = `
<form
action="application/path/1"
method="post"
......
import { GlButton, GlModal, GlSprintf } from '@gitlab/ui';
import { GlModal, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import DeleteApplication from '~/admin/applications/components/delete_application.vue';
const modalID = 'fake-id';
const path = 'application/path/1';
const name = 'Application name';
jest.mock('lodash/uniqueId', () => () => 'fake-id');
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
describe('DeleteApplication', () => {
......@@ -15,24 +12,20 @@ describe('DeleteApplication', () => {
const createComponent = () => {
wrapper = shallowMount(DeleteApplication, {
provide: {
path,
name,
},
directives: {
GlModal: createMockDirective(),
},
stubs: {
GlSprintf,
},
});
};
const findButton = () => wrapper.findComponent(GlButton);
const findModal = () => wrapper.findComponent(GlModal);
const findForm = () => wrapper.find('form');
beforeEach(() => {
setFixtures(`
<button class="js-application-delete-button" data-path="${path}" data-name="${name}">Destroy</button>
`);
createComponent();
});
......@@ -40,22 +33,12 @@ describe('DeleteApplication', () => {
wrapper.destroy();
});
describe('the button component', () => {
it('displays the destroy button', () => {
const button = findButton();
expect(button.exists()).toBe(true);
expect(button.text()).toBe('Destroy');
});
it('contains the correct modal ID', () => {
const buttonModalId = getBinding(findButton().element, 'gl-modal').value;
expect(buttonModalId).toBe(modalID);
describe('the modal component', () => {
beforeEach(() => {
wrapper.vm.$refs.deleteModal.show = jest.fn();
document.querySelector('.js-application-delete-button').click();
});
});
describe('the modal component', () => {
it('displays the modal component', () => {
const modal = findModal();
......@@ -64,10 +47,6 @@ describe('DeleteApplication', () => {
expect(modal.text()).toBe(`Are you sure that you want to destroy ${name}`);
});
it('contains the correct modal ID', () => {
expect(findModal().props('modalId')).toBe(modalID);
});
describe('form', () => {
it('matches the snapshot', () => {
expect(findForm().element).toMatchSnapshot();
......
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