Commit 55d57c62 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '268518-fix-generic-incoming-email-address-in-service-desk-form' into 'master'

Updated service desk incoming email to use custom email

See merge request gitlab-org/gitlab!46053
parents b957737f 9d3ff990
...@@ -20,7 +20,12 @@ export default { ...@@ -20,7 +20,12 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
initialIncomingEmail: { incomingEmail: {
type: String,
required: false,
default: '',
},
customEmail: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
...@@ -50,23 +55,18 @@ export default { ...@@ -50,23 +55,18 @@ export default {
data() { data() {
return { return {
isEnabled: this.initialIsEnabled, isEnabled: this.initialIsEnabled,
incomingEmail: this.initialIncomingEmail,
isTemplateSaving: false, isTemplateSaving: false,
isAlertShowing: false, isAlertShowing: false,
alertVariant: 'danger', alertVariant: 'danger',
alertMessage: '', alertMessage: '',
updatedCustomEmail: this.customEmail,
}; };
}, },
created() { created() {
eventHub.$on('serviceDeskEnabledCheckboxToggled', this.onEnableToggled); eventHub.$on('serviceDeskEnabledCheckboxToggled', this.onEnableToggled);
eventHub.$on('serviceDeskTemplateSave', this.onSaveTemplate); eventHub.$on('serviceDeskTemplateSave', this.onSaveTemplate);
this.service = new ServiceDeskService(this.endpoint); this.service = new ServiceDeskService(this.endpoint);
if (this.isEnabled && !this.incomingEmail) {
this.fetchIncomingEmail();
}
}, },
beforeDestroy() { beforeDestroy() {
...@@ -75,22 +75,6 @@ export default { ...@@ -75,22 +75,6 @@ export default {
}, },
methods: { methods: {
fetchIncomingEmail() {
this.service
.fetchIncomingEmail()
.then(({ data }) => {
const email = data.service_desk_address;
if (!email) {
throw new Error(__("Response didn't include `service_desk_address`"));
}
this.incomingEmail = email;
})
.catch(() =>
this.showAlert(__('An error occurred while fetching the Service Desk address.')),
);
},
onEnableToggled(isChecked) { onEnableToggled(isChecked) {
this.isEnabled = isChecked; this.isEnabled = isChecked;
this.incomingEmail = ''; this.incomingEmail = '';
...@@ -119,7 +103,7 @@ export default { ...@@ -119,7 +103,7 @@ export default {
this.service this.service
.updateTemplate({ selectedTemplate, outgoingName, projectKey }, this.isEnabled) .updateTemplate({ selectedTemplate, outgoingName, projectKey }, this.isEnabled)
.then(({ data }) => { .then(({ data }) => {
this.incomingEmail = data?.service_desk_address; this.updatedCustomEmail = data?.service_desk_address;
this.showAlert(__('Changes were successfully made.'), 'success'); this.showAlert(__('Changes were successfully made.'), 'success');
}) })
.catch(err => { .catch(err => {
...@@ -155,6 +139,7 @@ export default { ...@@ -155,6 +139,7 @@ export default {
<service-desk-setting <service-desk-setting
:is-enabled="isEnabled" :is-enabled="isEnabled"
:incoming-email="incomingEmail" :incoming-email="incomingEmail"
:custom-email="updatedCustomEmail"
:initial-selected-template="selectedTemplate" :initial-selected-template="selectedTemplate"
:initial-outgoing-name="outgoingName" :initial-outgoing-name="outgoingName"
:initial-project-key="projectKey" :initial-project-key="projectKey"
......
...@@ -26,6 +26,11 @@ export default { ...@@ -26,6 +26,11 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
customEmail: {
type: String,
required: false,
default: '',
},
initialSelectedTemplate: { initialSelectedTemplate: {
type: String, type: String,
required: false, required: false,
...@@ -57,7 +62,6 @@ export default { ...@@ -57,7 +62,6 @@ export default {
selectedTemplate: this.initialSelectedTemplate, selectedTemplate: this.initialSelectedTemplate,
outgoingName: this.initialOutgoingName || __('GitLab Support Bot'), outgoingName: this.initialOutgoingName || __('GitLab Support Bot'),
projectKey: this.initialProjectKey, projectKey: this.initialProjectKey,
baseEmail: this.incomingEmail.replace(this.initialProjectKey, ''),
}; };
}, },
computed: { computed: {
...@@ -67,6 +71,12 @@ export default { ...@@ -67,6 +71,12 @@ export default {
hasProjectKeySupport() { hasProjectKeySupport() {
return Boolean(this.glFeatures.serviceDeskCustomAddress); return Boolean(this.glFeatures.serviceDeskCustomAddress);
}, },
email() {
return this.customEmail || this.incomingEmail;
},
hasCustomEmail() {
return this.customEmail && this.customEmail !== this.incomingEmail;
},
}, },
methods: { methods: {
onCheckboxToggle(isChecked) { onCheckboxToggle(isChecked) {
...@@ -101,30 +111,31 @@ export default { ...@@ -101,30 +111,31 @@ export default {
<strong id="incoming-email-describer" class="d-block mb-1"> <strong id="incoming-email-describer" class="d-block mb-1">
{{ __('Forward external support email address to') }} {{ __('Forward external support email address to') }}
</strong> </strong>
<template v-if="incomingEmail"> <template v-if="email">
<div class="input-group"> <div class="input-group">
<input <input
ref="service-desk-incoming-email" ref="service-desk-incoming-email"
type="text" type="text"
class="form-control incoming-email" class="form-control"
data-testid="incoming-email"
:placeholder="__('Incoming email')" :placeholder="__('Incoming email')"
:aria-label="__('Incoming email')" :aria-label="__('Incoming email')"
aria-describedby="incoming-email-describer" aria-describedby="incoming-email-describer"
:value="incomingEmail" :value="email"
disabled="true" disabled="true"
/> />
<div class="input-group-append"> <div class="input-group-append">
<clipboard-button <clipboard-button
:title="__('Copy')" :title="__('Copy')"
:text="incomingEmail" :text="email"
css-class="input-group-text qa-clipboard-button" css-class="input-group-text qa-clipboard-button"
/> />
</div> </div>
</div> </div>
<span v-if="projectKey" class="form-text text-muted"> <span v-if="hasCustomEmail" class="form-text text-muted">
<gl-sprintf :message="__('Emails sent to %{email} will still be supported')"> <gl-sprintf :message="__('Emails sent to %{email} will still be supported')">
<template #email> <template #email>
<code>{{ baseEmail }}</code> <code>{{ incomingEmail }}</code>
</template> </template>
</gl-sprintf> </gl-sprintf>
</span> </span>
......
...@@ -17,6 +17,7 @@ export default () => { ...@@ -17,6 +17,7 @@ export default () => {
initialIsEnabled: parseBoolean(dataset.enabled), initialIsEnabled: parseBoolean(dataset.enabled),
endpoint: dataset.endpoint, endpoint: dataset.endpoint,
incomingEmail: dataset.incomingEmail, incomingEmail: dataset.incomingEmail,
customEmail: dataset.customEmail,
selectedTemplate: dataset.selectedTemplate, selectedTemplate: dataset.selectedTemplate,
outgoingName: dataset.outgoingName, outgoingName: dataset.outgoingName,
projectKey: dataset.projectKey, projectKey: dataset.projectKey,
...@@ -28,7 +29,8 @@ export default () => { ...@@ -28,7 +29,8 @@ export default () => {
props: { props: {
initialIsEnabled: this.initialIsEnabled, initialIsEnabled: this.initialIsEnabled,
endpoint: this.endpoint, endpoint: this.endpoint,
initialIncomingEmail: this.incomingEmail, incomingEmail: this.incomingEmail,
customEmail: this.customEmail,
selectedTemplate: this.selectedTemplate, selectedTemplate: this.selectedTemplate,
outgoingName: this.outgoingName, outgoingName: this.outgoingName,
projectKey: this.projectKey, projectKey: this.projectKey,
......
...@@ -5,10 +5,6 @@ class ServiceDeskService { ...@@ -5,10 +5,6 @@ class ServiceDeskService {
this.endpoint = endpoint; this.endpoint = endpoint;
} }
fetchIncomingEmail() {
return axios.get(this.endpoint);
}
toggleServiceDesk(enable) { toggleServiceDesk(enable) {
return axios.put(this.endpoint, { service_desk_enabled: enable }); return axios.put(this.endpoint, { service_desk_enabled: enable });
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
- if ::Gitlab::ServiceDesk.supported? - if ::Gitlab::ServiceDesk.supported?
.js-service-desk-setting-root{ data: { endpoint: project_service_desk_path(@project), .js-service-desk-setting-root{ data: { endpoint: project_service_desk_path(@project),
enabled: "#{@project.service_desk_enabled}", enabled: "#{@project.service_desk_enabled}",
incoming_email: (@project.service_desk_address if @project.service_desk_enabled), incoming_email: (@project.service_desk_incoming_address if @project.service_desk_enabled),
custom_email: (@project.service_desk_custom_address if @project.service_desk_enabled), custom_email: (@project.service_desk_custom_address if @project.service_desk_enabled),
selected_template: "#{@project.service_desk_setting&.issue_template_key}", selected_template: "#{@project.service_desk_setting&.issue_template_key}",
outgoing_name: "#{@project.service_desk_setting&.outgoing_name}", outgoing_name: "#{@project.service_desk_setting&.outgoing_name}",
......
...@@ -3027,9 +3027,6 @@ msgstr "" ...@@ -3027,9 +3027,6 @@ msgstr ""
msgid "An error occurred while fetching terraform reports." msgid "An error occurred while fetching terraform reports."
msgstr "" msgstr ""
msgid "An error occurred while fetching the Service Desk address."
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 ""
......
...@@ -28,6 +28,6 @@ RSpec.describe 'Service Desk Setting', :js do ...@@ -28,6 +28,6 @@ RSpec.describe 'Service Desk Setting', :js do
project.reload project.reload
expect(project.service_desk_enabled).to be_truthy expect(project.service_desk_enabled).to be_truthy
expect(project.service_desk_address).to be_present expect(project.service_desk_address).to be_present
expect(find('.incoming-email').value).to eq(project.service_desk_address) expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_address)
end end
end end
import { shallowMount, mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter'; import AxiosMockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import ServiceDeskRoot from '~/projects/settings_service_desk/components/service_desk_root.vue'; import ServiceDeskRoot from '~/projects/settings_service_desk/components/service_desk_root.vue';
import ServiceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
...@@ -24,65 +25,6 @@ describe('ServiceDeskRoot', () => { ...@@ -24,65 +25,6 @@ describe('ServiceDeskRoot', () => {
} }
}); });
it('fetches incoming email when there is no incoming email provided', () => {
axiosMock.onGet(endpoint).replyOnce(httpStatusCodes.OK);
wrapper = shallowMount(ServiceDeskRoot, {
propsData: {
initialIsEnabled: true,
initialIncomingEmail: '',
endpoint,
},
});
return wrapper.vm
.$nextTick()
.then(waitForPromises)
.then(() => {
expect(axiosMock.history.get).toHaveLength(1);
});
});
it('does not fetch incoming email when there is an incoming email provided', () => {
axiosMock.onGet(endpoint).replyOnce(httpStatusCodes.OK);
wrapper = shallowMount(ServiceDeskRoot, {
propsData: {
initialIsEnabled: true,
initialIncomingEmail,
endpoint,
},
});
return wrapper.vm
.$nextTick()
.then(waitForPromises)
.then(() => {
expect(axiosMock.history.get).toHaveLength(0);
});
});
it('shows an error message when incoming email is not fetched correctly', () => {
axiosMock.onGet(endpoint).networkError();
wrapper = shallowMount(ServiceDeskRoot, {
propsData: {
initialIsEnabled: true,
initialIncomingEmail: '',
endpoint,
},
});
return wrapper.vm
.$nextTick()
.then(waitForPromises)
.then(() => {
expect(wrapper.html()).toContain(
'An error occurred while fetching the Service Desk address.',
);
});
});
it('sends a request to toggle service desk off when the toggle is clicked from the on state', () => { it('sends a request to toggle service desk off when the toggle is clicked from the on state', () => {
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK); axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK);
...@@ -221,4 +163,18 @@ describe('ServiceDeskRoot', () => { ...@@ -221,4 +163,18 @@ describe('ServiceDeskRoot', () => {
expect(wrapper.html()).toContain('An error occured while making the changes:'); expect(wrapper.html()).toContain('An error occured while making the changes:');
}); });
}); });
it('passes customEmail through updatedCustomEmail correctly', () => {
const customEmail = 'foo';
wrapper = mount(ServiceDeskRoot, {
propsData: {
initialIsEnabled: true,
endpoint,
customEmail,
},
});
expect(wrapper.find(ServiceDeskSetting).props('customEmail')).toEqual(customEmail);
});
}); });
...@@ -13,6 +13,7 @@ describe('ServiceDeskSetting', () => { ...@@ -13,6 +13,7 @@ describe('ServiceDeskSetting', () => {
}); });
const findTemplateDropdown = () => wrapper.find('#service-desk-template-select'); const findTemplateDropdown = () => wrapper.find('#service-desk-template-select');
const findIncomingEmail = () => wrapper.find('[data-testid="incoming-email"]');
describe('when isEnabled=true', () => { describe('when isEnabled=true', () => {
describe('only isEnabled', () => { describe('only isEnabled', () => {
...@@ -35,7 +36,7 @@ describe('ServiceDeskSetting', () => { ...@@ -35,7 +36,7 @@ describe('ServiceDeskSetting', () => {
it('should see loading spinner and not the incoming email', () => { it('should see loading spinner and not the incoming email', () => {
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
expect(wrapper.find('.incoming-email').exists()).toBe(false); expect(findIncomingEmail().exists()).toBe(false);
}); });
}); });
}); });
...@@ -73,7 +74,7 @@ describe('ServiceDeskSetting', () => { ...@@ -73,7 +74,7 @@ describe('ServiceDeskSetting', () => {
}); });
it('should see email and not the loading spinner', () => { it('should see email and not the loading spinner', () => {
expect(wrapper.find('.incoming-email').element.value).toEqual(incomingEmail); expect(findIncomingEmail().element.value).toEqual(incomingEmail);
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
}); });
...@@ -85,6 +86,45 @@ describe('ServiceDeskSetting', () => { ...@@ -85,6 +86,45 @@ describe('ServiceDeskSetting', () => {
}); });
}); });
describe('with customEmail', () => {
describe('customEmail is different than incomingEmail', () => {
const incomingEmail = 'foo@bar.com';
const customEmail = 'custom@bar.com';
beforeEach(() => {
wrapper = mount(ServiceDeskSetting, {
propsData: {
isEnabled: true,
incomingEmail,
customEmail,
},
});
});
it('should see custom email', () => {
expect(findIncomingEmail().element.value).toEqual(customEmail);
});
});
describe('customEmail is the same as incomingEmail', () => {
const email = 'foo@bar.com';
beforeEach(() => {
wrapper = mount(ServiceDeskSetting, {
propsData: {
isEnabled: true,
incomingEmail: email,
customEmail: email,
},
});
});
it('should see custom email', () => {
expect(findIncomingEmail().element.value).toEqual(email);
});
});
});
describe('templates dropdown', () => { describe('templates dropdown', () => {
it('renders a dropdown to choose a template', () => { it('renders a dropdown to choose a template', () => {
wrapper = shallowMount(ServiceDeskSetting, { wrapper = shallowMount(ServiceDeskSetting, {
......
...@@ -19,24 +19,6 @@ describe('ServiceDeskService', () => { ...@@ -19,24 +19,6 @@ describe('ServiceDeskService', () => {
axiosMock.restore(); axiosMock.restore();
}); });
describe('fetchIncomingEmail', () => {
it('makes a request to fetch incoming email', () => {
axiosMock.onGet(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse);
return service.fetchIncomingEmail().then(response => {
expect(response.data).toEqual(dummyResponse);
});
});
it('fails on error response', () => {
axiosMock.onGet(endpoint).networkError();
return service.fetchIncomingEmail().catch(error => {
expect(error.message).toBe(errorMessage);
});
});
});
describe('toggleServiceDesk', () => { describe('toggleServiceDesk', () => {
it('makes a request to set service desk', () => { it('makes a request to set service desk', () => {
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse); axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse);
......
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