solid_queue_web 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7de0f3d542cd6cd6d162d4069eb5ca373e5ee6fca1738937c2a00ac3f9560956
4
- data.tar.gz: f8bb5e17912f2e87287aba8a5e6a057eb64adafbea6934aecac8b2559bc17290
3
+ metadata.gz: 439fb2adc133452cb89ebcf1d4376e9fd45d4e19a7f1ebc4a37d4b72e89f4b54
4
+ data.tar.gz: 644a02acffccaeba6420d1374f411796e4219b4883d6cdaa17ffe25b1c2a4b01
5
5
  SHA512:
6
- metadata.gz: ad6b13a2fe53124e78d5365d112eeb1e8811db4a5ba2be56e0e1d5fb4ac7da13c6f503cc0b71c68e4c295119764d3b4211767609a10efeca2ea8abc472dc51ef
7
- data.tar.gz: 6d046fa5771188fe639ad72960ec4d3ab55916fc4e8d702e68d21b838ee5bdf9b25e6eda641b051ed6d10ecfec69dcdb4720841f170ba02b834d23e2113d516a
6
+ metadata.gz: b65ef968cbcd72f56df7039b7cfa22fbbc94db21d7e1edeabdad1a07293ba35f17b614471d1034fdcf0d2979ed8bfb3deacb2101b99667f87f1553546b6ad36c
7
+ data.tar.gz: 616474ab808602a116c997787580e0d665c6e4ba1dab9b36eab60d74b36285bd629198666fcbd4e16a0128a63875f079a43571470ff3a0320e9316b9a8c8d599
@@ -139,6 +139,18 @@ body {
139
139
  .sqd-stat--queues .sqd-stat__value { color: var(--purple); }
140
140
  .sqd-stat--processes .sqd-stat__value { color: var(--muted); }
141
141
 
142
+ .sqd-stat--link {
143
+ display: block;
144
+ text-decoration: none;
145
+ color: inherit;
146
+ transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
147
+ }
148
+ .sqd-stat--link:hover {
149
+ border-color: var(--primary);
150
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
151
+ transform: translateY(-2px);
152
+ }
153
+
142
154
  /* Tables */
143
155
  .sqd-card {
144
156
  background: var(--surface);
@@ -3,19 +3,21 @@ module SolidQueueWeb
3
3
  STATUSES = %w[ready scheduled claimed blocked failed].freeze
4
4
  DISCARDABLE = %w[ready scheduled blocked].freeze
5
5
 
6
+ before_action :set_status_and_queue, only: [ :destroy, :discard_all ]
7
+
8
+ EXECUTION_MODELS = {
9
+ "ready" => SolidQueue::ReadyExecution,
10
+ "scheduled" => SolidQueue::ScheduledExecution,
11
+ "claimed" => SolidQueue::ClaimedExecution,
12
+ "blocked" => SolidQueue::BlockedExecution,
13
+ "failed" => SolidQueue::FailedExecution
14
+ }.freeze
15
+
6
16
  def index
7
17
  @status = params[:status].presence_in(STATUSES) || "ready"
8
18
  @queue = params[:queue].presence
9
-
10
- @jobs = case @status
11
- when "ready" then SolidQueue::ReadyExecution.includes(:job)
12
- when "scheduled" then SolidQueue::ScheduledExecution.includes(:job)
13
- when "claimed" then SolidQueue::ClaimedExecution.includes(:job)
14
- when "blocked" then SolidQueue::BlockedExecution.includes(:job)
15
- when "failed" then SolidQueue::FailedExecution.includes(:job)
16
- end
17
-
18
- @jobs = @jobs.where(jobs: { queue_name: @queue }) if @queue.present?
19
+ @jobs = EXECUTION_MODELS[@status].includes(:job)
20
+ @jobs = @jobs.where(jobs: { queue_name: @queue }) if @queue.present?
19
21
  @pagy, @jobs = pagy(@jobs.order(created_at: :desc))
20
22
  end
21
23
 
@@ -28,27 +30,30 @@ module SolidQueueWeb
28
30
  end
29
31
 
30
32
  def destroy
31
- execution = execution_model_for!(params[:status]).find(params[:id])
32
- execution.discard
33
- redirect_to jobs_path(status: params[:status], queue: params[:queue]), notice: "Job discarded."
33
+ model = execution_model_for!(@status)
34
+ @execution = model.find(params[:id])
35
+ @execution.discard
36
+ @remaining_count = filtered_scope(model).count
37
+ respond_to do |format|
38
+ format.turbo_stream
39
+ format.html { redirect_to jobs_path(status: @status, queue: @queue), notice: "Job discarded." }
40
+ end
34
41
  rescue ArgumentError => e
35
- redirect_to jobs_path(status: params[:status], queue: params[:queue]), alert: e.message
42
+ redirect_to jobs_path(status: @status, queue: @queue), alert: e.message
36
43
  rescue => e
37
- redirect_to jobs_path(status: params[:status], queue: params[:queue]), alert: "Could not discard job: #{e.message}"
44
+ redirect_to jobs_path(status: @status, queue: @queue), alert: "Could not discard job: #{e.message}"
38
45
  end
39
46
 
40
47
  def discard_all
41
- model = execution_model_for!(params[:status])
42
- scope = model.includes(:job)
43
- scope = scope.where(jobs: { queue_name: params[:queue] }) if params[:queue].present?
44
- jobs = scope.map(&:job)
48
+ model = execution_model_for!(@status)
49
+ jobs = filtered_scope(model).map(&:job)
45
50
  model.discard_all_from_jobs(jobs)
46
- redirect_to jobs_path(status: params[:status], queue: params[:queue]),
51
+ redirect_to jobs_path(status: @status, queue: @queue),
47
52
  notice: "#{jobs.size} #{"job".pluralize(jobs.size)} discarded."
48
53
  rescue ArgumentError => e
49
- redirect_to jobs_path(status: params[:status], queue: params[:queue]), alert: e.message
54
+ redirect_to jobs_path(status: @status, queue: @queue), alert: e.message
50
55
  rescue => e
51
- redirect_to jobs_path(status: params[:status], queue: params[:queue]), alert: "Could not discard jobs: #{e.message}"
56
+ redirect_to jobs_path(status: @status, queue: @queue), alert: "Could not discard jobs: #{e.message}"
52
57
  end
53
58
 
54
59
  private
@@ -62,13 +67,19 @@ module SolidQueueWeb
62
67
  "finished"
63
68
  end
64
69
 
70
+ def set_status_and_queue
71
+ @status = params[:status]
72
+ @queue = params[:queue].presence
73
+ end
74
+
75
+ def filtered_scope(model)
76
+ scope = model.includes(:job)
77
+ @queue.present? ? scope.where(jobs: { queue_name: @queue }) : scope
78
+ end
79
+
65
80
  def execution_model_for!(status)
66
- case status
67
- when "ready" then SolidQueue::ReadyExecution
68
- when "scheduled" then SolidQueue::ScheduledExecution
69
- when "blocked" then SolidQueue::BlockedExecution
70
- else raise ArgumentError, "Cannot discard #{status} jobs from this page."
71
- end
81
+ raise ArgumentError, "Cannot discard #{status} jobs from this page." unless DISCARDABLE.include?(status)
82
+ EXECUTION_MODELS[status]
72
83
  end
73
84
  end
74
85
  end
@@ -1,34 +1,34 @@
1
1
  <h1 class="sqd-page-title">Dashboard</h1>
2
2
 
3
3
  <div class="sqd-stats">
4
- <div class="sqd-stat sqd-stat--ready">
4
+ <%= link_to jobs_path(status: "ready"), class: "sqd-stat sqd-stat--ready sqd-stat--link" do %>
5
5
  <div class="sqd-stat__value"><%= @stats[:ready] %></div>
6
6
  <div class="sqd-stat__label">Ready</div>
7
- </div>
8
- <div class="sqd-stat sqd-stat--scheduled">
7
+ <% end %>
8
+ <%= link_to jobs_path(status: "scheduled"), class: "sqd-stat sqd-stat--scheduled sqd-stat--link" do %>
9
9
  <div class="sqd-stat__value"><%= @stats[:scheduled] %></div>
10
10
  <div class="sqd-stat__label">Scheduled</div>
11
- </div>
12
- <div class="sqd-stat sqd-stat--claimed">
11
+ <% end %>
12
+ <%= link_to jobs_path(status: "claimed"), class: "sqd-stat sqd-stat--claimed sqd-stat--link" do %>
13
13
  <div class="sqd-stat__value"><%= @stats[:claimed] %></div>
14
14
  <div class="sqd-stat__label">Running</div>
15
- </div>
16
- <div class="sqd-stat sqd-stat--blocked">
15
+ <% end %>
16
+ <%= link_to jobs_path(status: "blocked"), class: "sqd-stat sqd-stat--blocked sqd-stat--link" do %>
17
17
  <div class="sqd-stat__value"><%= @stats[:blocked] %></div>
18
18
  <div class="sqd-stat__label">Blocked</div>
19
- </div>
20
- <div class="sqd-stat sqd-stat--failed">
19
+ <% end %>
20
+ <%= link_to failed_jobs_path, class: "sqd-stat sqd-stat--failed sqd-stat--link" do %>
21
21
  <div class="sqd-stat__value"><%= @stats[:failed] %></div>
22
22
  <div class="sqd-stat__label">Failed</div>
23
- </div>
24
- <div class="sqd-stat sqd-stat--queues">
23
+ <% end %>
24
+ <%= link_to queues_path, class: "sqd-stat sqd-stat--queues sqd-stat--link" do %>
25
25
  <div class="sqd-stat__value"><%= @stats[:queues] %></div>
26
26
  <div class="sqd-stat__label">Queues</div>
27
- </div>
28
- <div class="sqd-stat sqd-stat--processes">
27
+ <% end %>
28
+ <%= link_to processes_path, class: "sqd-stat sqd-stat--processes sqd-stat--link" do %>
29
29
  <div class="sqd-stat__value"><%= @stats[:processes] %></div>
30
30
  <div class="sqd-stat__label">Processes</div>
31
- </div>
31
+ <% end %>
32
32
  </div>
33
33
 
34
34
  <div style="display:grid; grid-template-columns: 1fr 1fr; gap: 1rem;">
@@ -0,0 +1,9 @@
1
+ <% if @remaining_count == 0 %>
2
+ <%= turbo_stream.replace "jobs-list" do %>
3
+ <div class="sqd-card" id="jobs-list">
4
+ <div class="sqd-empty">No <%= @status %> jobs.</div>
5
+ </div>
6
+ <% end %>
7
+ <% else %>
8
+ <%= turbo_stream.remove "execution_#{@execution.id}" %>
9
+ <% end %>
@@ -1,7 +1,16 @@
1
+ <h1 class="sqd-page-title" style="margin-bottom: 1.5rem;">Jobs</h1>
2
+
3
+ <%= turbo_frame_tag "jobs-table" do %>
1
4
  <% discardable = SolidQueueWeb::JobsController::DISCARDABLE.include?(@status) %>
2
5
 
3
6
  <div class="sqd-page-header">
4
- <h1 class="sqd-page-title">Jobs</h1>
7
+ <div class="sqd-filters">
8
+ <%= link_to "Ready", jobs_path(status: "ready", queue: @queue), class: @status == "ready" ? "active" : "" %>
9
+ <%= link_to "Scheduled", jobs_path(status: "scheduled", queue: @queue), class: @status == "scheduled" ? "active" : "" %>
10
+ <%= link_to "Running", jobs_path(status: "claimed", queue: @queue), class: @status == "claimed" ? "active" : "" %>
11
+ <%= link_to "Blocked", jobs_path(status: "blocked", queue: @queue), class: @status == "blocked" ? "active" : "" %>
12
+ <%= link_to "Failed", jobs_path(status: "failed", queue: @queue), class: @status == "failed" ? "active" : "" %>
13
+ </div>
5
14
  <% if discardable && @jobs.any? %>
6
15
  <div class="sqd-actions">
7
16
  <%= button_to "Discard All", discard_all_jobs_path,
@@ -13,15 +22,7 @@
13
22
  <% end %>
14
23
  </div>
15
24
 
16
- <div class="sqd-filters">
17
- <%= link_to "Ready", jobs_path(status: "ready", queue: @queue), class: @status == "ready" ? "active" : "" %>
18
- <%= link_to "Scheduled", jobs_path(status: "scheduled", queue: @queue), class: @status == "scheduled" ? "active" : "" %>
19
- <%= link_to "Running", jobs_path(status: "claimed", queue: @queue), class: @status == "claimed" ? "active" : "" %>
20
- <%= link_to "Blocked", jobs_path(status: "blocked", queue: @queue), class: @status == "blocked" ? "active" : "" %>
21
- <%= link_to "Failed", jobs_path(status: "failed", queue: @queue), class: @status == "failed" ? "active" : "" %>
22
- </div>
23
-
24
- <div class="sqd-card">
25
+ <div class="sqd-card" id="jobs-list">
25
26
  <% if @jobs.empty? %>
26
27
  <div class="sqd-empty">No <%= @status %> jobs.</div>
27
28
  <% else %>
@@ -39,7 +40,7 @@
39
40
  <tbody>
40
41
  <% @jobs.each do |execution| %>
41
42
  <% job = execution.job %>
42
- <tr>
43
+ <tr id="execution_<%= execution.id %>">
43
44
  <td>
44
45
  <span class="sqd-badge sqd-badge--<%= @status %>"><%= @status %></span>
45
46
  <%= link_to job.class_name, job_path(job), style: "margin-left: 0.5rem;" %>
@@ -78,4 +79,5 @@
78
79
  Filtering by queue: <strong><%= @queue %></strong> &mdash;
79
80
  <%= link_to "Clear filter", jobs_path(status: @status) %>
80
81
  </p>
82
+ <% end %>
81
83
  <% end %>
@@ -1,6 +1,7 @@
1
1
  require "solid_queue"
2
2
  require "pagy"
3
3
  require "pagy/toolbox/paginators/method"
4
+ require "turbo-rails"
4
5
 
5
6
  module SolidQueueWeb
6
7
  class Engine < ::Rails::Engine
@@ -1,3 +1,3 @@
1
1
  module SolidQueueWeb
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_queue_web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith
@@ -51,6 +51,20 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '43.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: turbo-rails
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '2.0'
54
68
  description: Mount SolidQueueWeb in any Rails app using Solid Queue to get a dashboard
55
69
  for your queues, jobs by status, failed executions, and job actions (retry, discard)
56
70
  — all without leaving your app.
@@ -76,6 +90,7 @@ files:
76
90
  - app/views/layouts/solid_queue_web/application.html.erb
77
91
  - app/views/solid_queue_web/dashboard/index.html.erb
78
92
  - app/views/solid_queue_web/failed_jobs/index.html.erb
93
+ - app/views/solid_queue_web/jobs/destroy.turbo_stream.erb
79
94
  - app/views/solid_queue_web/jobs/index.html.erb
80
95
  - app/views/solid_queue_web/jobs/show.html.erb
81
96
  - app/views/solid_queue_web/processes/index.html.erb