Commit e7adf4ab authored by Justin Ho Tuan Duong's avatar Justin Ho Tuan Duong Committed by Nicolò Maria Mezzopera

Add confirmation modal on integration form

- For instance-level integration
- Replaces "Save changes" button which saved
immediately (without confirmation)
parent c215b24d
<script>
import { mapGetters } from 'vuex';
import { GlModal } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: {
GlModal,
},
computed: {
...mapGetters(['isSavingOrTesting']),
primaryProps() {
return {
text: __('Save'),
attributes: [
{ variant: 'success' },
{ category: 'primary' },
{ disabled: this.isSavingOrTesting },
],
};
},
cancelProps() {
return {
text: __('Cancel'),
};
},
},
methods: {
onSubmit() {
this.$emit('submit');
},
},
};
</script>
<template>
<gl-modal
modal-id="confirmSaveIntegration"
size="sm"
:title="s__('Integrations|Save settings?')"
:action-primary="primaryProps"
:action-cancel="cancelProps"
@primary="onSubmit"
>
<p>
{{
s__(
'Integrations|Saving will update the default settings for all projects that are not using custom settings.',
)
}}
</p>
<p class="gl-mb-0">
{{
s__(
'Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults.',
)
}}
</p>
</gl-modal>
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex';
import { GlButton } from '@gitlab/ui';
import { GlButton, GlModalDirective } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
import { integrationLevels } from '../constants';
import OverrideDropdown from './override_dropdown.vue';
import ActiveCheckbox from './active_checkbox.vue';
......@@ -10,6 +11,7 @@ import JiraTriggerFields from './jira_trigger_fields.vue';
import JiraIssuesFields from './jira_issues_fields.vue';
import TriggerFields from './trigger_fields.vue';
import DynamicField from './dynamic_field.vue';
import ConfirmationModal from './confirmation_modal.vue';
export default {
name: 'IntegrationForm',
......@@ -20,8 +22,12 @@ export default {
JiraIssuesFields,
TriggerFields,
DynamicField,
ConfirmationModal,
GlButton,
},
directives: {
'gl-modal': GlModalDirective,
},
mixins: [glFeatureFlagsMixin()],
computed: {
...mapGetters(['currentKey', 'propsSource', 'isSavingOrTesting']),
......@@ -32,6 +38,9 @@ export default {
isJira() {
return this.propsSource.type === 'jira';
},
isInstanceLevel() {
return this.propsSource.integrationLevel === integrationLevels.INSTANCE;
},
showJiraIssuesFields() {
return this.isJira && this.glFeatures.jiraIssuesIntegration;
},
......@@ -82,7 +91,21 @@ export default {
v-bind="propsSource.jiraIssuesProps"
/>
<div v-if="isEditable" class="footer-block row-content-block">
<template v-if="isInstanceLevel">
<gl-button
v-gl-modal.confirmSaveIntegration
category="primary"
variant="success"
:loading="isSaving"
:disabled="isSavingOrTesting"
data-qa-selector="save_changes_button"
>
{{ __('Save changes') }}
</gl-button>
<confirmation-modal @submit="onSaveClick" />
</template>
<gl-button
v-else
category="primary"
variant="success"
type="submit"
......@@ -93,6 +116,7 @@ export default {
>
{{ __('Save changes') }}
</gl-button>
<gl-button
v-if="propsSource.canTest"
:loading="isTesting"
......
---
title: Add confirmation modal on instance-level integration form
merge_request: 42840
author:
type: changed
......@@ -13773,6 +13773,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
msgstr ""
msgid "Integrations|Save settings?"
msgstr ""
msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
msgstr ""
msgid "Integrations|Standard"
msgstr ""
......
import { shallowMount } from '@vue/test-utils';
import { GlModal } from '@gitlab/ui';
import { createStore } from '~/integrations/edit/store';
import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
describe('ConfirmationModal', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(ConfirmationModal, {
store: createStore(),
});
};
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
});
const findGlModal = () => wrapper.find(GlModal);
describe('template', () => {
beforeEach(() => {
createComponent();
});
it('renders GlModal with correct copy', () => {
expect(findGlModal().exists()).toBe(true);
expect(findGlModal().attributes('title')).toBe('Save settings?');
expect(findGlModal().text()).toContain(
'Saving will update the default settings for all projects that are not using custom settings.',
);
expect(findGlModal().text()).toContain(
'Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults.',
);
});
it('emits `submit` event when `primary` event is emitted on GlModal', async () => {
expect(wrapper.emitted().submit).toBeUndefined();
findGlModal().vm.$emit('primary');
await wrapper.vm.$nextTick();
expect(wrapper.emitted().submit).toHaveLength(1);
});
});
});
......@@ -4,6 +4,7 @@ import { createStore } from '~/integrations/edit/store';
import IntegrationForm from '~/integrations/edit/components/integration_form.vue';
import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue';
import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue';
import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
......@@ -22,6 +23,7 @@ describe('IntegrationForm', () => {
stubs: {
OverrideDropdown,
ActiveCheckbox,
ConfirmationModal,
JiraTriggerFields,
TriggerFields,
},
......@@ -40,6 +42,7 @@ describe('IntegrationForm', () => {
const findOverrideDropdown = () => wrapper.find(OverrideDropdown);
const findActiveCheckbox = () => wrapper.find(ActiveCheckbox);
const findConfirmationModal = () => wrapper.find(ConfirmationModal);
const findJiraTriggerFields = () => wrapper.find(JiraTriggerFields);
const findJiraIssuesFields = () => wrapper.find(JiraIssuesFields);
const findTriggerFields = () => wrapper.find(TriggerFields);
......@@ -63,6 +66,26 @@ describe('IntegrationForm', () => {
});
});
describe('integrationLevel is instance', () => {
it('renders ConfirmationModal', () => {
createComponent({
integrationLevel: 'instance',
});
expect(findConfirmationModal().exists()).toBe(true);
});
});
describe('integrationLevel is not instance', () => {
it('does not render ConfirmationModal', () => {
createComponent({
integrationLevel: 'project',
});
expect(findConfirmationModal().exists()).toBe(false);
});
});
describe('type is "slack"', () => {
beforeEach(() => {
createComponent({ type: 'slack' });
......
......@@ -2,6 +2,7 @@ export const mockIntegrationProps = {
id: 25,
initialActivated: true,
showActive: true,
editable: true,
triggerFieldsProps: {
initialTriggerCommit: false,
initialTriggerMergeRequest: false,
......
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