2016-02-15 09:19:23 -05:00
|
|
|
module IssuablesHelper
|
2017-03-08 19:14:16 -05:00
|
|
|
include GitlabRoutingHelper
|
|
|
|
|
2016-02-15 09:19:23 -05:00
|
|
|
def sidebar_gutter_toggle_icon
|
2017-03-01 05:36:15 -05:00
|
|
|
sidebar_gutter_collapsed? ? icon('angle-double-left', { 'aria-hidden': 'true' }) : icon('angle-double-right', { 'aria-hidden': 'true' })
|
2016-02-15 09:19:23 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def sidebar_gutter_collapsed_class
|
|
|
|
"right-sidebar-#{sidebar_gutter_collapsed? ? 'collapsed' : 'expanded'}"
|
|
|
|
end
|
|
|
|
|
2016-07-19 05:26:49 -04:00
|
|
|
def multi_label_name(current_labels, default_label)
|
2016-07-20 04:45:53 -04:00
|
|
|
if current_labels && current_labels.any?
|
2016-07-19 05:05:38 -04:00
|
|
|
title = current_labels.first.try(:title)
|
2016-07-19 05:26:49 -04:00
|
|
|
if current_labels.size > 1
|
|
|
|
"#{title} +#{current_labels.size - 1} more"
|
2016-04-07 14:57:21 -04:00
|
|
|
else
|
2016-07-16 04:32:08 -04:00
|
|
|
title
|
2016-04-07 14:57:21 -04:00
|
|
|
end
|
2016-04-19 12:22:55 -04:00
|
|
|
else
|
2016-07-19 05:26:49 -04:00
|
|
|
default_label
|
2016-04-07 14:57:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-25 08:00:16 -04:00
|
|
|
def issuable_json_path(issuable)
|
|
|
|
project = issuable.project
|
|
|
|
|
2017-02-22 12:25:50 -05:00
|
|
|
if issuable.is_a?(MergeRequest)
|
2016-03-25 08:00:16 -04:00
|
|
|
namespace_project_merge_request_path(project.namespace, project, issuable.iid, :json)
|
|
|
|
else
|
|
|
|
namespace_project_issue_path(project.namespace, project, issuable.iid, :json)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-12-23 00:44:02 -05:00
|
|
|
def serialize_issuable(issuable)
|
|
|
|
case issuable
|
|
|
|
when Issue
|
|
|
|
IssueSerializer.new.represent(issuable).to_json
|
|
|
|
when MergeRequest
|
|
|
|
MergeRequestSerializer.new.represent(issuable).to_json
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-11-02 13:52:04 -04:00
|
|
|
def template_dropdown_tag(issuable, &block)
|
|
|
|
title = selected_template(issuable) || "Choose a template"
|
|
|
|
options = {
|
|
|
|
toggle_class: 'js-issuable-selector',
|
|
|
|
title: title,
|
|
|
|
filter: true,
|
|
|
|
placeholder: 'Filter',
|
|
|
|
footer_content: true,
|
|
|
|
data: {
|
|
|
|
data: issuable_templates(issuable),
|
|
|
|
field_name: 'issuable_template',
|
|
|
|
selected: selected_template(issuable),
|
|
|
|
project_path: ref_project.path,
|
2017-02-23 18:55:01 -05:00
|
|
|
namespace_path: ref_project.namespace.full_path
|
2016-11-02 13:52:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dropdown_tag(title, options: options) do
|
|
|
|
capture(&block)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-15 13:17:05 -04:00
|
|
|
def user_dropdown_label(user_id, default_label)
|
2016-04-19 10:58:20 -04:00
|
|
|
return default_label if user_id.nil?
|
2016-03-15 13:17:05 -04:00
|
|
|
return "Unassigned" if user_id == "0"
|
|
|
|
|
2016-04-19 10:58:20 -04:00
|
|
|
user = User.find_by(id: user_id)
|
2016-03-15 13:17:05 -04:00
|
|
|
|
|
|
|
if user
|
|
|
|
user.name
|
|
|
|
else
|
|
|
|
default_label
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-08-27 18:45:01 -04:00
|
|
|
def project_dropdown_label(project_id, default_label)
|
|
|
|
return default_label if project_id.nil?
|
|
|
|
return "Any project" if project_id == "0"
|
|
|
|
|
|
|
|
project = Project.find_by(id: project_id)
|
|
|
|
|
|
|
|
if project
|
2016-08-27 19:09:21 -04:00
|
|
|
project.name_with_namespace
|
2016-08-27 18:45:01 -04:00
|
|
|
else
|
|
|
|
default_label
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-29 10:26:12 -04:00
|
|
|
def milestone_dropdown_label(milestone_title, default_label = "Milestone")
|
2017-03-10 14:01:05 -05:00
|
|
|
title =
|
|
|
|
case milestone_title
|
|
|
|
when Milestone::Upcoming.name then Milestone::Upcoming.title
|
|
|
|
when Milestone::Started.name then Milestone::Started.title
|
|
|
|
else milestone_title.presence
|
|
|
|
end
|
2016-03-29 07:19:09 -04:00
|
|
|
|
2017-03-10 14:01:05 -05:00
|
|
|
h(title || default_label)
|
2016-03-24 11:20:35 -04:00
|
|
|
end
|
|
|
|
|
2017-03-08 19:14:16 -05:00
|
|
|
def to_url_reference(issuable)
|
|
|
|
case issuable
|
|
|
|
when Issue
|
|
|
|
link_to issuable.to_reference, issue_url(issuable)
|
|
|
|
when MergeRequest
|
|
|
|
link_to issuable.to_reference, merge_request_url(issuable)
|
|
|
|
else
|
|
|
|
issuable.to_reference
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-01 07:20:54 -04:00
|
|
|
def issuable_meta(issuable, project, text)
|
2017-03-08 19:14:16 -05:00
|
|
|
output = content_tag(:strong, class: "identifier") do
|
|
|
|
concat("#{text} ")
|
|
|
|
concat(to_url_reference(issuable))
|
|
|
|
end
|
|
|
|
|
2016-05-27 06:44:28 -04:00
|
|
|
output << " opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe
|
2016-04-01 07:20:54 -04:00
|
|
|
output << content_tag(:strong) do
|
2016-07-12 10:46:28 -04:00
|
|
|
author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs", tooltip: true)
|
2016-04-01 07:20:54 -04:00
|
|
|
author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg")
|
|
|
|
end
|
2016-09-26 17:36:11 -04:00
|
|
|
|
|
|
|
if issuable.tasks?
|
|
|
|
output << " ".html_safe
|
2016-12-22 14:54:54 -05:00
|
|
|
output << content_tag(:span, issuable.task_status, id: "task_status", class: "hidden-xs hidden-sm")
|
|
|
|
output << content_tag(:span, issuable.task_status_short, id: "task_status_short", class: "hidden-md hidden-lg")
|
2016-09-26 17:36:11 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
output
|
2016-04-01 07:20:54 -04:00
|
|
|
end
|
|
|
|
|
2016-06-17 04:01:03 -04:00
|
|
|
def issuable_todo(issuable)
|
2016-06-17 04:10:23 -04:00
|
|
|
if current_user
|
2016-06-17 04:01:03 -04:00
|
|
|
current_user.todos.find_by(target: issuable, state: :pending)
|
2016-06-07 05:54:02 -04:00
|
|
|
end
|
2016-06-07 04:44:01 -04:00
|
|
|
end
|
|
|
|
|
2016-08-18 06:38:12 -04:00
|
|
|
def issuable_labels_tooltip(labels, limit: 5)
|
2016-08-18 08:59:09 -04:00
|
|
|
first, last = labels.partition.with_index{ |_, i| i < limit }
|
2016-07-13 06:53:27 -04:00
|
|
|
|
2016-08-18 06:38:12 -04:00
|
|
|
label_names = first.collect(&:name)
|
|
|
|
label_names << "and #{last.size} more" unless last.empty?
|
2016-07-13 06:53:27 -04:00
|
|
|
|
2016-08-18 06:38:12 -04:00
|
|
|
label_names.join(', ')
|
2016-07-13 06:53:27 -04:00
|
|
|
end
|
|
|
|
|
2016-09-26 13:12:16 -04:00
|
|
|
def issuables_state_counter_text(issuable_type, state)
|
|
|
|
titles = {
|
|
|
|
opened: "Open"
|
|
|
|
}
|
|
|
|
|
|
|
|
state_title = titles[state] || state.to_s.humanize
|
|
|
|
|
|
|
|
count =
|
|
|
|
Rails.cache.fetch(issuables_state_counter_cache_key(issuable_type, state), expires_in: 2.minutes) do
|
|
|
|
issuables_count_for_state(issuable_type, state)
|
|
|
|
end
|
|
|
|
|
|
|
|
html = content_tag(:span, state_title)
|
|
|
|
html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge')
|
|
|
|
|
|
|
|
html.html_safe
|
|
|
|
end
|
|
|
|
|
2017-04-19 11:17:46 -04:00
|
|
|
def assigned_issuables_count(issuable_type)
|
|
|
|
current_user.public_send("assigned_open_#{issuable_type}_count")
|
2016-11-09 01:59:51 -05:00
|
|
|
end
|
|
|
|
|
2016-11-27 12:35:44 -05:00
|
|
|
def issuable_filter_params
|
|
|
|
[
|
|
|
|
:search,
|
|
|
|
:author_id,
|
|
|
|
:assignee_id,
|
|
|
|
:milestone_title,
|
|
|
|
:label_name
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
2017-01-12 07:28:37 -05:00
|
|
|
def issuable_reference(issuable)
|
|
|
|
@show_full_reference ? issuable.to_reference(full: true) : issuable.to_reference(@group || @project)
|
|
|
|
end
|
|
|
|
|
2016-11-27 12:35:44 -05:00
|
|
|
def issuable_filter_present?
|
|
|
|
issuable_filter_params.any? { |k| params.key?(k) }
|
|
|
|
end
|
|
|
|
|
2016-02-15 09:19:23 -05:00
|
|
|
private
|
|
|
|
|
|
|
|
def sidebar_gutter_collapsed?
|
|
|
|
cookies[:collapsed_gutter] == 'true'
|
|
|
|
end
|
|
|
|
|
|
|
|
def base_issuable_scope(issuable)
|
2016-02-16 06:58:12 -05:00
|
|
|
issuable.project.send(issuable.class.table_name).send(issuable_state_scope(issuable))
|
2016-02-15 09:19:23 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def issuable_state_scope(issuable)
|
2016-03-01 06:32:20 -05:00
|
|
|
if issuable.respond_to?(:merged?) && issuable.merged?
|
|
|
|
:merged
|
|
|
|
else
|
|
|
|
issuable.open? ? :opened : :closed
|
|
|
|
end
|
2016-02-15 09:19:23 -05:00
|
|
|
end
|
2016-09-26 13:12:16 -04:00
|
|
|
|
|
|
|
def issuables_count_for_state(issuable_type, state)
|
2016-11-25 08:57:56 -05:00
|
|
|
@counts ||= {}
|
|
|
|
@counts[issuable_type] ||= public_send("#{issuable_type}_finder").count_by_state
|
|
|
|
@counts[issuable_type][state]
|
2016-09-26 13:12:16 -04:00
|
|
|
end
|
|
|
|
|
2017-02-21 18:32:18 -05:00
|
|
|
IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page].freeze
|
2016-09-26 13:12:16 -04:00
|
|
|
private_constant :IRRELEVANT_PARAMS_FOR_CACHE_KEY
|
|
|
|
|
|
|
|
def issuables_state_counter_cache_key(issuable_type, state)
|
2016-09-29 10:55:55 -04:00
|
|
|
opts = params.with_indifferent_access
|
|
|
|
opts[:state] = state
|
|
|
|
opts.except!(*IRRELEVANT_PARAMS_FOR_CACHE_KEY)
|
2016-11-28 10:06:40 -05:00
|
|
|
opts.delete_if { |_, value| value.blank? }
|
2016-09-26 13:12:16 -04:00
|
|
|
|
|
|
|
hexdigest(['issuables_count', issuable_type, opts.sort].flatten.join('-'))
|
|
|
|
end
|
2016-11-02 13:52:04 -04:00
|
|
|
|
|
|
|
def issuable_templates(issuable)
|
|
|
|
@issuable_templates ||=
|
|
|
|
case issuable
|
|
|
|
when Issue
|
|
|
|
issue_template_names
|
|
|
|
when MergeRequest
|
|
|
|
merge_request_template_names
|
|
|
|
else
|
|
|
|
raise 'Unknown issuable type!'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def merge_request_template_names
|
|
|
|
@merge_request_templates ||= Gitlab::Template::MergeRequestTemplate.dropdown_names(ref_project)
|
|
|
|
end
|
|
|
|
|
|
|
|
def issue_template_names
|
|
|
|
@issue_templates ||= Gitlab::Template::IssueTemplate.dropdown_names(ref_project)
|
|
|
|
end
|
|
|
|
|
|
|
|
def selected_template(issuable)
|
2017-03-22 12:26:47 -04:00
|
|
|
params[:issuable_template] if issuable_templates(issuable).any?{ |template| template[:name] == params[:issuable_template] }
|
2016-11-02 13:52:04 -04:00
|
|
|
end
|
2017-03-24 12:17:38 -04:00
|
|
|
|
|
|
|
def issuable_todo_button_data(issuable, todo, is_collapsed)
|
|
|
|
{
|
|
|
|
todo_text: "Add todo",
|
|
|
|
mark_text: "Mark done",
|
|
|
|
todo_icon: (is_collapsed ? icon('plus-square') : nil),
|
|
|
|
mark_icon: (is_collapsed ? icon('check-square', class: 'todo-undone') : nil),
|
|
|
|
issuable_id: issuable.id,
|
|
|
|
issuable_type: issuable.class.name.underscore,
|
|
|
|
url: namespace_project_todos_path(@project.namespace, @project),
|
|
|
|
delete_path: (dashboard_todo_path(todo) if todo),
|
|
|
|
placement: (is_collapsed ? 'left' : nil),
|
|
|
|
container: (is_collapsed ? 'body' : nil)
|
|
|
|
}
|
|
|
|
end
|
2016-02-15 09:19:23 -05:00
|
|
|
end
|