Module: ApplicationHelper

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.promo_hostObject

This needs to be used outside of Rails


217
218
219
# File 'app/helpers/application_helper.rb', line 217

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') }

329
330
331
# File 'app/helpers/application_helper.rb', line 329

def active_when(condition)
  'active' if condition
end

#add_page_specific_style(path, defer: true) ⇒ Object


381
382
383
384
385
386
387
388
389
# File 'app/helpers/application_helper.rb', line 381

def add_page_specific_style(path, defer: true)
  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


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

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

#admin_section?Boolean

Returns:

  • (Boolean)

86
87
88
# File 'app/helpers/application_helper.rb', line 86

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

#asset_to_string(name) ⇒ Object


426
427
428
429
430
431
432
433
# File 'app/helpers/application_helper.rb', line 426

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


400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'app/helpers/application_helper.rb', line 400

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)
    }
  end
end

#body_dataObject


130
131
132
133
134
135
136
137
# File 'app/helpers/application_helper.rb', line 130

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

#body_data_pageObject


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

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

#client_class_listObject


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

def client_class_list
  "gl-browser-#{browser.id} gl-platform-#{browser.platform.id}"
end

#client_js_flagsObject


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

def client_js_flags
  {
    "is#{browser.id.to_s.titlecase}": true,
    "is#{browser.platform.id.to_s.titlecase}": true
  }
end

#collapsed_sidebar?Boolean

Returns:

  • (Boolean)

355
356
357
# File 'app/helpers/application_helper.rb', line 355

def collapsed_sidebar?
  cookies["sidebar_collapsed"] == "true"
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.


294
295
296
297
298
299
300
# File 'app/helpers/application_helper.rb', line 294

def conditional_link_to(condition, options, html_options = {}, &block)
  if condition
    link_to options, html_options, &block
  else
    capture(&block)
  end
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)

82
83
84
# File 'app/helpers/application_helper.rb', line 82

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)

66
67
68
69
70
# File 'app/helpers/application_helper.rb', line 66

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

#dispensable_renderObject


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

def dispensable_render(...)
  render(...)
rescue StandardError => error
  if Feature.enabled?(:dispensable_render)
    Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error)
    nil
  else
    raise error
  end
end

#dispensable_render_if_existsObject


31
32
33
34
35
36
37
38
39
40
# File 'app/helpers/application_helper.rb', line 31

def dispensable_render_if_exists(...)
  render_if_exists(...)
rescue StandardError => error
  if Feature.enabled?(:dispensable_render)
    Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error)
    nil
  else
    raise error
  end
end

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


200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'app/helpers/application_helper.rb', line 200

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

   :small, class: 'edited-text' do
    output = (:span, 'Edited ')
    output << time_ago_with_tooltip(object.last_edited_at, placement: placement, html_class: html_class)

    if !exclude_author && object.last_edited_by
      output << (:span, ' by ')
      output << link_to_member(object.project, object.last_edited_by, avatar: false, author_class: nil)
    end

    output
  end
end

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


242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'app/helpers/application_helper.rb', line 242

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


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

def extra_config
  Gitlab.config.extra
end

#gitlab_configObject

shortcut for gitlab config


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

def gitlab_config
  Gitlab.config.gitlab
end

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


435
436
437
438
439
# File 'app/helpers/application_helper.rb', line 435

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

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

#hexdigest(string) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


122
123
124
# File 'app/helpers/application_helper.rb', line 122

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

#instance_review_permitted?Boolean

Returns:

  • (Boolean)

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

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

#last_commit(project) ⇒ Object


90
91
92
93
94
95
96
97
98
# File 'app/helpers/application_helper.rb', line 90

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


337
338
339
340
341
342
343
344
# File 'app/helpers/application_helper.rb', line 337

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

#locale_pathObject


359
360
361
# File 'app/helpers/application_helper.rb', line 359

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

#outdated_browser?Boolean

Returns:

  • (Boolean)

275
276
277
# File 'app/helpers/application_helper.rb', line 275

def outdated_browser?
  browser.ie?
end

#page_classObject


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

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 << 'environment-logs-page' if current_controller?(:logs)
  class_names << 'with-performance-bar' if performance_bar_enabled?
  class_names << system_message_class
  class_names << marketing_header_experiment_class
  class_names
end

#page_filter_path(options = {}) ⇒ Object


257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'app/helpers/application_helper.rb', line 257

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


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

def page_startup_api_calls
  @api_startup_calls
end

#partial_exists?(partial) ⇒ Boolean

Returns:

  • (Boolean)

42
43
44
# File 'app/helpers/application_helper.rb', line 42

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

#path_to_key(key, admin = false) ⇒ Object


279
280
281
282
283
284
285
# File 'app/helpers/application_helper.rb', line 279

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

#project_dataObject


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

def project_data
  return {} unless @project

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

#promo_hostObject

Convenient method for Rails helper


222
223
224
# File 'app/helpers/application_helper.rb', line 222

def promo_host
  ApplicationHelper.promo_host
end

#promo_urlObject


226
227
228
# File 'app/helpers/application_helper.rb', line 226

def promo_url
  'https://' + promo_host
end

#read_only_messageObject

Overridden in EE


364
365
366
367
368
# File 'app/helpers/application_helper.rb', line 364

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


165
166
167
# File 'app/helpers/application_helper.rb', line 165

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)

333
334
335
# File 'app/helpers/application_helper.rb', line 333

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)

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/helpers/application_helper.rb', line 103

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

#simple_sanitize(str) ⇒ Object


126
127
128
# File 'app/helpers/application_helper.rb', line 126

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

#static_objects_external_storage_enabled?Boolean

Returns:

  • (Boolean)

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

def static_objects_external_storage_enabled?
  Gitlab::CurrentSettings.static_objects_external_storage_enabled?
end

271
272
273
# File 'app/helpers/application_helper.rb', line 271

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

#support_urlObject


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

def support_url
  Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || promo_url + '/getting-help/'
end

#system_message_classObject


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

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
end

#template_exists?(template) ⇒ Boolean

Returns:

  • (Boolean)

46
47
48
# File 'app/helpers/application_helper.rb', line 46

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


185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'app/helpers/application_helper.rb', line 185

def time_ago_with_tooltip(time, placement: 'top', html_class: '', short_format: false)
  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


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

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

#twitter_url(user) ⇒ Object


346
347
348
349
350
351
352
353
# File 'app/helpers/application_helper.rb', line 346

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