Module: ApplicationHelper

Includes:
ControllerHelper
Defined in:
app/helpers/application_helper.rb

Overview

rubocop:todo Metrics/ModuleLength

Instance Method Summary collapse

Methods included from ControllerHelper

#add, #logger

Methods included from Informatics::Globals

#application, #application=, #defaults, #defaults=, #global_searchable_classes, #search_options

Instance Method Details

#about(title = '') ⇒ Object

From Pipelines



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

def about(title = '')
  add :about, title
end

#api_dataObject



84
85
86
# File 'app/helpers/application_helper.rb', line 84

def api_data
  { api_version: RELEASE.api_version }
end

#apple_iconString

Return the appropriate apple icon for the current environment

Returns:

  • (String)

    The path to the apple icon



64
65
66
# File 'app/helpers/application_helper.rb', line 64

def apple_icon
  "apple-icon#{icon_suffix}.png"
end

#badge(status, type: 'generic-badge', style: status) ⇒ type

Renders a badge containing the supplied text, with appropriate styling. By default the ‘badge-#{status}’ class is applied. These states are mapped to bootstrap colours in components.scss (grep ‘// State-colour extensions’)

If you can’t map the text directly to a style, such as if you are displaying a number that you want to change its colours at certain thresholds, then you can override the applied style with the style: argument.

If the string passed in is empty, no badge will be rendered

Examples:

Render a request state badge.

badge(request.state, type: 'request')

Render the size of a batch, which is red if too large.

status = batch.size > MAX_SIZE ? 'danger' : 'success'
badge(batch.size, type: 'batch-size', style: status )

Parameters:

  • status (String)

    The text to display in the badge. Will also be used to set the style if not otherwise specified

  • type (String) (defaults to: 'generic-badge')

    Optional: Additional css-class applied to the badge (generic-badge by default)

  • style (String) (defaults to: status)

    Optional: Override the badge-* class otherwise set directly from the status.

Returns:

  • (type)

    HTML to render a badge



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

def badge(status, type: 'generic-badge', style: status)
  return if status.blank?

  tag.span(status, class: "#{type} badge badge-#{style}")
end

#counter_badge(counter, suffix = '') ⇒ String

Used to add a counter to headers or links. Renders a blue badge containing the supplied number Only supply a suffix if it can’t be worked out from the context what is being counted.

Parameters:

  • counter (Integer)

    The value to show in the badge

  • suffix (Integer, String) (defaults to: '')

    Optional: The type of thing being counted.

Returns:

  • (String)

    HTML to render a badge



138
139
140
141
# File 'app/helpers/application_helper.rb', line 138

def counter_badge(counter, suffix = '')
  status = suffix.present? ? pluralize(counter, suffix) : counter
  badge(status, type: 'counter-badge', style: 'primary')
end

#custom_text(identifier, differential = nil) ⇒ Object

Should return either the custom text or a blank string



7
8
9
10
11
12
13
14
15
# File 'app/helpers/application_helper.rb', line 7

def custom_text(identifier, differential = nil)
  Rails
    .cache
    .fetch("#{identifier}-#{differential}") do
      custom_text = CustomText.find_by(identifier:, differential:)

      custom_text.try(:content) || ''
    end
end

#display_boolean_results(result) ⇒ Object



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

def display_boolean_results(result)
  return 'NA' if result.blank?

  if %w[pass 1 true].include?(result)
    icon('far', 'check-circle', title: result)
  else
    icon('fas', 'exclamation-circle', class: 'text-danger', title: result)
  end
end

#display_follow(item, user, msg) ⇒ Object



197
198
199
# File 'app/helpers/application_helper.rb', line 197

def display_follow(item, user, msg)
  user.follower_of?(item) ? 'Unfollow ' + msg : 'Follow ' + msg
end

#display_user_error(display_text, link = nil) ⇒ Object



98
99
100
# File 'app/helpers/application_helper.rb', line 98

def display_user_error(display_text, link = nil)
  alert(:danger) { link.present? ? link_to(display_text, link) : display_text }
end

#display_user_guide(display_text, link = nil) ⇒ type

Renders a user guide with optional link. Applies appropriate styling

Parameters:

  • display_text (String)

    The text of the user guide

  • link (String) (defaults to: nil)

    Optional url to link the guide to.

Returns:

  • (type)

    [description]



94
95
96
# File 'app/helpers/application_helper.rb', line 94

def display_user_guide(display_text, link = nil)
  alert(:user_guide) { concat link.present? ? link_to(display_text, link) : display_text }
end

rubocop:todo Metrics/MethodLength



144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'app/helpers/application_helper.rb', line 144

def dynamic_link_to(summary_item) # rubocop:todo Metrics/AbcSize
  object = summary_item.object
  if object.instance_of?(Submission)
    link_to("Submission #{object.id}", study_information_submission_path(object.study, object))
  elsif object.instance_of?(Receptacle)
    link_to("#{object.label.capitalize} #{object.name}", receptacle_path(object))
  elsif object.instance_of?(Labware)
    link_to("#{object.label.capitalize} #{object.name}", labware_path(object))
  elsif object.instance_of?(Request)
    link_to("Request #{object.id}", request_path(object))
  else
    'No link available'
  end
end

#faviconString

Return the appropriate favicon for the current environment

Returns:

  • (String)

    The path to the favicon



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

def favicon
  "favicon#{icon_suffix}.ico"
end


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

def fresh_sevice_link
  link_to 'FreshService', configatron.fresh_sevice_new_ticket_url
end


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

def help_link(text, entry = '', options = {})
  url = "#{configatron.help_link_base_url}/#{entry}"
  options[:class] = "#{options[:class]} external_help"
  link_to text, url, options
end

#help_textObject



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

def help_text(&)
  tag.small(class: 'form-text text-muted col', &)
end

#hidden_label_tag_for_testing(name, text = nil, options = {}) ⇒ Object

Creates a label that is hidden from the view so that testing is easier



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

def hidden_label_tag_for_testing(name, text = nil, options = {})
  label_tag(name, text, options.merge(style: 'display:none;'))
end

#icon_suffixString

Returns the appropriate icon suffix for the current environment Returns empty string for production Returns “-#environment” for training, staging Returns “-development” for any other environment

Returns:

  • (String)

    The suffix to append to the icon name



44
45
46
47
48
49
50
51
52
53
54
# File 'app/helpers/application_helper.rb', line 44

def icon_suffix
  environment = Rails.env
  case environment
  when 'production'
    ''
  when 'training', 'staging'
    "-#{environment}"
  else
    '-development'
  end
end

#legacy_javascript_tagString

Ideally we don’t want inline script tags, however there is a fair chunk of legacy code, some of which isn’t trivial to migrate, as it uses erb to generate javascript, rather than using data-attributes.

This tag: - Ensures we add a nonce for security - If the page is still loading, delays script execution until DOMContentLoaded to ensure that the modern JS has had a chance to export jQuery - If the page has already loaded, executes the script immediately. This is needed for use cases where the partial that renders this script is loaded after the main page has loaded e.g. the admin study edit page, within the admin study index page.

Returns:

  • (String)

    Script tag



341
342
343
344
345
346
347
348
349
# File 'app/helpers/application_helper.rb', line 341

def legacy_javascript_tag
  javascript_tag nonce: true do
    concat 'if (document.readyState === "loading") {window.addEventListener("DOMContentLoaded", function() {'.html_safe # rubocop:disable Layout/LineLength
    yield
    concat '});} else {'.html_safe
    yield
    concat '}'.html_safe
  end
end

#remote_error(identifier = 'remote_error') ⇒ Object

TODO:

Probably remove this and the references to it in app/views/studies/information/_items.html.erb Or possibly restore the intended behaviour in app/assets/javascripts/sequencescape/ajax_link_handling.js

Renders a non-displayed error div warning of a data failure Appears to have been intended to be used to provide error feedback on the studies in app/views/studies/information/_items.html.erb but actual behaviour will result in the error payload being placed in the div, but remaining invisible.

Parameters:

  • identifier (String) (defaults to: 'remote_error')

    The id of the element



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

def remote_error(identifier = 'remote_error')
  tag.div(id: identifier, class: 'error', style: 'display:none;') do
    'An error has occurred and the results can not be shown at the moment'
  end
end

#render_flashesObject



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

def render_flashes
  flash.each { |key, message| concat(alert(key, id: "message_#{key}") { render_message(message) }) }
  nil
end

#render_message(messages) ⇒ Object

A helper method for render_flashes - If multiple messages, render them as a list, else render as a single div

Parameters:

  • messages (Array<String>, String)

    The flash message or messages to be rendered



75
76
77
78
79
80
81
82
# File 'app/helpers/application_helper.rb', line 75

def render_message(messages)
  messages = Array(messages)
  if messages.size > 1
    tag.ul { messages.each { |m| concat tag.li(m) } }
  else
    tag.div(messages.first)
  end
end

#render_parsed_json(json) ⇒ String

Handles rendering of JSON to a series of nested lists. Does the following: String: Rendered as-is Array: Unordered list (Strictly speaking arrays are ordered, but we probably don’t care.) Object: Descriptive list Other: Calls to_s Processes each in turn and called recursively

rubocop:todo Metrics/MethodLength

Parameters:

  • json (Hash, String, Array, , #to_s)

    The Object to render

Returns:

  • (String)

    HTML formatted for rendering



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'app/helpers/application_helper.rb', line 302

def render_parsed_json(json) # rubocop:todo Metrics/AbcSize
  case json
  when String
    json
  when Array
    tag.ul { json.each { |elem| concat tag.li(render_parsed_json(elem)) } }
  when Hash
    tag.dl do
      json.each do |key, value|
        # Strictly speaking json should only have strings as keys. But the same constraint doesn't apply to hashes,
        # so we're a little more permissive here for flexibilities sake
        concat tag.dt(render_parsed_json(key))
        concat tag.dd(render_parsed_json(value))
      end
    end
  else
    json.to_s
  end
end

rubocop:enable Metrics/MethodLength



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'app/helpers/application_helper.rb', line 161

def request_count_link(study, asset, state, request_type) # rubocop:todo Metrics/AbcSize
  matching_requests =
    asset.requests.select { |request| (request.request_type_id == request_type.id) and request.state == state }
  html_options, count = { title: "#{asset.try(:human_barcode) || asset.id} #{state}" }, matching_requests.size

  # 0 requests => no link, just '0'
  # 1 request  => request summary page
  # N requests => summary overview
  if count == 1
    url_path = request_path(matching_requests.first)
    link_to count, url_path, html_options
  elsif count > 1
    url_path = study_requests_path(study, state: state, request_type_id: request_type.id, asset_id: asset.id)
    link_to count, url_path, html_options
  end
end

rubocop:todo Metrics/ParameterLists



179
180
181
182
# File 'app/helpers/application_helper.rb', line 179

def request_link(object, count, request_type, status = nil, options = {}, link_options = {})
  # rubocop:enable Metrics/ParameterLists
  link_to_if((count != 0), count, request_list_path(object, request_type, status, options), link_options)
end

#request_list_path(object, request_type = nil, status = nil, options = {}) ⇒ Object



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

def request_list_path(object, request_type = nil, status = nil, options = {})
  options[:state] = status unless status.nil?
  options[:request_type_id] = request_type.id unless request_type.nil?

  if object.instance_of?(Receptacle)
    receptacle_path(object, options)
  elsif object.instance_of?(Labware)
    labware_path(object, options)
  elsif object.instance_of?(Study)
    study_requests_path(object, options)
  end
end

#required_markerString

Inserts the icon used to indicate a field is required. This will also be displayed on any <label> tags with the .required class

Returns:

  • (String)

    HTML representing the required marker



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

def required_marker
  icon('fas', 'asterisk', class: 'text-warning', title: 'required')
end

#sorted_requests_for_search(requests) ⇒ Object



263
264
265
266
267
268
# File 'app/helpers/application_helper.rb', line 263

def sorted_requests_for_search(requests)
  sorted_requests = requests.select { |r| r.pipeline_id.nil? }
  new_requests = requests - sorted_requests
  new_requests.sort_by(&:pipeline_id)
  requests += sorted_requests
end

#tab(name, target: nil, active: false, id: nil) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/helpers/application_helper.rb', line 226

def tab(name, target: nil, active: false, id: nil)
  target ||= name.parameterize
  active_class = active ? 'active' : ''
  id ||= "#{name}-tab".parameterize
  tag.li(class: 'nav-item') do
    link_to name,
            "##{target}",
            id: id,
            data: {
              toggle: 'tab'
            },
            role: 'tab',
            aria_controls: target,
            class: ['nav-link', active_class]
  end
end

#tab_pane(name, id: nil, tab_id: nil, active: false) ⇒ Object

yield


246
247
248
249
250
251
# File 'app/helpers/application_helper.rb', line 246

def tab_pane(name, id: nil, tab_id: nil, active: false, &)
  tab_id ||= "#{name}-tab".parameterize
  id ||= name.parameterize
  active_class = active ? 'active' : ''
  tag.div(class: ['tab-pane', 'fade', 'show', active_class], id: id, role: 'tabpanel', aria_labelledby: tab_id, &)
end

#tabulated_error_messages_for(*params) ⇒ Object

rubocop:todo Metrics/AbcSize



207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'app/helpers/application_helper.rb', line 207

def tabulated_error_messages_for(*params) # rubocop:todo Metrics/AbcSize
  options = params.last.is_a?(Hash) ? params.pop.symbolize_keys : {}
  objects = params.filter_map { |object_name| instance_variable_get(:"@#{object_name}") }
  count = objects.inject(0) { |sum, object| sum + object.errors.count }
  if count.zero?
    ''
  else
    error_messages = objects.map { |object| object.errors.full_messages.map { |msg| tag.div(msg) } }.join
    [
      tag.td(class: 'error item') { "Your #{params.first} has not been created." },
      tag.td(class: 'error') { raw(error_messages) }
    ].join.html_safe
  end
end