Module: ApplicationHelper

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.community_forumObject

This needs to be used outside of Rails



224
225
226
# File 'app/helpers/application_helper.rb', line 224

def self.community_forum
  'https://forum.gitlab.com'
end

.promo_hostObject

This needs to be used outside of Rails



214
215
216
# File 'app/helpers/application_helper.rb', line 214

def self.promo_host
  'about.gitlab.com'
end

Instance Method Details

#active_when(condition) ⇒ Object

Returns active css class when condition returns true otherwise returns nil.

Example:

%li{ class: active_when(params[:filter] == '1') }


342
343
344
# File 'app/helpers/application_helper.rb', line 342

def active_when(condition)
  'active' if condition
end

#add_page_specific_style(path, defer: true) ⇒ Object



406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'app/helpers/application_helper.rb', line 406

def add_page_specific_style(path, defer: true)
  @already_added_styles ||= Set.new
  return if @already_added_styles.include?(path)

  @already_added_styles.add(path)
  content_for :page_specific_styles do
    if defer
      stylesheet_link_tag_defer path
    else
      stylesheet_link_tag path
    end
  end
end

#add_page_startup_api_call(api_path, options: {}) ⇒ Object



424
425
426
427
# File 'app/helpers/application_helper.rb', line 424

def add_page_startup_api_call(api_path, options: {})
  @api_startup_calls ||= {}
  @api_startup_calls[api_path] = options
end

#admin_section?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'app/helpers/application_helper.rb', line 78

def admin_section?
  controller.class.ancestors.include?(Admin::ApplicationController)
end

#asset_to_string(name) ⇒ Object



455
456
457
458
459
460
461
462
# File 'app/helpers/application_helper.rb', line 455

def asset_to_string(name)
  app = Rails.application
  if Rails.configuration.assets.compile
    app.assets.find_asset(name).to_s
  else
    controller.view_context.render(file: Rails.root.join('public/assets', app.assets_manifest.assets[name]).to_s)
  end
end

#autocomplete_data_sources(object, noteable_type) ⇒ Object



429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
# File 'app/helpers/application_helper.rb', line 429

def autocomplete_data_sources(object, noteable_type)
  return {} unless object && noteable_type

  if object.is_a?(Group)
    {
      members: members_group_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]),
      issues: issues_group_autocomplete_sources_path(object),
      mergeRequests: merge_requests_group_autocomplete_sources_path(object),
      labels: labels_group_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]),
      milestones: milestones_group_autocomplete_sources_path(object),
      commands: commands_group_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id])
    }
  else
    {
      members: members_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]),
      issues: issues_project_autocomplete_sources_path(object),
      mergeRequests: merge_requests_project_autocomplete_sources_path(object),
      labels: labels_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]),
      milestones: milestones_project_autocomplete_sources_path(object),
      commands: commands_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]),
      snippets: snippets_project_autocomplete_sources_path(object),
      contacts: contacts_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id])
    }
  end
end

#body_dataObject



122
123
124
125
126
127
128
129
130
# File 'app/helpers/application_helper.rb', line 122

def body_data
  {
    page: body_data_page,
    page_type_id: controller.params[:id],
    find_file: find_file_path,
    group: @group&.path,
    group_full_path: @group&.full_path
  }.merge(project_data)
end

#body_data_pageObject



144
145
146
# File 'app/helpers/application_helper.rb', line 144

def body_data_page
  [*controller.controller_path.split('/'), controller.action_name].compact.join(':')
end

#client_class_listObject



395
396
397
# File 'app/helpers/application_helper.rb', line 395

def client_class_list
  "gl-browser-#{browser_id} gl-platform-#{platform_id}"
end

#client_js_flagsObject



399
400
401
402
403
404
# File 'app/helpers/application_helper.rb', line 399

def client_js_flags
  {
    "is#{browser_id.titlecase}": true,
    "is#{platform_id.titlecase}": true
  }
end

#collapsed_sidebar?Boolean

Returns:

  • (Boolean)


374
375
376
# File 'app/helpers/application_helper.rb', line 374

def collapsed_sidebar?
  cookies["sidebar_collapsed"] == "true"
end

#collapsed_super_sidebar?Boolean

Returns:

  • (Boolean)


378
379
380
381
382
# File 'app/helpers/application_helper.rb', line 378

def collapsed_super_sidebar?
  return false if @force_desktop_expanded_sidebar

  cookies["super_sidebar_collapsed"] == "true"
end

#community_forumObject

Convenient method for Rails helper



229
230
231
# File 'app/helpers/application_helper.rb', line 229

def community_forum
  ApplicationHelper.community_forum
end

While similarly named to Rails’s ‘link_to_if`, this method behaves quite differently. If `condition` is truthy, a link will be returned with the result of the block as its body. If `condition` is falsy, only the result of the block will be returned.



305
306
307
308
309
310
311
# File 'app/helpers/application_helper.rb', line 305

def conditional_link_to(condition, options, html_options = {}, &block)
  if condition
    link_to options, html_options, &block
  else
    capture(&block)
  end
end

#controller_full_pathObject



493
494
495
496
497
498
499
500
# File 'app/helpers/application_helper.rb', line 493

def controller_full_path
  action = case controller.action_name
           when 'create' then 'new'
           when 'update' then 'edit'
           else controller.action_name
           end
  "#{controller.controller_path}/#{action}"
end

#current_action?(*args) ⇒ Boolean

Check if a particular action is the current one

args - One or more action names to check

Examples

# On Projects#new
current_action?(:new)           # => true
current_action?(:create)        # => false
current_action?(:new, :create)  # => true

Returns:

  • (Boolean)


74
75
76
# File 'app/helpers/application_helper.rb', line 74

def current_action?(*args)
  args.any? { |v| Gitlab::Utils.safe_downcase!(v.to_s) == action_name }
end

#current_controller?(*args) ⇒ Boolean

Check if a particular controller is the current one

args - One or more controller names to check (using path notation when inside namespaces)

Examples

# On TreeController
current_controller?(:tree)           # => true
current_controller?(:commits)        # => false
current_controller?(:commits, :tree) # => true

# On Admin::ApplicationController
current_controller?(:application)         # => true
current_controller?('admin/application')  # => true
current_controller?('gitlab/application') # => false

Returns:

  • (Boolean)


58
59
60
61
62
# File 'app/helpers/application_helper.rb', line 58

def current_controller?(*args)
  args.any? do |v|
    Gitlab::Utils.safe_downcase!(v.to_s) == controller.controller_name || Gitlab::Utils.safe_downcase!(v.to_s) == controller.controller_path
  end
end

#discord_url(user) ⇒ Object



368
369
370
371
372
# File 'app/helpers/application_helper.rb', line 368

def discord_url(user)
  return '' if user.discord.blank?

  "https://discord.com/users/#{user.discord}"
end

#dispensable_renderObject



20
21
22
23
24
25
# File 'app/helpers/application_helper.rb', line 20

def dispensable_render(...)
  render(...)
rescue StandardError => e
  Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
  nil
end

#dispensable_render_if_existsObject



27
28
29
30
31
32
# File 'app/helpers/application_helper.rb', line 27

def dispensable_render_if_exists(...)
  render_if_exists(...)
rescue StandardError => e
  Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
  nil
end

#edited_time_ago_with_tooltip(editable_object, placement: 'top', html_class: 'time_ago', exclude_author: false) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'app/helpers/application_helper.rb', line 196

def edited_time_ago_with_tooltip(editable_object, placement: 'top', html_class: 'time_ago', exclude_author: false)
  return unless editable_object.edited?

   :small, class: 'edited-text' do
    timeago = time_ago_with_tooltip(editable_object.last_edited_at, placement: placement, html_class: html_class)

    if !exclude_author && editable_object.last_edited_by
      author_link = link_to_member(editable_object.project, editable_object.last_edited_by, avatar: false, extra_class: 'gl-hover-text-decoration-underline', author_class: nil)
      output = safe_format(_("Edited %{timeago} by %{author}"), timeago: timeago, author: author_link)
    else
      output = safe_format(_("Edited %{timeago}"), timeago: timeago)
    end

    output
  end
end

#external_storage_url_or_path(path, project = @project) ⇒ Object



249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'app/helpers/application_helper.rb', line 249

def external_storage_url_or_path(path, project = @project)
  return path if @snippet || !static_objects_external_storage_enabled?

  uri = URI(Gitlab::CurrentSettings.static_objects_external_storage_url)
  path = URI(path) # `path` could have query parameters, so we need to split query and path apart

  query = Rack::Utils.parse_nested_query(path.query)
  query['token'] = current_user.static_object_token unless project.public?

  uri.path = path.path
  uri.query = query.to_query unless query.empty?

  uri.to_s
end

#extra_configObject

shortcut for gitlab extra config



154
155
156
# File 'app/helpers/application_helper.rb', line 154

def extra_config
  Gitlab.config.extra
end

#gitlab_configObject

shortcut for gitlab config



149
150
151
# File 'app/helpers/application_helper.rb', line 149

def gitlab_config
  Gitlab.config.gitlab
end

#gitlab_ui_form_for(record, *args, &block) ⇒ Object



464
465
466
467
468
# File 'app/helpers/application_helper.rb', line 464

def gitlab_ui_form_for(record, *args, &block)
  options = args.extract_options!

  form_for(record, *(args << options.merge({ builder: ::Gitlab::FormBuilders::GitlabUiFormBuilder })), &block)
end

#gitlab_ui_form_with(**args, &block) ⇒ Object



470
471
472
# File 'app/helpers/application_helper.rb', line 470

def gitlab_ui_form_with(**args, &block)
  form_with(**args.merge({ builder: ::Gitlab::FormBuilders::GitlabUiFormBuilder }), &block)
end

#hexdigest(string) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord



114
115
116
# File 'app/helpers/application_helper.rb', line 114

def hexdigest(string)
  Digest::SHA1.hexdigest string
end

#hidden_resource_icon(resource, css_class: nil) ⇒ Object



474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
# File 'app/helpers/application_helper.rb', line 474

def hidden_resource_icon(resource, css_class: nil)
  issuable_title = _('This %{issuable} is hidden because its author has been banned.')

  case resource
  when Issue
    title = format(issuable_title, issuable: _('issue'))
  when MergeRequest
    title = format(issuable_title, issuable: _('merge request'))
  when Project
    title = _('This project is hidden because its creator has been banned')
  end

  return unless title

  (:span, class: 'has-tooltip', title: title) do
    sprite_icon('spam', css_class: ['gl-vertical-align-text-bottom', css_class].compact_blank.join(' '))
  end
end

#instance_review_permitted?Boolean

Returns:

  • (Boolean)


241
242
243
# File 'app/helpers/application_helper.rb', line 241

def instance_review_permitted?
  ::Gitlab::CurrentSettings.instance_review_permitted? && current_user&.can_read_all_resources?
end

#last_commit(project) ⇒ Object



82
83
84
85
86
87
88
89
90
# File 'app/helpers/application_helper.rb', line 82

def last_commit(project)
  if project.repo_exists?
    time_ago_with_tooltip(project.repository.commit.committed_date)
  else
    'Never'
  end
rescue StandardError
  'Never'
end

#linkedin_url(user) ⇒ Object



350
351
352
353
354
355
356
357
# File 'app/helpers/application_helper.rb', line 350

def linkedin_url(user)
  name = user.linkedin
  if %r{\Ahttps?://(www\.)?linkedin\.com/in/}.match?(name)
    name
  else
    "https://www.linkedin.com/in/#{name}"
  end
end

#locale_pathObject



384
385
386
# File 'app/helpers/application_helper.rb', line 384

def locale_path
  asset_path("locale/#{Gitlab::I18n.locale}/app.js")
end

#outdated_browser?Boolean

Returns:

  • (Boolean)


286
287
288
# File 'app/helpers/application_helper.rb', line 286

def outdated_browser?
  browser.ie?
end

#page_classObject



313
314
315
316
317
318
319
320
321
322
323
324
# File 'app/helpers/application_helper.rb', line 313

def page_class
  class_names = []
  class_names << 'issue-boards-page gl-overflow-auto' if current_controller?(:boards)
  class_names << 'epic-boards-page gl-overflow-auto' if current_controller?(:epic_boards)
  class_names << 'with-performance-bar' if performance_bar_enabled?
  class_names << 'with-header' if !show_super_sidebar? || !current_user
  class_names << 'with-top-bar' if show_super_sidebar? && !@hide_top_bar_padding
  class_names << system_message_class
  class_names << 'logged-out-marketing-header' if !current_user && ::Gitlab.com? && !show_super_sidebar?

  class_names
end

#page_filter_path(options = {}) ⇒ Object



264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'app/helpers/application_helper.rb', line 264

def page_filter_path(options = {})
  without = options.delete(:without)

  options = request.query_parameters.merge(options)

  if without.present?
    without.each do |key|
      options.delete(key)
    end
  end

  "#{request.path}?#{options.compact.to_param}"
end

#page_startup_api_callsObject



420
421
422
# File 'app/helpers/application_helper.rb', line 420

def page_startup_api_calls
  @api_startup_calls
end

#partial_exists?(partial) ⇒ Boolean

Returns:

  • (Boolean)


34
35
36
# File 'app/helpers/application_helper.rb', line 34

def partial_exists?(partial)
  lookup_context.exists?(partial, [], true)
end

#path_to_key(key, admin = false) ⇒ Object



290
291
292
293
294
295
296
# File 'app/helpers/application_helper.rb', line 290

def path_to_key(key, admin = false)
  if admin
    admin_user_key_path(@user, key)
  else
    profile_key_path(key)
  end
end

#project_dataObject



132
133
134
135
136
137
138
139
140
141
142
# File 'app/helpers/application_helper.rb', line 132

def project_data
  return {} unless @project

  {
    project_id: @project.id,
    project: @project.path,
    group: @project.group&.path,
    group_full_path: @project.group&.full_path,
    namespace_id: @project.namespace&.id
  }
end

#promo_hostObject

Convenient method for Rails helper



219
220
221
# File 'app/helpers/application_helper.rb', line 219

def promo_host
  ApplicationHelper.promo_host
end

#promo_urlObject



233
234
235
# File 'app/helpers/application_helper.rb', line 233

def promo_url
  "https://#{promo_host}"
end

#read_only_messageObject

Overridden in EE



389
390
391
392
393
# File 'app/helpers/application_helper.rb', line 389

def read_only_message
  return unless Gitlab::Database.read_only?

  _('You are on a read-only GitLab instance.')
end

#registry_configObject

shortcut for gitlab registry config



159
160
161
# File 'app/helpers/application_helper.rb', line 159

def registry_config
  Gitlab.config.registry
end

#render_if_exists(partial = nil, **options) ⇒ Object

See docs.gitlab.com/ee/development/ee_features.html#code-in-appviews rubocop: disable CodeReuse/ActiveRecord We allow partial to be nil so that collection views can be passed in ‘render partial: ’some/view’, collection: @some_collection`



10
11
12
13
14
15
16
17
18
# File 'app/helpers/application_helper.rb', line 10

def render_if_exists(partial = nil, **options)
  return unless partial_exists?(partial || options[:partial])

  if partial.nil?
    render(**options)
  else
    render(partial, options)
  end
end

#show_callout?(name) ⇒ Boolean

Returns:

  • (Boolean)


346
347
348
# File 'app/helpers/application_helper.rb', line 346

def show_callout?(name)
  cookies[name] != 'true'
end

#show_last_push_widget?(event) ⇒ Boolean

Define whenever show last push event with suggestion to create MR rubocop: disable CodeReuse/ActiveRecord

Returns:

  • (Boolean)


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'app/helpers/application_helper.rb', line 95

def show_last_push_widget?(event)
  # Skip if event is not about added or modified non-master branch
  return false unless event && event.last_push_to_non_root? && !event.rm_ref?

  project = event.project

  # Skip if project repo is empty or MR disabled
  return false unless project && !project.empty_repo? && project.feature_available?(:merge_requests, current_user)

  # Skip if user already created appropriate MR
  return false if project.merge_requests.where(source_branch: event.branch_name).opened.any?

  # Skip if user removed branch right after that
  return false unless project.repository.branch_exists?(event.branch_name)

  true
end

#sign_in_with_redirect?Boolean

Returns:

  • (Boolean)


282
283
284
# File 'app/helpers/application_helper.rb', line 282

def 
  current_page?(new_user_session_path) && session[:user_return_to].present?
end

#simple_sanitize(str) ⇒ Object



118
119
120
# File 'app/helpers/application_helper.rb', line 118

def simple_sanitize(str)
  sanitize(str, tags: %w[a span])
end

#static_objects_external_storage_enabled?Boolean

Returns:

  • (Boolean)


245
246
247
# File 'app/helpers/application_helper.rb', line 245

def static_objects_external_storage_enabled?
  Gitlab::CurrentSettings.static_objects_external_storage_enabled?
end


278
279
280
# File 'app/helpers/application_helper.rb', line 278

def stylesheet_link_tag_defer(path)
  stylesheet_link_tag(path, media: "all", crossorigin: ActionController::Base.asset_host ? 'anonymous' : nil)
end

#support_urlObject



237
238
239
# File 'app/helpers/application_helper.rb', line 237

def support_url
  Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || "#{promo_url}/get-help/"
end

#system_message_classObject



326
327
328
329
330
331
332
333
334
335
# File 'app/helpers/application_helper.rb', line 326

def system_message_class
  class_names = []

  return class_names unless appearance

  class_names << 'with-system-header' if appearance.show_header?
  class_names << 'with-system-footer' if appearance.show_footer?

  class_names.join(' ')
end

#template_exists?(template) ⇒ Boolean

Returns:

  • (Boolean)


38
39
40
# File 'app/helpers/application_helper.rb', line 38

def template_exists?(template)
  lookup_context.exists?(template, [], false)
end

#time_ago_with_tooltip(time, placement: 'top', html_class: '', short_format: false) ⇒ Object

Render a ‘time` element with Javascript-based relative date and tooltip

time - Time object placement - Tooltip placement String (default: “top”) html_class - Custom class for ‘time` element (default: “time_ago”)

By default also includes a ‘script` element with Javascript necessary to initialize the `timeago` jQuery extension. If this method is called many times, for example rendering hundreds of commits, it’s advisable to disable this behavior using the ‘skip_js` argument and re-initializing `timeago` manually once all of the elements have been rendered.

A ‘js-timeago` class is always added to the element, even when a custom `html_class` argument is provided.

Returns an HTML-safe String



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'app/helpers/application_helper.rb', line 179

def time_ago_with_tooltip(time, placement: 'top', html_class: '', short_format: false)
  return "" if time.nil?

  css_classes = [short_format ? 'js-short-timeago' : 'js-timeago']
  css_classes << html_class unless html_class.blank?

   :time, l(time, format: "%b %d, %Y"),
    class: css_classes.join(' '),
    title: l(time.to_time.in_time_zone, format: :timeago_tooltip),
    datetime: time.to_time.getutc.iso8601,
    data: {
      toggle: 'tooltip',
      placement: placement,
      container: 'body'
    }
end

#truncate_first_line(message, length = 50) ⇒ Object



298
299
300
# File 'app/helpers/application_helper.rb', line 298

def truncate_first_line(message, length = 50)
  truncate(message.each_line.first.chomp, length: length) if message
end

#twitter_url(user) ⇒ Object



359
360
361
362
363
364
365
366
# File 'app/helpers/application_helper.rb', line 359

def twitter_url(user)
  name = user.twitter
  if %r{\Ahttps?://(www\.)?twitter\.com/}.match?(name)
    name
  else
    "https://twitter.com/#{name}"
  end
end