Skip to content
Snippets Groups Projects
Commit f39f0af7 authored by Jacob Schatz's avatar Jacob Schatz
Browse files

Merge branch '3049-service-desk-should-be-given-more-prominence-in-the-ui' into 'master'

Give Service Desk more prominence in the UI

Closes #3049

See merge request !2733
parents 0e0dcf00 a8e858bb
No related branches found
No related tags found
1 merge request!2733Give Service Desk more prominence in the UI
Pipeline #
Showing
with 228 additions and 39 deletions
Loading
Loading
@@ -345,7 +345,14 @@ class FilteredSearchManager {
const removeElements = [];
 
[].forEach.call(this.tokensContainer.children, (t) => {
if (t.classList.contains('js-visual-token')) {
let canClearToken = t.classList.contains('js-visual-token');
if (canClearToken) {
const tokenKey = t.querySelector('.name').textContent.trim();
canClearToken = this.canEdit && this.canEdit(tokenKey);
}
if (canClearToken) {
removeElements.push(t);
}
});
Loading
Loading
@@ -424,8 +431,14 @@ class FilteredSearchManager {
});
}
 
// allows for modifying params array when a param can't be included in the URL (e.g. Service Desk)
getAllParams(urlParams) {
return this.modifyUrlParams ? this.modifyUrlParams(urlParams) : urlParams;
}
loadSearchParamsFromURL() {
const params = gl.utils.getUrlParamsArray();
const urlParams = gl.utils.getUrlParamsArray();
const params = this.getAllParams(urlParams);
const usernameParams = this.getUsernameParams();
let hasFilteredSearch = false;
 
Loading
Loading
/* eslint-disable class-methods-use-this */
const AUTHOR_PARAM_KEY = 'author_username';
export default class FilteredSearchServiceDesk extends gl.FilteredSearchManager {
constructor(supportBotData) {
super('service_desk');
this.supportBotData = supportBotData;
}
canEdit(tokenName) {
return tokenName !== 'author';
}
modifyUrlParams(paramsArray) {
const supportBotParamPair = `${AUTHOR_PARAM_KEY}=${this.supportBotData.username}`;
const onlyValidParams = paramsArray.filter(param => param.indexOf(AUTHOR_PARAM_KEY) === -1);
// unshift ensures author param is always first token element
onlyValidParams.unshift(supportBotParamPair);
return onlyValidParams;
}
}
import FilteredSearchServiceDesk from './filtered_search';
document.addEventListener('DOMContentLoaded', () => {
const supportBotData = JSON.parse(
document.querySelector('.js-service-desk-issues').dataset.supportBot,
);
this.filteredSearchManager = new FilteredSearchServiceDesk(supportBotData);
this.filteredSearchManager.setup();
});
Loading
Loading
@@ -43,3 +43,9 @@
* Styles for JS behaviors.
*/
@import "behaviors";
/*
* EE-only stylesheets
*/
@import "../../../ee/app/assets/stylesheets/**/*";
Loading
Loading
@@ -10,6 +10,23 @@ module IssuableCollections
 
private
 
def set_issues_index
@collection_type = "Issue"
@issues = issues_collection
@issues = @issues.page(params[:page])
@issuable_meta_data = issuable_meta_data(@issues, @collection_type)
if @issues.out_of_range? && @issues.total_pages != 0
return redirect_to url_for(params.merge(page: @issues.total_pages, only_path: true))
end
if params[:label_name].present?
@labels = LabelsFinder.new(current_user, project_id: @project.id, title: params[:label_name]).execute
end
@users = []
end
def issues_collection
issues_finder.execute.preload(:project, :author, :assignees, :labels, :milestone, project: :namespace)
end
Loading
Loading
Loading
Loading
@@ -6,12 +6,11 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableCollections
include SpammableActions
 
prepend ::EE::Projects::IssuesController
prepend_before_action :authenticate_user!, only: [:new, :export_csv]
 
before_action :check_issues_available!
before_action :issue, except: [:index, :new, :create, :bulk_update, :export_csv]
before_action :set_issues_index, only: [:index]
 
# Allow write(create) issue
before_action :authorize_create_issue!, only: [:new, :create]
Loading
Loading
@@ -22,25 +21,11 @@ class Projects::IssuesController < Projects::ApplicationController
# Allow create a new branch and empty WIP merge request from current issue
before_action :authorize_create_merge_request!, only: [:create_merge_request]
 
prepend ::EE::Projects::IssuesController
respond_to :html
 
def index
@collection_type = "Issue"
@issues = issues_collection
@issues = @issues.page(params[:page])
@issuable_meta_data = issuable_meta_data(@issues, @collection_type)
if @issues.out_of_range? && @issues.total_pages != 0
return redirect_to url_for(params.merge(page: @issues.total_pages, only_path: true))
end
if params[:label_name].present?
@labels = LabelsFinder.new(current_user, project_id: @project.id, title: params[:label_name]).execute
end
@users = []
if params[:assignee_id].present?
assignee = User.find_by_id(params[:assignee_id])
@users.push(assignee) if assignee
Loading
Loading
Loading
Loading
@@ -110,7 +110,7 @@
= number_with_delimiter(@project.open_issues_count)
 
%ul.sidebar-sub-level-items
= nav_link(controller: :issues, html_options: { class: "fly-out-top-item" } ) do
= nav_link(controller: :issues, action: :index, html_options: { class: "fly-out-top-item" } ) do
= link_to project_issues_path(@project) do
%strong.fly-out-top-item-name
#{ _('Issues') }
Loading
Loading
@@ -147,6 +147,11 @@
%span
Labels
 
- if EE::Gitlab::ServiceDesk.enabled?(project: @project)
= nav_link(controller: :issues, action: :service_desk ) do
= link_to service_desk_project_issues_path(@project), title: 'Service Desk' do
%span Service Desk
= nav_link(controller: :milestones) do
= link_to project_milestones_path(@project), title: 'Milestones' do
%span
Loading
Loading
- empty_state_path = local_assigns.fetch(:empty_state_path, 'shared/empty_states/issues')
%ul.content-list.issues-list.issuable-list
= render partial: "projects/issues/issue", collection: @issues
- if @issues.blank?
= render 'shared/empty_states/issues'
= render empty_state_path
 
- if @issues.present?
= paginate @issues, theme: "gitlab"
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10 has-tooltip', title: 'Subscribe' do
= icon('rss')
= render 'projects/issues/export_issues/button'
- show_rss_button = local_assigns.fetch(:show_rss_button, true)
- show_export_button = local_assigns.fetch(:show_export_button, true)
- if show_rss_button
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10 has-tooltip', title: 'Subscribe' do
= icon('rss')
- if show_export_button
= render 'projects/issues/export_issues/button'
- if @can_bulk_update
= button_tag "Edit issues", class: "btn btn-default append-right-10 js-bulk-update-toggle"
= link_to "New issue", new_project_issue_path(@project,
issue: { assignee_id: issues_finder.assignee.try(:id),
milestone_id: issues_finder.milestones.first.try(:id) }),
Loading
Loading
<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76 19.575 76 3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><rect width="7" height="1" x="59" y="38" fill="#E1DBF2" rx=".5"/><path fill="#6B4FBB" d="M60.5 42a3.5 3.5 0 0 0 0-7v7z"/><rect width="7" height="1" x="12" y="38" fill="#E1DBF2" transform="matrix(-1 0 0 1 31 0)" rx=".5"/><path fill="#6B4FBB" d="M17.5 42a3.5 3.5 0 0 1 0-7v7z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M39 58c10.493 0 19-8.507 19-19s-8.507-19-19-19-19 8.507-19 19 8.507 19 19 19zm0 4c-12.703 0-23-10.297-23-23s10.297-23 23-23 23 10.297 23 23-10.297 23-23 23z"/><path fill="#6B4FBB" d="M35 56a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M26.5 40c0 4.143 3.355 7.5 7.494 7.5h10.012A7.497 7.497 0 0 0 51.5 40c0-4.143-3.355-7.5-7.494-7.5H33.994A7.497 7.497 0 0 0 26.5 40zm-3 0c0-5.799 4.698-10.5 10.494-10.5h10.012C49.802 29.5 54.5 34.2 54.5 40c0 5.799-4.698 10.5-10.494 10.5H33.994C28.198 50.5 23.5 45.8 23.5 40z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M35.255 42.406a1 1 0 1 1 1.872-.703 2.001 2.001 0 0 0 3.76-.038 1 1 0 1 1 1.886.665 4 4 0 0 1-7.518.076zM31.5 40a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm15 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/><path fill="#6B4FBB" d="M38 22h2a1 1 0 0 1 0 2h-2a1 1 0 0 1 0-2zm0 3h2a1 1 0 0 1 0 2h-2a1 1 0 0 1 0-2z" style="mix-blend-mode:multiply"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="226" height="178" viewBox="0 0 226 178"><g fill="none" fill-rule="evenodd"><path fill="#EEE" fill-rule="nonzero" d="M109.496 165.895c2.06.108 4.113.134 6.158.08 1.104-.03 1.975-.95 1.945-2.055-.03-1.104-.95-1.975-2.055-1.945-1.94.053-3.886.028-5.84-.074-1.102-.057-2.043.79-2.1 1.893-.06 1.104.788 2.045 1.89 2.102zm18.408-1.245c2.02-.386 4.023-.853 6-1.4 1.066-.295 1.69-1.396 1.396-2.46-.295-1.066-1.397-1.69-2.46-1.396-1.875.52-3.772.96-5.686 1.327-1.085.208-1.797 1.255-1.59 2.34.207 1.085 1.255 1.797 2.34 1.59zm17.572-5.636c1.865-.86 3.696-1.795 5.486-2.803.962-.54 1.303-1.76.762-2.723-.542-.962-1.762-1.303-2.724-.762-1.697.955-3.43 1.84-5.2 2.656-1.002.464-1.44 1.652-.978 2.655.462 1.003 1.65 1.44 2.654.98zm44.342-74.897c-.142-2.056-.367-4.1-.674-6.127-.165-1.092-1.184-1.844-2.276-1.678-1.092.165-1.844 1.184-1.68 2.276.29 1.92.505 3.857.64 5.805.076 1.102 1.03 1.934 2.133 1.857 1.103-.076 1.934-1.03 1.858-2.133zm-3.505-18.144c-.632-1.956-1.343-3.884-2.13-5.78-.425-1.02-1.595-1.504-2.615-1.08-1.02.424-1.503 1.594-1.08 2.614.747 1.797 1.42 3.624 2.02 5.476.34 1.05 1.467 1.628 2.518 1.288 1.05-.34 1.627-1.466 1.287-2.517zm-7.754-16.73c-1.083-1.745-2.235-3.447-3.454-5.1-.655-.89-1.907-1.08-2.797-.423-.89.655-1.08 1.907-.424 2.796 1.155 1.568 2.247 3.18 3.273 4.835.58.94 1.814 1.23 2.753.647.938-.582 1.228-1.815.646-2.754zm-11.582-14.446c-1.468-1.437-2.993-2.814-4.572-4.128-.85-.708-2.11-.592-2.816.256-.707.85-.592 2.11.257 2.817 1.496 1.246 2.942 2.55 4.334 3.913.79.773 2.057.76 2.83-.03.772-.79.758-2.057-.032-2.83zm-101.422-4.91c-1.6 1.288-3.148 2.64-4.64 4.05-.802.76-.837 2.026-.078 2.828.76.802 2.025.837 2.827.078 1.415-1.338 2.882-2.62 4.4-3.84.86-.692.996-1.95.303-2.812-.692-.86-1.95-.996-2.812-.303zM52.7 43.062c-1.25 1.632-2.433 3.313-3.546 5.04-.6.93-.33 2.167.597 2.765.93.6 2.167.33 2.766-.597 1.055-1.637 2.176-3.23 3.36-4.777.67-.878.504-2.133-.374-2.804-.877-.672-2.132-.505-2.803.372zm-9.373 15.924c-.82 1.882-1.56 3.8-2.226 5.745-.356 1.047.2 2.183 1.247 2.54 1.045.358 2.182-.2 2.54-1.246.63-1.844 1.333-3.66 2.108-5.443.44-1.012-.023-2.19-1.036-2.63-1.014-.44-2.192.023-2.633 1.036zm-5.26 17.74c-.34 2.02-.6 4.058-.777 6.11-.096 1.102.72 2.07 1.82 2.167 1.1.095 2.07-.72 2.165-1.82.17-1.947.415-3.88.737-5.793.183-1.09-.552-2.12-1.64-2.304-1.09-.183-2.122.552-2.305 1.64zM74.87 155.55c1.772 1.038 3.585 2.005 5.437 2.897.995.48 2.19.062 2.67-.933.48-.995.062-2.19-.933-2.67-1.755-.845-3.473-1.76-5.152-2.745-.953-.56-2.178-.24-2.737.714-.558.954-.238 2.18.715 2.738zm16.97 7.34c1.966.578 3.96 1.078 5.975 1.498 1.082.225 2.14-.47 2.366-1.55.226-1.082-.468-2.14-1.55-2.366-1.91-.398-3.798-.872-5.662-1.42-1.06-.312-2.172.294-2.483 1.354-.312 1.06.294 2.17 1.354 2.483z"/><path fill="#F9F9F9" d="M2.12 130c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3-1.527 19.032-17.455 34-36.88 34-19.425 0-35.353-14.968-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M39 166c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 92 39 92 4 107.67 4 127s15.67 35 35 35z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M53.925 116.226c-.277-.144-.59-.226-.925-.226H25c-.323 0-.628.076-.898.212l14.663 13.406c.39.357.99.348 1.37-.02l13.79-13.372zm1.075 4.53L42.92 132.47c-1.898 1.84-4.902 1.885-6.854.1L23 120.624V138c0 1.105.895 2 2 2h28c1.105 0 2-.895 2-2v-17.244zM25 112h28c3.314 0 6 2.686 6 6v20c0 3.314-2.686 6-6 6H25c-3.314 0-6-2.686-6-6v-20c0-3.314 2.686-6 6-6z"/><g><path fill="#F9F9F9" d="M150.12 131c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3-1.527 19.032-17.455 34-36.88 34-19.425 0-35.353-14.968-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M187 167c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35s-15.67-35-35-35-35 15.67-35 35 15.67 35 35 35z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M180.51 137H199c1.105 0 2-.895 2-2v-16c0-1.105-.895-2-2-2h-24c-1.105 0-2 .895-2 2v22.743l7.51-4.743zm1.157 4l-9.6 6.062c-.32.202-.69.31-1.067.31-1.105 0-2-.896-2-2V119c0-3.314 2.686-6 6-6h24c3.314 0 6 2.686 6 6v16c0 3.314-2.686 6-6 6h-17.333z"/><path fill="#6B4FBB" d="M180 129c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2zm7 0c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2zm7 0c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2z"/></g><g><path fill="#F9F9F9" d="M76.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3-1.527 19.032-17.455 34-36.88 34-19.425 0-35.353-14.968-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M113 78c-21.54 0-39-17.46-39-39S91.46 0 113 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S132.33 4 113 4 78 19.67 78 39s15.67 35 35 35z"/><g transform="translate(133 35)"><rect width="7" height="1" y="3" fill="#E1DBF2" rx=".5"/><path fill="#6B4FBB" d="M1.5 7C3.433 7 5 5.433 5 3.5S3.433 0 1.5 0v7z"/></g><g transform="matrix(-1 0 0 1 93 35)"><rect width="7" height="1" y="3" fill="#E1DBF2" rx=".5"/><path fill="#6B4FBB" d="M1.5 7C3.433 7 5 5.433 5 3.5S3.433 0 1.5 0v7z"/></g><path fill="#E1DBF1" fill-rule="nonzero" d="M113 58c10.493 0 19-8.507 19-19s-8.507-19-19-19-19 8.507-19 19 8.507 19 19 19zm0 4c-12.703 0-23-10.297-23-23s10.297-23 23-23 23 10.297 23 23-10.297 23-23 23z"/><path fill="#6B4FBB" d="M109 56c-.552 0-1-.448-1-1s.448-1 1-1 1 .448 1 1-.448 1-1 1zm4 0c-.552 0-1-.448-1-1s.448-1 1-1 1 .448 1 1-.448 1-1 1zm4 0c-.552 0-1-.448-1-1s.448-1 1-1 1 .448 1 1-.448 1-1 1z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M97.5 40c0-5.8 4.698-10.5 10.494-10.5h10.012c5.796 0 10.494 4.7 10.494 10.5s-4.698 10.5-10.494 10.5h-10.012C102.198 50.5 97.5 45.8 97.5 40zm3 0c0 4.143 3.355 7.5 7.494 7.5h10.012c4.14 0 7.494-3.358 7.494-7.5 0-4.143-3.355-7.5-7.494-7.5h-10.012c-4.14 0-7.494 3.358-7.494 7.5z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M109.255 42.406c-.195-.517.067-1.093.584-1.287.516-.196 1.093.066 1.287.583.29.774 1.033 1.297 1.873 1.297.855 0 1.608-.542 1.887-1.335.184-.52.755-.794 1.276-.61.52.183.794.754.61 1.275-.56 1.587-2.063 2.67-3.773 2.67-1.68 0-3.164-1.046-3.745-2.594zM105.5 40c-.828 0-1.5-.672-1.5-1.5s.672-1.5 1.5-1.5 1.5.672 1.5 1.5-.672 1.5-1.5 1.5zm15 0c-.828 0-1.5-.672-1.5-1.5s.672-1.5 1.5-1.5 1.5.672 1.5 1.5-.672 1.5-1.5 1.5z"/><path fill="#6B4FBB" d="M112 22h2c.552 0 1 .448 1 1s-.448 1-1 1h-2c-.552 0-1-.448-1-1s.448-1 1-1zm0 3h2c.552 0 1 .448 1 1s-.448 1-1 1h-2c-.552 0-1-.448-1-1s.448-1 1-1z" style="mix-blend-mode:multiply"/></g></g></svg>
Loading
Loading
@@ -350,6 +350,8 @@
collection do
post :bulk_update
post :export_csv
get :service_desk ## EE-specific
end
 
resources :issue_links, only: [:index, :create, :destroy], as: 'links', path: 'links'
Loading
Loading
Loading
Loading
@@ -74,6 +74,7 @@ var config = {
protected_tags: './protected_tags',
ee_protected_tags: 'ee/protected_tags',
service_desk: './projects/settings_service_desk/service_desk_bundle.js',
service_desk_issues: './service_desk_issues/index.js',
repo: './repo/index.js',
sidebar: './sidebar/sidebar_bundle.js',
schedule_form: './pipeline_schedules/pipeline_schedule_form_bundle.js',
Loading
Loading
doc/user/project/img/service_desk_issue_tracker.png

129 KiB

doc/user/project/img/service_desk_nav_item.png

99.2 KiB

Loading
Loading
@@ -6,12 +6,13 @@
 
Service Desk is a module that allows your team to connect directly
with any external party through email right inside of GitLab; no external tools required.
An ongoing conversation right where your software is built ensures that user feedback ends up directly where needed,
helping you build the right features to solve your user's real problems.
An ongoing conversation right where your software is built ensures that user feedback ends
up directly where it's needed, helping you build the right features to solve your users'
real problems.
 
Provide efficient email support to your customers, who can email bug reports,
feature requests, or any other general feedback directly into your GitLab project as a new issue.
In turn, your team can respond straight from the project.
With Service Desk, you can provide efficient email support to your customers, who can now
email you bug reports, feature requests, or general feedback that will all end up in your
GitLab project as new issues. In turn, your team can respond straight from the project.
 
As Service Desk is built right into GitLab itself, the complexity and inefficiencies
of multiple tools and external integrations are eliminated, significantly shortening
Loading
Loading
@@ -23,12 +24,15 @@ For instance, let's assume you develop a game for iOS or Android.
The codebase is hosted in your GitLab instance, built and deployed
with GitLab CI.
 
1. Offer email support to your paying customers, who can email you directly from their app
1. The email they send creates an issue in the appropriate project
1. Your team members reply to that issue thread to follow up with your customer
Here's how Service Desk will work for you:
1. You'll provide a project-specific email address to your paying customers, who can email you directly from within the app
1. Each email they send creates an issue in the appropriate project
1. Your team members navigate to the Service Desk issue tracker, where they can see new support requests and respond inside associated issues
1. Your team communicates back and forth with the customer to understand the request
1. Your team starts working on implementing code to solve your customer's problem
1. When your team finishes the implementation, their merged merge request will close the issue
1. The customer will have been attended successfully through GitLab, without having real access to your GitLab instance
1. When your team finishes the implementation, whereupon the merge request is merged and the issue is closed automatically
1. The customer will have been attended successfully via email, without having real access to your GitLab instance
1. Your team saved time by not having to leave GitLab (or setup any integrations) to follow up with your customer
 
## How it works
Loading
Loading
@@ -67,7 +71,9 @@ you can skip the step 1 below; you only need to enable it per project.
checking to this service.
 
![Service Desk enabled](img/service_desk_enabled.png)
5. Service Desk is now enabled for this project!
5. Service Desk is now enabled for this project! You should be able to access it from your project's navigation **Issue submenu**:
![Service Desk Navigation Item](img/service_desk_nav_item.png)
 
## Using Service Desk
 
Loading
Loading
@@ -90,13 +96,18 @@ And any responses they send will be displayed in the issue itself.
 
### As a responder to the issue
 
For responders to the issue, everything works as usual. Messages from the end
user will show as coming from the special Support Bot user, but apart from that,
For responders to the issue, everything works as usual. They'll see a familiar looking
issue tracker, where they can see issues created via customer support requests and
filter and interact with them just like other GitLab issues.
![Service Desk Issue tracker](img/service_desk_issue_tracker.png)
Messages from the end user will show as coming from the special Support Bot user, but apart from that,
you can read and write comments as you normally do:
 
![Service Desk issue thread](img/service_desk_thread.png)
 
> Note that the project's visibility (private, internal, public) does not affect Service Desk.
> Note that the project's visibility (private, internal, public) does not affect Service Desk.
 
[ee-149]: https://gitlab.com/gitlab-org/gitlab-ee/issues/149 "Service Desk with email"
[ee]: https://about.gitlab.com/gitlab-ee/ "GitLab Enterprise Edition landing page"
Loading
Loading
.service-desk-issues {
.empty-state {
max-width: 450px;
text-align: center;
}
.non-empty-state {
text-align: left;
padding-bottom: $gl-padding-top;
border-bottom: 1px solid $border-color;
.service-desk-graphic {
margin-top: $gl-padding;
}
.media-body {
margin-top: $gl-padding-top;
margin-left: $gl-padding;
}
}
.turn-on-btn-container {
margin-top: $gl-padding-top;
}
}
Loading
Loading
@@ -5,6 +5,18 @@ module IssuesController
 
prepended do
before_action :check_export_issues_available!, only: [:export_csv]
before_action :check_service_desk_available!, only: [:service_desk]
before_action :set_issues_index, only: [:index, :service_desk]
skip_before_action :issue, only: [:service_desk]
end
def service_desk
if params[:assignee_id].present?
assignee = User.find_by_id(params[:assignee_id])
@users.push(assignee) if assignee
end
@users.push(::User.support_bot)
end
 
def export_csv
Loading
Loading
@@ -14,6 +26,8 @@ def export_csv
redirect_to(index_path, notice: "Your CSV export has started. It will be emailed to #{current_user.notification_email} when complete.")
end
 
private
def issue_params_attributes
attrs = super
attrs.unshift(:weight) if project.feature_available?(:issue_weights)
Loading
Loading
@@ -25,8 +39,17 @@ def filter_params
params = super
params.reject! { |key| key == 'weight' } unless project.feature_available?(:issue_weights)
 
if service_desk?
params.reject! { |key| key == 'author_username' || key == 'author_id' }
params[:author_id] = ::User.support_bot
end
params
end
def service_desk?
action_name == 'service_desk'
end
end
end
end
- is_empty_state = @issues.blank?
- service_desk_enabled = @project.service_desk_enabled?
- callout_selector = is_empty_state ? 'empty-state' : 'non-empty-state media'
- svg_path = !is_empty_state ? 'shared/empty_states/icons/service_desk_callout.svg' : 'shared/empty_states/icons/service_desk_empty_state.svg'
%div{ class: "#{callout_selector}" }
.service-desk-graphic
= render svg_path
.media-body
%h5 Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab.
- if service_desk_enabled
%p
Have your users email
%code= @project.service_desk_address
%span Those emails automatically become issues (with the comments becoming the email conversation) listed here.
= link_to 'Read more', help_page_path('user/project/service_desk')
- if !service_desk_enabled
.turn-on-btn-container
= link_to "Turn on Service Desk", edit_project_path(@project), class: 'btn btn-new btn-inverted'
- @no_container = true
- @can_bulk_update = false
- page_title "Service Desk"
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
= webpack_bundle_tag 'service_desk_issues'
= webpack_bundle_tag 'issues'
- content_for :breadcrumbs_extra do
= render "projects/issues/nav_btns", show_export_button: false, show_rss_button: false
- support_bot_attrs = User.support_bot.to_json(only: [:id, :name, :username, :avatar_url])
%div{ class: "#{container_class} js-service-desk-issues service-desk-issues", data: { support_bot: support_bot_attrs } }
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls.visible-xs
= render "projects/issues/nav_btns", show_export_button: false, show_rss_button: false
= render 'shared/issuable/search_bar', type: :issues
- if @issues.present?
= render 'service_desk_info_content'
.issues-holder
= render 'projects/issues/issues', empty_state_path: 'service_desk_info_content'
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment