solid_queue_dashboard 0.0.1 → 0.1.1
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +5 -1
- data/Procfile.dev +2 -0
- data/README.md +73 -21
- data/app/assets/javascripts/solid_queue_dashboard/alpine.js +5 -0
- data/app/assets/javascripts/solid_queue_dashboard/application.js +46 -0
- data/app/assets/stylesheets/solid_queue_dashboard/application.css +2049 -0
- data/app/assets/stylesheets/solid_queue_dashboard/tailwind.css +554 -0
- data/app/controllers/solid_queue_dashboard/appearance_controller.rb +8 -0
- data/app/controllers/solid_queue_dashboard/application_controller.rb +7 -0
- data/app/controllers/solid_queue_dashboard/dashboard_controller.rb +8 -0
- data/app/controllers/solid_queue_dashboard/jobs_controller.rb +42 -0
- data/app/controllers/solid_queue_dashboard/processes_controller.rb +28 -0
- data/app/controllers/solid_queue_dashboard/recurring_tasks_controller.rb +30 -0
- data/app/helpers/solid_queue_dashboard/appearance_helper.rb +7 -0
- data/app/helpers/solid_queue_dashboard/application_helper.rb +7 -0
- data/app/helpers/solid_queue_dashboard/icons_helper.rb +231 -0
- data/app/helpers/solid_queue_dashboard/jobs_helper.rb +51 -0
- data/app/helpers/solid_queue_dashboard/pagination_helper.rb +38 -0
- data/app/helpers/solid_queue_dashboard/processes_helper.rb +35 -0
- data/app/helpers/solid_queue_dashboard/recurring_tasks_helper.rb +33 -0
- data/app/views/layouts/solid_queue_dashboard/application.html.erb +21 -0
- data/app/views/solid_queue_dashboard/application/_flash_messages.html.erb +38 -0
- data/app/views/solid_queue_dashboard/application/_footer.html.erb +11 -0
- data/app/views/solid_queue_dashboard/application/_navbar.html.erb +50 -0
- data/app/views/solid_queue_dashboard/application/_pagination.html.erb +19 -0
- data/app/views/solid_queue_dashboard/dashboard/index.html.erb +41 -0
- data/app/views/solid_queue_dashboard/jobs/_filters.html.erb +87 -0
- data/app/views/solid_queue_dashboard/jobs/_table.html.erb +19 -0
- data/app/views/solid_queue_dashboard/jobs/_table_row.html.erb +82 -0
- data/app/views/solid_queue_dashboard/jobs/index.html.erb +57 -0
- data/app/views/solid_queue_dashboard/jobs/show.html.erb +192 -0
- data/app/views/solid_queue_dashboard/processes/_filters.html.erb +64 -0
- data/app/views/solid_queue_dashboard/processes/_table.html.erb +18 -0
- data/app/views/solid_queue_dashboard/processes/_table_row.html.erb +32 -0
- data/app/views/solid_queue_dashboard/processes/index.html.erb +27 -0
- data/app/views/solid_queue_dashboard/processes/show.html.erb +79 -0
- data/app/views/solid_queue_dashboard/recurring_tasks/_filters.html.erb +26 -0
- data/app/views/solid_queue_dashboard/recurring_tasks/_table.html.erb +19 -0
- data/app/views/solid_queue_dashboard/recurring_tasks/_table_row.html.erb +31 -0
- data/app/views/solid_queue_dashboard/recurring_tasks/index.html.erb +21 -0
- data/app/views/solid_queue_dashboard/recurring_tasks/show.html.erb +129 -0
- data/bun.lockb +0 -0
- data/config/routes.rb +18 -0
- data/lib/solid_queue_dashboard/configuration.rb +17 -0
- data/lib/solid_queue_dashboard/decorators/job_decorator.rb +63 -0
- data/lib/solid_queue_dashboard/decorators/jobs_decorator.rb +74 -0
- data/lib/solid_queue_dashboard/decorators/process_decorator.rb +13 -0
- data/lib/solid_queue_dashboard/decorators/processes_decorator.rb +15 -0
- data/lib/solid_queue_dashboard/decorators/recurring_task_decorator.rb +22 -0
- data/lib/solid_queue_dashboard/decorators/recurring_tasks_decorator.rb +26 -0
- data/lib/solid_queue_dashboard/engine.rb +13 -0
- data/lib/solid_queue_dashboard/job.rb +26 -0
- data/lib/solid_queue_dashboard/process.rb +24 -0
- data/lib/solid_queue_dashboard/recurring_task.rb +14 -0
- data/lib/solid_queue_dashboard/version.rb +1 -1
- data/lib/solid_queue_dashboard.rb +39 -1
- data/package.json +13 -0
- data/tailwind.config.js +83 -0
- metadata +73 -4
@@ -0,0 +1,21 @@
|
|
1
|
+
<div class="card">
|
2
|
+
<div class="card-header border-b">
|
3
|
+
<h2 class="card-title">Recurring Tasks</h2>
|
4
|
+
|
5
|
+
<div class="!mt-4">
|
6
|
+
<%= render "solid_queue_dashboard/recurring_tasks/filters" %>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<div class="card-content !p-0">
|
11
|
+
<% if @recurring_tasks.any? %>
|
12
|
+
<%= render "solid_queue_dashboard/recurring_tasks/table", recurring_tasks: @recurring_tasks %>
|
13
|
+
<% else %>
|
14
|
+
<div class="px-6 py-12">
|
15
|
+
<p class="text-muted-foreground text-center">
|
16
|
+
No recurring tasks found
|
17
|
+
</p>
|
18
|
+
</div>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
21
|
+
</div>
|
@@ -0,0 +1,129 @@
|
|
1
|
+
<h1 class="text-4xl flex items-center gap-2">
|
2
|
+
<%= recurring_task_circle(@recurring_task.type, class: "size-4") %>
|
3
|
+
|
4
|
+
<span class="tracking-tighter font-bold">
|
5
|
+
Recurring Task #<%= @recurring_task.id %>
|
6
|
+
</span>
|
7
|
+
</h1>
|
8
|
+
|
9
|
+
<div class="card mt-6">
|
10
|
+
<div class="card-content pt-6 grid grid-cols-1 sm:grid-cols-2 sm:gap-16">
|
11
|
+
<div class="space-y-4">
|
12
|
+
<div class="info-line">
|
13
|
+
<span class="info-line-label">Type</span>
|
14
|
+
<div class="info-line-separator"></div>
|
15
|
+
<span class="info-line-value"><%= recurring_task_type_badge(@recurring_task.type) %></span>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="info-line">
|
19
|
+
<span class="info-line-label">Key</span>
|
20
|
+
<div class="info-line-separator"></div>
|
21
|
+
<span class="info-line-value"><%= @recurring_task.key %></span>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div class="info-line">
|
25
|
+
<span class="info-line-label">Schedule</span>
|
26
|
+
<div class="info-line-separator"></div>
|
27
|
+
<span class="info-line-value"><%= @recurring_task.schedule %></span>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<% if @recurring_task.queue_name? %>
|
31
|
+
<div class="info-line">
|
32
|
+
<span class="info-line-label">Queue Name</span>
|
33
|
+
<div class="info-line-separator"></div>
|
34
|
+
<span class="info-line-value"><%= @recurring_task.queue_name %></span>
|
35
|
+
</div>
|
36
|
+
<% end %>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<div class="space-y-4">
|
40
|
+
<% if @recurring_task.priority? %>
|
41
|
+
<div class="info-line">
|
42
|
+
<span class="info-line-label">Priority</span>
|
43
|
+
<div class="info-line-separator"></div>
|
44
|
+
<span class="info-line-value"><%= @recurring_task.priority %></span>
|
45
|
+
</div>
|
46
|
+
<% end %>
|
47
|
+
|
48
|
+
<div class="info-line">
|
49
|
+
<span class="info-line-label">Static</span>
|
50
|
+
<div class="info-line-separator"></div>
|
51
|
+
<span class="info-line-value"><%= @recurring_task.static ? "Yes" : "No" %></span>
|
52
|
+
</div>
|
53
|
+
|
54
|
+
<div class="info-line">
|
55
|
+
<span class="info-line-label">Created At</span>
|
56
|
+
<div class="info-line-separator"></div>
|
57
|
+
<span class="info-line-value" data-date><%= @recurring_task.created_at.to_fs(:database) %></span>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
<div class="info-line">
|
61
|
+
<span class="info-line-label">Updated At</span>
|
62
|
+
<div class="info-line-separator"></div>
|
63
|
+
<span class="info-line-value" data-date><%= @recurring_task.updated_at.to_fs(:database) %></span>
|
64
|
+
</div>
|
65
|
+
</div>
|
66
|
+
</div>
|
67
|
+
</div>
|
68
|
+
|
69
|
+
<% if @recurring_task.command.present? %>
|
70
|
+
<div class="card mt-8 overflow-hidden">
|
71
|
+
<div class="card-header border-b border-t-4 border-t-amber-500 dark:border-t-amber-600">
|
72
|
+
<h3 class="card-title">Command</h3>
|
73
|
+
<p class="card-description">The command to be executed</p>
|
74
|
+
</div>
|
75
|
+
<div class="card-content pt-6">
|
76
|
+
<pre><%= @recurring_task.command %></pre>
|
77
|
+
</div>
|
78
|
+
</div>
|
79
|
+
<% end %>
|
80
|
+
|
81
|
+
<% if @recurring_task.class_name.present? %>
|
82
|
+
<div class="card mt-8 overflow-hidden">
|
83
|
+
<div class="card-header border-b border-t-4 border-t-blue-500 dark:border-t-blue-600">
|
84
|
+
<h3 class="card-title">Job Class</h3>
|
85
|
+
<p class="card-description">The job class to be executed</p>
|
86
|
+
</div>
|
87
|
+
<div class="card-content pt-6">
|
88
|
+
<pre><%= @recurring_task.class_name %></pre>
|
89
|
+
</div>
|
90
|
+
</div>
|
91
|
+
<% end %>
|
92
|
+
|
93
|
+
<% if @recurring_task.arguments.present? %>
|
94
|
+
<div class="card mt-8 overflow-hidden">
|
95
|
+
<div class="card-header border-b border-t-4 border-t-purple-500 dark:border-t-purple-600">
|
96
|
+
<h3 class="card-title">Arguments</h3>
|
97
|
+
<p class="card-description">The arguments to be passed to the job</p>
|
98
|
+
</div>
|
99
|
+
<div class="card-content pt-6">
|
100
|
+
<pre><%= JSON.pretty_generate(@recurring_task.arguments) %></pre>
|
101
|
+
</div>
|
102
|
+
</div>
|
103
|
+
<% end %>
|
104
|
+
|
105
|
+
<% if @recurring_task.description.present? %>
|
106
|
+
<div class="card mt-8 overflow-hidden">
|
107
|
+
<div class="card-header border-b border-t-4 border-t-amber-500 dark:border-t-amber-600">
|
108
|
+
<h3 class="card-title">Description</h3>
|
109
|
+
<p class="card-description">Additional information about this recurring task</p>
|
110
|
+
</div>
|
111
|
+
<div class="card-content pt-6">
|
112
|
+
<pre><%= @recurring_task.description %></pre>
|
113
|
+
</div>
|
114
|
+
</div>
|
115
|
+
<% end %>
|
116
|
+
|
117
|
+
<div class="card mt-8 overflow-hidden">
|
118
|
+
<div class="card-header border-b border-t-4 border-t-zinc-500 dark:border-t-zinc-600">
|
119
|
+
<h3 class="card-title">Next Runs</h3>
|
120
|
+
<p class="card-description">Based on the current schedule</p>
|
121
|
+
</div>
|
122
|
+
<div class="card-content pt-5">
|
123
|
+
<ul class="list-decimal marker:text-sm marker:text-muted-foreground ml-4 space-y-1">
|
124
|
+
<% @recurring_task.next_runs.each do |run_time| %>
|
125
|
+
<li data-date><%= run_time.strftime("%Y-%m-%d %H:%M:%S %Z") %></li>
|
126
|
+
<% end %>
|
127
|
+
</ul>
|
128
|
+
</div>
|
129
|
+
</div>
|
data/bun.lockb
ADDED
Binary file
|
data/config/routes.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
SolidQueueDashboard::Engine.routes.draw do
|
2
|
+
resources :jobs, only: [ :index, :show ] do
|
3
|
+
member do
|
4
|
+
post :retry
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
resources :processes, only: [ :index, :show ]
|
9
|
+
|
10
|
+
resources :recurring_tasks, path: "recurring-tasks", only: [ :index, :show ] do
|
11
|
+
member do
|
12
|
+
post :enqueue
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
post "appearance/toggle", to: "appearance#toggle", as: :toggle_appearance
|
17
|
+
root "dashboard#index"
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :title
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@title = "Solid Queue Dashboard"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configuration
|
11
|
+
@configuration ||= Configuration.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.configure
|
15
|
+
yield(configuration)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
module Decorators
|
3
|
+
class JobDecorator < SimpleDelegator
|
4
|
+
def color
|
5
|
+
Job.status_color(status)
|
6
|
+
end
|
7
|
+
|
8
|
+
def status
|
9
|
+
return @status if defined?(@status)
|
10
|
+
|
11
|
+
@status = if retried?
|
12
|
+
Job::RETRIED
|
13
|
+
elsif failed?
|
14
|
+
Job::FAILED
|
15
|
+
elsif success?
|
16
|
+
Job::SUCCESS
|
17
|
+
elsif scheduled?
|
18
|
+
Job::SCHEDULED
|
19
|
+
else
|
20
|
+
Job::PENDING
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def success?
|
25
|
+
return @success if defined?(@success)
|
26
|
+
@success = finished_at.present? && !failed? && !retried?
|
27
|
+
end
|
28
|
+
|
29
|
+
def retried?
|
30
|
+
return @retried if defined?(@retried)
|
31
|
+
@retried = finished_at.present? && !failed_execution.present? &&
|
32
|
+
(arguments["executions"].to_i > 0 || execution_history.where(scheduled_at: finished_at..).any?)
|
33
|
+
end
|
34
|
+
|
35
|
+
def failed?
|
36
|
+
return @failed if defined?(@failed)
|
37
|
+
@failed = failed_execution.present?
|
38
|
+
end
|
39
|
+
|
40
|
+
def scheduled?
|
41
|
+
return @scheduled if defined?(@scheduled)
|
42
|
+
@scheduled = scheduled_at.present? && scheduled_at > Time.current
|
43
|
+
end
|
44
|
+
|
45
|
+
def pending?
|
46
|
+
return @pending if defined?(@pending)
|
47
|
+
@pending = !finished_at.present?
|
48
|
+
end
|
49
|
+
|
50
|
+
def execution_history
|
51
|
+
SolidQueue::Job.where(active_job_id: active_job_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def error_message
|
55
|
+
return @error_message if defined?(@error_message)
|
56
|
+
|
57
|
+
@error_message = failed_execution ?
|
58
|
+
"#{failed_execution.error["exception_class"]}: #{failed_execution.error["message"]}" :
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
module Decorators
|
3
|
+
class JobsDecorator < SimpleDelegator
|
4
|
+
def with_status(status)
|
5
|
+
case status.to_sym
|
6
|
+
when Job::SUCCESS
|
7
|
+
success
|
8
|
+
when Job::FAILED
|
9
|
+
failed
|
10
|
+
when Job::SCHEDULED
|
11
|
+
scheduled
|
12
|
+
when Job::PENDING
|
13
|
+
pending
|
14
|
+
when Job::RETRIED
|
15
|
+
retried
|
16
|
+
else
|
17
|
+
raise "Invalid status: #{status}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def success
|
22
|
+
where.not(finished_at: nil)
|
23
|
+
.where.not(id: failed)
|
24
|
+
.where.not(id: retried)
|
25
|
+
end
|
26
|
+
|
27
|
+
def scheduled
|
28
|
+
where(finished_at: nil, scheduled_at: Time.current..)
|
29
|
+
end
|
30
|
+
|
31
|
+
def pending
|
32
|
+
where(finished_at: nil, scheduled_at: ..Time.current)
|
33
|
+
.where.not(id: failed)
|
34
|
+
end
|
35
|
+
|
36
|
+
def retried
|
37
|
+
where(finished_at: ..Time.current)
|
38
|
+
.where.not(id: failed)
|
39
|
+
.where(
|
40
|
+
active_job_id: SolidQueue::Job
|
41
|
+
.select(:active_job_id)
|
42
|
+
.group(:active_job_id)
|
43
|
+
.having("COUNT(*) > 1")
|
44
|
+
)
|
45
|
+
.where.not(
|
46
|
+
id: SolidQueue::Job
|
47
|
+
.select("MAX(id)")
|
48
|
+
.group(:active_job_id)
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def failure_rate
|
53
|
+
success_count = success.count
|
54
|
+
retried_count = retried.count
|
55
|
+
failed_count = failed.count
|
56
|
+
|
57
|
+
total = success_count + retried_count + failed_count
|
58
|
+
return 0 if total.zero?
|
59
|
+
|
60
|
+
(failed_count + retried_count).to_f / total * 100
|
61
|
+
end
|
62
|
+
|
63
|
+
def each
|
64
|
+
super do |job|
|
65
|
+
yield JobDecorator.new(job)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_a
|
70
|
+
super.map { |job| JobDecorator.new(job) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
module Decorators
|
3
|
+
class ProcessesDecorator < SimpleDelegator
|
4
|
+
def each
|
5
|
+
super do |job|
|
6
|
+
yield ProcessDecorator.new(job)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_a
|
11
|
+
super.map { |job| ProcessDecorator.new(job) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
module Decorators
|
3
|
+
class RecurringTaskDecorator < SimpleDelegator
|
4
|
+
def type
|
5
|
+
if command.present?
|
6
|
+
RecurringTask::COMMAND
|
7
|
+
elsif class_name.present?
|
8
|
+
RecurringTask::JOB
|
9
|
+
else
|
10
|
+
"Unknown"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def next_runs(count: 5)
|
15
|
+
cron = Fugit.parse(schedule)
|
16
|
+
return [] unless cron
|
17
|
+
|
18
|
+
cron.next.take(count)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
module Decorators
|
3
|
+
class RecurringTasksDecorator < SimpleDelegator
|
4
|
+
def with_type(type)
|
5
|
+
case type.to_sym
|
6
|
+
when RecurringTask::JOB
|
7
|
+
where.not(class_name: nil)
|
8
|
+
when RecurringTask::COMMAND
|
9
|
+
where.not(command: nil)
|
10
|
+
else
|
11
|
+
raise "Unknown type: #{type}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def each
|
16
|
+
super do |task|
|
17
|
+
yield RecurringTaskDecorator.new(task)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_a
|
22
|
+
super.map { |task| RecurringTaskDecorator.new(task) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace SolidQueueDashboard
|
4
|
+
|
5
|
+
initializer "solid_queue_dashboard.assets.precompile" do |app|
|
6
|
+
app.config.assets.precompile += %w[
|
7
|
+
solid_queue_dashboard/alpine.js
|
8
|
+
solid_queue_dashboard/application.js
|
9
|
+
solid_queue_dashboard/application.css
|
10
|
+
]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
module Job
|
3
|
+
# Constants
|
4
|
+
SUCCESS = :success
|
5
|
+
RETRIED = :retried
|
6
|
+
FAILED = :failed
|
7
|
+
PENDING = :pending
|
8
|
+
SCHEDULED = :scheduled
|
9
|
+
|
10
|
+
STATUSES = [ SUCCESS, RETRIED, FAILED, SCHEDULED, PENDING ]
|
11
|
+
|
12
|
+
STATUS_COLORS = {
|
13
|
+
SUCCESS => "green",
|
14
|
+
RETRIED => "amber",
|
15
|
+
FAILED => "red",
|
16
|
+
SCHEDULED => "blue",
|
17
|
+
PENDING => "zinc"
|
18
|
+
}
|
19
|
+
|
20
|
+
COMMAND_CLASS_NAME = "SolidQueue::RecurringJob"
|
21
|
+
|
22
|
+
def self.status_color(status)
|
23
|
+
STATUS_COLORS[status] || "zinc"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SolidQueueDashboard
|
2
|
+
module Process
|
3
|
+
# Constants
|
4
|
+
SUPERVISOR = "Supervisor"
|
5
|
+
DISPATCHER = "Dispatcher"
|
6
|
+
WORKER = "Worker"
|
7
|
+
SCHEDULER = "Scheduler"
|
8
|
+
|
9
|
+
KINDS = [ SUPERVISOR, DISPATCHER, WORKER, SCHEDULER ]
|
10
|
+
|
11
|
+
KIND_COLORS = {
|
12
|
+
SUPERVISOR => "blue",
|
13
|
+
DISPATCHER => "green",
|
14
|
+
WORKER => "yellow",
|
15
|
+
SCHEDULER => "purple"
|
16
|
+
}
|
17
|
+
|
18
|
+
HEARTBEAT_DEAD_THRESHOLD = 1.minute
|
19
|
+
|
20
|
+
def self.kind_color(kind)
|
21
|
+
KIND_COLORS[kind] || "zinc"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,8 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rails"
|
3
4
|
require_relative "solid_queue_dashboard/version"
|
5
|
+
require_relative "solid_queue_dashboard/configuration"
|
6
|
+
require_relative "solid_queue_dashboard/engine"
|
7
|
+
require_relative "solid_queue_dashboard/job"
|
8
|
+
require_relative "solid_queue_dashboard/process"
|
9
|
+
require_relative "solid_queue_dashboard/recurring_task"
|
10
|
+
require_relative "solid_queue_dashboard/decorators/job_decorator"
|
11
|
+
require_relative "solid_queue_dashboard/decorators/jobs_decorator"
|
12
|
+
require_relative "solid_queue_dashboard/decorators/process_decorator"
|
13
|
+
require_relative "solid_queue_dashboard/decorators/processes_decorator"
|
14
|
+
require_relative "solid_queue_dashboard/decorators/recurring_task_decorator"
|
15
|
+
require_relative "solid_queue_dashboard/decorators/recurring_tasks_decorator"
|
4
16
|
|
5
17
|
module SolidQueueDashboard
|
6
18
|
class Error < StandardError; end
|
7
|
-
|
19
|
+
|
20
|
+
def self.job_queue_names
|
21
|
+
SolidQueue::Job.distinct.pluck(:queue_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.job_class_names
|
25
|
+
SolidQueue::Job.distinct.pluck(:class_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.decorate(object)
|
29
|
+
case object
|
30
|
+
when SolidQueue::Job
|
31
|
+
Decorators::JobDecorator.new(object)
|
32
|
+
when SolidQueue::Job.const_get(:ActiveRecord_Relation)
|
33
|
+
Decorators::JobsDecorator.new(object)
|
34
|
+
when SolidQueue::Process
|
35
|
+
Decorators::ProcessDecorator.new(object)
|
36
|
+
when SolidQueue::Process.const_get(:ActiveRecord_Relation)
|
37
|
+
Decorators::ProcessesDecorator.new(object)
|
38
|
+
when SolidQueue::RecurringTask
|
39
|
+
Decorators::RecurringTaskDecorator.new(object)
|
40
|
+
when SolidQueue::RecurringTask.const_get(:ActiveRecord_Relation)
|
41
|
+
Decorators::RecurringTasksDecorator.new(object)
|
42
|
+
else
|
43
|
+
raise Error, "Cannot decorate #{object.class}"
|
44
|
+
end
|
45
|
+
end
|
8
46
|
end
|
data/package.json
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"private": true,
|
3
|
+
"scripts": {
|
4
|
+
"build": "tailwindcss -i ./app/assets/stylesheets/solid_queue_dashboard/tailwind.css -o ./app/assets/stylesheets/solid_queue_dashboard/application.css",
|
5
|
+
"watch": "tailwindcss -i ./app/assets/stylesheets/solid_queue_dashboard/tailwind.css -o ./app/assets/stylesheets/solid_queue_dashboard/application.css --watch"
|
6
|
+
},
|
7
|
+
"devDependencies": {
|
8
|
+
"@tailwindcss/forms": "^0.5.9",
|
9
|
+
"@tailwindcss/typography": "^0.5.15",
|
10
|
+
"tailwindcss": "^3.4.13",
|
11
|
+
"tailwindcss-animate": "^1.0.7"
|
12
|
+
}
|
13
|
+
}
|
data/tailwind.config.js
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
const { fontFamily } = require("tailwindcss/defaultTheme")
|
2
|
+
|
3
|
+
/** @type {import('tailwindcss').Config} */
|
4
|
+
module.exports = {
|
5
|
+
darkMode: ["class"],
|
6
|
+
content: [
|
7
|
+
"./app/views/**/*.html.erb",
|
8
|
+
"./app/helpers/**/*.rb",
|
9
|
+
"./app/javascript/**/*.js",
|
10
|
+
],
|
11
|
+
theme: {
|
12
|
+
container: {
|
13
|
+
center: true,
|
14
|
+
padding: "2rem",
|
15
|
+
screens: {
|
16
|
+
"2xl": "1400px",
|
17
|
+
},
|
18
|
+
},
|
19
|
+
extend: {
|
20
|
+
colors: {
|
21
|
+
border: "hsl(var(--border))",
|
22
|
+
input: "hsl(var(--input))",
|
23
|
+
ring: "hsl(var(--ring))",
|
24
|
+
background: "hsl(var(--background))",
|
25
|
+
foreground: "hsl(var(--foreground))",
|
26
|
+
primary: {
|
27
|
+
DEFAULT: "hsl(var(--primary))",
|
28
|
+
foreground: "hsl(var(--primary-foreground))",
|
29
|
+
},
|
30
|
+
secondary: {
|
31
|
+
DEFAULT: "hsl(var(--secondary))",
|
32
|
+
foreground: "hsl(var(--secondary-foreground))",
|
33
|
+
},
|
34
|
+
destructive: {
|
35
|
+
DEFAULT: "hsl(var(--destructive))",
|
36
|
+
foreground: "hsl(var(--destructive-foreground))",
|
37
|
+
},
|
38
|
+
muted: {
|
39
|
+
DEFAULT: "hsl(var(--muted))",
|
40
|
+
foreground: "hsl(var(--muted-foreground))",
|
41
|
+
},
|
42
|
+
accent: {
|
43
|
+
DEFAULT: "hsl(var(--accent))",
|
44
|
+
foreground: "hsl(var(--accent-foreground))",
|
45
|
+
},
|
46
|
+
popover: {
|
47
|
+
DEFAULT: "hsl(var(--popover))",
|
48
|
+
foreground: "hsl(var(--popover-foreground))",
|
49
|
+
},
|
50
|
+
card: {
|
51
|
+
DEFAULT: "hsl(var(--card))",
|
52
|
+
foreground: "hsl(var(--card-foreground))",
|
53
|
+
},
|
54
|
+
},
|
55
|
+
borderRadius: {
|
56
|
+
lg: `var(--radius)`,
|
57
|
+
md: `calc(var(--radius) - 2px)`,
|
58
|
+
sm: "calc(var(--radius) - 4px)",
|
59
|
+
},
|
60
|
+
opacity: {
|
61
|
+
7.5: "0.075",
|
62
|
+
},
|
63
|
+
keyframes: {
|
64
|
+
"accordion-down": {
|
65
|
+
from: { height: "0" },
|
66
|
+
to: { height: "var(--radix-accordion-content-height)" },
|
67
|
+
},
|
68
|
+
"accordion-up": {
|
69
|
+
from: { height: "var(--radix-accordion-content-height)" },
|
70
|
+
to: { height: "0" },
|
71
|
+
},
|
72
|
+
},
|
73
|
+
animation: {
|
74
|
+
"accordion-down": "accordion-down 0.2s ease-out",
|
75
|
+
"accordion-up": "accordion-up 0.2s ease-out",
|
76
|
+
},
|
77
|
+
},
|
78
|
+
},
|
79
|
+
plugins: [
|
80
|
+
require("tailwindcss-animate"),
|
81
|
+
require("@tailwindcss/forms")({ strategy: "class" }),
|
82
|
+
],
|
83
|
+
}
|