good_job 3.0.2 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,122 +1,151 @@
1
- <div class="my-3">
2
- <div class="table-responsive">
3
- <%= form_with(url: mass_update_jobs_path(filter.to_params), method: :put, local: true, data: { "checkbox-toggle": "job_ids" }) do |form| %>
4
- <table class="table table-hover table-sm mb-0 table-jobs">
5
- <thead>
6
- <tr>
7
- <th><%= check_box_tag('toggle_job_ids', "1", false, data: { "checkbox-toggle-all": "job_ids" }) %></th>
8
- <th>ActiveJob ID</th>
9
- <th>State</th>
10
- <th>Job Class</th>
11
- <th>Queue</th>
12
- <th>Scheduled At</th>
13
- <th>Executions</th>
14
- <th>Error</th>
15
- <th>
16
- ActiveJob Params&nbsp;
17
- <%= tag.button "Toggle", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
18
- data: { bs_toggle: "collapse", bs_target: ".job-params" },
19
- aria: { expanded: false, controls: jobs.map { |job| "##{dom_id(job, "params")}" }.join(" ") }
20
- %>
21
- </th>
22
- <th>
23
- Actions<br>
1
+ <%= form_with(url: mass_update_jobs_path(filter.to_params), method: :put, local: true, data: { "checkbox-toggle": "job_ids" }) do |form| %>
2
+ <div class="my-3 card" data-gj-poll-replace id="jobs-table">
3
+ <div class="list-group list-group-flush text-nowrap table-jobs" role="table">
4
+ <header class="list-group-item bg-light">
5
+ <div class="row small text-muted text-uppercase align-items-center">
6
+ <div class="col-auto">
7
+ <%= check_box_tag('toggle_job_ids', "1", false, data: { "checkbox-toggle-all": "job_ids" }) %>
8
+ </div>
9
+ <div class="col-4">
10
+ <%= form.button type: 'submit', name: 'mass_action', value: 'reschedule', class: 'btn btn-sm btn-outline-secondary', title: "Reschedule all", data: { confirm: "Are you sure you want to reschedule the selected jobs?", disable: true } do %>
11
+ <span class="me-1"><%= render_icon "skip_forward" %></span> Reschedule
12
+ <% end %>
24
13
 
25
- <div class="d-inline text-nowrap">
26
- <%= form.button type: 'submit', name: 'mass_action', value: 'reschedule', class: 'btn btn-sm btn-outline-primary', title: "Reschedule all", data: { confirm: "Confirm reschedule all", disable: true } do %>
27
- <%= render_icon "skip_forward" %> All
28
- <% end %>
14
+ <%= form.button type: 'submit', name: 'mass_action', value: 'retry', class: 'btn btn-sm btn-outline-secondary', title: "Retry all", data: { confirm: "Are you sure you want to retry the selected jobs?", disable: true } do %>
15
+ <span class="me-1"><%= render_icon "arrow_clockwise" %></span> Retry
16
+ <% end %>
29
17
 
30
- <%= form.button type: 'submit', name: 'mass_action', value: 'discard', class: 'btn btn-sm btn-outline-primary', title: "Discard all", data: { confirm: "Confirm discard all", disable: true } do %>
31
- <%= render_icon "stop" %> All
18
+ <div class="btn-group" role="group">
19
+ <%= form.button type: 'submit', name: 'mass_action', value: 'discard', class: 'btn btn-sm btn-outline-secondary', title: "Discard all", data: { confirm: "Are you usure you want to discard the selected jobs?", disable: true } do %>
20
+ <span class="me-1"><%= render_icon "stop" %></span> Discard
21
+ <% end %>
22
+ <button id="destroy-dropdown-toggle" type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
23
+ <span class="visually-hidden">Toggle Actions</span>
24
+ </button>
25
+ <div class="dropdown-menu" aria-labelledby="destroy-dropdown-toggle">
26
+ <li>
27
+ <%= form.button type: 'submit', name: 'mass_action', value: 'destroy', class: 'btn', title: "Destroy all", data: { confirm: "Are you sure you want to destroy the selected jobs?", disable: true } do %>
28
+ <span class="me-1"><%= render_icon "trash" %></span> Destroy
32
29
  <% end %>
30
+ </li>
31
+ </div>
32
+ </div>
33
33
 
34
- <%= form.button type: 'submit', name: 'mass_action', value: 'retry', class: 'btn btn-sm btn-outline-primary', title: "Retry all", data: { confirm: "Confirm retry all", disable: true } do %>
35
- <%= render_icon "arrow_clockwise" %> All
36
- <% end %>
34
+ </div>
35
+ <div class="col-1">Queue</div>
36
+ <div class="col-1">Priority</div>
37
+ <div class="col-1 text-end">Attempts</div>
38
+ <div class="col text-end">
39
+ <%= tag.button type: "button", class: "btn btn-sm text-muted", role: "button",
40
+ data: { bs_toggle: "collapse", bs_target: ".job-params" },
41
+ aria: { expanded: false, controls: jobs.map { |job| "##{dom_id(job, "params")}" }.join(" ") } do %>
42
+ <%= render_icon "info" %>
43
+ <span class="visually-hidden">Inspect</span>
44
+ <% end %>
45
+ </div>
46
+ </div>
47
+ </header>
48
+ <label role="row" class="list-group-item list-group-item-warning list-group-item-action py-3 d-none" data-checkbox-toggle-show="job_ids">
49
+ <div class="row">
50
+ <div class="col-auto">
51
+ <%= check_box_tag "all_job_ids", 1, false, disabled: true, data: { "checkbox-toggle-show": "job_ids"} %>
52
+ </div>
53
+ <div class="col-auto">
54
+ Apply to all <%= filter.filtered_count %> <%= "job".pluralize(filter.filtered_count) %>.
55
+ </div>
56
+ </div>
57
+ </label>
37
58
 
38
- <%= form.button type: 'submit', name: 'mass_action', value: 'destroy', class: 'btn btn-sm btn-outline-primary', title: "Destroy all", data: { confirm: "Confirm destroy all", disable: true } do %>
39
- <%= render_icon "trash" %> All
40
- <% end %>
41
- </div>
42
- </th>
43
- </tr>
44
- <tr class="d-none" data-checkbox-toggle-show="job_ids">
45
- <td class="text-center table-warning" colspan="10">
46
- <label>
47
- <%= check_box_tag "all_job_ids", 1, false, disabled: true, data: { "checkbox-toggle-show": "job_ids"} %>
48
- Apply to all <%= filter.filtered_count %> <%= "job".pluralize(filter.filtered_count) %>.
49
- </label>
50
- </td>
51
- </tr>
52
- </thead>
53
- <tbody>
54
- <% if jobs.present? %>
55
- <% jobs.each do |job| %>
56
- <tr class="<%= dom_class(job) %>" id="<%= dom_id(job) %>">
57
- <td><%= check_box_tag 'job_ids[]', job.id, false, data: { "checkbox-toggle-each": "job_ids" } %></td>
58
- <td>
59
- <%= link_to job_path(job.id) do %>
60
- <code><%= job.id %></code>
61
- <% end %>
62
- </td>
63
- <td><%= status_badge(job.status) %></td>
64
- <td><%= job.job_class %></td>
65
- <td><%= job.queue_name %></td>
66
- <td><%= relative_time(job.scheduled_at || job.created_at) %></td>
67
- <td><%= job.executions_count %></td>
68
- <td class="text-break"><%= truncate(job.recent_error, length: 1_000) %></td>
69
- <td>
70
- <%= tag.button "Inspect", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
71
- data: { bs_toggle: "collapse", bs_target: "##{dom_id(job, 'params')}" },
72
- aria: { expanded: false, controls: dom_id(job, "params") }
73
- %>
74
- <%= tag.pre JSON.pretty_generate(job.serialized_params), id: dom_id(job, "params"), class: "collapse job-params" %>
75
- </td>
76
- <td>
77
- <div class="text-nowrap">
78
- <% if job.status.in? [:scheduled, :retried, :queued] %>
79
- <%= link_to reschedule_job_path(job.id), method: :put, class: "btn btn-sm btn-outline-primary", title: "Reschedule job", data: { confirm: "Confirm reschedule", disable: true } do %>
80
- <%= render_icon "skip_forward" %>
81
- <% end %>
82
- <% else %>
83
- <button class="btn btn-sm btn-outline-secondary" disabled><%= render_icon "skip_forward" %></button>
59
+ <% if jobs.present? %>
60
+ <% jobs.each do |job| %>
61
+ <%= label_tag dom_id(job, :checkbox), id: dom_id(job), role: "row", class: "list-group-item list-group-item-action py-3" do %>
62
+ <div class="row align-items-center">
63
+ <div class="col-auto">
64
+ <%= check_box_tag 'job_ids[]', job.id, false, id: dom_id(job, :checkbox), data: { "checkbox-toggle-each": "job_ids" } %>
65
+ </div>
66
+ <div class="col-4">
67
+ <%= tag.code link_to(job.id, job_path(job), class: "small text-muted text-decoration-none") %>
68
+ <%= tag.h5 tag.code(link_to(job.job_class, job_path(job), class: "text-reset text-decoration-none")), class: "text-reset mb-0" %>
69
+ </div>
70
+ <div class="col-1">
71
+ <span class="badge bg-primary bg-opacity-25 text-dark font-monospace"><%= job.queue_name %></span>
72
+ </div>
73
+ <div class="col-1 small text-center">
74
+ <span class="font-monospace fw-bold"><%= job.priority %></span>
75
+ </div>
76
+ <div class="col-1 text-center">
77
+ <% if job.executions_count > 0 && job.status != :finished %>
78
+ <%= tag.span job.executions_count, class: "badge rounded-pill bg-danger", data: {
79
+ bs_toggle: "popover",
80
+ bs_trigger: "hover focus click",
81
+ bs_placement: "bottom",
82
+ bs_content: job.recent_error
83
+ } %>
84
+ <% else %>
85
+ <span class="badge bg-secondary bg-opacity-50 rounded-pill"><%= job.executions_count %></span>
86
+ <% end %>
87
+ </div>
88
+ <div class="col d-flex gap-3 align-items-center justify-content-end">
89
+ <%= tag.span relative_time(job.last_status_at), class: "small" %>
90
+ <%= status_badge job.status %>
91
+ </div>
92
+ <div class="col-auto">
93
+ <div class="dropdown float-end">
94
+ <button class="d-flex align-items-center btn btn-sm" type="button" id="<%= dom_id(job, :actions) %>" data-bs-toggle="dropdown" aria-expanded="false">
95
+ <%= render "good_job/shared/icons/dots" %>
96
+ <span class="visually-hidden">Actions</span>
97
+ </button>
98
+ <ul class="dropdown-menu shadow" aria-labelledby="<%= dom_id(job, :actions) %>">
99
+ <li>
100
+ <% job_reschedulable = job.status.in? [:scheduled, :retried, :queued] %>
101
+ <%= link_to reschedule_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job_reschedulable}", title: "Reschedule job", data: { confirm: "Confirm reschedule", disable: true } do %>
102
+ <%= render "good_job/shared/icons/skip_forward" %>
103
+ Reschedule
84
104
  <% end %>
85
-
86
- <% if job.status.in? [:scheduled, :retried, :queued] %>
87
- <%= link_to discard_job_path(job.id), method: :put, class: "btn btn-sm btn-outline-primary", title: "Discard job", data: { confirm: "Confirm discard", disable: true } do %>
88
- <%= render_icon "stop" %>
89
- <% end %>
90
- <% else %>
91
- <button class="btn btn-sm btn-outline-secondary" disabled><%= render_icon "stop" %></button>
105
+ </li>
106
+ <li>
107
+ <% job_discardable = job.status.in? [:scheduled, :retried, :queued] %>
108
+ <%= link_to discard_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job_discardable}", title: "Discard job", data: { confirm: "Confirm discard", disable: true } do %>
109
+ <%= render "good_job/shared/icons/stop" %>
110
+ Discard
92
111
  <% end %>
93
-
94
- <% if job.status == :discarded %>
95
- <%= link_to retry_job_path(job.id), method: :put, class: "btn btn-sm btn-outline-primary", title: "Retry job", data: { confirm: "Confirm retry", disable: true } do %>
96
- <%= render_icon "arrow_clockwise" %>
97
- <% end %>
98
- <% else %>
99
- <button class="btn btn-sm btn-outline-secondary" disabled><%= render_icon "arrow_clockwise" %></button>
112
+ </li>
113
+ <li>
114
+ <%= link_to retry_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job.status == :discarded}", title: "Retry job", data: { confirm: "Confirm retry", disable: true } do %>
115
+ <%= render "good_job/shared/icons/arrow_clockwise" %>
116
+ Retry
117
+ <% end %>
118
+ </li>
119
+ <li>
120
+ <%= link_to job_path(job.id), method: :delete, class: "dropdown-item #{'disabled' unless job.status.in? [:discarded, :finished]}", title: "Destroy job", data: { confirm: "Confirm destroy", disable: true } do %>
121
+ <%= render_icon "trash" %>
122
+ Destroy
100
123
  <% end %>
124
+ </li>
101
125
 
102
- <% if job.status.in? [:discarded, :finished] %>
103
- <%= link_to job_path(job.id), method: :delete, class: "btn btn-sm btn-outline-primary", title: "Destroy job", data: { confirm: "Confirm destroy", disable: true } do %>
104
- <%= render_icon "trash" %>
105
- <% end %>
106
- <% else %>
107
- <button class="btn btn-sm btn-outline-secondary" disabled><%= render_icon "trash" %></button>
126
+ <li>
127
+ <%= link_to "##{dom_id(job, 'params')}",
128
+ class: "dropdown-item",
129
+ data: { bs_toggle: "collapse" },
130
+ aria: { expanded: false, controls: dom_id(job, "params") } do %>
131
+ <%= render_icon "info" %>
132
+ Inspect
108
133
  <% end %>
109
- </div>
110
- </td>
111
- </tr>
112
- <% end %>
113
- <% else %>
114
- <tr>
115
- <td colspan="10" class="py-2 text-center text-muted">No jobs found.</td>
116
- </tr>
117
- <% end %>
118
- </tbody>
119
- </table>
134
+ </li>
135
+ </ul>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ <% end %>
140
+ <%= tag.div id: dom_id(job, "params"), class: "job-params list-group-item collapse small bg-dark text-light" do %>
141
+ <%= tag.pre JSON.pretty_generate(job.display_serialized_params) %>
142
+ <% end %>
143
+ <% end %>
144
+ <% else %>
145
+ <div class="list-group-item py-4 text-center text-muted">
146
+ No jobs found.
147
+ </div>
120
148
  <% end %>
121
149
  </div>
122
150
  </div>
151
+ <% end %>
@@ -1,48 +1,57 @@
1
1
  <div class="break-out bg-light border-bottom py-2 mb-3">
2
2
  <div class="container-fluid pt-2">
3
- <div class="d-flex align-items-center">
4
- <div class="flex-fill">
3
+ <div class="row align-items-center">
4
+ <div class="col-5">
5
5
  <nav aria-label="breadcrumb">
6
6
  <ol class="breadcrumb small mb-0">
7
7
  <li class="breadcrumb-item"><%= link_to "Jobs", jobs_path %></li>
8
- <li class="breadcrumb-item active" aria-current="page">ActiveJob ID: <%= tag.code @job.id %></li>
8
+ <li class="breadcrumb-item active" aria-current="page"><%= tag.code @job.id, class: "text-muted" %></li>
9
9
  </ol>
10
10
  </nav>
11
- <h2 class="mb-1"><%= tag.code @job.job_class %></h2>
12
- <div class="text-muted small d-flex gap-2">
13
- <div>Queue: <%= tag.strong @job.queue_name %></div>
14
-
15
- <div>Priority: <%= tag.strong @job.priority %></div>
11
+ <h2 class="mb-0"><%= tag.code @job.job_class %></h2>
12
+ </div>
13
+ <div class="col-2">
14
+ <div class="small text-muted text-uppercase">Queue</div>
15
+ <div class="badge bg-primary bg-opacity-25 text-dark font-monospace my-2">
16
+ <%= tag.strong @job.queue_name %>
16
17
  </div>
17
18
  </div>
18
- <div>
19
- <% job_reschedulable = @job.status.in? [:scheduled, :retried, :queued] %>
20
- <%= button_to reschedule_job_path(@job.id), method: :put,
21
- class: "btn btn-sm #{job_reschedulable ? 'btn-outline-primary' : 'btn-outline-secondary'}",
22
- form_class: "d-inline-block",
23
- disabled: !job_reschedulable,
24
- aria: { label: "Reschedule job" },
25
- title: "Reschedule job",
26
- data: { confirm: "Confirm reschedule" } do %>
27
- <%= render_icon "skip_forward" %>
28
- Reschedule
19
+ <div class="col-2">
20
+ <div class="small text-muted text-uppercase">Priority</div>
21
+ <div class="font-monospace fw-bold small my-2"><%= tag.strong @job.priority %></div>
22
+ </div>
23
+ <div class="col text-end">
24
+ <% if @job.status.in? [:scheduled, :retried, :queued] %>
25
+ <%= button_to reschedule_job_path(@job.id), method: :put,
26
+ class: "btn btn-sm btn-outline-primary",
27
+ form_class: "d-inline-block",
28
+ aria: { label: "Reschedule job" },
29
+ title: "Reschedule job",
30
+ data: { confirm: "Confirm reschedule" } do %>
31
+ <%= render_icon "skip_forward" %>
32
+ Reschedule
33
+ <% end %>
29
34
  <% end %>
30
35
 
31
- <% job_discardable = @job.status.in? [:scheduled, :retried, :queued] %>
32
- <%= button_to discard_job_path(@job.id), method: :put, class: "btn btn-sm #{job_discardable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_discardable, aria: { label: "Discard job" }, title: "Discard job", data: { confirm: "Confirm discard" } do %>
33
- <%= render_icon "stop" %>
34
- Discard
36
+ <% if @job.status.in? [:scheduled, :retried, :queued] %>
37
+ <%= button_to discard_job_path(@job.id), method: :put, class: "btn btn-sm btn-outline-primary", form_class: "d-inline-block", aria: { label: "Discard job" }, title: "Discard job", data: { confirm: "Confirm discard" } do %>
38
+ <%= render_icon "stop" %>
39
+ Discard
40
+ <% end %>
35
41
  <% end %>
36
42
 
37
- <%= button_to retry_job_path(@job.id), method: :put, class: "btn btn-sm #{@job.status == :discarded ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: @job.status != :discarded, aria: { label: "Retry job" }, title: "Retry job", data: { confirm: "Confirm retry" } do %>
38
- <%= render_icon "arrow_clockwise" %>
39
- Retry
43
+ <% if @job.status == :discarded %>
44
+ <%= button_to retry_job_path(@job.id), method: :put, class: "btn btn-sm btn-outline-primary", form_class: "d-inline-block", aria: { label: "Retry job" }, title: "Retry job", data: { confirm: "Confirm retry" } do %>
45
+ <%= render_icon "arrow_clockwise" %>
46
+ Retry
47
+ <% end %>
40
48
  <% end %>
41
49
 
42
- <% job_destroyable = @job.status.in? [:discarded, :finished] %>
43
- <%= button_to job_path(@job.id), method: :delete, class: "btn btn-sm #{job_destroyable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_destroyable, aria: { label: "Destroy job" }, title: "Destroy job", data: { confirm: "Confirm destroy" } do %>
44
- <%= render_icon "trash" %>
45
- Destroy
50
+ <% if @job.status.in? [:discarded, :finished] %>
51
+ <%= button_to job_path(@job.id), method: :delete, class: "btn btn-sm btn-outline-primary", form_class: "d-inline-block", aria: { label: "Destroy job" }, title: "Destroy job", data: { confirm: "Confirm destroy" } do %>
52
+ <%= render_icon "trash" %>
53
+ Destroy
54
+ <% end %>
46
55
  <% end %>
47
56
  </div>
48
57
  </div>
@@ -51,7 +60,7 @@
51
60
 
52
61
  <div class="my-4">
53
62
  <h5>Arguments</h5>
54
- <%= tag.pre @job.serialized_params["arguments"].map(&:inspect).join(', ') %>
63
+ <%= tag.pre @job.serialized_params["arguments"].map(&:inspect).join(', '), class: 'text-wrap text-break' %>
55
64
  </div>
56
65
 
57
- <%= render 'executions', executions: @job.executions.reverse %>
66
+ <%= render 'executions', executions: @job.executions.includes_advisory_locks.reverse %>
@@ -1,38 +1,66 @@
1
- <div class="my-3 flex">
2
- <h2>Processes</h2>
1
+ <div class="bg-light break-out border-bottom">
2
+ <h2 class="container-fluid pt-3 pb-2">Processes</h2>
3
3
  </div>
4
4
 
5
- <div data-live-poll-region="processes">
6
- <% if @processes.present? %>
7
- <div class="card my-3">
8
- <div class="table-responsive">
9
- <table class="table card-table table-bordered table-hover table-sm mb-0">
10
- <thead>
11
- <tr>
12
- <th>Process UUID</th>
13
- <th>Created At</th></th>
14
- <th>State</th>
15
- </tr>
16
- </thead>
17
- <tbody>
18
- <% @processes.each do |process| %>
19
- <tr class="<%= dom_class(process) %>" id="<%= dom_id(process) %>">
20
- <td><%= process.id %></td>
21
- <td><%= relative_time(process.created_at) %></td>
22
- <td><%= tag.pre JSON.pretty_generate(process.state) %></td>
23
- </tr>
5
+ <div class="card my-3" data-live-poll-region="processes">
6
+ <div class="list-group list-group-flush text-nowrap" role="table">
7
+ <header class="list-group-item bg-light">
8
+ <div class="row small text-muted text-uppercase align-items-center">
9
+ <div class="col">Process</div>
10
+ <div class="col">Schedulers</div>
11
+ <div class="col-2 d-flex gap-2">
12
+ <span>Started</span>
13
+ </div>
14
+ <div class="col-auto">
15
+ <%= tag.button type: "button", class: "btn btn-sm text-muted ms-auto", role: "button",
16
+ data: { bs_toggle: "collapse", bs_target: ".process-state" },
17
+ aria: { expanded: false, controls: @processes.map { |process| "##{dom_id(process, 'state')}" }.join(" ") } do %>
18
+ <%= render_icon "info" %>
19
+ <span class="visually-hidden">Inspect</span>
24
20
  <% end %>
25
- </tbody>
26
- </table>
21
+ </div>
27
22
  </div>
28
- </div>
29
- <% else %>
30
- <div class="card my-3">
31
- <div class="card-body">
32
- <p class="card-text">
33
- <em>No GoodJob processes found.</em>
34
- </p>
23
+ </header>
24
+ <% @processes.each do |process| %>
25
+ <div id="<%= dom_id(process) %>" class="<%= dom_class(process) %> list-group-item py-3" role="row">
26
+ <div class="row align-items-center">
27
+ <div class="col">
28
+ <code class="font-monospace">
29
+ <span class="text-muted opacity-50">$</span>
30
+ <%= process.state["proctitle"] %>
31
+ </code>
32
+ <div>
33
+ <span class="text-muted small">PID</span>
34
+ <span class="badge rounded-pill bg-light text-dark"><%= process.state["pid"] %></span>
35
+ <span class="text-muted small">@</span>
36
+ <span class="badge rounded-pill bg-light text-dark"><%= process.state["hostname"] %></span>
37
+ </div>
38
+ </div>
39
+ <div class="col">
40
+ <% process.state["schedulers"].each do |scheduler| %>
41
+ <pre class="mb-0"><%= scheduler %></pre>
42
+ <% end %>
43
+ </div>
44
+ <div class="col-2 small"><%= relative_time(process.created_at) %></div>
45
+ <div class="col-auto">
46
+ <%= tag.button type: "button", class: "btn btn-sm text-muted ms-auto", role: "button",
47
+ title: "Inspect",
48
+ data: { bs_toggle: "collapse", bs_target: "##{dom_id(process, 'state')}" },
49
+ aria: { expanded: false, controls: dom_id(process, "state") } do %>
50
+ <%= render_icon "info" %>
51
+ <span class="visually-hidden">Inspect</span>
52
+ <% end %>
53
+ </div>
54
+ </div>
35
55
  </div>
36
- </div>
37
- <% end %>
56
+ <%= tag.div id: dom_id(process, "state"), class: "process-state list-group-item collapse small bg-dark text-light" do %>
57
+ <%= tag.pre JSON.pretty_generate(process.state) %>
58
+ <% end %>
59
+ <% end %>
60
+ <% if @processes.empty? %>
61
+ <div class="list-group-item py-4 text-center text-muted">
62
+ No GoodJob processes found.
63
+ </div>
64
+ <% end %>
65
+ </div>
38
66
  </div>
@@ -11,7 +11,7 @@
11
11
  <li class="nav-item">
12
12
  <%= link_to url_for({state: name}), class: "nav-link #{"active" if params[:state] == name}" do %>
13
13
  <%= t(name, scope: 'good_job.status') %>
14
- <span class="badge bg-primary rounded-pill <%= "bg-secondary" if count == 0 %>"><%= count %></span>
14
+ <span class="badge bg-primary rounded-pill <%= "bg-secondary" if count == 0 %>"><%= number_with_delimiter(count) %></span>
15
15
  <% end %>
16
16
  </li>
17
17
  <% end %>
@@ -8,13 +8,25 @@
8
8
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
9
9
  <ul class="navbar-nav me-auto">
10
10
  <li class="nav-item">
11
- <%= link_to t(".jobs"), jobs_path, class: ["nav-link", ("active" if controller_name == 'jobs')] %>
11
+ <%= link_to jobs_path, class: ["nav-link", ("active" if controller_name == 'jobs')] do %>
12
+ <%= t(".jobs") %>
13
+ <% jobs_count = GoodJob::Job.count %>
14
+ <span class="badge bg-secondary rounded-pill"><%= number_to_human(jobs_count) %></span>
15
+ <% end %>
12
16
  </li>
13
17
  <li class="nav-item">
14
- <%= link_to t(".cron_schedules"), cron_entries_path, class: ["nav-link", ("active" if controller_name == 'cron_entries')] %>
18
+ <%= link_to cron_entries_path, class: ["nav-link", ("active" if controller_name == 'cron_entries')] do %>
19
+ <%= t(".cron_schedules") %>
20
+ <% cron_entries_count = GoodJob::CronEntry.all.size %>
21
+ <span class="badge bg-secondary rounded-pill"><%= cron_entries_count %></span>
22
+ <% end %>
15
23
  </li>
16
24
  <li class="nav-item">
17
- <%= link_to t(".processes"), processes_path, class: ["nav-link", ("active" if controller_name == 'processes')] %>
25
+ <%= link_to processes_path, class: ["nav-link", ("active" if controller_name == 'processes')] do %>
26
+ <%= t(".processes") %>
27
+ <% processes_count = GoodJob::Process.count %>
28
+ <span class="badge bg-secondary rounded-pill <%= "bg-danger" if processes_count == 0 %>"><%= processes_count %></span>
29
+ <% end %>
18
30
  </li>
19
31
  </ul>
20
32
  <div class="nav-item pe-2">
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-three-dots" viewBox="0 0 16 16">
2
+ <path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z" />
3
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16">
2
+ <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
3
+ <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
4
+ </svg>
@@ -63,3 +63,22 @@ en:
63
63
  retried: Retried
64
64
  running: Running
65
65
  scheduled: Scheduled
66
+ number:
67
+ format:
68
+ delimiter: ","
69
+ separator: "."
70
+ human:
71
+ decimal_units:
72
+ format: "%n%u"
73
+ units:
74
+ billion: B
75
+ hundred: ''
76
+ million: M
77
+ quadrillion: Q
78
+ thousand: K
79
+ trillion: T
80
+ unit: ''
81
+ format:
82
+ delimiter: ","
83
+ precision: 3
84
+ separator: "."
@@ -63,3 +63,22 @@ es:
63
63
  retried: reintentado
64
64
  running: Corriendo
65
65
  scheduled: Programado
66
+ number:
67
+ format:
68
+ delimiter: " "
69
+ separator: ","
70
+ human:
71
+ decimal_units:
72
+ format: "%n%u"
73
+ units:
74
+ billion: B
75
+ hundred: ''
76
+ million: M
77
+ quadrillion: q
78
+ thousand: k
79
+ trillion: T
80
+ unit: ''
81
+ format:
82
+ delimiter: " "
83
+ precision: 3
84
+ separator: ","
@@ -63,3 +63,22 @@ nl:
63
63
  retried: Opnieuw geprobeerd
64
64
  running: Rennen
65
65
  scheduled: Gepland
66
+ number:
67
+ format:
68
+ delimiter: "."
69
+ separator: ","
70
+ human:
71
+ decimal_units:
72
+ format: "%n%u"
73
+ units:
74
+ billion: B
75
+ hundred: ''
76
+ million: M
77
+ quadrillion: Q
78
+ thousand: K
79
+ trillion: T
80
+ unit: ''
81
+ format:
82
+ delimiter: "."
83
+ precision: 3
84
+ separator: ","
@@ -87,3 +87,22 @@ ru:
87
87
  retried: Повторная попытка
88
88
  running: Бег
89
89
  scheduled: по расписанию
90
+ number:
91
+ format:
92
+ delimiter: " "
93
+ separator: ","
94
+ human:
95
+ decimal_units:
96
+ format: "%n%u"
97
+ units:
98
+ billion: Б
99
+ hundred: ''
100
+ million: М
101
+ quadrillion: Q
102
+ thousand: К
103
+ trillion: Т
104
+ unit: ''
105
+ format:
106
+ delimiter: " "
107
+ precision: 3
108
+ separator: ","