Commit 000037cb authored by Sean McGivern's avatar Sean McGivern

Merge branch 'service-desk-fe-updates-v1' into 'master'

Service Desk FE updates v1

See merge request !1604
parents e4cb7156 07a7d88e
...@@ -18,6 +18,11 @@ export default { ...@@ -18,6 +18,11 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
isInstanceAdmin: {
type: Boolean,
required: false,
default: false,
},
}, },
methods: { methods: {
...@@ -32,15 +37,23 @@ export default { ...@@ -32,15 +37,23 @@ export default {
<div class="checkbox"> <div class="checkbox">
<label for="service-desk-enabled-checkbox"> <label for="service-desk-enabled-checkbox">
<input <input
ref="enabled-checkbox"
type="checkbox" type="checkbox"
id="service-desk-enabled-checkbox" id="service-desk-enabled-checkbox"
:disabled="!isInstanceAdmin"
:checked="isEnabled" :checked="isEnabled"
@change="onCheckboxToggle($event)"> @change="onCheckboxToggle($event)">
<span class="descr"> <span class="descr">
Activate service desk Activate Service Desk
</span> </span>
</label> </label>
</div> </div>
<p
ref="only-instance-admin-activate-message"
v-if="!isInstanceAdmin"
class="settings-message">
Only instance admins can activate/deactivate Service Desk
</p>
<template v-if="isEnabled"> <template v-if="isEnabled">
<div <div
class="panel-slim panel-default"> class="panel-slim panel-default">
...@@ -55,7 +68,8 @@ export default { ...@@ -55,7 +68,8 @@ export default {
An error occurred while fetching the incoming email An error occurred while fetching the incoming email
</template> </template>
<template v-else-if="incomingEmail"> <template v-else-if="incomingEmail">
<span ref="service-desk-incoming-email"> <span
ref="service-desk-incoming-email">
{{ incomingEmail }} {{ incomingEmail }}
</span> </span>
<button <button
...@@ -74,7 +88,9 @@ export default { ...@@ -74,7 +88,9 @@ export default {
</template> </template>
</div> </div>
</div> </div>
<p class="settings-message"> <p
ref="recommend-protect-email-from-spam-message"
class="settings-message">
We recommend you protect the external support email address. We recommend you protect the external support email address.
Unblocked email spam would result in many spam issues being created, Unblocked email spam would result in many spam issues being created,
and may disrupt your GitLab service. and may disrupt your GitLab service.
......
...@@ -8,14 +8,17 @@ import eventHub from './event_hub'; ...@@ -8,14 +8,17 @@ import eventHub from './event_hub';
class ServiceDeskRoot { class ServiceDeskRoot {
constructor(wrapperElement) { constructor(wrapperElement) {
this.wrapperElement = wrapperElement; this.wrapperElement = wrapperElement;
const isEnabled = this.wrapperElement.dataset.enabled !== undefined && const isEnabled = typeof this.wrapperElement.dataset.enabled !== 'undefined' &&
this.wrapperElement.dataset.enabled !== 'false'; this.wrapperElement.dataset.enabled !== 'false';
const incomingEmail = this.wrapperElement.dataset.incomingEmail; const incomingEmail = this.wrapperElement.dataset.incomingEmail;
const endpoint = this.wrapperElement.dataset.endpoint; const endpoint = this.wrapperElement.dataset.endpoint;
const isInstanceAdmin = typeof this.wrapperElement.dataset.isInstanceAdmin !== 'undefined' &&
this.wrapperElement.dataset.isInstanceAdmin !== 'false';
this.store = new ServiceDeskStore({ this.store = new ServiceDeskStore({
isEnabled, isEnabled,
incomingEmail, incomingEmail,
isInstanceAdmin,
}); });
this.service = new ServiceDeskService(endpoint); this.service = new ServiceDeskService(endpoint);
} }
...@@ -37,7 +40,7 @@ class ServiceDeskRoot { ...@@ -37,7 +40,7 @@ class ServiceDeskRoot {
} }
unbindEvents() { unbindEvents() {
eventHub.$on('serviceDeskEnabledCheckboxToggled', this.onEnableToggledWrapper); eventHub.$off('serviceDeskEnabledCheckboxToggled', this.onEnableToggledWrapper);
} }
render() { render() {
...@@ -48,7 +51,8 @@ class ServiceDeskRoot { ...@@ -48,7 +51,8 @@ class ServiceDeskRoot {
<service-desk-setting <service-desk-setting
:isEnabled="isEnabled" :isEnabled="isEnabled"
:incomingEmail="incomingEmail" :incomingEmail="incomingEmail"
:fetchError="fetchError" /> :fetchError="fetchError"
:isInstanceAdmin="isInstanceAdmin" />
`, `,
components: { components: {
'service-desk-setting': ServiceDeskSetting, 'service-desk-setting': ServiceDeskSetting,
......
...@@ -4,6 +4,7 @@ class ServiceDeskStore { ...@@ -4,6 +4,7 @@ class ServiceDeskStore {
isEnabled: false, isEnabled: false,
incomingEmail: '', incomingEmail: '',
fetchError: null, fetchError: null,
isInstanceAdmin: false,
}, initialState); }, initialState);
} }
...@@ -18,6 +19,10 @@ class ServiceDeskStore { ...@@ -18,6 +19,10 @@ class ServiceDeskStore {
setFetchError(value) { setFetchError(value) {
this.state.fetchError = value; this.state.fetchError = value;
} }
setIsInstanceAdmin(value) {
this.state.isInstanceAdmin = value;
}
} }
export default ServiceDeskStore; export default ServiceDeskStore;
module Emails module Emails
module EE module EE
module ServiceDesk module ServiceDesk
extend ActiveSupport::Concern
included do
layout 'service_desk', only: [:service_desk_thank_you_email, :service_desk_new_note_email]
end
def service_desk_thank_you_email(issue_id) def service_desk_thank_you_email(issue_id)
setup_service_desk_mail(issue_id) setup_service_desk_mail(issue_id)
......
%html{ lang: "en" }
%head
%meta{ content: "text/html; charset=utf-8", "http-equiv" => "Content-Type" }
%title
GitLab
= stylesheet_link_tag 'notify'
= yield :head
%body
.content
= yield
.footer{ style: "margin-top: 10px;" }
%p
&mdash;
%br
= link_to "Unsubscribe", @sent_notification_url
- if current_application_settings.email_author_in_body
%div
#{link_to @note.author_name, user_url(@note.author)} wrote:
%div
= markdown(@note.note, pipeline: :email, author: @note.author)
%p
Thank you for your support request! We are tracking your request as ticket ##{@issue.iid}, and will respond as soon as we can.
...@@ -131,10 +131,11 @@ ...@@ -131,10 +131,11 @@
%fieldset.js-service-desk-setting-wrapper.features.append-bottom-default %fieldset.js-service-desk-setting-wrapper.features.append-bottom-default
%h5.prepend-top-0 %h5.prepend-top-0
Service Desk Service Desk
= link_to icon('question-circle'), help_page_path("TODO") = link_to icon('question-circle'), help_page_path('user/project/service_desk')
.js-service-desk-setting-root{ data: { endpoint: namespace_project_service_desk_path(@project.namespace, @project), .js-service-desk-setting-root{ data: { endpoint: namespace_project_service_desk_path(@project.namespace, @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_address if @project.service_desk_enabled),
is_instance_admin: current_user.is_admin? } }
%hr %hr
%fieldset.features.append-bottom-default %fieldset.features.append-bottom-default
......
...@@ -3,25 +3,63 @@ require 'spec_helper' ...@@ -3,25 +3,63 @@ require 'spec_helper'
describe 'Service Desk Setting', js: true, feature: true do describe 'Service Desk Setting', js: true, feature: true do
include WaitForAjax include WaitForAjax
let(:project) { create(:project_empty_repo, :private) } describe 'as project master/admin' do
let(:user) { create(:user) } let(:project) { create(:project_empty_repo, :private) }
let(:user) { create(:user) }
before do before do
project.add_master(user) project.add_master(user)
login_as(user) login_as(user)
allow_any_instance_of(License).to receive(:add_on?).and_call_original allow_any_instance_of(License).to receive(:add_on?).and_call_original
allow_any_instance_of(License).to receive(:add_on?).with('GitLab_ServiceDesk') { true } allow_any_instance_of(License).to receive(:add_on?).with('GitLab_ServiceDesk') { true }
end
visit edit_namespace_project_path(project.namespace, project) describe 'when disabled' do
end before do
visit edit_namespace_project_path(project.namespace, project)
end
it 'shows disabled activation checkbox' do
expect(page).to have_selector("#service-desk-enabled-checkbox[disabled]")
end
end
describe 'when enabled' do
before do
project.update(service_desk_enabled: true)
visit edit_namespace_project_path(project.namespace, project)
end
it 'shows disabled activation checkbox' do
expect(page).to have_selector("#service-desk-enabled-checkbox[disabled]")
end
it 'shows service desk activation checkbox' do it 'shows service_desk_address when enabled' do
expect(page).to have_selector("#service-desk-enabled-checkbox") expect(find('.js-service-desk-setting-wrapper .panel-body')).to have_content(project.service_desk_address)
end
end
end end
it 'shows incoming email after activating' do describe 'as instance admin' do
find("#service-desk-enabled-checkbox").click let(:project) { create(:project_empty_repo, :private) }
wait_for_ajax let(:user) { create(:user, :admin) }
expect(find('.js-service-desk-setting-wrapper .panel-body')).to have_content(project.service_desk_address)
before do
login_as(user)
allow_any_instance_of(License).to receive(:add_on?).and_call_original
allow_any_instance_of(License).to receive(:add_on?).with('GitLab_ServiceDesk') { true }
visit edit_namespace_project_path(project.namespace, project)
end
it 'shows activation checkbox' do
expect(page).to have_selector("#service-desk-enabled-checkbox")
end
it 'shows incoming email after activating' do
find("#service-desk-enabled-checkbox").click
wait_for_ajax
expect(find('.js-service-desk-setting-wrapper .panel-body')).to have_content(project.service_desk_address)
end
end end
end end
...@@ -23,25 +23,49 @@ describe('ServiceDeskSetting', () => { ...@@ -23,25 +23,49 @@ describe('ServiceDeskSetting', () => {
let el; let el;
describe('only isEnabled', () => { describe('only isEnabled', () => {
beforeEach(() => { describe('as project admin', () => {
vm = createComponent({ beforeEach(() => {
isEnabled: true, vm = createComponent({
isEnabled: true,
});
el = vm.$el;
}); });
el = vm.$el;
});
it('see main panel with the email info', () => { it('should see disabled activation checkbox', () => {
expect(el.querySelector('.panel')).toBeDefined(); expect(vm.$refs['enabled-checkbox'].getAttribute('disabled')).toEqual('disabled');
}); });
it('see loading spinner', () => { it('should see only instance admin can activate/deactivate message', () => {
expect(el.querySelector('.fa-spinner')).toBeDefined(); expect(vm.$refs['only-instance-admin-activate-message']).toBeDefined();
expect(el.querySelector('.fa-exclamation-circle')).toBeNull(); });
expect(vm.$refs['service-desk-incoming-email']).toBeUndefined();
it('should see main panel with the email info', () => {
expect(el.querySelector('.panel')).toBeDefined();
});
it('should see loading spinner', () => {
expect(el.querySelector('.fa-spinner')).toBeDefined();
expect(el.querySelector('.fa-exclamation-circle')).toBeNull();
expect(vm.$refs['service-desk-incoming-email']).toBeUndefined();
});
it('should see warning message', () => {
expect(vm.$refs['recommend-protect-email-from-spam-message']).toBeDefined();
});
}); });
it('see warning message', () => { describe('as instance admin', () => {
expect(el.querySelector('.settings-message')).toBeDefined(); beforeEach(() => {
vm = createComponent({
isEnabled: true,
isInstanceAdmin: true,
});
el = vm.$el;
});
it('should see activation checkbox (not disabled)', () => {
expect(vm.$refs['enabled-checkbox'].getAttribute('disabled')).toEqual(null);
});
}); });
}); });
...@@ -54,7 +78,7 @@ describe('ServiceDeskSetting', () => { ...@@ -54,7 +78,7 @@ describe('ServiceDeskSetting', () => {
el = vm.$el; el = vm.$el;
}); });
it('see email', () => { it('should see email', () => {
expect(vm.$refs['service-desk-incoming-email'].textContent.trim()).toEqual('foo@bar.com'); expect(vm.$refs['service-desk-incoming-email'].textContent.trim()).toEqual('foo@bar.com');
expect(el.querySelector('.fa-spinner')).toBeNull(); expect(el.querySelector('.fa-spinner')).toBeNull();
expect(el.querySelector('.fa-exclamation-circle')).toBeNull(); expect(el.querySelector('.fa-exclamation-circle')).toBeNull();
...@@ -70,7 +94,7 @@ describe('ServiceDeskSetting', () => { ...@@ -70,7 +94,7 @@ describe('ServiceDeskSetting', () => {
el = vm.$el; el = vm.$el;
}); });
it('see error message', () => { it('should see error message', () => {
expect(el.querySelector('.fa-exclamation-circle')).toBeDefined(); expect(el.querySelector('.fa-exclamation-circle')).toBeDefined();
expect(el.querySelector('.panel-body').textContent.trim()).toEqual('An error occurred while fetching the incoming email'); expect(el.querySelector('.panel-body').textContent.trim()).toEqual('An error occurred while fetching the incoming email');
expect(el.querySelector('.fa-spinner')).toBeNull(); expect(el.querySelector('.fa-spinner')).toBeNull();
...@@ -94,7 +118,7 @@ describe('ServiceDeskSetting', () => { ...@@ -94,7 +118,7 @@ describe('ServiceDeskSetting', () => {
}); });
it('should not see warning message', () => { it('should not see warning message', () => {
expect(el.querySelector('.settings-message')).toBeNull(); expect(vm.$refs['recommend-protect-email-from-spam-message']).toBeUndefined();
}); });
}); });
......
...@@ -26,7 +26,7 @@ describe('ServiceDeskService', () => { ...@@ -26,7 +26,7 @@ describe('ServiceDeskService', () => {
}); });
describe('toggleServiceDesk', () => { describe('toggleServiceDesk', () => {
it('enable service desk', (done) => { it('enable Service Desk', (done) => {
spyOn(service.serviceDeskResource, 'update').and.returnValue(Promise.resolve({ spyOn(service.serviceDeskResource, 'update').and.returnValue(Promise.resolve({
data: { data: {
service_desk_enabled: true, service_desk_enabled: true,
...@@ -40,11 +40,11 @@ describe('ServiceDeskService', () => { ...@@ -40,11 +40,11 @@ describe('ServiceDeskService', () => {
done(); done();
}) })
.catch((err) => { .catch((err) => {
done.fail(`Failed to enable service desk and fetch incoming email:\n${err}`); done.fail(`Failed to enable Service Desk and fetch incoming email:\n${err}`);
}); });
}); });
it('disable service desk', (done) => { it('disable Service Desk', (done) => {
spyOn(service.serviceDeskResource, 'update').and.returnValue(Promise.resolve({ spyOn(service.serviceDeskResource, 'update').and.returnValue(Promise.resolve({
data: { data: {
service_desk_enabled: false, service_desk_enabled: false,
...@@ -58,7 +58,7 @@ describe('ServiceDeskService', () => { ...@@ -58,7 +58,7 @@ describe('ServiceDeskService', () => {
done(); done();
}) })
.catch((err) => { .catch((err) => {
done.fail(`Failed to disable service desk and reset incoming email:\n${err}`); done.fail(`Failed to disable Service Desk and reset incoming email:\n${err}`);
}); });
}); });
}); });
......
...@@ -50,4 +50,22 @@ describe('ServiceDeskStore', () => { ...@@ -50,4 +50,22 @@ describe('ServiceDeskStore', () => {
expect(store.state.fetchError).toEqual(err); expect(store.state.fetchError).toEqual(err);
}); });
}); });
describe('setIsInstanceAdmin', () => {
it('defaults to false', () => {
expect(store.state.isInstanceAdmin).toEqual(false);
});
it('set true', () => {
store.setIsInstanceAdmin(true);
expect(store.state.isInstanceAdmin).toEqual(true);
});
it('set false', () => {
store.setIsInstanceAdmin(false);
expect(store.state.isInstanceAdmin).toEqual(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