Module: SolidObserver::ApplicationHelper

Includes:
DashboardHelper
Defined in:
app/helpers/solid_observer/application_helper.rb

Constant Summary collapse

STATUS_COLORS =
{
  "completed" => "success",
  "ready" => "success",
  "failed" => "danger",
  "retry_stopped" => "danger",
  "scheduled" => "warning",
  "claimed" => "warning",
  "enqueued" => "info",
  "discarded" => "info"
}.freeze
DURATION_SEMANTICS =
{
  "job_enqueued" => "Time spent in the ActiveJob enqueue call (Rails internal; typically sub-millisecond to single-digit ms)",
  "job_completed" => "Time spent performing the job",
  "job_failed" => "Time spent performing the job before the exception was raised",
  "job_discarded" => "Time before discard decision was made"
}.freeze
STABILITY_STATES =
{
  stable: {label: "Stable", tone: "success"},
  degraded: {label: "Degraded", tone: "warning"},
  critical: {label: "Critical", tone: "danger"}
}.freeze
CACHE_OUTCOME_STATES =
{
  hit: {label: "Hit", tone: "success"},
  miss: {label: "Miss", tone: "info"},
  error: {label: "Error", tone: "danger"},
  recorded: {label: "Recorded", tone: "recorded"}
}.freeze
CACHE_RANGE_LABELS =
{
  "15m" => "in last 15m",
  "30m" => "in last 30m",
  "1h" => "in last hour",
  "7h" => "in last 7h",
  "1d" => "in last day",
  "7d" => "in last 7d",
  "14d" => "in last 14d"
}.freeze

Constants included from DashboardHelper

DashboardHelper::RANGE_LABELS, DashboardHelper::SVG_H, DashboardHelper::SVG_W

Instance Method Summary collapse

Methods included from DashboardHelper

#build_spark_context, #format_spark_point, #range_label, #spark_points

Instance Method Details

#cache_component_enabled?Boolean

Returns:

  • (Boolean)


188
189
190
# File 'app/helpers/solid_observer/application_helper.rb', line 188

def cache_component_enabled?
  SolidObserver.config.solid_cache_enabled?
end

#cache_event_digest(key_digest, visible_chars: 10) ⇒ Object



147
148
149
150
151
152
153
# File 'app/helpers/solid_observer/application_helper.rb', line 147

def cache_event_digest(key_digest, visible_chars: 10)
  digest = key_digest.to_s
  return "" if digest.empty?
  return digest if digest.length <= visible_chars

  "#{digest.first(visible_chars)}"
end

#cache_event_outcome_badge(event) ⇒ Object



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

def cache_event_outcome_badge(event)
  meta = cache_event_outcome_meta(event)
  dot = tag.svg(
    tag.circle(r: 3, cx: 3, cy: 3),
    class: "so-badge__dot",
    viewBox: "0 0 6 6",
    "aria-hidden": "true"
  )

  tag.span(class: "so-badge so-badge--pill so-badge--#{meta[:tone]}") do
    safe_join([dot, meta[:label]], " ")
  end
end

#cache_range_label(range_key) ⇒ Object



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

def cache_range_label(range_key)
  CACHE_RANGE_LABELS.fetch(range_key.to_s, "in selected range")
end

#cache_ratio_percent(value) ⇒ Object



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

def cache_ratio_percent(value)
  number_to_percentage(value.to_f * 100, precision: 1, strip_insignificant_zeros: true)
end

#cache_stability_badge(state) ⇒ Object



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

def cache_stability_badge(state)
  stability_badge_for(state.to_sym)
end

#cache_stability_detail(stability) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'app/helpers/solid_observer/application_helper.rb', line 159

def cache_stability_detail(stability)
  state = (stability || {})[:state]&.to_sym
  state = :stable unless STABILITY_STATES.key?(state)

  case state
  when :critical
    critical_cache_stability_detail(stability)
  when :degraded
    degraded_cache_stability_detail(stability)
  else
    "No sampled cache errors or slow events in the selected range"
  end
end

#cache_storage_summary(storage_components) ⇒ Object



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

def cache_storage_summary(storage_components)
  snapshots = Array(storage_components)
  reason = cache_storage_unavailable_reason(snapshots)
  return {value: "", subtitle: "#{reason}"} if reason

  {
    value: number_to_human_size(cache_storage_total_bytes(snapshots), precision: 1, significant: false, strip_insignificant_zeros: false),
    subtitle: "SolidCache + cache observer"
  }
end

#dashboard_section_active?(component) ⇒ Boolean

Returns:

  • (Boolean)


192
193
194
195
# File 'app/helpers/solid_observer/application_helper.rb', line 192

def dashboard_section_active?(component)
  current_component = @component.presence || "queue"
  controller_name == "dashboard" && current_component == component.to_s
end

#duration_with_semantic(value, event_type) ⇒ Object



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

def duration_with_semantic(value, event_type)
  return (:span, "", class: "so-text-muted") unless value

  (:abbr, format_duration(value), title: DURATION_SEMANTICS.fetch(event_type.to_s))
end

#execution_status(execution) ⇒ Object



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

def execution_status(execution)
  ExecutionPresenter.new(execution).status
end

#format_duration(seconds) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'app/helpers/solid_observer/application_helper.rb', line 50

def format_duration(seconds)
  return "0ms" if seconds.to_f.zero?

  if seconds < 1
    "#{(seconds * 1000).round}ms"
  else
    "#{"%.1f" % seconds}s"
  end
end

#latest_failure_phrase(timestamp) ⇒ Object



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

def latest_failure_phrase(timestamp)
  timestamp ? "#{time_ago_in_words(timestamp)} ago" : "unknown"
end

#mode_badgeObject



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

def mode_badge
  config = SolidObserver.config
  color = config.persistence_mode? ? "info" : "warning"
  dot = tag.svg(
    tag.circle(r: 3, cx: 3, cy: 3),
    class: "so-badge__dot",
    viewBox: "0 0 6 6",
    "aria-hidden": "true"
  )
  tag.span(class: "so-badge so-badge--pill so-badge--#{color}") do
    safe_join([dot, config.storage_mode.to_s.capitalize], " ")
  end
end

#queue_component_enabled?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'app/helpers/solid_observer/application_helper.rb', line 184

def queue_component_enabled?
  SolidObserver.config.solid_queue_enabled?
end

#stability_badge(stats) ⇒ Object



110
111
112
# File 'app/helpers/solid_observer/application_helper.rb', line 110

def stability_badge(stats)
  stability_badge_for(stability_state(stats))
end

#stability_detail(stats) ⇒ Object



173
174
175
176
177
178
# File 'app/helpers/solid_observer/application_helper.rb', line 173

def stability_detail(stats)
  failures_24h = stats[:failed_last_24h].to_i
  return "No failures in the last 24h" if failures_24h.zero?

  "#{pluralize(failures_24h, "failure")} in the last 24h, latest #{latest_failure_phrase(stats[:latest_failure_at])}"
end

#stability_state(stats) ⇒ Object



103
104
105
106
107
108
# File 'app/helpers/solid_observer/application_helper.rb', line 103

def stability_state(stats)
  return :critical if stats[:failed_last_hour].to_i.positive?
  return :degraded if stats[:failed_last_24h].to_i.positive?

  :stable
end

#status_badge(status) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/helpers/solid_observer/application_helper.rb', line 60

def status_badge(status)
  status_str = status.to_s
  color = STATUS_COLORS.fetch(status_str, "default")
  dot = tag.svg(
    tag.circle(r: 3, cx: 3, cy: 3),
    class: "so-badge__dot",
    viewBox: "0 0 6 6",
    "aria-hidden": "true"
  )
  tag.span(class: "so-badge so-badge--pill so-badge--#{color}") do
    safe_join([dot, status_str.humanize], " ")
  end
end

#turbo_frame_tag(id, **options, &block) ⇒ Object



94
95
96
97
98
99
100
101
# File 'app/helpers/solid_observer/application_helper.rb', line 94

def turbo_frame_tag(id, **options, &block)
  return super if defined?(super)

  content = options.delete(:content)
  body = block_given? ? capture(&block) : content

  (:"turbo-frame", body, **options.merge(id: id).compact)
end