Commit ba77f398 authored by Jannik Lehmann's avatar Jannik Lehmann Committed by Brandon Labuschagne

Replace window.confirm with GlModal for registration token reset

This commit replaces window.confirm dialog with
a GlModal for the reset of the registration token.

Changelog: changed
parent 279b5324
<script> <script>
import { GlDropdownItem, GlLoadingIcon } from '@gitlab/ui'; import { GlDropdownItem, GlLoadingIcon, GlModal, GlModalDirective } from '@gitlab/ui';
import { createAlert } from '~/flash'; import { createAlert } from '~/flash';
import { TYPE_GROUP, TYPE_PROJECT } from '~/graphql_shared/constants'; import { TYPE_GROUP, TYPE_PROJECT } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
...@@ -10,9 +10,17 @@ import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants'; ...@@ -10,9 +10,17 @@ import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
export default { export default {
name: 'RunnerRegistrationTokenReset', name: 'RunnerRegistrationTokenReset',
i18n: {
modalTitle: __('Reset registration token'),
modalCopy: __('Are you sure you want to reset the registration token?'),
},
components: { components: {
GlDropdownItem, GlDropdownItem,
GlLoadingIcon, GlLoadingIcon,
GlModal,
},
directives: {
GlModal: GlModalDirective,
}, },
inject: { inject: {
groupId: { groupId: {
...@@ -22,6 +30,7 @@ export default { ...@@ -22,6 +30,7 @@ export default {
default: null, default: null,
}, },
}, },
modalID: 'token-reset-modal',
props: { props: {
type: { type: {
type: String, type: String,
...@@ -59,14 +68,10 @@ export default { ...@@ -59,14 +68,10 @@ export default {
}, },
}, },
methods: { methods: {
handleModalPrimary() {
this.resetToken();
},
async resetToken() { async resetToken() {
// TODO Replace confirmation with gl-modal
// See: https://gitlab.com/gitlab-org/gitlab/-/issues/333810
// eslint-disable-next-line no-alert
if (!window.confirm(__('Are you sure you want to reset the registration token?'))) {
return;
}
this.loading = true; this.loading = true;
try { try {
const { const {
...@@ -106,8 +111,15 @@ export default { ...@@ -106,8 +111,15 @@ export default {
}; };
</script> </script>
<template> <template>
<gl-dropdown-item @click.capture.native.stop="resetToken"> <gl-dropdown-item v-gl-modal="$options.modalID">
{{ __('Reset registration token') }} {{ __('Reset registration token') }}
<gl-modal
:modal-id="$options.modalID"
:title="$options.i18n.modalTitle"
@primary="handleModalPrimary"
>
<p>{{ $options.i18n.modalCopy }}</p>
</gl-modal>
<gl-loading-icon v-if="loading" inline /> <gl-loading-icon v-if="loading" inline />
</gl-dropdown-item> </gl-dropdown-item>
</template> </template>
...@@ -451,7 +451,9 @@ RSpec.describe "Admin Runners" do ...@@ -451,7 +451,9 @@ RSpec.describe "Admin Runners" do
before do before do
click_on 'Reset registration token' click_on 'Reset registration token'
page.accept_alert within_modal do
click_button('OK', match: :first)
end
wait_for_requests wait_for_requests
end end
......
import { GlDropdownItem, GlLoadingIcon, GlToast } from '@gitlab/ui'; import { GlDropdownItem, GlLoadingIcon, GlToast, GlModal } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
...@@ -9,6 +9,7 @@ import RegistrationTokenResetDropdownItem from '~/runner/components/registration ...@@ -9,6 +9,7 @@ import RegistrationTokenResetDropdownItem from '~/runner/components/registration
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants'; import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants';
import runnersRegistrationTokenResetMutation from '~/runner/graphql/runners_registration_token_reset.mutation.graphql'; import runnersRegistrationTokenResetMutation from '~/runner/graphql/runners_registration_token_reset.mutation.graphql';
import { captureException } from '~/runner/sentry_utils'; import { captureException } from '~/runner/sentry_utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('~/runner/sentry_utils'); jest.mock('~/runner/sentry_utils');
...@@ -18,14 +19,18 @@ localVue.use(VueApollo); ...@@ -18,14 +19,18 @@ localVue.use(VueApollo);
localVue.use(GlToast); localVue.use(GlToast);
const mockNewToken = 'NEW_TOKEN'; const mockNewToken = 'NEW_TOKEN';
const modalID = 'token-reset-modal';
describe('RegistrationTokenResetDropdownItem', () => { describe('RegistrationTokenResetDropdownItem', () => {
let wrapper; let wrapper;
let runnersRegistrationTokenResetMutationHandler; let runnersRegistrationTokenResetMutationHandler;
let showToast; let showToast;
const mockEvent = { preventDefault: jest.fn() };
const findDropdownItem = () => wrapper.findComponent(GlDropdownItem); const findDropdownItem = () => wrapper.findComponent(GlDropdownItem);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findModal = () => wrapper.findComponent(GlModal);
const clickSubmit = () => findModal().vm.$emit('primary', mockEvent);
const createComponent = ({ props, provide = {} } = {}) => { const createComponent = ({ props, provide = {} } = {}) => {
wrapper = shallowMount(RegistrationTokenResetDropdownItem, { wrapper = shallowMount(RegistrationTokenResetDropdownItem, {
...@@ -38,6 +43,9 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -38,6 +43,9 @@ describe('RegistrationTokenResetDropdownItem', () => {
apolloProvider: createMockApollo([ apolloProvider: createMockApollo([
[runnersRegistrationTokenResetMutation, runnersRegistrationTokenResetMutationHandler], [runnersRegistrationTokenResetMutation, runnersRegistrationTokenResetMutationHandler],
]), ]),
directives: {
GlModal: createMockDirective(),
},
}); });
showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null; showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null;
...@@ -54,8 +62,6 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -54,8 +62,6 @@ describe('RegistrationTokenResetDropdownItem', () => {
}); });
createComponent(); createComponent();
jest.spyOn(window, 'confirm');
}); });
afterEach(() => { afterEach(() => {
...@@ -66,6 +72,18 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -66,6 +72,18 @@ describe('RegistrationTokenResetDropdownItem', () => {
expect(findDropdownItem().exists()).toBe(true); expect(findDropdownItem().exists()).toBe(true);
}); });
describe('modal directive integration', () => {
it('has the correct ID on the dropdown', () => {
const binding = getBinding(findDropdownItem().element, 'gl-modal');
expect(binding.value).toBe(modalID);
});
it('has the correct ID on the modal', () => {
expect(findModal().props('modalId')).toBe(modalID);
});
});
describe('On click and confirmation', () => { describe('On click and confirmation', () => {
const mockGroupId = '11'; const mockGroupId = '11';
const mockProjectId = '22'; const mockProjectId = '22';
...@@ -82,9 +100,8 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -82,9 +100,8 @@ describe('RegistrationTokenResetDropdownItem', () => {
props: { type }, props: { type },
}); });
window.confirm.mockReturnValueOnce(true);
findDropdownItem().trigger('click'); findDropdownItem().trigger('click');
clickSubmit();
await waitForPromises(); await waitForPromises();
}); });
...@@ -114,7 +131,6 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -114,7 +131,6 @@ describe('RegistrationTokenResetDropdownItem', () => {
describe('On click without confirmation', () => { describe('On click without confirmation', () => {
beforeEach(async () => { beforeEach(async () => {
window.confirm.mockReturnValueOnce(false);
findDropdownItem().vm.$emit('click'); findDropdownItem().vm.$emit('click');
await waitForPromises(); await waitForPromises();
}); });
...@@ -142,8 +158,8 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -142,8 +158,8 @@ describe('RegistrationTokenResetDropdownItem', () => {
runnersRegistrationTokenResetMutationHandler.mockRejectedValueOnce(new Error(mockErrorMsg)); runnersRegistrationTokenResetMutationHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
window.confirm.mockReturnValueOnce(true);
findDropdownItem().trigger('click'); findDropdownItem().trigger('click');
clickSubmit();
await waitForPromises(); await waitForPromises();
expect(createAlert).toHaveBeenLastCalledWith({ expect(createAlert).toHaveBeenLastCalledWith({
...@@ -168,8 +184,8 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -168,8 +184,8 @@ describe('RegistrationTokenResetDropdownItem', () => {
}, },
}); });
window.confirm.mockReturnValueOnce(true);
findDropdownItem().trigger('click'); findDropdownItem().trigger('click');
clickSubmit();
await waitForPromises(); await waitForPromises();
expect(createAlert).toHaveBeenLastCalledWith({ expect(createAlert).toHaveBeenLastCalledWith({
...@@ -184,8 +200,8 @@ describe('RegistrationTokenResetDropdownItem', () => { ...@@ -184,8 +200,8 @@ describe('RegistrationTokenResetDropdownItem', () => {
describe('Immediately after click', () => { describe('Immediately after click', () => {
it('shows loading state', async () => { it('shows loading state', async () => {
window.confirm.mockReturnValue(true);
findDropdownItem().trigger('click'); findDropdownItem().trigger('click');
clickSubmit();
await nextTick(); await nextTick();
expect(findLoadingIcon().exists()).toBe(true); expect(findLoadingIcon().exists()).toBe(true);
......
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