issuables_helper.rb 10.3 KB
Newer Older
1
module IssuablesHelper
2 3
  include GitlabRoutingHelper

4
  def sidebar_gutter_toggle_icon
F
Filipa Lacerda 已提交
5
    sidebar_gutter_collapsed? ? icon('angle-double-left', { 'aria-hidden': 'true' }) : icon('angle-double-right', { 'aria-hidden': 'true' })
6 7 8 9 10 11
  end

  def sidebar_gutter_collapsed_class
    "right-sidebar-#{sidebar_gutter_collapsed? ? 'collapsed' : 'expanded'}"
  end

12
  def multi_label_name(current_labels, default_label)
13
    if current_labels && current_labels.any?
14
      title = current_labels.first.try(:title)
15 16
      if current_labels.size > 1
        "#{title} +#{current_labels.size - 1} more"
J
Jacob Schatz 已提交
17
      else
18
        title
J
Jacob Schatz 已提交
19
      end
A
Arinde Eniola 已提交
20
    else
21
      default_label
J
Jacob Schatz 已提交
22 23 24
    end
  end

J
Jacob Schatz 已提交
25 26 27
  def issuable_json_path(issuable)
    project = issuable.project

D
Douwe Maan 已提交
28
    if issuable.is_a?(MergeRequest)
29
      project_merge_request_path(project, issuable.iid, :json)
J
Jacob Schatz 已提交
30
    else
31
      project_issue_path(project, issuable.iid, :json)
J
Jacob Schatz 已提交
32 33 34
    end
  end

35 36 37
  def serialize_issuable(issuable)
    case issuable
    when Issue
D
Douwe Maan 已提交
38
      IssueSerializer.new(current_user: current_user, project: issuable.project).represent(issuable).to_json
39
    when MergeRequest
F
Fatih Acet 已提交
40 41 42 43
      MergeRequestSerializer
        .new(current_user: current_user, project: issuable.project)
        .represent(issuable)
        .to_json
44 45 46
    end
  end

47 48 49 50 51 52 53 54 55 56 57 58 59
  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,
60
        namespace_path: ref_project.namespace.full_path
61 62 63 64 65 66 67 68
      }
    }

    dropdown_tag(title, options: options) do
      capture(&block)
    end
  end

69
  def users_dropdown_label(selected_users)
70 71
    case selected_users.length
    when 0
72
      "Unassigned"
73
    when 1
74 75 76 77 78 79
      selected_users[0].name
    else
      "#{selected_users[0].name} + #{selected_users.length - 1} more"
    end
  end

80
  def user_dropdown_label(user_id, default_label)
P
Phil Hughes 已提交
81
    return default_label if user_id.nil?
82 83
    return "Unassigned" if user_id == "0"

P
Phil Hughes 已提交
84
    user = User.find_by(id: user_id)
85 86 87 88 89 90 91 92

    if user
      user.name
    else
      default_label
    end
  end

93 94 95 96 97 98 99
  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
100
      project.name_with_namespace
101 102 103 104 105
    else
      default_label
    end
  end

P
Phil Hughes 已提交
106
  def milestone_dropdown_label(milestone_title, default_label = "Milestone")
107 108 109 110 111 112
    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
P
Phil Hughes 已提交
113

114
    h(title || default_label)
115 116
  end

117 118 119 120 121 122 123 124 125 126 127
  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

128
  def issuable_meta(issuable, project, text)
129
    output = ""
P
Phil Hughes 已提交
130
    output << "Opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe
131
    output << content_tag(:strong) do
132
      author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs", tooltip: true)
133 134
      author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg")
    end
135

136
    output << "&ensp;".html_safe
M
micael.bergeron 已提交
137
    output << content_tag(:span, (issuable_first_contribution_icon if issuable.first_contribution?), class: 'has-tooltip', title: _('1st contribution!'))
138

139 140
    output << content_tag(:span, (issuable.task_status if issuable.tasks?), id: "task_status", class: "hidden-xs hidden-sm")
    output << content_tag(:span, (issuable.task_status_short if issuable.tasks?), id: "task_status_short", class: "hidden-md hidden-lg")
141

142
    output.html_safe
143 144
  end

P
Phil Hughes 已提交
145
  def issuable_todo(issuable)
146
    if current_user
P
Phil Hughes 已提交
147
      current_user.todos.find_by(target: issuable, state: :pending)
148
    end
P
Phil Hughes 已提交
149 150
  end

P
Phil Hughes 已提交
151
  def issuable_labels_tooltip(labels, limit: 5)
152
    first, last = labels.partition.with_index { |_, i| i < limit  }
153

P
Phil Hughes 已提交
154 155
    label_names = first.collect(&:name)
    label_names << "and #{last.size} more" unless last.empty?
156

P
Phil Hughes 已提交
157
    label_names.join(', ')
158 159
  end

160 161 162 163 164 165
  def issuables_state_counter_text(issuable_type, state)
    titles = {
      opened: "Open"
    }

    state_title = titles[state] || state.to_s.humanize
166
    count = issuables_count_for_state(issuable_type, state)
167 168 169 170 171 172 173

    html = content_tag(:span, state_title)
    html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge')

    html.html_safe
  end

174
  def issuable_first_contribution_icon
M
micael.bergeron 已提交
175
    content_tag(:span, class: 'fa-stack') do
176 177
      concat(icon('certificate', class: "fa-stack-2x"))
      concat(content_tag(:strong, '1', class: 'fa-inverse fa-stack-1x'))
M
micael.bergeron 已提交
178
    end
179 180
  end

181
  def assigned_issuables_count(issuable_type)
182 183 184 185 186 187 188 189
    case issuable_type
    when :issues
      current_user.assigned_open_issues_count
    when :merge_requests
      current_user.assigned_open_merge_requests_count
    else
      raise ArgumentError, "invalid issuable `#{issuable_type}`"
    end
190 191
  end

192 193 194 195 196 197 198 199 200 201
  def issuable_filter_params
    [
      :search,
      :author_id,
      :assignee_id,
      :milestone_title,
      :label_name
    ]
  end

202 203 204 205
  def issuable_reference(issuable)
    @show_full_reference ? issuable.to_reference(full: true) : issuable.to_reference(@group || @project)
  end

206 207 208 209
  def issuable_filter_present?
    issuable_filter_params.any? { |k| params.key?(k) }
  end

210
  def issuable_initial_data(issuable)
211
    data = {
212
      endpoint: project_issue_path(@project, issuable),
213 214 215
      canUpdate: can?(current_user, :update_issue, issuable),
      canDestroy: can?(current_user, :destroy_issue, issuable),
      issuableRef: issuable.to_reference,
216 217
      markdownPreviewPath: preview_markdown_path(@project),
      markdownDocsPath: help_page_path('user/markdown'),
218
      issuableTemplates: issuable_templates(issuable),
219 220 221 222 223
      projectPath: ref_project.path,
      projectNamespace: ref_project.namespace.full_path,
      initialTitleHtml: markdown_field(issuable, :title),
      initialTitleText: issuable.title,
      initialDescriptionHtml: markdown_field(issuable, :description),
224 225
      initialDescriptionText: issuable.description,
      initialTaskStatus: issuable.task_status
226 227
    }

L
Luke "Jared" Bennett 已提交
228 229 230
    data.merge!(updated_at_by(issuable))

    data.to_json
231 232 233
  end

  def updated_at_by(issuable)
234
    return {} unless issuable.edited?
235 236

    {
237 238
      updatedAt: issuable.updated_at.to_time.iso8601,
      updatedBy: {
239 240 241 242 243 244
        name: issuable.last_edited_by.name,
        path: user_path(issuable.last_edited_by)
      }
    }
  end

245 246
  def issuables_count_for_state(issuable_type, state)
    finder = public_send("#{issuable_type}_finder") # rubocop:disable GitlabSecurity/PublicSend
247 248

    Gitlab::IssuablesCountForState.new(finder)[state]
249 250
  end

251
  def close_issuable_url(issuable)
252
    issuable_url(issuable, close_reopen_params(issuable, :close))
253 254
  end

255
  def reopen_issuable_url(issuable)
256
    issuable_url(issuable, close_reopen_params(issuable, :reopen))
257 258
  end

259
  def close_reopen_issuable_url(issuable, should_inverse = false)
260
    issuable.closed? ^ should_inverse ? reopen_issuable_url(issuable) : close_issuable_url(issuable)
261 262
  end

263
  def issuable_url(issuable, *options)
264
    case issuable
265 266 267 268
    when Issue
      issue_url(issuable, *options)
    when MergeRequest
      merge_request_url(issuable, *options)
269 270 271
    end
  end

272 273
  def issuable_button_visibility(issuable, closed)
    case issuable
274 275 276 277
    when Issue
      issue_button_visibility(issuable, closed)
    when MergeRequest
      merge_request_button_visibility(issuable, closed)
278 279 280 281 282
    end
  end

  def issuable_close_reopen_button_method(issuable)
    case issuable
283 284 285 286
    when Issue
      ''
    when MergeRequest
      'put'
287 288 289
    end
  end

290 291 292 293 294 295 296 297
  def issuable_author_is_current_user(issuable)
    issuable.author == current_user
  end

  def issuable_display_type(issuable)
    issuable.model_name.human.downcase
  end

298 299 300 301 302 303
  private

  def sidebar_gutter_collapsed?
    cookies[:collapsed_gutter] == 'true'
  end

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
  def issuable_templates(issuable)
    @issuable_templates ||=
      case issuable
      when Issue
        issue_template_names
      when MergeRequest
        merge_request_template_names
      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)
323
    params[:issuable_template] if issuable_templates(issuable).any? { |template| template[:name] == params[:issuable_template] }
324
  end
P
Phil Hughes 已提交
325 326 327 328 329 330 331 332 333

  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,
334
      url: project_todos_path(@project),
P
Phil Hughes 已提交
335 336 337 338 339
      delete_path: (dashboard_todo_path(todo) if todo),
      placement: (is_collapsed ? 'left' : nil),
      container: (is_collapsed ? 'body' : nil)
    }
  end
340 341

  def close_reopen_params(issuable, action)
342 343 344 345 346
    {
      issuable.model_name.to_s.underscore => { state_event: action }
    }.tap do |params|
      params[:format] = :json if issuable.is_a?(Issue)
    end
347
  end
P
Phil Hughes 已提交
348

F
Felipe Artur 已提交
349 350 351 352 353 354 355 356
  def labels_path
    if @project
      project_labels_path(@project)
    elsif @group
      group_labels_path(@group)
    end
  end

P
Phil Hughes 已提交
357 358 359
  def issuable_sidebar_options(issuable, can_edit_issuable)
    {
      endpoint: "#{issuable_json_path(issuable)}?basic=true",
360 361
      moveIssueEndpoint: move_namespace_project_issue_path(namespace_id: issuable.project.namespace.to_param, project_id: issuable.project, id: issuable),
      projectsAutocompleteEndpoint: autocomplete_projects_path(project_id: @project.id),
P
Phil Hughes 已提交
362 363 364 365 366 367
      editable: can_edit_issuable,
      currentUser: current_user.as_json(only: [:username, :id, :name], methods: :avatar_url),
      rootPath: root_path,
      fullPath: @project.full_path
    }
  end
368
end