solid_queue_monitor 1.2.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +36 -1
- data/app/assets/javascripts/solid_queue_monitor/application.js +393 -0
- data/app/{services/solid_queue_monitor/stylesheet_generator.rb → assets/stylesheets/solid_queue_monitor/application.css} +80 -12
- data/app/controllers/solid_queue_monitor/application_controller.rb +2 -2
- data/app/controllers/solid_queue_monitor/assets_controller.rb +52 -0
- data/app/controllers/solid_queue_monitor/base_controller.rb +0 -28
- data/app/controllers/solid_queue_monitor/failed_jobs_controller.rb +3 -6
- data/app/controllers/solid_queue_monitor/in_progress_jobs_controller.rb +3 -6
- data/app/controllers/solid_queue_monitor/jobs_controller.rb +3 -6
- data/app/controllers/solid_queue_monitor/overview_controller.rb +3 -12
- data/app/controllers/solid_queue_monitor/queues_controller.rb +4 -18
- data/app/controllers/solid_queue_monitor/ready_jobs_controller.rb +3 -6
- data/app/controllers/solid_queue_monitor/recurring_jobs_controller.rb +3 -6
- data/app/controllers/solid_queue_monitor/scheduled_jobs_controller.rb +3 -6
- data/app/controllers/solid_queue_monitor/search_controller.rb +3 -4
- data/app/controllers/solid_queue_monitor/workers_controller.rb +24 -8
- data/app/helpers/solid_queue_monitor/application_helper.rb +46 -0
- data/app/helpers/solid_queue_monitor/chart_helper.rb +293 -0
- data/app/helpers/solid_queue_monitor/job_details_helper.rb +66 -0
- data/app/helpers/solid_queue_monitor/jobs_helper.rb +134 -0
- data/app/helpers/solid_queue_monitor/pagination_helper.rb +23 -0
- data/app/helpers/solid_queue_monitor/sort_helper.rb +30 -0
- data/app/helpers/solid_queue_monitor/workers_helper.rb +88 -0
- data/app/services/solid_queue_monitor/asset_cache.rb +56 -0
- data/app/services/solid_queue_monitor/chart_data_service.rb +2 -2
- data/app/views/layouts/solid_queue_monitor/application.html.erb +25 -0
- data/app/views/solid_queue_monitor/failed_jobs/_row.html.erb +26 -0
- data/app/views/solid_queue_monitor/failed_jobs/index.html.erb +38 -0
- data/app/views/solid_queue_monitor/in_progress_jobs/_row.html.erb +13 -0
- data/app/views/solid_queue_monitor/in_progress_jobs/index.html.erb +25 -0
- data/app/views/solid_queue_monitor/jobs/_arguments.html.erb +9 -0
- data/app/views/solid_queue_monitor/jobs/_error.html.erb +26 -0
- data/app/views/solid_queue_monitor/jobs/_execution_history.html.erb +25 -0
- data/app/views/solid_queue_monitor/jobs/_header.html.erb +37 -0
- data/app/views/solid_queue_monitor/jobs/_metadata.html.erb +22 -0
- data/app/views/solid_queue_monitor/jobs/_raw_data.html.erb +11 -0
- data/app/views/solid_queue_monitor/jobs/_timeline.html.erb +29 -0
- data/app/views/solid_queue_monitor/jobs/_timing.html.erb +9 -0
- data/app/views/solid_queue_monitor/jobs/_worker.html.erb +12 -0
- data/app/views/solid_queue_monitor/jobs/show.html.erb +22 -0
- data/app/views/solid_queue_monitor/overview/_chart.html.erb +1 -0
- data/app/views/solid_queue_monitor/overview/_recent_job_row.html.erb +26 -0
- data/app/views/solid_queue_monitor/overview/_recent_jobs.html.erb +31 -0
- data/app/views/solid_queue_monitor/overview/_stat_card.html.erb +4 -0
- data/app/views/solid_queue_monitor/overview/_stats.html.erb +11 -0
- data/app/views/solid_queue_monitor/overview/index.html.erb +9 -0
- data/app/views/solid_queue_monitor/queues/_job_row.html.erb +26 -0
- data/app/views/solid_queue_monitor/queues/_row.html.erb +33 -0
- data/app/views/solid_queue_monitor/queues/index.html.erb +18 -0
- data/app/views/solid_queue_monitor/queues/show.html.erb +63 -0
- data/app/views/solid_queue_monitor/ready_jobs/_row.html.erb +7 -0
- data/app/views/solid_queue_monitor/ready_jobs/index.html.erb +25 -0
- data/app/views/solid_queue_monitor/recurring_jobs/_row.html.erb +8 -0
- data/app/views/solid_queue_monitor/recurring_jobs/index.html.erb +26 -0
- data/app/views/solid_queue_monitor/scheduled_jobs/_row.html.erb +7 -0
- data/app/views/solid_queue_monitor/scheduled_jobs/index.html.erb +36 -0
- data/app/views/solid_queue_monitor/search/_completed_row.html.erb +6 -0
- data/app/views/solid_queue_monitor/search/_failed_row.html.erb +6 -0
- data/app/views/solid_queue_monitor/search/_job_row.html.erb +9 -0
- data/app/views/solid_queue_monitor/search/_recurring_row.html.erb +6 -0
- data/app/views/solid_queue_monitor/search/_section.html.erb +25 -0
- data/app/views/solid_queue_monitor/search/index.html.erb +23 -0
- data/app/views/solid_queue_monitor/shared/_filters.html.erb +48 -0
- data/app/views/solid_queue_monitor/shared/_flash.html.erb +17 -0
- data/app/views/solid_queue_monitor/shared/_footer.html.erb +3 -0
- data/app/views/solid_queue_monitor/shared/_header.html.erb +81 -0
- data/app/views/solid_queue_monitor/shared/_jobs_table.html.erb +20 -0
- data/app/views/solid_queue_monitor/shared/_pagination.html.erb +25 -0
- data/app/views/solid_queue_monitor/workers/_row.html.erb +22 -0
- data/app/views/solid_queue_monitor/workers/index.html.erb +82 -0
- data/config/routes.rb +6 -1
- data/lib/solid_queue_monitor/engine.rb +2 -0
- data/lib/solid_queue_monitor/version.rb +1 -1
- metadata +57 -17
- data/app/presenters/solid_queue_monitor/base_presenter.rb +0 -211
- data/app/presenters/solid_queue_monitor/failed_jobs_presenter.rb +0 -312
- data/app/presenters/solid_queue_monitor/in_progress_jobs_presenter.rb +0 -84
- data/app/presenters/solid_queue_monitor/job_details_presenter.rb +0 -696
- data/app/presenters/solid_queue_monitor/jobs_presenter.rb +0 -144
- data/app/presenters/solid_queue_monitor/queue_details_presenter.rb +0 -195
- data/app/presenters/solid_queue_monitor/queues_presenter.rb +0 -89
- data/app/presenters/solid_queue_monitor/ready_jobs_presenter.rb +0 -81
- data/app/presenters/solid_queue_monitor/recurring_jobs_presenter.rb +0 -81
- data/app/presenters/solid_queue_monitor/scheduled_jobs_presenter.rb +0 -173
- data/app/presenters/solid_queue_monitor/search_results_presenter.rb +0 -190
- data/app/presenters/solid_queue_monitor/stats_presenter.rb +0 -36
- data/app/presenters/solid_queue_monitor/workers_presenter.rb +0 -320
- data/app/services/solid_queue_monitor/chart_presenter.rb +0 -239
- data/app/services/solid_queue_monitor/html_generator.rb +0 -401
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SolidQueueMonitor
|
|
4
|
-
class FailedJobsPresenter < BasePresenter
|
|
5
|
-
include Rails.application.routes.url_helpers
|
|
6
|
-
include SolidQueueMonitor::Engine.routes.url_helpers
|
|
7
|
-
|
|
8
|
-
def initialize(jobs, current_page: 1, total_pages: 1, filters: {}, sort: {})
|
|
9
|
-
@jobs = jobs
|
|
10
|
-
@current_page = current_page
|
|
11
|
-
@total_pages = total_pages
|
|
12
|
-
@filters = filters
|
|
13
|
-
@sort = sort
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def render
|
|
17
|
-
section_wrapper('Failed Jobs',
|
|
18
|
-
generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def generate_filter_form
|
|
24
|
-
<<-HTML
|
|
25
|
-
<div class="filter-form-container">
|
|
26
|
-
<form method="get" action="#{failed_jobs_path}" class="filter-form">
|
|
27
|
-
<div class="filter-group">
|
|
28
|
-
<label for="class_name">Job Class:</label>
|
|
29
|
-
<input type="text" name="class_name" id="class_name" value="#{@filters[:class_name]}" placeholder="Filter by class name">
|
|
30
|
-
</div>
|
|
31
|
-
|
|
32
|
-
<div class="filter-group">
|
|
33
|
-
<label for="queue_name">Queue:</label>
|
|
34
|
-
<input type="text" name="queue_name" id="queue_name" value="#{@filters[:queue_name]}" placeholder="Filter by queue">
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<div class="filter-group">
|
|
38
|
-
<label for="arguments">Arguments:</label>
|
|
39
|
-
<input type="text" name="arguments" id="arguments" value="#{@filters[:arguments]}" placeholder="Filter by arguments">
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div class="filter-actions">
|
|
43
|
-
<button type="submit" class="filter-button">Apply Filters</button>
|
|
44
|
-
<a href="#{failed_jobs_path}" class="reset-button">Reset</a>
|
|
45
|
-
</div>
|
|
46
|
-
</form>
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
<div class="bulk-actions-bar">
|
|
50
|
-
<button type="button" class="action-button retry-button" id="retry-selected-top" disabled>Retry Selected</button>
|
|
51
|
-
<button type="button" class="action-button discard-button" id="discard-selected-top" disabled>Discard Selected</button>
|
|
52
|
-
</div>
|
|
53
|
-
HTML
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def generate_table
|
|
57
|
-
<<-HTML
|
|
58
|
-
<form method="post" id="failed-jobs-form">
|
|
59
|
-
<div class="table-container">
|
|
60
|
-
<table>
|
|
61
|
-
<thead>
|
|
62
|
-
<tr>
|
|
63
|
-
<th><input type="checkbox" id="select-all" class="select-all-checkbox"></th>
|
|
64
|
-
#{sortable_header('class_name', 'Job')}
|
|
65
|
-
#{sortable_header('queue_name', 'Queue')}
|
|
66
|
-
<th>Error</th>
|
|
67
|
-
<th>Arguments</th>
|
|
68
|
-
#{sortable_header('created_at', 'Failed At')}
|
|
69
|
-
<th>Actions</th>
|
|
70
|
-
</tr>
|
|
71
|
-
</thead>
|
|
72
|
-
<tbody>
|
|
73
|
-
#{@jobs.map { |failed_execution| generate_row(failed_execution) }.join}
|
|
74
|
-
</tbody>
|
|
75
|
-
</table>
|
|
76
|
-
</div>
|
|
77
|
-
</form>
|
|
78
|
-
|
|
79
|
-
<script>
|
|
80
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
81
|
-
// Handle select all checkboxes
|
|
82
|
-
const selectAllHeader = document.getElementById('select-all');
|
|
83
|
-
const checkboxes = document.querySelectorAll('.job-checkbox');
|
|
84
|
-
const retrySelectedBtn = document.getElementById('retry-selected-top');
|
|
85
|
-
const discardSelectedBtn = document.getElementById('discard-selected-top');
|
|
86
|
-
const form = document.getElementById('failed-jobs-form');
|
|
87
|
-
#{' '}
|
|
88
|
-
function updateButtonState() {
|
|
89
|
-
const checkedBoxes = document.querySelectorAll('.job-checkbox:checked');
|
|
90
|
-
retrySelectedBtn.disabled = checkedBoxes.length === 0;
|
|
91
|
-
discardSelectedBtn.disabled = checkedBoxes.length === 0;
|
|
92
|
-
}
|
|
93
|
-
#{' '}
|
|
94
|
-
function toggleAll(checked) {
|
|
95
|
-
checkboxes.forEach(checkbox => {
|
|
96
|
-
checkbox.checked = checked;
|
|
97
|
-
});
|
|
98
|
-
selectAllHeader.checked = checked;
|
|
99
|
-
updateButtonState();
|
|
100
|
-
}
|
|
101
|
-
#{' '}
|
|
102
|
-
selectAllHeader.addEventListener('change', function() {
|
|
103
|
-
toggleAll(this.checked);
|
|
104
|
-
});
|
|
105
|
-
#{' '}
|
|
106
|
-
checkboxes.forEach(checkbox => {
|
|
107
|
-
checkbox.addEventListener('change', function() {
|
|
108
|
-
updateButtonState();
|
|
109
|
-
#{' '}
|
|
110
|
-
// Update select all checkboxes if needed
|
|
111
|
-
const allChecked = document.querySelectorAll('.job-checkbox:checked').length === checkboxes.length;
|
|
112
|
-
selectAllHeader.checked = allChecked;
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
#{' '}
|
|
116
|
-
// Handle bulk actions
|
|
117
|
-
retrySelectedBtn.addEventListener('click', function() {
|
|
118
|
-
const selectedIds = Array.from(document.querySelectorAll('.job-checkbox:checked')).map(cb => cb.value);
|
|
119
|
-
if (selectedIds.length === 0) return;
|
|
120
|
-
#{' '}
|
|
121
|
-
if (confirm('Are you sure you want to retry the selected jobs?')) {
|
|
122
|
-
form.action = '#{retry_failed_jobs_path}';
|
|
123
|
-
#{' '}
|
|
124
|
-
// Add a special flag to indicate this should redirect properly
|
|
125
|
-
const redirectInput = document.createElement('input');
|
|
126
|
-
redirectInput.type = 'hidden';
|
|
127
|
-
redirectInput.name = 'redirect_cleanly';
|
|
128
|
-
redirectInput.value = 'true';
|
|
129
|
-
form.appendChild(redirectInput);
|
|
130
|
-
#{' '}
|
|
131
|
-
// Add selected IDs as hidden inputs
|
|
132
|
-
selectedIds.forEach(id => {
|
|
133
|
-
const input = document.createElement('input');
|
|
134
|
-
input.type = 'hidden';
|
|
135
|
-
input.name = 'job_ids[]';
|
|
136
|
-
input.value = id;
|
|
137
|
-
form.appendChild(input);
|
|
138
|
-
});
|
|
139
|
-
#{' '}
|
|
140
|
-
// Submit the form and then replace the URL location immediately after
|
|
141
|
-
form.submit();
|
|
142
|
-
#{' '}
|
|
143
|
-
// Delay the redirect to give the form time to submit
|
|
144
|
-
setTimeout(function() {
|
|
145
|
-
// Reset to the clean URL without query parameters
|
|
146
|
-
window.history.replaceState({}, '', window.location.pathname);
|
|
147
|
-
}, 100);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
#{' '}
|
|
151
|
-
discardSelectedBtn.addEventListener('click', function() {
|
|
152
|
-
const selectedIds = Array.from(document.querySelectorAll('.job-checkbox:checked')).map(cb => cb.value);
|
|
153
|
-
if (selectedIds.length === 0) return;
|
|
154
|
-
#{' '}
|
|
155
|
-
if (confirm('Are you sure you want to discard the selected jobs?')) {
|
|
156
|
-
form.action = '#{discard_failed_jobs_path}';
|
|
157
|
-
#{' '}
|
|
158
|
-
// Add a special flag to indicate this should redirect properly
|
|
159
|
-
const redirectInput = document.createElement('input');
|
|
160
|
-
redirectInput.type = 'hidden';
|
|
161
|
-
redirectInput.name = 'redirect_cleanly';
|
|
162
|
-
redirectInput.value = 'true';
|
|
163
|
-
form.appendChild(redirectInput);
|
|
164
|
-
#{' '}
|
|
165
|
-
// Add selected IDs as hidden inputs
|
|
166
|
-
selectedIds.forEach(id => {
|
|
167
|
-
const input = document.createElement('input');
|
|
168
|
-
input.type = 'hidden';
|
|
169
|
-
input.name = 'job_ids[]';
|
|
170
|
-
input.value = id;
|
|
171
|
-
form.appendChild(input);
|
|
172
|
-
});
|
|
173
|
-
#{' '}
|
|
174
|
-
// Submit the form and then replace the URL location immediately after
|
|
175
|
-
form.submit();
|
|
176
|
-
#{' '}
|
|
177
|
-
// Delay the redirect to give the form time to submit
|
|
178
|
-
setTimeout(function() {
|
|
179
|
-
// Reset to the clean URL without query parameters
|
|
180
|
-
window.history.replaceState({}, '', window.location.pathname);
|
|
181
|
-
}, 100);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
#{' '}
|
|
185
|
-
// Initialize button state
|
|
186
|
-
updateButtonState();
|
|
187
|
-
#{' '}
|
|
188
|
-
// Global function for retry action
|
|
189
|
-
window.submitRetryForm = function(id) {
|
|
190
|
-
const form = document.createElement('form');
|
|
191
|
-
form.method = 'post';
|
|
192
|
-
form.action = '#{retry_failed_job_path(id: 'PLACEHOLDER')}';
|
|
193
|
-
form.action = form.action.replace('PLACEHOLDER', id);
|
|
194
|
-
form.style.display = 'none';
|
|
195
|
-
#{' '}
|
|
196
|
-
// Add a special flag to indicate this should redirect properly
|
|
197
|
-
const redirectInput = document.createElement('input');
|
|
198
|
-
redirectInput.type = 'hidden';
|
|
199
|
-
redirectInput.name = 'redirect_cleanly';
|
|
200
|
-
redirectInput.value = 'true';
|
|
201
|
-
form.appendChild(redirectInput);
|
|
202
|
-
#{' '}
|
|
203
|
-
document.body.appendChild(form);
|
|
204
|
-
#{' '}
|
|
205
|
-
// Submit the form and then replace the URL location immediately after
|
|
206
|
-
form.submit();
|
|
207
|
-
#{' '}
|
|
208
|
-
// Delay the redirect to give the form time to submit
|
|
209
|
-
setTimeout(function() {
|
|
210
|
-
// Reset to the clean URL without query parameters
|
|
211
|
-
window.history.replaceState({}, '', window.location.pathname);
|
|
212
|
-
}, 100);
|
|
213
|
-
};
|
|
214
|
-
#{' '}
|
|
215
|
-
// Global function for discard action
|
|
216
|
-
window.submitDiscardForm = function(id) {
|
|
217
|
-
if (confirm('Are you sure you want to discard this job?')) {
|
|
218
|
-
const form = document.createElement('form');
|
|
219
|
-
form.method = 'post';
|
|
220
|
-
form.action = '#{discard_failed_job_path(id: 'PLACEHOLDER')}';
|
|
221
|
-
form.action = form.action.replace('PLACEHOLDER', id);
|
|
222
|
-
form.style.display = 'none';
|
|
223
|
-
#{' '}
|
|
224
|
-
// Add a special flag to indicate this should redirect properly
|
|
225
|
-
const redirectInput = document.createElement('input');
|
|
226
|
-
redirectInput.type = 'hidden';
|
|
227
|
-
redirectInput.name = 'redirect_cleanly';
|
|
228
|
-
redirectInput.value = 'true';
|
|
229
|
-
form.appendChild(redirectInput);
|
|
230
|
-
#{' '}
|
|
231
|
-
document.body.appendChild(form);
|
|
232
|
-
#{' '}
|
|
233
|
-
// Submit the form and then replace the URL location immediately after
|
|
234
|
-
form.submit();
|
|
235
|
-
#{' '}
|
|
236
|
-
// Delay the redirect to give the form time to submit
|
|
237
|
-
setTimeout(function() {
|
|
238
|
-
// Reset to the clean URL without query parameters
|
|
239
|
-
window.history.replaceState({}, '', window.location.pathname);
|
|
240
|
-
}, 100);
|
|
241
|
-
}
|
|
242
|
-
};
|
|
243
|
-
});
|
|
244
|
-
</script>
|
|
245
|
-
HTML
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def generate_row(failed_execution)
|
|
249
|
-
job = failed_execution.job
|
|
250
|
-
error = parse_error(failed_execution.error)
|
|
251
|
-
|
|
252
|
-
<<-HTML
|
|
253
|
-
<tr>
|
|
254
|
-
<td><input type="checkbox" class="job-checkbox" value="#{failed_execution.id}"></td>
|
|
255
|
-
<td>
|
|
256
|
-
<div class="job-class"><a href="#{job_path(job)}" class="job-class-link">#{job.class_name}</a></div>
|
|
257
|
-
<div class="job-meta">
|
|
258
|
-
<span class="job-timestamp">Queued at: #{format_datetime(job.created_at)}</span>
|
|
259
|
-
</div>
|
|
260
|
-
</td>
|
|
261
|
-
<td>
|
|
262
|
-
<div class="job-queue">#{queue_link(job.queue_name)}</div>
|
|
263
|
-
</td>
|
|
264
|
-
<td>
|
|
265
|
-
<div class="error-message">#{error[:message].to_s.truncate(100)}</div>
|
|
266
|
-
</td>
|
|
267
|
-
<td>#{format_arguments(job.arguments)}</td>
|
|
268
|
-
<td>#{format_datetime(failed_execution.created_at)}</td>
|
|
269
|
-
<td class="actions-cell">
|
|
270
|
-
<div class="job-actions">
|
|
271
|
-
<a href="javascript:void(0)"#{' '}
|
|
272
|
-
onclick="submitRetryForm(#{failed_execution.id})"#{' '}
|
|
273
|
-
class="action-button retry-button">Retry</a>
|
|
274
|
-
#{' '}
|
|
275
|
-
<a href="javascript:void(0)"#{' '}
|
|
276
|
-
onclick="submitDiscardForm(#{failed_execution.id})"#{' '}
|
|
277
|
-
class="action-button discard-button">Discard</a>
|
|
278
|
-
</div>
|
|
279
|
-
</td>
|
|
280
|
-
</tr>
|
|
281
|
-
HTML
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def parse_error(error)
|
|
285
|
-
return { message: 'Unknown error', backtrace: '' } unless error
|
|
286
|
-
|
|
287
|
-
if error.is_a?(String)
|
|
288
|
-
{ message: error, backtrace: '' }
|
|
289
|
-
elsif error.is_a?(Hash)
|
|
290
|
-
message = error['message'] || error[:message] || 'Unknown error'
|
|
291
|
-
backtrace = error['backtrace'] || error[:backtrace] || []
|
|
292
|
-
backtrace = backtrace.join("\n") if backtrace.is_a?(Array)
|
|
293
|
-
{ message: message, backtrace: backtrace }
|
|
294
|
-
else
|
|
295
|
-
{ message: 'Unknown error format', backtrace: error.to_s }
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
def get_queue_name(failed_execution, job)
|
|
300
|
-
# Try to get queue_name from failed_execution if the method exists
|
|
301
|
-
if failed_execution.respond_to?(:queue_name) && !failed_execution.queue_name.nil?
|
|
302
|
-
failed_execution.queue_name
|
|
303
|
-
else
|
|
304
|
-
# Fall back to job's queue_name
|
|
305
|
-
job.queue_name
|
|
306
|
-
end
|
|
307
|
-
rescue NoMethodError
|
|
308
|
-
# If there's an error accessing queue_name, fall back to job's queue_name
|
|
309
|
-
job.queue_name
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
end
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SolidQueueMonitor
|
|
4
|
-
class InProgressJobsPresenter < BasePresenter
|
|
5
|
-
include SolidQueueMonitor::Engine.routes.url_helpers
|
|
6
|
-
|
|
7
|
-
def initialize(jobs, current_page: 1, total_pages: 1, filters: {}, sort: {})
|
|
8
|
-
@jobs = jobs
|
|
9
|
-
@current_page = current_page
|
|
10
|
-
@total_pages = total_pages
|
|
11
|
-
@filters = filters
|
|
12
|
-
@sort = sort
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def render
|
|
16
|
-
section_wrapper('In Progress Jobs',
|
|
17
|
-
generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def generate_filter_form
|
|
23
|
-
<<-HTML
|
|
24
|
-
<div class="filter-form-container">
|
|
25
|
-
<form method="get" action="#{in_progress_jobs_path}" class="filter-form">
|
|
26
|
-
<div class="filter-group">
|
|
27
|
-
<label for="class_name">Job Class:</label>
|
|
28
|
-
<input type="text" name="class_name" id="class_name" value="#{@filters[:class_name]}" placeholder="Filter by class name">
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<div class="filter-group">
|
|
32
|
-
<label for="arguments">Arguments:</label>
|
|
33
|
-
<input type="text" name="arguments" id="arguments" value="#{@filters[:arguments]}" placeholder="Filter by arguments">
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
<div class="filter-actions">
|
|
37
|
-
<button type="submit" class="filter-button">Apply Filters</button>
|
|
38
|
-
<a href="#{in_progress_jobs_path}" class="reset-button">Reset</a>
|
|
39
|
-
</div>
|
|
40
|
-
</form>
|
|
41
|
-
</div>
|
|
42
|
-
HTML
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def generate_table
|
|
46
|
-
<<-HTML
|
|
47
|
-
<div class="table-container">
|
|
48
|
-
<table>
|
|
49
|
-
<thead>
|
|
50
|
-
<tr>
|
|
51
|
-
#{sortable_header('class_name', 'Job')}
|
|
52
|
-
#{sortable_header('queue_name', 'Queue')}
|
|
53
|
-
<th>Arguments</th>
|
|
54
|
-
#{sortable_header('created_at', 'Started At')}
|
|
55
|
-
<th>Process ID</th>
|
|
56
|
-
</tr>
|
|
57
|
-
</thead>
|
|
58
|
-
<tbody>
|
|
59
|
-
#{@jobs.map { |execution| generate_row(execution) }.join}
|
|
60
|
-
</tbody>
|
|
61
|
-
</table>
|
|
62
|
-
</div>
|
|
63
|
-
HTML
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def generate_row(execution)
|
|
67
|
-
job = execution.job
|
|
68
|
-
<<-HTML
|
|
69
|
-
<tr>
|
|
70
|
-
<td>
|
|
71
|
-
<div class="job-class"><a href="#{job_path(job)}" class="job-class-link">#{job.class_name}</a></div>
|
|
72
|
-
<div class="job-meta">
|
|
73
|
-
<span class="job-timestamp">Queued at: #{format_datetime(job.created_at)}</span>
|
|
74
|
-
</div>
|
|
75
|
-
</td>
|
|
76
|
-
<td>#{queue_link(job.queue_name)}</td>
|
|
77
|
-
<td>#{format_arguments(job.arguments)}</td>
|
|
78
|
-
<td>#{format_datetime(execution.created_at)}</td>
|
|
79
|
-
<td>#{execution.process_id}</td>
|
|
80
|
-
</tr>
|
|
81
|
-
HTML
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|