solid_queue_tui 0.1.1 → 0.1.2
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/exe/sqtui +20 -1
- data/lib/solid_queue_tui/actions/discard_job.rb +4 -21
- data/lib/solid_queue_tui/actions/discard_scheduled_job.rb +5 -21
- data/lib/solid_queue_tui/actions/dispatch_scheduled_job.rb +4 -23
- data/lib/solid_queue_tui/actions/enqueue_recurring_task.rb +12 -0
- data/lib/solid_queue_tui/actions/retry_job.rb +14 -59
- data/lib/solid_queue_tui/actions/toggle_queue_pause.rb +19 -0
- data/lib/solid_queue_tui/application.rb +73 -17
- data/lib/solid_queue_tui/cli.rb +15 -8
- data/lib/solid_queue_tui/components/header.rb +26 -27
- data/lib/solid_queue_tui/components/help_bar.rb +1 -0
- data/lib/solid_queue_tui/components/job_table.rb +14 -2
- data/lib/solid_queue_tui/data/failed_query.rb +37 -91
- data/lib/solid_queue_tui/data/jobs_query.rb +90 -123
- data/lib/solid_queue_tui/data/processes_query.rb +10 -34
- data/lib/solid_queue_tui/data/queues_query.rb +6 -15
- data/lib/solid_queue_tui/data/recurring_tasks_query.rb +36 -0
- data/lib/solid_queue_tui/data/stats.rb +9 -27
- data/lib/solid_queue_tui/railtie.rb +9 -0
- data/lib/solid_queue_tui/version.rb +1 -1
- data/lib/solid_queue_tui/views/blocked_view.rb +126 -46
- data/lib/solid_queue_tui/views/concerns/filterable.rb +128 -0
- data/lib/solid_queue_tui/views/dashboard_view.rb +2 -1
- data/lib/solid_queue_tui/views/failed_view.rb +62 -72
- data/lib/solid_queue_tui/views/finished_view.rb +54 -67
- data/lib/solid_queue_tui/views/in_progress_view.rb +124 -44
- data/lib/solid_queue_tui/views/queues_view.rb +119 -35
- data/lib/solid_queue_tui/views/recurring_tasks_view.rb +202 -0
- data/lib/solid_queue_tui/views/scheduled_view.rb +74 -8
- data/lib/solid_queue_tui.rb +15 -4
- data/lib/tasks/solid_queue_tui.rake +8 -0
- metadata +16 -24
- data/lib/solid_queue_tui/connection.rb +0 -58
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SolidQueueTui
|
|
4
|
+
module Views
|
|
5
|
+
class RecurringTasksView
|
|
6
|
+
def initialize(tui)
|
|
7
|
+
@tui = tui
|
|
8
|
+
@table_state = RatatuiRuby::TableState.new(nil)
|
|
9
|
+
@table_state.select(0)
|
|
10
|
+
@selected_row = 0
|
|
11
|
+
@tasks = []
|
|
12
|
+
@confirm_action = nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def update(tasks:)
|
|
16
|
+
@tasks = tasks
|
|
17
|
+
@selected_row = @selected_row.clamp(0, [@tasks.size - 1, 0].max)
|
|
18
|
+
@table_state.select(@selected_row)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def render(frame, area)
|
|
22
|
+
if @confirm_action
|
|
23
|
+
confirm_area, content_area = @tui.layout_split(
|
|
24
|
+
area,
|
|
25
|
+
direction: :vertical,
|
|
26
|
+
constraints: [
|
|
27
|
+
@tui.constraint_length(3),
|
|
28
|
+
@tui.constraint_fill(1)
|
|
29
|
+
]
|
|
30
|
+
)
|
|
31
|
+
render_confirm(frame, confirm_area)
|
|
32
|
+
render_table(frame, content_area)
|
|
33
|
+
else
|
|
34
|
+
render_table(frame, area)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def handle_input(event)
|
|
39
|
+
if @confirm_action
|
|
40
|
+
handle_confirm_input(event)
|
|
41
|
+
else
|
|
42
|
+
handle_normal_input(event)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def selected_item
|
|
47
|
+
return nil if @tasks.empty? || @selected_row >= @tasks.size
|
|
48
|
+
@tasks[@selected_row]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def capturing_input?
|
|
52
|
+
!!@confirm_action
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def bindings
|
|
56
|
+
if @confirm_action
|
|
57
|
+
[
|
|
58
|
+
{ key: "y", action: "Confirm" },
|
|
59
|
+
{ key: "n/Esc", action: "Cancel" }
|
|
60
|
+
]
|
|
61
|
+
else
|
|
62
|
+
[
|
|
63
|
+
{ key: "j/k", action: "Navigate" },
|
|
64
|
+
{ key: "N", action: "Run Now" },
|
|
65
|
+
{ key: "G/g", action: "Bottom/Top" }
|
|
66
|
+
]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def breadcrumb = "recurring"
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def handle_normal_input(event)
|
|
75
|
+
case event
|
|
76
|
+
in { type: :key, code: "j" } | { type: :key, code: "up" }
|
|
77
|
+
move_selection(-1)
|
|
78
|
+
in { type: :key, code: "k" } | { type: :key, code: "down" }
|
|
79
|
+
move_selection(1)
|
|
80
|
+
in { type: :key, code: "g" }
|
|
81
|
+
jump_to_top
|
|
82
|
+
in { type: :key, code: "G" }
|
|
83
|
+
jump_to_bottom
|
|
84
|
+
in { type: :key, code: "N" }
|
|
85
|
+
@confirm_action = :run_now if selected_item
|
|
86
|
+
nil
|
|
87
|
+
else
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def handle_confirm_input(event)
|
|
93
|
+
case event
|
|
94
|
+
in { type: :key, code: "y" }
|
|
95
|
+
@confirm_action = nil
|
|
96
|
+
task = selected_item
|
|
97
|
+
return nil unless task
|
|
98
|
+
Actions::EnqueueRecurringTask.call(task.key)
|
|
99
|
+
:refresh
|
|
100
|
+
in { type: :key, code: "n" } | { type: :key, code: "esc" }
|
|
101
|
+
@confirm_action = nil
|
|
102
|
+
nil
|
|
103
|
+
else
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def move_selection(delta)
|
|
109
|
+
return if @tasks.empty?
|
|
110
|
+
@selected_row = (@selected_row + delta).clamp(0, @tasks.size - 1)
|
|
111
|
+
@table_state.select(@selected_row)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def jump_to_top
|
|
115
|
+
@selected_row = 0
|
|
116
|
+
@table_state.select(0)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def jump_to_bottom
|
|
120
|
+
return if @tasks.empty?
|
|
121
|
+
@selected_row = @tasks.size - 1
|
|
122
|
+
@table_state.select(@selected_row)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def render_table(frame, area)
|
|
126
|
+
columns = [
|
|
127
|
+
{ key: :key, label: "KEY", width: :fill },
|
|
128
|
+
{ key: :class_name, label: "CLASS", width: :fill },
|
|
129
|
+
{ key: :schedule, label: "SCHEDULE", width: 20 },
|
|
130
|
+
{ key: :queue_name, label: "QUEUE", width: 14 },
|
|
131
|
+
{ key: :last_enqueued_at, label: "LAST ENQUEUED", width: 20 },
|
|
132
|
+
{ key: :next_time, label: "NEXT", width: 20 }
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
rows = @tasks.map do |task|
|
|
136
|
+
{
|
|
137
|
+
key: task.key,
|
|
138
|
+
class_name: task.class_name || task.command || "n/a",
|
|
139
|
+
schedule: task.schedule,
|
|
140
|
+
queue_name: task.queue_name || "default",
|
|
141
|
+
last_enqueued_at: time_ago(task.last_enqueued_at),
|
|
142
|
+
next_time: time_until(task.next_time)
|
|
143
|
+
}
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
table = Components::JobTable.new(
|
|
147
|
+
@tui,
|
|
148
|
+
title: "Recurring Tasks",
|
|
149
|
+
columns: columns,
|
|
150
|
+
rows: rows,
|
|
151
|
+
selected_row: @selected_row,
|
|
152
|
+
empty_message: "No recurring tasks configured"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
table.render(frame, area, @table_state)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def render_confirm(frame, area)
|
|
159
|
+
task = selected_item
|
|
160
|
+
message = "Run '#{task&.key}' (#{task&.class_name || task&.command}) now? [y/n]"
|
|
161
|
+
|
|
162
|
+
frame.render_widget(
|
|
163
|
+
@tui.paragraph(
|
|
164
|
+
text: " #{message}",
|
|
165
|
+
style: @tui.style(fg: :yellow, modifiers: [:bold]),
|
|
166
|
+
block: @tui.block(
|
|
167
|
+
title: " Confirm ",
|
|
168
|
+
title_style: @tui.style(fg: :red, modifiers: [:bold]),
|
|
169
|
+
borders: [:all],
|
|
170
|
+
border_type: :rounded,
|
|
171
|
+
border_style: @tui.style(fg: :red)
|
|
172
|
+
)
|
|
173
|
+
),
|
|
174
|
+
area
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def time_ago(time)
|
|
179
|
+
return "Never" unless time
|
|
180
|
+
seconds = (Time.now.utc - time).to_i
|
|
181
|
+
return "just now" if seconds < 5
|
|
182
|
+
"#{humanize_duration(seconds)} ago"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def time_until(time)
|
|
186
|
+
return "n/a" unless time
|
|
187
|
+
seconds = (time - Time.now.utc).to_i
|
|
188
|
+
return "now" if seconds <= 0
|
|
189
|
+
"in #{humanize_duration(seconds)}"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def humanize_duration(seconds)
|
|
193
|
+
case seconds.abs
|
|
194
|
+
when 0..59 then "#{seconds.abs}s"
|
|
195
|
+
when 60..3599 then "#{seconds.abs / 60}m"
|
|
196
|
+
when 3600..86399 then "#{seconds.abs / 3600}h"
|
|
197
|
+
else "#{seconds.abs / 86400}d"
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
@@ -3,33 +3,74 @@
|
|
|
3
3
|
module SolidQueueTui
|
|
4
4
|
module Views
|
|
5
5
|
class ScheduledView
|
|
6
|
+
include Filterable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
LOAD_THRESHOLD = 10
|
|
10
|
+
|
|
6
11
|
def initialize(tui)
|
|
7
12
|
@tui = tui
|
|
8
13
|
@table_state = RatatuiRuby::TableState.new(nil)
|
|
9
14
|
@table_state.select(0)
|
|
10
15
|
@selected_row = 0
|
|
11
16
|
@jobs = []
|
|
17
|
+
@total_count = nil
|
|
18
|
+
@all_loaded = false
|
|
12
19
|
@confirm_action = nil
|
|
20
|
+
init_filter
|
|
13
21
|
end
|
|
14
22
|
|
|
15
23
|
def update(jobs:)
|
|
16
24
|
@jobs = jobs
|
|
25
|
+
@all_loaded = jobs.size < SolidQueueTui.page_size
|
|
17
26
|
@selected_row = @selected_row.clamp(0, [@jobs.size - 1, 0].max)
|
|
18
27
|
@table_state.select(@selected_row)
|
|
19
28
|
end
|
|
20
29
|
|
|
30
|
+
def append(jobs:)
|
|
31
|
+
@jobs.concat(jobs)
|
|
32
|
+
@all_loaded = jobs.size < SolidQueueTui.page_size
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def total_count=(count)
|
|
36
|
+
@total_count = count
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def current_offset
|
|
40
|
+
@jobs.size
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reset_pagination!
|
|
44
|
+
@jobs = []
|
|
45
|
+
@total_count = nil
|
|
46
|
+
@all_loaded = false
|
|
47
|
+
@selected_row = 0
|
|
48
|
+
@table_state.select(0)
|
|
49
|
+
end
|
|
50
|
+
|
|
21
51
|
def render(frame, area)
|
|
22
52
|
if @confirm_action
|
|
23
|
-
|
|
53
|
+
confirm_area, content_area = @tui.layout_split(
|
|
24
54
|
area,
|
|
25
55
|
direction: :vertical,
|
|
26
56
|
constraints: [
|
|
27
|
-
@tui.
|
|
28
|
-
@tui.
|
|
57
|
+
@tui.constraint_length(3),
|
|
58
|
+
@tui.constraint_fill(1)
|
|
29
59
|
]
|
|
30
60
|
)
|
|
31
|
-
render_table(frame, content_area)
|
|
32
61
|
render_confirm(frame, confirm_area)
|
|
62
|
+
render_table(frame, content_area)
|
|
63
|
+
elsif filter_mode?
|
|
64
|
+
filter_area, content_area = @tui.layout_split(
|
|
65
|
+
area,
|
|
66
|
+
direction: :vertical,
|
|
67
|
+
constraints: [
|
|
68
|
+
@tui.constraint_length(3),
|
|
69
|
+
@tui.constraint_fill(1)
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
render_filter_input(frame, filter_area)
|
|
73
|
+
render_table(frame, content_area)
|
|
33
74
|
else
|
|
34
75
|
render_table(frame, area)
|
|
35
76
|
end
|
|
@@ -38,6 +79,8 @@ module SolidQueueTui
|
|
|
38
79
|
def handle_input(event)
|
|
39
80
|
if @confirm_action
|
|
40
81
|
handle_confirm_input(event)
|
|
82
|
+
elsif filter_mode?
|
|
83
|
+
handle_filter_input(event)
|
|
41
84
|
else
|
|
42
85
|
handle_normal_input(event)
|
|
43
86
|
end
|
|
@@ -49,7 +92,7 @@ module SolidQueueTui
|
|
|
49
92
|
end
|
|
50
93
|
|
|
51
94
|
def capturing_input?
|
|
52
|
-
|
|
95
|
+
filter_mode? || @confirm_action
|
|
53
96
|
end
|
|
54
97
|
|
|
55
98
|
def bindings
|
|
@@ -58,10 +101,13 @@ module SolidQueueTui
|
|
|
58
101
|
{ key: "y", action: "Confirm" },
|
|
59
102
|
{ key: "n/Esc", action: "Cancel" }
|
|
60
103
|
]
|
|
104
|
+
elsif filter_mode?
|
|
105
|
+
filter_bindings
|
|
61
106
|
else
|
|
62
107
|
[
|
|
63
108
|
{ key: "j/k", action: "Navigate" },
|
|
64
109
|
{ key: "Enter", action: "Detail" },
|
|
110
|
+
{ key: "/", action: "Filter" },
|
|
65
111
|
{ key: "N", action: "Run Now" },
|
|
66
112
|
{ key: "D", action: "Discard" },
|
|
67
113
|
{ key: "G/g", action: "Bottom/Top" }
|
|
@@ -69,16 +115,24 @@ module SolidQueueTui
|
|
|
69
115
|
end
|
|
70
116
|
end
|
|
71
117
|
|
|
72
|
-
def breadcrumb
|
|
118
|
+
def breadcrumb
|
|
119
|
+
@filters.empty? ? "scheduled" : "scheduled:filtered"
|
|
120
|
+
end
|
|
73
121
|
|
|
74
122
|
private
|
|
75
123
|
|
|
124
|
+
def needs_more?
|
|
125
|
+
!@all_loaded && @selected_row >= @jobs.size - LOAD_THRESHOLD
|
|
126
|
+
end
|
|
127
|
+
|
|
76
128
|
def handle_normal_input(event)
|
|
77
129
|
case event
|
|
78
130
|
in { type: :key, code: "j" } | { type: :key, code: "up" }
|
|
79
131
|
move_selection(-1)
|
|
80
132
|
in { type: :key, code: "k" } | { type: :key, code: "down" }
|
|
81
|
-
move_selection(1)
|
|
133
|
+
result = move_selection(1)
|
|
134
|
+
return :load_more if result == :load_more
|
|
135
|
+
nil
|
|
82
136
|
in { type: :key, code: "g" }
|
|
83
137
|
jump_to_top
|
|
84
138
|
in { type: :key, code: "G" }
|
|
@@ -89,6 +143,11 @@ module SolidQueueTui
|
|
|
89
143
|
in { type: :key, code: "D" }
|
|
90
144
|
@confirm_action = :discard if selected_item
|
|
91
145
|
nil
|
|
146
|
+
in { type: :key, code: "/" }
|
|
147
|
+
enter_filter_mode
|
|
148
|
+
nil
|
|
149
|
+
in { type: :key, code: "esc" }
|
|
150
|
+
clear_filter
|
|
92
151
|
else
|
|
93
152
|
nil
|
|
94
153
|
end
|
|
@@ -123,6 +182,7 @@ module SolidQueueTui
|
|
|
123
182
|
return if @jobs.empty?
|
|
124
183
|
@selected_row = (@selected_row + delta).clamp(0, @jobs.size - 1)
|
|
125
184
|
@table_state.select(@selected_row)
|
|
185
|
+
:load_more if needs_more?
|
|
126
186
|
end
|
|
127
187
|
|
|
128
188
|
def jump_to_top
|
|
@@ -134,6 +194,7 @@ module SolidQueueTui
|
|
|
134
194
|
return if @jobs.empty?
|
|
135
195
|
@selected_row = @jobs.size - 1
|
|
136
196
|
@table_state.select(@selected_row)
|
|
197
|
+
return :load_more if needs_more?
|
|
137
198
|
end
|
|
138
199
|
|
|
139
200
|
def render_table(frame, area)
|
|
@@ -143,26 +204,31 @@ module SolidQueueTui
|
|
|
143
204
|
{ key: :queue_name, label: "QUEUE", width: 14 },
|
|
144
205
|
{ key: :priority, label: "PRI", width: 5 },
|
|
145
206
|
{ key: :scheduled_at, label: "SCHEDULED AT", width: 20 },
|
|
207
|
+
{ key: :status, label: "STATUS", width: 10, color_by: :status },
|
|
146
208
|
{ key: :created_at, label: "CREATED", width: 12 }
|
|
147
209
|
]
|
|
148
210
|
|
|
211
|
+
now = Time.now.utc
|
|
149
212
|
rows = @jobs.map do |job|
|
|
213
|
+
delayed = job.scheduled_at && job.scheduled_at < now
|
|
150
214
|
{
|
|
151
215
|
id: job.id,
|
|
152
216
|
class_name: job.class_name,
|
|
153
217
|
queue_name: job.queue_name,
|
|
154
218
|
priority: job.priority,
|
|
155
219
|
scheduled_at: format_time(job.scheduled_at),
|
|
220
|
+
status: delayed ? "DELAYED" : "pending",
|
|
156
221
|
created_at: time_ago(job.created_at)
|
|
157
222
|
}
|
|
158
223
|
end
|
|
159
224
|
|
|
160
225
|
table = Components::JobTable.new(
|
|
161
226
|
@tui,
|
|
162
|
-
title: "Scheduled Jobs",
|
|
227
|
+
title: filter_title("Scheduled Jobs"),
|
|
163
228
|
columns: columns,
|
|
164
229
|
rows: rows,
|
|
165
230
|
selected_row: @selected_row,
|
|
231
|
+
total_count: @total_count,
|
|
166
232
|
empty_message: "No scheduled jobs"
|
|
167
233
|
)
|
|
168
234
|
|
data/lib/solid_queue_tui.rb
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
|
-
require "time"
|
|
5
|
-
|
|
6
3
|
require_relative "solid_queue_tui/version"
|
|
7
|
-
require_relative "solid_queue_tui/connection"
|
|
8
4
|
|
|
9
5
|
# Data layer
|
|
10
6
|
require_relative "solid_queue_tui/data/stats"
|
|
@@ -12,18 +8,24 @@ require_relative "solid_queue_tui/data/jobs_query"
|
|
|
12
8
|
require_relative "solid_queue_tui/data/queues_query"
|
|
13
9
|
require_relative "solid_queue_tui/data/processes_query"
|
|
14
10
|
require_relative "solid_queue_tui/data/failed_query"
|
|
11
|
+
require_relative "solid_queue_tui/data/recurring_tasks_query"
|
|
15
12
|
|
|
16
13
|
# Actions
|
|
17
14
|
require_relative "solid_queue_tui/actions/retry_job"
|
|
18
15
|
require_relative "solid_queue_tui/actions/discard_job"
|
|
19
16
|
require_relative "solid_queue_tui/actions/dispatch_scheduled_job"
|
|
20
17
|
require_relative "solid_queue_tui/actions/discard_scheduled_job"
|
|
18
|
+
require_relative "solid_queue_tui/actions/toggle_queue_pause"
|
|
19
|
+
require_relative "solid_queue_tui/actions/enqueue_recurring_task"
|
|
21
20
|
|
|
22
21
|
# Components
|
|
23
22
|
require_relative "solid_queue_tui/components/header"
|
|
24
23
|
require_relative "solid_queue_tui/components/job_table"
|
|
25
24
|
require_relative "solid_queue_tui/components/help_bar"
|
|
26
25
|
|
|
26
|
+
# View concerns
|
|
27
|
+
require_relative "solid_queue_tui/views/concerns/filterable"
|
|
28
|
+
|
|
27
29
|
# Views
|
|
28
30
|
require_relative "solid_queue_tui/views/dashboard_view"
|
|
29
31
|
require_relative "solid_queue_tui/views/queues_view"
|
|
@@ -32,6 +34,7 @@ require_relative "solid_queue_tui/views/in_progress_view"
|
|
|
32
34
|
require_relative "solid_queue_tui/views/blocked_view"
|
|
33
35
|
require_relative "solid_queue_tui/views/scheduled_view"
|
|
34
36
|
require_relative "solid_queue_tui/views/finished_view"
|
|
37
|
+
require_relative "solid_queue_tui/views/recurring_tasks_view"
|
|
35
38
|
require_relative "solid_queue_tui/views/processes_view"
|
|
36
39
|
require_relative "solid_queue_tui/views/job_detail_view"
|
|
37
40
|
|
|
@@ -43,4 +46,12 @@ require_relative "solid_queue_tui/application"
|
|
|
43
46
|
require_relative "solid_queue_tui/cli"
|
|
44
47
|
|
|
45
48
|
module SolidQueueTui
|
|
49
|
+
@refresh_interval = 200
|
|
50
|
+
@page_size = 100
|
|
51
|
+
|
|
52
|
+
class << self
|
|
53
|
+
attr_accessor :refresh_interval, :page_size
|
|
54
|
+
end
|
|
46
55
|
end
|
|
56
|
+
|
|
57
|
+
require_relative "solid_queue_tui/railtie" if defined?(Rails::Railtie)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solid_queue_tui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shiva Reddy
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ratatui_ruby
|
|
@@ -25,47 +25,33 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.3'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: solid_queue
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '1.0'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '1.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: railties
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
48
|
-
type: :
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - ">="
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: pg
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0'
|
|
62
|
-
type: :development
|
|
47
|
+
version: '7.1'
|
|
48
|
+
type: :runtime
|
|
63
49
|
prerelease: false
|
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
51
|
requirements:
|
|
66
52
|
- - ">="
|
|
67
53
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
54
|
+
version: '7.1'
|
|
69
55
|
- !ruby/object:Gem::Dependency
|
|
70
56
|
name: rake
|
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -108,21 +94,25 @@ files:
|
|
|
108
94
|
- lib/solid_queue_tui/actions/discard_job.rb
|
|
109
95
|
- lib/solid_queue_tui/actions/discard_scheduled_job.rb
|
|
110
96
|
- lib/solid_queue_tui/actions/dispatch_scheduled_job.rb
|
|
97
|
+
- lib/solid_queue_tui/actions/enqueue_recurring_task.rb
|
|
111
98
|
- lib/solid_queue_tui/actions/retry_job.rb
|
|
99
|
+
- lib/solid_queue_tui/actions/toggle_queue_pause.rb
|
|
112
100
|
- lib/solid_queue_tui/application.rb
|
|
113
101
|
- lib/solid_queue_tui/cli.rb
|
|
114
102
|
- lib/solid_queue_tui/components/header.rb
|
|
115
103
|
- lib/solid_queue_tui/components/help_bar.rb
|
|
116
104
|
- lib/solid_queue_tui/components/job_table.rb
|
|
117
|
-
- lib/solid_queue_tui/connection.rb
|
|
118
105
|
- lib/solid_queue_tui/data/failed_query.rb
|
|
119
106
|
- lib/solid_queue_tui/data/jobs_query.rb
|
|
120
107
|
- lib/solid_queue_tui/data/processes_query.rb
|
|
121
108
|
- lib/solid_queue_tui/data/queues_query.rb
|
|
109
|
+
- lib/solid_queue_tui/data/recurring_tasks_query.rb
|
|
122
110
|
- lib/solid_queue_tui/data/stats.rb
|
|
123
111
|
- lib/solid_queue_tui/dev_reloader.rb
|
|
112
|
+
- lib/solid_queue_tui/railtie.rb
|
|
124
113
|
- lib/solid_queue_tui/version.rb
|
|
125
114
|
- lib/solid_queue_tui/views/blocked_view.rb
|
|
115
|
+
- lib/solid_queue_tui/views/concerns/filterable.rb
|
|
126
116
|
- lib/solid_queue_tui/views/dashboard_view.rb
|
|
127
117
|
- lib/solid_queue_tui/views/failed_view.rb
|
|
128
118
|
- lib/solid_queue_tui/views/finished_view.rb
|
|
@@ -130,7 +120,9 @@ files:
|
|
|
130
120
|
- lib/solid_queue_tui/views/job_detail_view.rb
|
|
131
121
|
- lib/solid_queue_tui/views/processes_view.rb
|
|
132
122
|
- lib/solid_queue_tui/views/queues_view.rb
|
|
123
|
+
- lib/solid_queue_tui/views/recurring_tasks_view.rb
|
|
133
124
|
- lib/solid_queue_tui/views/scheduled_view.rb
|
|
125
|
+
- lib/tasks/solid_queue_tui.rake
|
|
134
126
|
homepage: https://github.com/shivareddy-Aluri/solid-queue-tui
|
|
135
127
|
licenses:
|
|
136
128
|
- MIT
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "active_record"
|
|
4
|
-
require "yaml"
|
|
5
|
-
|
|
6
|
-
module SolidQueueTui
|
|
7
|
-
class Connection
|
|
8
|
-
CONFIG_FILE = "config/solid_tui.yml"
|
|
9
|
-
|
|
10
|
-
# Loads config, establishes the DB connection, and returns the parsed config hash.
|
|
11
|
-
def self.establish!
|
|
12
|
-
config = load_config
|
|
13
|
-
|
|
14
|
-
url = config["database_url"]
|
|
15
|
-
raise ConnectionError, <<~MSG unless url
|
|
16
|
-
No database_url found in #{CONFIG_FILE}.
|
|
17
|
-
|
|
18
|
-
Create #{CONFIG_FILE} with:
|
|
19
|
-
database_url: postgres://user:pass@localhost/myapp_queue
|
|
20
|
-
refresh: 2
|
|
21
|
-
MSG
|
|
22
|
-
|
|
23
|
-
ActiveRecord::Base.establish_connection(url)
|
|
24
|
-
verify_solid_queue_tables!
|
|
25
|
-
|
|
26
|
-
config
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def self.load_config
|
|
30
|
-
path = File.join(Dir.pwd, CONFIG_FILE)
|
|
31
|
-
|
|
32
|
-
unless File.exist?(path)
|
|
33
|
-
raise ConnectionError, <<~MSG
|
|
34
|
-
Config file not found: #{CONFIG_FILE}
|
|
35
|
-
|
|
36
|
-
Create #{CONFIG_FILE} with:
|
|
37
|
-
database_url: postgres://user:pass@localhost/myapp_queue
|
|
38
|
-
refresh: 2
|
|
39
|
-
MSG
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
YAML.safe_load(File.read(path), permitted_classes: [Symbol]) || {}
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def self.verify_solid_queue_tables!
|
|
46
|
-
conn = ActiveRecord::Base.connection
|
|
47
|
-
required = %w[solid_queue_jobs solid_queue_ready_executions]
|
|
48
|
-
missing = required.reject { |t| conn.table_exists?(t) }
|
|
49
|
-
|
|
50
|
-
unless missing.empty?
|
|
51
|
-
raise ConnectionError, "Missing Solid Queue tables: #{missing.join(', ')}. " \
|
|
52
|
-
"Is this a Solid Queue database?"
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
class ConnectionError < StandardError; end
|
|
57
|
-
end
|
|
58
|
-
end
|