solid_queue_monitor 1.0.1 → 1.2.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -1
  3. data/app/controllers/solid_queue_monitor/base_controller.rb +49 -33
  4. data/app/controllers/solid_queue_monitor/failed_jobs_controller.rb +7 -3
  5. data/app/controllers/solid_queue_monitor/in_progress_jobs_controller.rb +9 -7
  6. data/app/controllers/solid_queue_monitor/overview_controller.rb +13 -9
  7. data/app/controllers/solid_queue_monitor/queues_controller.rb +39 -16
  8. data/app/controllers/solid_queue_monitor/ready_jobs_controller.rb +7 -3
  9. data/app/controllers/solid_queue_monitor/recurring_jobs_controller.rb +7 -3
  10. data/app/controllers/solid_queue_monitor/scheduled_jobs_controller.rb +7 -3
  11. data/app/controllers/solid_queue_monitor/search_controller.rb +12 -0
  12. data/app/controllers/solid_queue_monitor/workers_controller.rb +7 -4
  13. data/app/presenters/solid_queue_monitor/base_presenter.rb +47 -5
  14. data/app/presenters/solid_queue_monitor/failed_jobs_presenter.rb +6 -6
  15. data/app/presenters/solid_queue_monitor/in_progress_jobs_presenter.rb +5 -4
  16. data/app/presenters/solid_queue_monitor/jobs_presenter.rb +5 -4
  17. data/app/presenters/solid_queue_monitor/queue_details_presenter.rb +4 -3
  18. data/app/presenters/solid_queue_monitor/queues_presenter.rb +10 -22
  19. data/app/presenters/solid_queue_monitor/ready_jobs_presenter.rb +6 -5
  20. data/app/presenters/solid_queue_monitor/recurring_jobs_presenter.rb +6 -5
  21. data/app/presenters/solid_queue_monitor/scheduled_jobs_presenter.rb +5 -4
  22. data/app/presenters/solid_queue_monitor/search_results_presenter.rb +190 -0
  23. data/app/presenters/solid_queue_monitor/stats_presenter.rb +1 -2
  24. data/app/presenters/solid_queue_monitor/workers_presenter.rb +4 -3
  25. data/app/services/solid_queue_monitor/chart_data_service.rb +53 -57
  26. data/app/services/solid_queue_monitor/html_generator.rb +23 -2
  27. data/app/services/solid_queue_monitor/search_service.rb +126 -0
  28. data/app/services/solid_queue_monitor/stats_calculator.rb +12 -8
  29. data/app/services/solid_queue_monitor/stylesheet_generator.rb +118 -0
  30. data/config/routes.rb +1 -0
  31. data/lib/generators/solid_queue_monitor/templates/initializer.rb +3 -0
  32. data/lib/solid_queue_monitor/version.rb +1 -1
  33. data/lib/solid_queue_monitor.rb +2 -1
  34. metadata +5 -2
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueMonitor
4
+ class SearchService
5
+ RESULTS_LIMIT = 25
6
+
7
+ def initialize(query)
8
+ @query = query
9
+ end
10
+
11
+ def search
12
+ return empty_results if @query.blank?
13
+
14
+ term = "%#{sanitize_query(@query)}%"
15
+
16
+ {
17
+ ready: search_ready_jobs(term),
18
+ scheduled: search_scheduled_jobs(term),
19
+ failed: search_failed_jobs(term),
20
+ in_progress: search_in_progress_jobs(term),
21
+ completed: search_completed_jobs(term),
22
+ recurring: search_recurring_tasks(term)
23
+ }
24
+ end
25
+
26
+ private
27
+
28
+ def empty_results
29
+ {
30
+ ready: [],
31
+ scheduled: [],
32
+ failed: [],
33
+ in_progress: [],
34
+ completed: [],
35
+ recurring: []
36
+ }
37
+ end
38
+
39
+ def sanitize_query(query)
40
+ # Escape % to prevent LIKE pattern injection
41
+ # We don't escape _ because it requires database-specific ESCAPE clauses
42
+ query.to_s.gsub('%', '\%')
43
+ end
44
+
45
+ def search_ready_jobs(term)
46
+ SolidQueue::ReadyExecution
47
+ .joins(:job)
48
+ .where(job_search_conditions, term: term)
49
+ .includes(:job)
50
+ .limit(RESULTS_LIMIT)
51
+ end
52
+
53
+ def search_scheduled_jobs(term)
54
+ SolidQueue::ScheduledExecution
55
+ .joins(:job)
56
+ .where(job_search_conditions, term: term)
57
+ .includes(:job)
58
+ .limit(RESULTS_LIMIT)
59
+ end
60
+
61
+ def search_failed_jobs(term)
62
+ SolidQueue::FailedExecution
63
+ .joins(:job)
64
+ .where(failed_job_search_conditions, term: term)
65
+ .includes(:job)
66
+ .limit(RESULTS_LIMIT)
67
+ end
68
+
69
+ def search_in_progress_jobs(term)
70
+ SolidQueue::ClaimedExecution
71
+ .joins(:job)
72
+ .where(job_search_conditions, term: term)
73
+ .includes(:job)
74
+ .limit(RESULTS_LIMIT)
75
+ end
76
+
77
+ def search_completed_jobs(term)
78
+ SolidQueue::Job
79
+ .where.not(finished_at: nil)
80
+ .where(completed_job_search_conditions, term: term)
81
+ .order(finished_at: :desc)
82
+ .limit(RESULTS_LIMIT)
83
+ end
84
+
85
+ def search_recurring_tasks(term)
86
+ SolidQueue::RecurringTask
87
+ .where(recurring_task_search_conditions, term: term)
88
+ .limit(RESULTS_LIMIT)
89
+ end
90
+
91
+ def job_search_conditions
92
+ <<~SQL.squish
93
+ solid_queue_jobs.class_name LIKE :term
94
+ OR solid_queue_jobs.queue_name LIKE :term
95
+ OR solid_queue_jobs.arguments LIKE :term
96
+ OR solid_queue_jobs.active_job_id LIKE :term
97
+ SQL
98
+ end
99
+
100
+ def failed_job_search_conditions
101
+ <<~SQL.squish
102
+ solid_queue_jobs.class_name LIKE :term
103
+ OR solid_queue_jobs.queue_name LIKE :term
104
+ OR solid_queue_jobs.arguments LIKE :term
105
+ OR solid_queue_jobs.active_job_id LIKE :term
106
+ OR solid_queue_failed_executions.error LIKE :term
107
+ SQL
108
+ end
109
+
110
+ def completed_job_search_conditions
111
+ <<~SQL.squish
112
+ class_name LIKE :term
113
+ OR queue_name LIKE :term
114
+ OR arguments LIKE :term
115
+ OR active_job_id LIKE :term
116
+ SQL
117
+ end
118
+
119
+ def recurring_task_search_conditions
120
+ <<~SQL.squish
121
+ solid_queue_recurring_tasks.key LIKE :term
122
+ OR solid_queue_recurring_tasks.class_name LIKE :term
123
+ SQL
124
+ end
125
+ end
126
+ end
@@ -3,15 +3,19 @@
3
3
  module SolidQueueMonitor
4
4
  class StatsCalculator
5
5
  def self.calculate
6
+ scheduled = SolidQueue::ScheduledExecution.count
7
+ ready = SolidQueue::ReadyExecution.count
8
+ failed = SolidQueue::FailedExecution.count
9
+ in_progress = SolidQueue::ClaimedExecution.count
10
+ recurring = SolidQueue::RecurringTask.count
11
+
6
12
  {
7
- total_jobs: SolidQueue::Job.count,
8
- unique_queues: SolidQueue::Job.distinct.count(:queue_name),
9
- scheduled: SolidQueue::ScheduledExecution.count,
10
- ready: SolidQueue::ReadyExecution.count,
11
- failed: SolidQueue::FailedExecution.count,
12
- in_progress: SolidQueue::ClaimedExecution.count,
13
- completed: SolidQueue::Job.where.not(finished_at: nil).count,
14
- recurring: SolidQueue::RecurringTask.count
13
+ active_jobs: ready + scheduled + in_progress + failed,
14
+ scheduled: scheduled,
15
+ ready: ready,
16
+ failed: failed,
17
+ in_progress: in_progress,
18
+ recurring: recurring
15
19
  }
16
20
  end
17
21
  end
@@ -66,6 +66,16 @@ module SolidQueueMonitor
66
66
  margin-bottom: 0.5rem;
67
67
  }
68
68
 
69
+ .solid_queue_monitor .header-title-link {
70
+ color: var(--text-color);
71
+ text-decoration: none;
72
+ transition: color 0.2s;
73
+ }
74
+
75
+ .solid_queue_monitor .header-title-link:hover {
76
+ color: var(--primary-color);
77
+ }
78
+
69
79
  .solid_queue_monitor .navigation {
70
80
  display: flex;
71
81
  flex-wrap: wrap;
@@ -195,6 +205,22 @@ module SolidQueueMonitor
195
205
  color: var(--text-muted);
196
206
  }
197
207
 
208
+ .solid_queue_monitor .sortable-header {
209
+ color: var(--text-muted);
210
+ text-decoration: none;
211
+ cursor: pointer;
212
+ transition: color 0.2s;
213
+ }
214
+
215
+ .solid_queue_monitor .sortable-header:hover {
216
+ color: var(--primary-color);
217
+ }
218
+
219
+ .solid_queue_monitor .sortable-header.active {
220
+ color: var(--primary-color);
221
+ font-weight: 600;
222
+ }
223
+
198
224
  .solid_queue_monitor .status-badge {
199
225
  display: inline-block;
200
226
  padding: 0.25rem 0.5rem;
@@ -1178,6 +1204,98 @@ module SolidQueueMonitor
1178
1204
  gap: 0.75rem;
1179
1205
  }
1180
1206
 
1207
+ /* Header Search Box */
1208
+ .solid_queue_monitor .header-search-form {
1209
+ display: flex;
1210
+ align-items: center;
1211
+ gap: 0;
1212
+ flex: 1;
1213
+ max-width: 400px;
1214
+ margin: 0 1rem;
1215
+ }
1216
+
1217
+ .solid_queue_monitor .header-search-input {
1218
+ flex: 1;
1219
+ padding: 0.5rem 0.75rem;
1220
+ border: 1px solid var(--input-border);
1221
+ border-right: none;
1222
+ border-radius: 0.375rem 0 0 0.375rem;
1223
+ font-size: 0.875rem;
1224
+ background: var(--input-background);
1225
+ color: var(--text-color);
1226
+ outline: none;
1227
+ transition: border-color 0.2s, box-shadow 0.2s;
1228
+ }
1229
+
1230
+ .solid_queue_monitor .header-search-input:focus {
1231
+ border-color: var(--primary-color);
1232
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
1233
+ }
1234
+
1235
+ .solid_queue_monitor .header-search-input::placeholder {
1236
+ color: var(--text-muted);
1237
+ }
1238
+
1239
+ .solid_queue_monitor .header-search-button {
1240
+ display: flex;
1241
+ align-items: center;
1242
+ justify-content: center;
1243
+ padding: 0.5rem 0.75rem;
1244
+ background: var(--primary-color);
1245
+ color: white;
1246
+ border: 1px solid var(--primary-color);
1247
+ border-radius: 0 0.375rem 0.375rem 0;
1248
+ cursor: pointer;
1249
+ transition: background-color 0.2s;
1250
+ }
1251
+
1252
+ .solid_queue_monitor .header-search-button:hover {
1253
+ background: #2563eb;
1254
+ border-color: #2563eb;
1255
+ }
1256
+
1257
+ .solid_queue_monitor .header-search-button svg {
1258
+ width: 16px;
1259
+ height: 16px;
1260
+ }
1261
+
1262
+ @media (max-width: 768px) {
1263
+ .solid_queue_monitor .header-search-form {
1264
+ max-width: 100%;
1265
+ margin: 0.5rem 0;
1266
+ order: 3;
1267
+ width: 100%;
1268
+ }
1269
+ }
1270
+
1271
+ /* Search Results Page */
1272
+ .solid_queue_monitor .results-summary {
1273
+ margin: 1rem 0;
1274
+ padding: 0.75rem 1rem;
1275
+ background: var(--card-background);
1276
+ border-radius: 0.375rem;
1277
+ box-shadow: var(--card-shadow);
1278
+ }
1279
+
1280
+ .solid_queue_monitor .results-summary p {
1281
+ margin: 0;
1282
+ color: var(--text-muted);
1283
+ font-size: 0.875rem;
1284
+ }
1285
+
1286
+ .solid_queue_monitor .search-results-section {
1287
+ margin-top: 1.5rem;
1288
+ }
1289
+
1290
+ .solid_queue_monitor .search-results-section h3 {
1291
+ font-size: 1rem;
1292
+ font-weight: 600;
1293
+ color: var(--text-color);
1294
+ margin-bottom: 0.75rem;
1295
+ padding-bottom: 0.5rem;
1296
+ border-bottom: 1px solid var(--border-color);
1297
+ }
1298
+
1181
1299
  /* Workers Page Styles */
1182
1300
  .solid_queue_monitor .workers-summary {
1183
1301
  display: grid;
data/config/routes.rb CHANGED
@@ -7,6 +7,7 @@ SolidQueueMonitor::Engine.routes.draw do
7
7
  root to: 'overview#index'
8
8
 
9
9
  get 'chart_data', to: 'overview#chart_data', as: :chart_data
10
+ get 'search', to: 'search#index', as: :search
10
11
 
11
12
  resources :ready_jobs, only: [:index]
12
13
  resources :scheduled_jobs, only: [:index]
@@ -20,4 +20,7 @@ SolidQueueMonitor.setup do |config|
20
20
 
21
21
  # Auto-refresh interval in seconds (default: 30)
22
22
  # config.auto_refresh_interval = 30
23
+
24
+ # Disable the chart on the overview page to skip chart queries entirely.
25
+ # config.show_chart = true
23
26
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidQueueMonitor
4
- VERSION = '1.0.1'
4
+ VERSION = '1.2.0'
5
5
  end
@@ -7,7 +7,7 @@ module SolidQueueMonitor
7
7
  class Error < StandardError; end
8
8
  class << self
9
9
  attr_accessor :username, :password, :jobs_per_page, :authentication_enabled,
10
- :auto_refresh_enabled, :auto_refresh_interval
10
+ :auto_refresh_enabled, :auto_refresh_interval, :show_chart
11
11
  end
12
12
 
13
13
  @username = 'admin'
@@ -16,6 +16,7 @@ module SolidQueueMonitor
16
16
  @authentication_enabled = false
17
17
  @auto_refresh_enabled = true
18
18
  @auto_refresh_interval = 30 # seconds
19
+ @show_chart = true
19
20
 
20
21
  def self.setup
21
22
  yield self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_queue_monitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vishal Sadriya
@@ -58,6 +58,7 @@ files:
58
58
  - app/controllers/solid_queue_monitor/ready_jobs_controller.rb
59
59
  - app/controllers/solid_queue_monitor/recurring_jobs_controller.rb
60
60
  - app/controllers/solid_queue_monitor/scheduled_jobs_controller.rb
61
+ - app/controllers/solid_queue_monitor/search_controller.rb
61
62
  - app/controllers/solid_queue_monitor/workers_controller.rb
62
63
  - app/presenters/solid_queue_monitor/base_presenter.rb
63
64
  - app/presenters/solid_queue_monitor/failed_jobs_presenter.rb
@@ -69,6 +70,7 @@ files:
69
70
  - app/presenters/solid_queue_monitor/ready_jobs_presenter.rb
70
71
  - app/presenters/solid_queue_monitor/recurring_jobs_presenter.rb
71
72
  - app/presenters/solid_queue_monitor/scheduled_jobs_presenter.rb
73
+ - app/presenters/solid_queue_monitor/search_results_presenter.rb
72
74
  - app/presenters/solid_queue_monitor/stats_presenter.rb
73
75
  - app/presenters/solid_queue_monitor/workers_presenter.rb
74
76
  - app/services/solid_queue_monitor/authentication_service.rb
@@ -80,6 +82,7 @@ files:
80
82
  - app/services/solid_queue_monitor/pagination_service.rb
81
83
  - app/services/solid_queue_monitor/queue_pause_service.rb
82
84
  - app/services/solid_queue_monitor/reject_job_service.rb
85
+ - app/services/solid_queue_monitor/search_service.rb
83
86
  - app/services/solid_queue_monitor/stats_calculator.rb
84
87
  - app/services/solid_queue_monitor/status_calculator.rb
85
88
  - app/services/solid_queue_monitor/stylesheet_generator.rb
@@ -116,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
119
  - !ruby/object:Gem::Version
117
120
  version: '0'
118
121
  requirements: []
119
- rubygems_version: 3.6.7
122
+ rubygems_version: 4.0.6
120
123
  specification_version: 4
121
124
  summary: Simple monitoring interface for Solid Queue
122
125
  test_files: []