Module: Flightdeck::JobsHelper

Defined in:
app/helpers/flightdeck/jobs_helper.rb

Constant Summary collapse

STATE_LABELS =
{
  all: "All",
  ready: "Ready",
  scheduled: "Scheduled",
  in_progress: "In progress",
  blocked: "Blocked",
  finished: "Finished",
  failed: "Failed",
  unknown: "Unknown"
}.freeze
PILL_CLASSES =
{
  ready: "ready",
  scheduled: "scheduled",
  in_progress: "progress",
  blocked: "blocked",
  finished: "finished",
  failed: "failed",
  unknown: "scheduled"
}.freeze

Instance Method Summary collapse

Instance Method Details

#dom_id_for_job(id) ⇒ Object



102
# File 'app/helpers/flightdeck/jobs_helper.rb', line 102

def dom_id_for_job(id) = "fd-job-#{id}"

#fd_ago(time) ⇒ Object



60
61
62
63
64
# File 'app/helpers/flightdeck/jobs_helper.rb', line 60

def fd_ago(time)
  return "" if time.blank?

  "#{fd_duration(Time.current - time)} ago"
end

#fd_args_preview(preview, length: 120) ⇒ Object

Shows the job's own arguments rather than the ActiveJob envelope they are wrapped in; see Flightdeck::ArgumentsPreview.



92
93
94
# File 'app/helpers/flightdeck/jobs_helper.rb', line 92

def fd_args_preview(preview, length: 120)
  Flightdeck::ArgumentsPreview.format(preview, length: length)
end

#fd_count(count, capped: false) ⇒ Object

Counts are capped by JobsQuery, so a capped value is rendered as "500,000+" rather than pretending to be exact.



39
40
41
# File 'app/helpers/flightdeck/jobs_helper.rb', line 39

def fd_count(count, capped: false)
  "#{number_with_delimiter(count)}#{"+" if capped}"
end

#fd_current_list_urlObject

The frame refreshes itself by re-requesting the URL it is showing, so filters, state tab and cursor all survive a poll.



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

def fd_current_list_url
  jobs_path(request.query_parameters)
end

#fd_duration(seconds) ⇒ Object



56
57
58
# File 'app/helpers/flightdeck/jobs_helper.rb', line 56

def fd_duration(seconds)
  seconds.nil? ? "" : Flightdeck::Duration.humanize(seconds)
end

#fd_error_cell(summary, grouped: false) ⇒ Object

Under an exception-class group header, repeating the class on every row is noise — the message is the part that differs.



106
107
108
109
110
111
# File 'app/helpers/flightdeck/jobs_helper.rb', line 106

def fd_error_cell(summary, grouped: false)
  return "" unless summary.present?

  text = grouped ? summary.message.presence || summary.exception_class : summary.to_s
  text.to_s
end

#fd_full_time(time) ⇒ Object



50
51
52
53
54
# File 'app/helpers/flightdeck/jobs_helper.rb', line 50

def fd_full_time(time)
  return "" if time.blank?

  time.in_time_zone(Flightdeck.config.display_timezone).strftime("%Y-%m-%d %H:%M:%S %Z")
end

#fd_progress_label(row) ⇒ Object

Best-effort "what has this job been doing" column. Only ever derived from timestamps Solid Queue actually keeps — nothing here is estimated.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'app/helpers/flightdeck/jobs_helper.rb', line 68

def fd_progress_label(row)
  case row.state
  when :ready
    "waited #{fd_duration(Time.current - row.due_at)}"
  when :scheduled
    row.scheduled_at&.future? ? "due in #{fd_duration(row.scheduled_at - Time.current)}" : "due now"
  when :in_progress
    started = row.execution_started_at
    return "running" unless started

    "waited #{fd_duration(started - row.due_at)} · running #{fd_duration(Time.current - started)}"
  when :blocked
    row.concurrency_key.presence ? "concurrency: #{row.concurrency_key}" : "blocked"
  when :finished
    row.finished_at ? "total #{fd_duration(row.finished_at - row.enqueued_at)}" : ""
  when :failed
    row.failed_at ? "failed after #{fd_duration(row.failed_at - row.due_at)}" : ""
  else
    ""
  end
end

#fd_queue_badge(queue_name) ⇒ Object



33
34
35
# File 'app/helpers/flightdeck/jobs_helper.rb', line 33

def fd_queue_badge(queue_name)
  tag.span(queue_name.presence || "", class: "fd-qbadge")
end

#fd_state_label(state) ⇒ Object



26
# File 'app/helpers/flightdeck/jobs_helper.rb', line 26

def fd_state_label(state) = STATE_LABELS.fetch(state.to_sym, state.to_s.humanize)

#fd_state_pill(state) ⇒ Object



28
29
30
31
# File 'app/helpers/flightdeck/jobs_helper.rb', line 28

def fd_state_pill(state)
  tag.span(fd_state_label(state).upcase,
           class: "fd-pill #{PILL_CLASSES.fetch(state.to_sym, "scheduled")}")
end

#fd_time(time) ⇒ Object



43
44
45
46
47
48
# File 'app/helpers/flightdeck/jobs_helper.rb', line 43

def fd_time(time)
  return "" if time.blank?

  tag.span(time.in_time_zone(Flightdeck.config.display_timezone).strftime("%H:%M:%S"),
           title: fd_full_time(time))
end

#fd_toast_level_class(level) ⇒ Object



113
114
115
# File 'app/helpers/flightdeck/jobs_helper.rb', line 113

def fd_toast_level_class(level)
  level.to_sym == :error ? "fd-toast error" : "fd-toast"
end