Module: IssuablesHelper

Instance Method Summary collapse

Methods included from Sidebars::Concerns::HasPill

#format_cached_count, #has_pill?, #pill_count, #pill_html_options

Methods included from IssuablesDescriptionTemplatesHelper

#available_service_desk_templates_for, #default_template_name, #issuable_templates, #selected_template_name, #template_dropdown_tag, #template_names, #template_names_path

Methods included from Routing::PackagesHelper

#package_path

Methods included from Routing::PseudonymizationHelper

#masked_page_url

Methods included from Routing::GraphqlHelper

#graphql_etag_pipeline_path, #graphql_etag_pipeline_sha_path, #graphql_etag_project_on_demand_scan_counts_path

Methods included from Routing::WikiHelper

#wiki_page_path, #wiki_path

Methods included from Routing::SnippetsHelper

#gitlab_dashboard_snippets_path, #gitlab_raw_snippet_blob_path, #gitlab_raw_snippet_blob_url, #gitlab_raw_snippet_path, #gitlab_raw_snippet_url, #gitlab_snippet_note_path, #gitlab_snippet_note_url, #gitlab_snippet_notes_path, #gitlab_snippet_notes_url, #gitlab_snippet_path, #gitlab_snippet_url, #gitlab_toggle_award_emoji_snippet_note_path, #gitlab_toggle_award_emoji_snippet_note_url, #gitlab_toggle_award_emoji_snippet_path, #gitlab_toggle_award_emoji_snippet_url, #preview_markdown_path, #toggle_award_emoji_personal_snippet_path, #toggle_award_emoji_project_project_snippet_path, #toggle_award_emoji_project_project_snippet_url

Methods included from Routing::PipelineSchedulesHelper

#edit_pipeline_schedule_path, #pipeline_schedule_path, #pipeline_schedules_path, #play_pipeline_schedule_path, #take_ownership_pipeline_schedule_path

Methods included from Routing::ArtifactsHelper

#artifacts_action_path, #expose_fast_artifacts_path, #fast_browse_project_job_artifacts_path, #fast_download_project_job_artifacts_path, #fast_keep_project_job_artifacts_path

Methods included from Routing::MembersHelper

#source_members_url

Methods included from Routing::Groups::MembersHelper

#approve_access_request_group_member_path, #group_member_path, #group_members_url, #leave_group_members_path, #request_access_group_members_path, #resend_invite_group_member_path

Methods included from Routing::Projects::MembersHelper

#approve_access_request_project_member_path, #leave_project_members_path, #project_member_path, #project_members_url, #request_access_project_members_path, #resend_invite_project_member_path

Methods included from Routing::ProjectsHelper

#commit_url, #commits_url, #edit_milestone_path, #environment_delete_path, #environment_path, #issue_path, #issue_url, #merge_request_path, #merge_request_url, #pipeline_job_url, #pipeline_path, #pipeline_url, #project_commits_path, #project_ref_path, #project_tree_path, #release_url, #toggle_subscription_path, #work_item_url

Methods included from API::Helpers::RelatedResourcesHelpers

#expose_path, #expose_url, #issues_available?, #mrs_available?, #project_feature_string_access_level

Methods included from ApplicationSettingsHelper

#all_protocols_enabled?, #allowed_protocols_present?, #anti_spam_service_enabled?, #deprecated_attributes, #enabled_protocol, #enabled_protocol_button, #expanded_by_default?, #external_authorization_allow_token_help_text, #external_authorization_client_certificate_help_text, #external_authorization_client_key_help_text, #external_authorization_client_pass_help_text, #external_authorization_client_url_help_text, #external_authorization_description, #external_authorization_service_attributes, #external_authorization_timeout_help_text, #external_authorization_url_help_text, #http_enabled?, #import_sources_checkboxes, #instance_clusters_enabled?, #integration_expanded?, #key_restriction_options_for_select, #kroki_available_formats, #oauth_providers_checkboxes, #omnibus_protected_paths_throttle?, #pending_user_count, #registration_features_can_be_prompted?, #repository_storages_options_json, #restricted_level_checkboxes, #runner_token_expiration_interval_attributes, #sidekiq_job_limiter_mode_help_text, #sidekiq_job_limiter_modes_for_select, #signup_enabled?, #signup_form_data, #ssh_enabled?, #storage_weights, #user_oauth_applications?, #valid_runner_registrars, #visible_attributes

Methods included from ProjectsHelper

#able_to_see_forks_count?, #able_to_see_issues?, #able_to_see_merge_requests?, #any_projects?, #author_content_tag, #autodeploy_flash_notice, #badge_count, #branch_rules_path, #can_admin_associated_clusters?, #can_admin_project_member?, #can_change_visibility_level?, #can_disable_emails?, #can_push_code?, #can_view_branch_rules?, #clusters_deprecation_alert_message, #delete_confirm_phrase, #directory?, #error_tracking_setting_project_json, #explore_projects_tab?, #external_classification_label_help_message, #fork_button_data_attributes, #grafana_integration_enabled?, #grafana_integration_masked_token, #grafana_integration_url, #http_clone_url_to_repo, #import_from_bitbucket_message, #import_from_gitlab_message, #inactive_project_deletion_date, #last_pipeline_from_status_cache, #last_push_event, #link_to_autodeploy_doc, #link_to_member, #link_to_member_avatar, #link_to_project, #load_pipeline_status, #localized_project_human_access, #membership_locked?, #no_password_message, #project_can_be_shared?, #project_classes, #project_coverage_chart_data_attributes, #project_incident_management_setting, #project_license_name, #project_list_cache_key, #project_permissions_panel_data, #project_title, #push_to_create_project_command, #remote_mirror_setting_enabled?, #remove_fork_project_confirm_json, #remove_fork_project_description_message, #remove_fork_project_warning_message, #remove_project_message, #show_auto_devops_implicitly_enabled_banner?, #show_clusters_alert?, #show_count?, #show_inactive_project_deletion_banner?, #show_mobile_devops_project_promo?, #show_no_password_message?, #show_no_ssh_key_message?, #show_projects?, #show_terraform_banner?, #show_xcode_link?, #ssh_clone_url_to_repo, #transfer_project_message, #visibility_level_content, #visible_fork_source, #vue_fork_divergence_data, #xcode_uri_to_repo

Methods included from Gitlab::Allowable

#can?

Methods included from CompareHelper

#create_mr_button?, #create_mr_path, #project_compare_selector_data, #target_projects

Instance Method Details

#assigned_issuables_count(issuable_type) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'app/helpers/issuables_helper.rb', line 138

def assigned_issuables_count(issuable_type)
  case issuable_type
  when :issues
    ::Users::AssignedIssuesCountService.new(
      current_user: current_user,
      max_limit: User::MAX_LIMIT_FOR_ASSIGNEED_ISSUES_COUNT
    ).count
  when :merge_requests
    current_user.assigned_open_merge_requests_count
  else
    raise ArgumentError, "invalid issuable `#{issuable_type}`"
  end
end

#assigned_open_issues_count_textObject



152
153
154
155
156
157
158
159
160
# File 'app/helpers/issuables_helper.rb', line 152

def assigned_open_issues_count_text
  count = assigned_issuables_count(:issues)

  if count > User::MAX_LIMIT_FOR_ASSIGNEED_ISSUES_COUNT - 1
    "#{count - 1}+"
  else
    count.to_s
  end
end

#assignee_sidebar_data(assignee, merge_request: nil) ⇒ Object



219
220
221
222
223
224
# File 'app/helpers/issuables_helper.rb', line 219

def assignee_sidebar_data(assignee, merge_request: nil)
  { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }.tap do |data|
    data[:can_merge] = merge_request.can_be_merged_by?(assignee) if merge_request
    data[:availability] = assignee.status.availability if assignee.association(:status).loaded? && assignee.status&.availability
  end
end

#assignees_label(issuable, include_value: true) ⇒ Object



25
26
27
28
29
30
31
32
33
34
# File 'app/helpers/issuables_helper.rb', line 25

def assignees_label(issuable, include_value: true)
  assignees = issuable.assignees

  if include_value
    sanitized_list = sanitize_name(issuable.assignee_list)
    ns_('NotificationEmail|Assignee: %{users}', 'NotificationEmail|Assignees: %{users}', assignees.count) % { users: sanitized_list }
  else
    ns_('NotificationEmail|Assignee', 'NotificationEmail|Assignees', assignees.count)
  end
end

#close_issuable_path(issuable) ⇒ Object



199
200
201
# File 'app/helpers/issuables_helper.rb', line 199

def close_issuable_path(issuable)
  issuable_path(issuable, close_reopen_params(issuable, :close))
end

#group_dropdown_label(group_id, default_label) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord



104
105
106
107
108
109
110
111
112
113
114
115
# File 'app/helpers/issuables_helper.rb', line 104

def group_dropdown_label(group_id, default_label)
  return default_label if group_id.nil?
  return "Any group" if group_id == "0"

  group = ::Group.find_by(id: group_id)

  if group
    group.full_name
  else
    default_label
  end
end

#has_filter_bar_param?Boolean

Returns:

  • (Boolean)


215
216
217
# File 'app/helpers/issuables_helper.rb', line 215

def has_filter_bar_param?
  finder.class.scalar_params.any? { |p| params[p].present? }
end

#issuable_author_is_current_user(issuable) ⇒ Object



211
212
213
# File 'app/helpers/issuables_helper.rb', line 211

def issuable_author_is_current_user(issuable)
  issuable.author == current_user
end

#issuable_initial_data(issuable) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'app/helpers/issuables_helper.rb', line 170

def issuable_initial_data(issuable)
  data = {
    endpoint: issuable_path(issuable),
    updateEndpoint: "#{issuable_path(issuable)}.json",
    canUpdate: can?(current_user, :"update_#{issuable.to_ability_name}", issuable),
    canDestroy: can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable),
    issuableRef: issuable.to_reference,
    markdownPreviewPath: preview_markdown_path(parent, target_type: issuable.model_name, target_id: issuable.iid),
    markdownDocsPath: help_page_path('user/markdown'),
    lockVersion: issuable.lock_version,
    state: issuable.state,
    issuableTemplateNamesPath: template_names_path(parent, issuable),
    initialTitleHtml: markdown_field(issuable, :title),
    initialTitleText: issuable.title,
    initialDescriptionHtml: markdown_field(issuable, :description),
    initialDescriptionText: issuable.description,
    initialTaskCompletionStatus: issuable.task_completion_status
  }
  data.merge!(issue_only_initial_data(issuable))
  data.merge!(path_data(parent))
  data.merge!(updated_at_by(issuable))

  data
end

#issuable_label_selector_data(project, issuable) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'app/helpers/issuables_helper.rb', line 244

def issuable_label_selector_data(project, issuable)
  initial_labels = issuable.labels.map do |label|
    {
      __typename: "Label",
      id: label.id,
      title: label.title,
      description: label.description,
      color: label.color,
      text_color: label.text_color
    }
  end

  filter_base_path =
    if issuable.issuable_type == "merge_request"
      project_merge_requests_path(project)
    else
      project_issues_path(project)
    end

  {
    field_name: "#{issuable.class.model_name.param_key}[label_ids][]",
    full_path: project.full_path,
    initial_labels: initial_labels.to_json,
    issuable_type: issuable.issuable_type,
    labels_filter_base_path: filter_base_path,
    labels_manage_path: project_labels_path(project)
  }
end

#issuable_path(issuable, *options) ⇒ Object



207
208
209
# File 'app/helpers/issuables_helper.rb', line 207

def issuable_path(issuable, *options)
  polymorphic_path(issuable, *options)
end

#issuable_project_reference(issuable) ⇒ Object



166
167
168
# File 'app/helpers/issuables_helper.rb', line 166

def issuable_project_reference(issuable)
  "#{issuable.project.full_name} #{issuable.to_reference}"
end

#issuable_reference(issuable) ⇒ Object



162
163
164
# File 'app/helpers/issuables_helper.rb', line 162

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

#issuable_squash_option?(issuable, project) ⇒ Boolean

Returns:

  • (Boolean)


226
227
228
229
230
231
232
# File 'app/helpers/issuables_helper.rb', line 226

def issuable_squash_option?(issuable, project)
  if issuable.persisted?
    issuable.squash
  else
    project.squash_enabled_by_default?
  end
end

#issuable_type_selector_data(issuable) ⇒ Object



234
235
236
237
238
239
240
241
242
# File 'app/helpers/issuables_helper.rb', line 234

def issuable_type_selector_data(issuable)
  {
    selected_type: issuable.issue_type,
    is_issue_allowed: create_issue_type_allowed?(@project, :issue).to_s,
    is_incident_allowed: create_issue_type_allowed?(@project, :incident).to_s,
    issue_path: new_project_issue_path(@project),
    incident_path: new_project_issue_path(@project, { issuable_template: 'incident', issue: { issue_type: 'incident' } })
  }
end

#issuables_count_for_state(issuable_type, state) ⇒ Object



195
196
197
# File 'app/helpers/issuables_helper.rb', line 195

def issuables_count_for_state(issuable_type, state)
  Gitlab::IssuablesCountForState.new(finder, fast_fail: true, store_in_redis_cache: true)[state]
end

#issuables_state_counter_text(issuable_type, state, display_count) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'app/helpers/issuables_helper.rb', line 118

def issuables_state_counter_text(issuable_type, state, display_count)
  titles = {
    opened: _("Open"),
    closed: _("Closed"),
    merged: _("Merged"),
    all: _("All")
  }
  state_title = titles[state] || state.to_s.humanize
  html = (:span, state_title)

  return html.html_safe unless display_count

  count = issuables_count_for_state(issuable_type, state)
  if count != -1
    html << " " << gl_badge_tag(format_count(issuable_type, count, Gitlab::IssuablesCountForState::THRESHOLD), { variant: :muted, size: :sm }, { class: "gl-tab-counter-badge gl-display-none gl-sm-display-inline-flex" })
  end

  html.html_safe
end

#multi_label_name(current_labels, default_label) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
# File 'app/helpers/issuables_helper.rb', line 36

def multi_label_name(current_labels, default_label)
  return default_label if current_labels.blank?

  title = current_labels.first.try(:title) || current_labels.first[:title]

  if current_labels.size > 1
    "#{title} +#{current_labels.size - 1} more"
  else
    title
  end
end

#project_dropdown_label(project_id, default_label) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord



89
90
91
92
93
94
95
96
97
98
99
100
# File 'app/helpers/issuables_helper.rb', line 89

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
    project.full_name
  else
    default_label
  end
end

#reopen_issuable_path(issuable) ⇒ Object



203
204
205
# File 'app/helpers/issuables_helper.rb', line 203

def reopen_issuable_path(issuable)
  issuable_path(issuable, close_reopen_params(issuable, :reopen))
end

#serialize_issuable(issuable, opts = {}) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/helpers/issuables_helper.rb', line 48

def serialize_issuable(issuable, opts = {})
  serializer_klass = case issuable
                     when Issue
                       IssueSerializer
                     when MergeRequest
                       MergeRequestSerializer
                     end

  serializer_klass
    .new(current_user: current_user, project: issuable.project)
    .represent(issuable, opts)
    .to_json
end


15
16
17
18
19
# File 'app/helpers/issuables_helper.rb', line 15

def sidebar_gutter_collapsed_class(is_merge_request_with_flag)
  return "right-sidebar-expanded" if is_merge_request_with_flag

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


8
9
10
11
12
13
# File 'app/helpers/issuables_helper.rb', line 8

def sidebar_gutter_toggle_icon
  (:span, class: 'js-sidebar-toggle-container gl-button-text', data: { is_expanded: !sidebar_gutter_collapsed? }) do
    sprite_icon('chevron-double-lg-left', css_class: "js-sidebar-expand #{'hidden' unless sidebar_gutter_collapsed?}") +
    sprite_icon('chevron-double-lg-right', css_class: "js-sidebar-collapse #{'hidden' if sidebar_gutter_collapsed?}")
  end
end


21
22
23
# File 'app/helpers/issuables_helper.rb', line 21

def sidebar_gutter_tooltip_text
  sidebar_gutter_collapsed? ? _('Expand sidebar') : _('Collapse sidebar')
end

#user_dropdown_label(user_id, default_label) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord



74
75
76
77
78
79
80
81
82
83
84
85
# File 'app/helpers/issuables_helper.rb', line 74

def user_dropdown_label(user_id, default_label)
  return default_label if user_id.nil?
  return "Unassigned" if user_id == "0"

  user = User.find_by(id: user_id)

  if user
    user.name
  else
    default_label
  end
end

#users_dropdown_label(selected_users) ⇒ Object



62
63
64
65
66
67
68
69
70
71
# File 'app/helpers/issuables_helper.rb', line 62

def users_dropdown_label(selected_users)
  case selected_users.length
  when 0
    _('Unassigned')
  when 1
    selected_users[0].name
  else
    "#{selected_users[0].name} + #{selected_users.length - 1} more"
  end
end