Module: Karafka::Web::Ui::Helpers::ApplicationHelper

Included in:
Base
Defined in:
lib/karafka/web/ui/helpers/application_helper.rb

Overview

Main application helper

Instance Method Summary collapse

Instance Method Details

#deep_merge(hash1, hash2) ⇒ Hash

Merges two hashes deeply, combining nested hashes recursively.

Parameters:

  • hash1 (Hash)

    The first hash to merge.

  • hash2 (Hash)

    The second hash to merge.

Returns:

  • (Hash)

    A new hash that is the result of a deep merge of the two provided hashes.



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 353

def deep_merge(hash1, hash2)
  merged_hash = hash1.dup

  hash2.each_pair do |k, v|
    tv = merged_hash[k]

    merged_hash[k] = if tv.is_a?(Hash) && v.is_a?(Hash)
      deep_merge(tv, v)
    else
      v
    end
  end

  merged_hash
end

#empty_state(message, icon: "inbox", description: nil, action: nil, action_path: nil, card: nil, &block) ⇒ String

Renders the standardized "nothing here" empty state (icon + message, optionally with a description and a call-to-action button). The description can also be given as a block, in which case it may contain arbitrary markup (e.g. a checklist).

Parameters:

  • message (String)

    primary message describing what's empty

  • icon (String, Symbol) (defaults to: "inbox")

    one of: inbox, document, search, folder, key

  • description (String, nil) (defaults to: nil)

    optional secondary, smaller explanatory text

  • action (String, nil) (defaults to: nil)

    optional call-to-action button label

  • action_path (String, nil) (defaults to: nil)

    path the call-to-action button should link to

  • card (Boolean, nil) (defaults to: nil)

    whether to wrap the state in a bordered card (default true)

  • block (Proc)

    optional block producing the description markup

Returns:

  • (String)

    empty state html



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 324

def empty_state(
  message,
  icon: "inbox",
  description: nil,
  action: nil,
  action_path: nil,
  card: nil,
  &block
)
  description = capture_erb(&block) if block

  inject_erb partial(
    "shared/empty_state",
    locals: {
      message: message,
      icon_name: icon,
      description: description,
      action: action,
      action_path: action_path,
      card: card
    }
  )
end

#flat_hash(hash, parent_key = nil, result = {}) ⇒ Hash

Parameters:

  • hash (Hash)

    we want to flatten

  • parent_key (String) (defaults to: nil)

    key for recursion

  • result (Hash) (defaults to: {})

    result for recursion

Returns:

  • (Hash)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 215

def flat_hash(hash, parent_key = nil, result = {})
  hash.each do |key, value|
    current_key = parent_key ? "#{parent_key}.#{key}" : key.to_s
    if value.is_a?(Hash)
      flat_hash(value, current_key, result)
    elsif value.is_a?(Array)
      value.each_with_index do |item, index|
        flat_hash({ index => item }, current_key, result)
      end
    else
      result[current_key] = value
    end
  end

  result
end

#format_memory(mem_kb) ⇒ String

Returns formatted memory usage.

Parameters:

  • mem_kb (Integer)

    memory used in KB

Returns:

  • (String)

    formatted memory usage



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 107

def format_memory(mem_kb)
  return "0" if !mem_kb || mem_kb.zero?

  if mem_kb < 10_240
    "#{number_with_delimiter(mem_kb.round(4))} KB"
  elsif mem_kb < 1_000_000
    "#{number_with_delimiter((mem_kb / 1024.0).to_i)} MB"
  else
    "#{number_with_delimiter((mem_kb / (1024.0 * 1024.0)).round(1))} GB"
  end
end

#icon(name, size: nil) ⇒ String

Renders the svg icon out of our icon set

Parameters:

  • name (String, Symbol)

    name of the icon

  • size (Integer, nil) (defaults to: nil)

    optional size override (defaults to the icon's own size)

Returns:

  • (String)

    svg icon



308
309
310
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 308

def icon(name, size: nil)
  render "shared/icons/_#{name}", locals: { size: size }
end

#kafka_state_badge(state) ⇒ String

Takes a kafka report state and recommends background style color

Parameters:

  • state (String)

    state

Returns:

  • (String)

    background style



95
96
97
98
99
100
101
102
103
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 95

def kafka_state_badge(state)
  case state
  when "up" then "badge-success"
  when "active" then "badge-success"
  when "steady" then "badge-success"
  else
    "badge-warning"
  end
end

#lag_trend_badge(trend) ⇒ String

Takes the lag trend and gives it appropriate background style color for badge

Parameters:

  • trend (Numeric)

    lag trend

Returns:

  • (String)

    bg classes



75
76
77
78
79
80
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 75

def lag_trend_badge(trend)
  bg = "badge-success" if trend.negative?
  bg ||= "badge-warning" if trend.positive?
  bg ||= "badge-secondary"
  bg
end

#lag_with_label(lag) ⇒ String

Returns lag if correct or N/A with labeled explanation.

Parameters:

  • lag (Integer)

    lag

Returns:

  • (String)

    lag if correct or N/A with labeled explanation

See Also:



134
135
136
137
138
139
140
141
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 134

def lag_with_label(lag)
  if lag.negative?
    title = "Not available until first offset commit"
    %(<span class="badge badge-secondary" title="#{title}">N/A</span>)
  else
    lag.to_s
  end
end

#lso_risk_state_badge(details) ⇒ String

Returns background classes for row marking.

Parameters:

Returns:

  • (String)

    background classes for row marking



190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 190

def lso_risk_state_badge(details)
  case details.lso_risk_state
  when :active
    ""
  when :at_risk
    "badge-warning"
  when :stopped
    "badge-error"
  else
    raise ::Karafka::Errors::UnsupportedCaseError
  end
end

#lso_risk_state_bg(details) ⇒ String

Returns background classes for row marking.

Parameters:

Returns:

  • (String)

    background classes for row marking



174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 174

def lso_risk_state_bg(details)
  case details.lso_risk_state
  when :active
    ""
  when :at_risk
    "bg-warning bg-opacity-25"
  when :stopped
    "bg-error bg-opacity-25"
  else
    raise ::Karafka::Errors::UnsupportedCaseError
  end
end

Adds active class to the current location in the nav if needed

Parameters:

  • location (Hash)


35
36
37
38
39
40
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 35

def nav_class(location)
  comparator, value = location.to_a.first

  local_location = request.path.gsub(env.fetch("SCRIPT_NAME"), "")
  local_location.public_send(:"#{comparator}?", value) ? "active" : ""
end

#normalized_metric(value) ⇒ String

Normalizes the metric value for display. Negative values coming from statistics usually mean, that the value is not (yet) available.

Parameters:

  • value (Integer)

Returns:

  • (String)

    input value if not negative or N/A



167
168
169
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 167

def normalized_metric(value)
  value.negative? ? "N/A" : value.to_s
end

#number_with_delimiter(number, delimiter = ",") ⇒ String

Converts number to a more friendly delimiter based version

Parameters:

  • number (Numeric)
  • delimiter (String) (defaults to: ",")

    delimiter (comma by default)

Returns:

  • (String)

    number with delimiter



123
124
125
126
127
128
129
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 123

def number_with_delimiter(number, delimiter = ",")
  return "" unless number

  parts = number.to_s.to_str.split(".")
  parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
  parts.join(".")
end

#object_value_to_s(object) ⇒ String

Converts object into a string and for objects that would anyhow return their stringified instance value, it replaces it with the class name instead. Useful for deserializers, etc presentation.

Parameters:

  • object (Object)

Returns:

  • (String)


48
49
50
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 48

def object_value_to_s(object)
  object.to_s.include?("#<") ? object.class.to_s : object.to_s
end

#offset_with_label(topic_name, partition_id, offset, explore: false) ⇒ String

Returns offset if correct or N/A with labeled explanation for offsets that are less than 0. Offset with less than 0 indicates, that the offset was not yet committed and there is no value we know of.

Parameters:

  • topic_name (String)

    name of the topic for explorer path

  • partition_id (Integer)

    partition for the explorer path

  • offset (Integer)

    offset

  • explore (Boolean) (defaults to: false)

    should we generate (when allowed) a link to message explorer

Returns:

  • (String)

    offset if correct or N/A with labeled explanation for offsets that are less than 0. Offset with less than 0 indicates, that the offset was not yet committed and there is no value we know of



150
151
152
153
154
155
156
157
158
159
160
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 150

def offset_with_label(topic_name, partition_id, offset, explore: false)
  if offset.negative?
    title = "Not available until first offset commit"
    %(<span class="badge badge-secondary" title="#{title}">N/A</span>)
  elsif explore
    path = explorer_topics_path(topic_name, partition_id, offset)
    %(<a href="#{path}">#{offset}</a>)
  else
    offset.to_s
  end
end

Returns html link for sorting with arrow when attribute sort enabled.

Parameters:

  • name (String)

    link value

  • attribute (Symbol, nil) (defaults to: nil)

    sorting attribute or nil if we provide only symbol name

  • rev (Boolean) (defaults to: false)

    when set to true, arrows will be in the reverse position. This is used when the description in the link is reverse to data we sort. For example we have order on when processes were started and we display "x hours" ago but we sort on their age, meaning that it looks like it is the other way around. This flag allows us to reverse just he arrow making it look consistent with the presented data order

Returns:

  • (String)

    html link for sorting with arrow when attribute sort enabled



240
241
242
243
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
272
273
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 240

def sort_link(name, attribute = nil, rev: false)
  unless attribute
    attribute = name

    if SORT_NAMES[attribute]
      name = SORT_NAMES[attribute]
    else
      name = attribute.to_s.tr("_", " ").tr("?", "")
      # Always capitalize the name
      name = name.split.map(&:capitalize).join(" ")
    end
  end

  arrow_both = "&#x21D5;"
  arrow_down = "&#9662;"
  arrow_up = "&#9652;"

  desc = "#{attribute} desc"
  asc = "#{attribute} asc"
  path = current_path(sort: desc)
  full_name = "#{name}&nbsp;#{arrow_both}"

  if params.current_sort == desc
    path = current_path(sort: asc)
    full_name = "#{name}&nbsp;#{rev ? arrow_up : arrow_down}"
  end

  if params.current_sort == asc
    path = current_path(sort: desc)
    full_name = "#{name}&nbsp;#{rev ? arrow_down : arrow_up}"
  end

  "<a class=\"sort\" href=\"#{path}\">#{full_name}</a>"
end

#status_badge(status) ⇒ String

Takes a status and recommends background style color

Parameters:

  • status (String)

    status

Returns:

  • (String)

    background style



56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 56

def status_badge(status)
  case status
  when "initialized" then "badge-success"
  when "supervising" then "badge-success"
  when "running" then "badge-success"
  when "quieting" then "badge-warning"
  when "quiet" then "badge-warning"
  when "stopping" then "badge-warning"
  when "stopped" then "badge-error"
  when "terminated" then "badge-error"
  else
    raise ::Karafka::Errors::UnsupportedCaseError, status
  end
end

#tags(tags_array) ⇒ String

Renders tags one after another

Parameters:

  • tags_array (Array<String>)

Returns:

  • (String)

    tags badges



86
87
88
89
90
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 86

def tags(tags_array)
  tags_array
    .map { |tag| %(<span class="badge badge-info">#{tag}</span>) }
    .join(" ")
end

#truncate(string, length: 50, omission: "...", strategy: :default) ⇒ String

Truncates given text if it is too long and wraps it with a title with full text. Can use a middle-based strategy that keeps beginning and ending of a string instead of keeping just the beginning.

The :middle strategy is useful when we have strings such as really long process names that have important beginning and end but middle can be removed without risk of not allowing user to recognize the content.

Parameters:

  • string (String)

    string we want to truncate

  • length (Integer) (defaults to: 50)

    max length of the final string that we accept before truncating

  • omission (String) (defaults to: "...")

    truncation omission

  • strategy (Symbol) (defaults to: :default)

    :default or :middle how should we truncate

Returns:

  • (String)

    HTML span tag with truncated content and full content title



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 288

def truncate(string, length: 50, omission: "...", strategy: :default)
  return string if string.length <= length

  case strategy
  when :default
    truncated = string[0...(length - omission.length)] + omission
  when :middle
    part_length = (length - omission.length) / 2
    truncated = string[0...part_length] + omission + string[-part_length..]
  else
    raise Karafka::Errors::UnsupportedCaseError, "Unknown strategy: #{strategy}"
  end

  %(<span title="#{string}">#{truncated}</span>)
end

#view_title(title) ⇒ String

Sets the particular page title

Parameters:

  • title (String)

    page title

Returns:

  • (String)

    title html



207
208
209
# File 'lib/karafka/web/ui/helpers/application_helper.rb', line 207

def view_title(title)
  content_for(:title) { title }
end