solid_queue_monitor 0.2.0 → 0.3.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -10
  3. data/Rakefile +8 -8
  4. data/app/controllers/solid_queue_monitor/application_controller.rb +25 -0
  5. data/app/controllers/solid_queue_monitor/base_controller.rb +70 -67
  6. data/app/controllers/solid_queue_monitor/failed_jobs_controller.rb +8 -7
  7. data/app/controllers/solid_queue_monitor/in_progress_jobs_controller.rb +16 -10
  8. data/app/controllers/solid_queue_monitor/overview_controller.rb +13 -12
  9. data/app/controllers/solid_queue_monitor/queues_controller.rb +4 -2
  10. data/app/controllers/solid_queue_monitor/ready_jobs_controller.rb +8 -7
  11. data/app/controllers/solid_queue_monitor/recurring_jobs_controller.rb +7 -6
  12. data/app/controllers/solid_queue_monitor/scheduled_jobs_controller.rb +8 -7
  13. data/app/presenters/solid_queue_monitor/base_presenter.rb +42 -41
  14. data/app/presenters/solid_queue_monitor/failed_jobs_presenter.rb +51 -41
  15. data/app/presenters/solid_queue_monitor/in_progress_jobs_presenter.rb +13 -2
  16. data/app/presenters/solid_queue_monitor/jobs_presenter.rb +18 -9
  17. data/app/presenters/solid_queue_monitor/queues_presenter.rb +5 -5
  18. data/app/presenters/solid_queue_monitor/ready_jobs_presenter.rb +10 -2
  19. data/app/presenters/solid_queue_monitor/recurring_jobs_presenter.rb +5 -2
  20. data/app/presenters/solid_queue_monitor/scheduled_jobs_presenter.rb +15 -9
  21. data/app/presenters/solid_queue_monitor/stats_presenter.rb +3 -1
  22. data/app/services/solid_queue_monitor/authentication_service.rb +7 -5
  23. data/app/services/solid_queue_monitor/execute_job_service.rb +3 -1
  24. data/app/services/solid_queue_monitor/failed_job_service.rb +38 -36
  25. data/app/services/solid_queue_monitor/html_generator.rb +5 -2
  26. data/app/services/solid_queue_monitor/pagination_service.rb +3 -1
  27. data/app/services/solid_queue_monitor/stats_calculator.rb +3 -1
  28. data/app/services/solid_queue_monitor/status_calculator.rb +4 -1
  29. data/app/services/solid_queue_monitor/stylesheet_generator.rb +23 -21
  30. data/config/initializers/solid_queue_monitor.rb +3 -1
  31. data/config/routes.rb +6 -4
  32. data/lib/generators/solid_queue_monitor/install_generator.rb +7 -5
  33. data/lib/generators/solid_queue_monitor/templates/initializer.rb +3 -1
  34. data/lib/solid_queue_monitor/engine.rb +5 -3
  35. data/lib/solid_queue_monitor/version.rb +2 -2
  36. data/lib/solid_queue_monitor.rb +9 -13
  37. data/lib/tasks/app.rake +42 -40
  38. metadata +9 -148
  39. data/app/controllers/solid_queue_monitor/monitor_controller.rb +0 -318
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidQueueMonitor
2
4
  class BasePresenter
3
5
  include ActionView::Helpers::DateHelper
@@ -9,7 +11,7 @@ module SolidQueueMonitor
9
11
  { only_path: true }
10
12
  end
11
13
 
12
- def section_wrapper(title, content)
14
+ def section_wrapper(_title, content)
13
15
  <<-HTML
14
16
  <div class="section-wrapper">
15
17
  <div class="section">
@@ -21,36 +23,36 @@ module SolidQueueMonitor
21
23
 
22
24
  def generate_pagination(current_page, total_pages)
23
25
  return '' if total_pages <= 1
24
-
26
+
25
27
  html = '<div class="pagination">'
26
-
28
+
27
29
  # Previous page link
28
- if current_page > 1
29
- html += "<a href=\"?page=#{current_page - 1}#{query_params}\" class=\"pagination-link pagination-nav\">Previous</a>"
30
- else
31
- html += '<span class="pagination-link pagination-nav disabled">Previous</span>'
32
- end
33
-
30
+ html += if current_page > 1
31
+ "<a href=\"?page=#{current_page - 1}#{query_params}\" class=\"pagination-link pagination-nav\">Previous</a>"
32
+ else
33
+ '<span class="pagination-link pagination-nav disabled">Previous</span>'
34
+ end
35
+
34
36
  # Page links
35
37
  visible_pages = calculate_visible_pages(current_page, total_pages)
36
-
38
+
37
39
  visible_pages.each do |page|
38
- if page == :gap
39
- html += "<span class=\"pagination-gap\">...</span>"
40
- elsif page == current_page
41
- html += "<span class=\"pagination-current\">#{page}</span>"
42
- else
43
- html += "<a href=\"?page=#{page}#{query_params}\" class=\"pagination-link\">#{page}</a>"
44
- end
40
+ html += if page == :gap
41
+ '<span class="pagination-gap">...</span>'
42
+ elsif page == current_page
43
+ "<span class=\"pagination-current\">#{page}</span>"
44
+ else
45
+ "<a href=\"?page=#{page}#{query_params}\" class=\"pagination-link\">#{page}</a>"
46
+ end
45
47
  end
46
-
48
+
47
49
  # Next page link
48
- if current_page < total_pages
49
- html += "<a href=\"?page=#{current_page + 1}#{query_params}\" class=\"pagination-link pagination-nav\">Next</a>"
50
- else
51
- html += '<span class="pagination-link pagination-nav disabled">Next</span>'
52
- end
53
-
50
+ html += if current_page < total_pages
51
+ "<a href=\"?page=#{current_page + 1}#{query_params}\" class=\"pagination-link pagination-nav\">Next</a>"
52
+ else
53
+ '<span class="pagination-link pagination-nav disabled">Next</span>'
54
+ end
55
+
54
56
  html += '</div>'
55
57
  html
56
58
  end
@@ -72,30 +74,31 @@ module SolidQueueMonitor
72
74
 
73
75
  def format_datetime(datetime)
74
76
  return '-' unless datetime
77
+
75
78
  datetime.strftime('%Y-%m-%d %H:%M:%S')
76
79
  end
77
80
 
78
81
  def format_arguments(arguments)
79
- return '-' unless arguments.present?
80
-
82
+ return '-' if arguments.blank?
83
+
81
84
  # For ActiveJob format
82
85
  if arguments.is_a?(Hash) && arguments['arguments'].present?
83
86
  return "<code>#{arguments['arguments'].inspect}</code>"
84
87
  elsif arguments.is_a?(Array) && arguments.length == 1 && arguments[0].is_a?(Hash) && arguments[0]['arguments'].present?
85
88
  return "<code>#{arguments[0]['arguments'].inspect}</code>"
86
89
  end
87
-
90
+
88
91
  # For regular arguments format
89
92
  "<code>#{arguments.inspect}</code>"
90
93
  end
91
94
 
92
95
  def format_hash(hash)
93
- return '-' unless hash.present?
94
-
96
+ return '-' if hash.blank?
97
+
95
98
  formatted = hash.map do |key, value|
96
99
  "<strong>#{key}:</strong> #{value.to_s.truncate(50)}"
97
100
  end.join(', ')
98
-
101
+
99
102
  "<code>#{formatted}</code>"
100
103
  end
101
104
 
@@ -106,7 +109,7 @@ module SolidQueueMonitor
106
109
  controller.request.path
107
110
  else
108
111
  # Fallback to a default path if we can't get the current path
109
- "/solid_queue"
112
+ '/solid_queue'
110
113
  end
111
114
  end
112
115
 
@@ -116,7 +119,7 @@ module SolidQueueMonitor
116
119
  if path_parts.length >= 3
117
120
  "/#{path_parts[1]}/#{path_parts[2]}"
118
121
  else
119
- "/solid_queue"
122
+ '/solid_queue'
120
123
  end
121
124
  end
122
125
 
@@ -127,19 +130,17 @@ module SolidQueueMonitor
127
130
  params << "class_name=#{@filters[:class_name]}" if @filters && @filters[:class_name].present?
128
131
  params << "queue_name=#{@filters[:queue_name]}" if @filters && @filters[:queue_name].present?
129
132
  params << "status=#{@filters[:status]}" if @filters && @filters[:status].present?
130
-
133
+
131
134
  params.empty? ? '' : "&#{params.join('&')}"
132
135
  end
133
136
 
134
137
  # Helper method to get the full path for a route
135
138
  def full_path(route_name, *args)
136
- begin
137
- # Try to use the engine routes first
138
- SolidQueueMonitor::Engine.routes.url_helpers.send(route_name, *args)
139
- rescue NoMethodError
140
- # Fall back to main app routes
141
- Rails.application.routes.url_helpers.send("solid_queue_#{route_name}", *args)
142
- end
139
+ # Try to use the engine routes first
140
+ SolidQueueMonitor::Engine.routes.url_helpers.send(route_name, *args)
141
+ rescue NoMethodError
142
+ # Fall back to main app routes
143
+ Rails.application.routes.url_helpers.send("solid_queue_#{route_name}", *args)
143
144
  end
144
145
  end
145
- end
146
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidQueueMonitor
2
4
  class FailedJobsPresenter < BasePresenter
3
5
  include Rails.application.routes.url_helpers
@@ -11,7 +13,8 @@ module SolidQueueMonitor
11
13
  end
12
14
 
13
15
  def render
14
- section_wrapper('Failed Jobs', generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
16
+ section_wrapper('Failed Jobs',
17
+ generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
15
18
  end
16
19
 
17
20
  private
@@ -30,13 +33,18 @@ module SolidQueueMonitor
30
33
  <input type="text" name="queue_name" id="queue_name" value="#{@filters[:queue_name]}" placeholder="Filter by queue">
31
34
  </div>
32
35
 
36
+ <div class="filter-group">
37
+ <label for="arguments">Arguments:</label>
38
+ <input type="text" name="arguments" id="arguments" value="#{@filters[:arguments]}" placeholder="Filter by arguments">
39
+ </div>
40
+
33
41
  <div class="filter-actions">
34
42
  <button type="submit" class="filter-button">Apply Filters</button>
35
43
  <a href="#{failed_jobs_path}" class="reset-button">Reset</a>
36
44
  </div>
37
45
  </form>
38
46
  </div>
39
-
47
+
40
48
  <div class="bulk-actions-bar">
41
49
  <button type="button" class="action-button retry-button" id="retry-selected-top" disabled>Retry Selected</button>
42
50
  <button type="button" class="action-button discard-button" id="discard-selected-top" disabled>Discard Selected</button>
@@ -55,6 +63,7 @@ module SolidQueueMonitor
55
63
  <th>Job</th>
56
64
  <th>Queue</th>
57
65
  <th>Error</th>
66
+ <th>Arguments</th>
58
67
  <th>Actions</th>
59
68
  </tr>
60
69
  </thead>
@@ -64,7 +73,7 @@ module SolidQueueMonitor
64
73
  </table>
65
74
  </div>
66
75
  </form>
67
-
76
+
68
77
  <script>
69
78
  document.addEventListener('DOMContentLoaded', function() {
70
79
  // Handle select all checkboxes
@@ -73,13 +82,13 @@ module SolidQueueMonitor
73
82
  const retrySelectedBtn = document.getElementById('retry-selected-top');
74
83
  const discardSelectedBtn = document.getElementById('discard-selected-top');
75
84
  const form = document.getElementById('failed-jobs-form');
76
-
85
+ #{' '}
77
86
  function updateButtonState() {
78
87
  const checkedBoxes = document.querySelectorAll('.job-checkbox:checked');
79
88
  retrySelectedBtn.disabled = checkedBoxes.length === 0;
80
89
  discardSelectedBtn.disabled = checkedBoxes.length === 0;
81
90
  }
82
-
91
+ #{' '}
83
92
  function toggleAll(checked) {
84
93
  checkboxes.forEach(checkbox => {
85
94
  checkbox.checked = checked;
@@ -87,36 +96,36 @@ module SolidQueueMonitor
87
96
  selectAllHeader.checked = checked;
88
97
  updateButtonState();
89
98
  }
90
-
99
+ #{' '}
91
100
  selectAllHeader.addEventListener('change', function() {
92
101
  toggleAll(this.checked);
93
102
  });
94
-
103
+ #{' '}
95
104
  checkboxes.forEach(checkbox => {
96
105
  checkbox.addEventListener('change', function() {
97
106
  updateButtonState();
98
-
107
+ #{' '}
99
108
  // Update select all checkboxes if needed
100
109
  const allChecked = document.querySelectorAll('.job-checkbox:checked').length === checkboxes.length;
101
110
  selectAllHeader.checked = allChecked;
102
111
  });
103
112
  });
104
-
113
+ #{' '}
105
114
  // Handle bulk actions
106
115
  retrySelectedBtn.addEventListener('click', function() {
107
116
  const selectedIds = Array.from(document.querySelectorAll('.job-checkbox:checked')).map(cb => cb.value);
108
117
  if (selectedIds.length === 0) return;
109
-
118
+ #{' '}
110
119
  if (confirm('Are you sure you want to retry the selected jobs?')) {
111
120
  form.action = '#{retry_failed_jobs_path}';
112
-
121
+ #{' '}
113
122
  // Add a special flag to indicate this should redirect properly
114
123
  const redirectInput = document.createElement('input');
115
124
  redirectInput.type = 'hidden';
116
125
  redirectInput.name = 'redirect_cleanly';
117
126
  redirectInput.value = 'true';
118
127
  form.appendChild(redirectInput);
119
-
128
+ #{' '}
120
129
  // Add selected IDs as hidden inputs
121
130
  selectedIds.forEach(id => {
122
131
  const input = document.createElement('input');
@@ -125,10 +134,10 @@ module SolidQueueMonitor
125
134
  input.value = id;
126
135
  form.appendChild(input);
127
136
  });
128
-
137
+ #{' '}
129
138
  // Submit the form and then replace the URL location immediately after
130
139
  form.submit();
131
-
140
+ #{' '}
132
141
  // Delay the redirect to give the form time to submit
133
142
  setTimeout(function() {
134
143
  // Reset to the clean URL without query parameters
@@ -136,21 +145,21 @@ module SolidQueueMonitor
136
145
  }, 100);
137
146
  }
138
147
  });
139
-
148
+ #{' '}
140
149
  discardSelectedBtn.addEventListener('click', function() {
141
150
  const selectedIds = Array.from(document.querySelectorAll('.job-checkbox:checked')).map(cb => cb.value);
142
151
  if (selectedIds.length === 0) return;
143
-
152
+ #{' '}
144
153
  if (confirm('Are you sure you want to discard the selected jobs?')) {
145
154
  form.action = '#{discard_failed_jobs_path}';
146
-
155
+ #{' '}
147
156
  // Add a special flag to indicate this should redirect properly
148
157
  const redirectInput = document.createElement('input');
149
158
  redirectInput.type = 'hidden';
150
159
  redirectInput.name = 'redirect_cleanly';
151
160
  redirectInput.value = 'true';
152
161
  form.appendChild(redirectInput);
153
-
162
+ #{' '}
154
163
  // Add selected IDs as hidden inputs
155
164
  selectedIds.forEach(id => {
156
165
  const input = document.createElement('input');
@@ -159,10 +168,10 @@ module SolidQueueMonitor
159
168
  input.value = id;
160
169
  form.appendChild(input);
161
170
  });
162
-
171
+ #{' '}
163
172
  // Submit the form and then replace the URL location immediately after
164
173
  form.submit();
165
-
174
+ #{' '}
166
175
  // Delay the redirect to give the form time to submit
167
176
  setTimeout(function() {
168
177
  // Reset to the clean URL without query parameters
@@ -170,58 +179,58 @@ module SolidQueueMonitor
170
179
  }, 100);
171
180
  }
172
181
  });
173
-
182
+ #{' '}
174
183
  // Initialize button state
175
184
  updateButtonState();
176
-
185
+ #{' '}
177
186
  // Global function for retry action
178
187
  window.submitRetryForm = function(id) {
179
188
  const form = document.createElement('form');
180
189
  form.method = 'post';
181
- form.action = '#{retry_failed_job_path(id: "PLACEHOLDER")}';
190
+ form.action = '#{retry_failed_job_path(id: 'PLACEHOLDER')}';
182
191
  form.action = form.action.replace('PLACEHOLDER', id);
183
192
  form.style.display = 'none';
184
-
193
+ #{' '}
185
194
  // Add a special flag to indicate this should redirect properly
186
195
  const redirectInput = document.createElement('input');
187
196
  redirectInput.type = 'hidden';
188
197
  redirectInput.name = 'redirect_cleanly';
189
198
  redirectInput.value = 'true';
190
199
  form.appendChild(redirectInput);
191
-
200
+ #{' '}
192
201
  document.body.appendChild(form);
193
-
202
+ #{' '}
194
203
  // Submit the form and then replace the URL location immediately after
195
204
  form.submit();
196
-
205
+ #{' '}
197
206
  // Delay the redirect to give the form time to submit
198
207
  setTimeout(function() {
199
208
  // Reset to the clean URL without query parameters
200
209
  window.history.replaceState({}, '', window.location.pathname);
201
210
  }, 100);
202
211
  };
203
-
212
+ #{' '}
204
213
  // Global function for discard action
205
214
  window.submitDiscardForm = function(id) {
206
215
  if (confirm('Are you sure you want to discard this job?')) {
207
216
  const form = document.createElement('form');
208
217
  form.method = 'post';
209
- form.action = '#{discard_failed_job_path(id: "PLACEHOLDER")}';
218
+ form.action = '#{discard_failed_job_path(id: 'PLACEHOLDER')}';
210
219
  form.action = form.action.replace('PLACEHOLDER', id);
211
220
  form.style.display = 'none';
212
-
221
+ #{' '}
213
222
  // Add a special flag to indicate this should redirect properly
214
223
  const redirectInput = document.createElement('input');
215
224
  redirectInput.type = 'hidden';
216
225
  redirectInput.name = 'redirect_cleanly';
217
226
  redirectInput.value = 'true';
218
227
  form.appendChild(redirectInput);
219
-
228
+ #{' '}
220
229
  document.body.appendChild(form);
221
-
230
+ #{' '}
222
231
  // Submit the form and then replace the URL location immediately after
223
232
  form.submit();
224
-
233
+ #{' '}
225
234
  // Delay the redirect to give the form time to submit
226
235
  setTimeout(function() {
227
236
  // Reset to the clean URL without query parameters
@@ -237,7 +246,7 @@ module SolidQueueMonitor
237
246
  def generate_row(failed_execution)
238
247
  job = failed_execution.job
239
248
  error = parse_error(failed_execution.error)
240
-
249
+
241
250
  <<-HTML
242
251
  <tr>
243
252
  <td><input type="checkbox" class="job-checkbox" value="#{failed_execution.id}"></td>
@@ -260,14 +269,15 @@ module SolidQueueMonitor
260
269
  <pre class="error-backtrace">#{error[:backtrace]}</pre>
261
270
  </details>
262
271
  </td>
272
+ <td>#{format_arguments(job.arguments)}</td>
263
273
  <td class="actions-cell">
264
274
  <div class="job-actions">
265
- <a href="javascript:void(0)"
266
- onclick="submitRetryForm(#{failed_execution.id})"
275
+ <a href="javascript:void(0)"#{' '}
276
+ onclick="submitRetryForm(#{failed_execution.id})"#{' '}
267
277
  class="action-button retry-button">Retry</a>
268
-
269
- <a href="javascript:void(0)"
270
- onclick="submitDiscardForm(#{failed_execution.id})"
278
+ #{' '}
279
+ <a href="javascript:void(0)"#{' '}
280
+ onclick="submitDiscardForm(#{failed_execution.id})"#{' '}
271
281
  class="action-button discard-button">Discard</a>
272
282
  </div>
273
283
  </td>
@@ -277,7 +287,7 @@ module SolidQueueMonitor
277
287
 
278
288
  def parse_error(error)
279
289
  return { message: 'Unknown error', backtrace: '' } unless error
280
-
290
+
281
291
  if error.is_a?(String)
282
292
  { message: error, backtrace: '' }
283
293
  elsif error.is_a?(Hash)
@@ -303,4 +313,4 @@ module SolidQueueMonitor
303
313
  job.queue_name
304
314
  end
305
315
  end
306
- end
316
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidQueueMonitor
2
4
  class InProgressJobsPresenter < BasePresenter
3
5
  include SolidQueueMonitor::Engine.routes.url_helpers
@@ -10,7 +12,8 @@ module SolidQueueMonitor
10
12
  end
11
13
 
12
14
  def render
13
- section_wrapper('In Progress Jobs', generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
15
+ section_wrapper('In Progress Jobs',
16
+ generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
14
17
  end
15
18
 
16
19
  private
@@ -24,6 +27,11 @@ module SolidQueueMonitor
24
27
  <input type="text" name="class_name" id="class_name" value="#{@filters[:class_name]}" placeholder="Filter by class name">
25
28
  </div>
26
29
 
30
+ <div class="filter-group">
31
+ <label for="arguments">Arguments:</label>
32
+ <input type="text" name="arguments" id="arguments" value="#{@filters[:arguments]}" placeholder="Filter by arguments">
33
+ </div>
34
+
27
35
  <div class="filter-actions">
28
36
  <button type="submit" class="filter-button">Apply Filters</button>
29
37
  <a href="#{in_progress_jobs_path}" class="reset-button">Reset</a>
@@ -40,6 +48,8 @@ module SolidQueueMonitor
40
48
  <thead>
41
49
  <tr>
42
50
  <th>Job</th>
51
+ <th>Queue</th>
52
+ <th>Arguments</th>
43
53
  <th>Started At</th>
44
54
  <th>Process ID</th>
45
55
  </tr>
@@ -62,10 +72,11 @@ module SolidQueueMonitor
62
72
  <span class="job-timestamp">Queued at: #{format_datetime(job.created_at)}</span>
63
73
  </div>
64
74
  </td>
75
+ <td>#{format_arguments(job.arguments)}</td>
65
76
  <td>#{format_datetime(execution.created_at)}</td>
66
77
  <td>#{execution.process_id}</td>
67
78
  </tr>
68
79
  HTML
69
80
  end
70
81
  end
71
- end
82
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidQueueMonitor
2
4
  class JobsPresenter < BasePresenter
3
5
  include Rails.application.routes.url_helpers
@@ -39,6 +41,11 @@ module SolidQueueMonitor
39
41
  <input type="text" name="queue_name" id="queue_name" value="#{@filters[:queue_name]}" placeholder="Filter by queue">
40
42
  </div>
41
43
 
44
+ <div class="filter-group">
45
+ <label for="arguments">Arguments:</label>
46
+ <input type="text" name="arguments" id="arguments" value="#{@filters[:arguments]}" placeholder="Filter by arguments">
47
+ </div>
48
+
42
49
  <div class="filter-group">
43
50
  <label for="status">Status:</label>
44
51
  <select name="status" id="status">
@@ -68,6 +75,7 @@ module SolidQueueMonitor
68
75
  <th>ID</th>
69
76
  <th>Job</th>
70
77
  <th>Queue</th>
78
+ <th>Arguments</th>
71
79
  <th>Status</th>
72
80
  <th>Created At</th>
73
81
  <th>Actions</th>
@@ -90,6 +98,7 @@ module SolidQueueMonitor
90
98
  <td>#{job.id}</td>
91
99
  <td>#{job.class_name}</td>
92
100
  <td>#{job.queue_name}</td>
101
+ <td>#{format_arguments(job.arguments)}</td>
93
102
  <td><span class='status-badge status-#{status}'>#{status}</span></td>
94
103
  <td>#{format_datetime(job.created_at)}</td>
95
104
  HTML
@@ -99,8 +108,8 @@ module SolidQueueMonitor
99
108
  # Find the failed execution record for this job
100
109
  failed_execution = SolidQueue::FailedExecution.find_by(job_id: job.id)
101
110
 
102
- if failed_execution
103
- row_html += <<-HTML
111
+ row_html += if failed_execution
112
+ <<-HTML
104
113
  <td class="actions-cell">
105
114
  <div class="job-actions">
106
115
  <form method="post" action="#{retry_failed_job_path(id: failed_execution.id)}" class="inline-form">
@@ -115,15 +124,15 @@ module SolidQueueMonitor
115
124
  </form>
116
125
  </div>
117
126
  </td>
118
- HTML
119
- else
120
- row_html += "<td></td>"
121
- end
127
+ HTML
128
+ else
129
+ '<td></td>'
130
+ end
122
131
  else
123
- row_html += "<td></td>"
132
+ row_html += '<td></td>'
124
133
  end
125
134
 
126
- row_html += "</tr>"
135
+ row_html += '</tr>'
127
136
  row_html
128
137
  end
129
138
 
@@ -131,4 +140,4 @@ module SolidQueueMonitor
131
140
  SolidQueueMonitor::StatusCalculator.new(job).calculate
132
141
  end
133
142
  end
134
- end
143
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidQueueMonitor
2
4
  class QueuesPresenter < BasePresenter
3
5
  def initialize(records)
@@ -43,8 +45,6 @@ module SolidQueueMonitor
43
45
  HTML
44
46
  end
45
47
 
46
- private
47
-
48
48
  def ready_jobs_count(queue_name)
49
49
  SolidQueue::ReadyExecution.where(queue_name: queue_name).count
50
50
  end
@@ -55,8 +55,8 @@ module SolidQueueMonitor
55
55
 
56
56
  def failed_jobs_count(queue_name)
57
57
  SolidQueue::FailedExecution.joins(:job)
58
- .where(solid_queue_jobs: { queue_name: queue_name })
59
- .count
58
+ .where(solid_queue_jobs: { queue_name: queue_name })
59
+ .count
60
60
  end
61
61
  end
62
- end
62
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidQueueMonitor
2
4
  class ReadyJobsPresenter < BasePresenter
3
5
  def initialize(jobs, current_page: 1, total_pages: 1, filters: {})
@@ -8,7 +10,8 @@ module SolidQueueMonitor
8
10
  end
9
11
 
10
12
  def render
11
- section_wrapper('Ready Jobs', generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
13
+ section_wrapper('Ready Jobs',
14
+ generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
12
15
  end
13
16
 
14
17
  private
@@ -27,6 +30,11 @@ module SolidQueueMonitor
27
30
  <input type="text" name="queue_name" id="queue_name" value="#{@filters[:queue_name]}" placeholder="Filter by queue">
28
31
  </div>
29
32
 
33
+ <div class="filter-group">
34
+ <label for="arguments">Arguments:</label>
35
+ <input type="text" name="arguments" id="arguments" value="#{@filters[:arguments]}" placeholder="Filter by arguments">
36
+ </div>
37
+
30
38
  <div class="filter-actions">
31
39
  <button type="submit" class="filter-button">Apply Filters</button>
32
40
  <a href="#{ready_jobs_path}" class="reset-button">Reset</a>
@@ -69,4 +77,4 @@ module SolidQueueMonitor
69
77
  HTML
70
78
  end
71
79
  end
72
- end
80
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidQueueMonitor
2
4
  class RecurringJobsPresenter < BasePresenter
3
5
  include Rails.application.routes.url_helpers
@@ -11,7 +13,8 @@ module SolidQueueMonitor
11
13
  end
12
14
 
13
15
  def render
14
- section_wrapper('Recurring Jobs', generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
16
+ section_wrapper('Recurring Jobs',
17
+ generate_filter_form + generate_table + generate_pagination(@current_page, @total_pages))
15
18
  end
16
19
 
17
20
  private
@@ -74,4 +77,4 @@ module SolidQueueMonitor
74
77
  HTML
75
78
  end
76
79
  end
77
- end
80
+ end