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
|
@@ -3,42 +3,69 @@
|
|
|
3
3
|
module SolidQueueTui
|
|
4
4
|
module Views
|
|
5
5
|
class FinishedView
|
|
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 = []
|
|
12
|
-
@
|
|
13
|
-
@
|
|
14
|
-
|
|
17
|
+
@total_count = nil
|
|
18
|
+
@all_loaded = false
|
|
19
|
+
init_filter
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
def update(jobs:)
|
|
18
23
|
@jobs = jobs
|
|
24
|
+
@all_loaded = jobs.size < SolidQueueTui.page_size
|
|
19
25
|
@selected_row = @selected_row.clamp(0, [@jobs.size - 1, 0].max)
|
|
20
26
|
@table_state.select(@selected_row)
|
|
21
27
|
end
|
|
22
28
|
|
|
29
|
+
def append(jobs:)
|
|
30
|
+
@jobs.concat(jobs)
|
|
31
|
+
@all_loaded = jobs.size < SolidQueueTui.page_size
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def total_count=(count)
|
|
35
|
+
@total_count = count
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def current_offset
|
|
39
|
+
@jobs.size
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def reset_pagination!
|
|
43
|
+
@jobs = []
|
|
44
|
+
@total_count = nil
|
|
45
|
+
@all_loaded = false
|
|
46
|
+
@selected_row = 0
|
|
47
|
+
@table_state.select(0)
|
|
48
|
+
end
|
|
49
|
+
|
|
23
50
|
def render(frame, area)
|
|
24
|
-
if
|
|
25
|
-
|
|
51
|
+
if filter_mode?
|
|
52
|
+
filter_area, content_area = @tui.layout_split(
|
|
26
53
|
area,
|
|
27
54
|
direction: :vertical,
|
|
28
55
|
constraints: [
|
|
29
|
-
@tui.
|
|
30
|
-
@tui.
|
|
56
|
+
@tui.constraint_length(3),
|
|
57
|
+
@tui.constraint_fill(1)
|
|
31
58
|
]
|
|
32
59
|
)
|
|
33
|
-
render_table(frame, content_area)
|
|
34
60
|
render_filter_input(frame, filter_area)
|
|
61
|
+
render_table(frame, content_area)
|
|
35
62
|
else
|
|
36
63
|
render_table(frame, area)
|
|
37
64
|
end
|
|
38
65
|
end
|
|
39
66
|
|
|
40
67
|
def handle_input(event)
|
|
41
|
-
if
|
|
68
|
+
if filter_mode?
|
|
42
69
|
handle_filter_input(event)
|
|
43
70
|
else
|
|
44
71
|
handle_normal_input(event)
|
|
@@ -50,14 +77,9 @@ module SolidQueueTui
|
|
|
50
77
|
@jobs[@selected_row]
|
|
51
78
|
end
|
|
52
79
|
|
|
53
|
-
def filter = @filter
|
|
54
|
-
|
|
55
80
|
def bindings
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
-
{ key: "Enter", action: "Apply" },
|
|
59
|
-
{ key: "Esc", action: "Cancel" }
|
|
60
|
-
]
|
|
81
|
+
if filter_mode?
|
|
82
|
+
filter_bindings
|
|
61
83
|
else
|
|
62
84
|
[
|
|
63
85
|
{ key: "j/k", action: "Navigate" },
|
|
@@ -70,55 +92,36 @@ module SolidQueueTui
|
|
|
70
92
|
end
|
|
71
93
|
|
|
72
94
|
def capturing_input?
|
|
73
|
-
|
|
95
|
+
filter_mode?
|
|
74
96
|
end
|
|
75
97
|
|
|
76
98
|
def breadcrumb
|
|
77
|
-
@
|
|
99
|
+
@filters.empty? ? "finished" : "finished:filtered"
|
|
78
100
|
end
|
|
79
101
|
|
|
80
102
|
private
|
|
81
103
|
|
|
104
|
+
def needs_more?
|
|
105
|
+
!@all_loaded && @selected_row >= @jobs.size - LOAD_THRESHOLD
|
|
106
|
+
end
|
|
107
|
+
|
|
82
108
|
def handle_normal_input(event)
|
|
83
109
|
case event
|
|
84
110
|
in { type: :key, code: "j" } | { type: :key, code: "up" }
|
|
85
111
|
move_selection(-1)
|
|
86
112
|
in { type: :key, code: "k" } | { type: :key, code: "down" }
|
|
87
|
-
move_selection(1)
|
|
113
|
+
result = move_selection(1)
|
|
114
|
+
return :load_more if result == :load_more
|
|
115
|
+
nil
|
|
88
116
|
in { type: :key, code: "g" }
|
|
89
117
|
jump_to_top
|
|
90
118
|
in { type: :key, code: "G" }
|
|
91
119
|
jump_to_bottom
|
|
92
120
|
in { type: :key, code: "/" }
|
|
93
|
-
|
|
94
|
-
@filter_input = @filter || ""
|
|
95
|
-
in { type: :key, code: "esc" }
|
|
96
|
-
@filter = nil
|
|
97
|
-
@filter_input = ""
|
|
98
|
-
:refresh
|
|
99
|
-
else
|
|
121
|
+
enter_filter_mode
|
|
100
122
|
nil
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def handle_filter_input(event)
|
|
105
|
-
case event
|
|
106
|
-
in { type: :key, code: "enter" }
|
|
107
|
-
@filter = @filter_input.empty? ? nil : @filter_input
|
|
108
|
-
@filter_mode = false
|
|
109
|
-
@selected_row = 0
|
|
110
|
-
@table_state.select(0)
|
|
111
|
-
:refresh
|
|
112
123
|
in { type: :key, code: "esc" }
|
|
113
|
-
|
|
114
|
-
@filter_input = @filter || ""
|
|
115
|
-
nil
|
|
116
|
-
in { type: :key, code: "backspace" }
|
|
117
|
-
@filter_input = @filter_input[0...-1]
|
|
118
|
-
nil
|
|
119
|
-
in { type: :key, code: /\A.\z/ => char }
|
|
120
|
-
@filter_input += char
|
|
121
|
-
nil
|
|
124
|
+
clear_filter
|
|
122
125
|
else
|
|
123
126
|
nil
|
|
124
127
|
end
|
|
@@ -128,6 +131,7 @@ module SolidQueueTui
|
|
|
128
131
|
return if @jobs.empty?
|
|
129
132
|
@selected_row = (@selected_row + delta).clamp(0, @jobs.size - 1)
|
|
130
133
|
@table_state.select(@selected_row)
|
|
134
|
+
:load_more if needs_more?
|
|
131
135
|
end
|
|
132
136
|
|
|
133
137
|
def jump_to_top
|
|
@@ -139,6 +143,7 @@ module SolidQueueTui
|
|
|
139
143
|
return if @jobs.empty?
|
|
140
144
|
@selected_row = @jobs.size - 1
|
|
141
145
|
@table_state.select(@selected_row)
|
|
146
|
+
return :load_more if needs_more?
|
|
142
147
|
end
|
|
143
148
|
|
|
144
149
|
def render_table(frame, area)
|
|
@@ -162,37 +167,19 @@ module SolidQueueTui
|
|
|
162
167
|
}
|
|
163
168
|
end
|
|
164
169
|
|
|
165
|
-
title = @filter ? "Finished (filter: #{@filter})" : "Finished"
|
|
166
|
-
|
|
167
170
|
table = Components::JobTable.new(
|
|
168
171
|
@tui,
|
|
169
|
-
title:
|
|
172
|
+
title: filter_title("Finished"),
|
|
170
173
|
columns: columns,
|
|
171
174
|
rows: rows,
|
|
172
175
|
selected_row: @selected_row,
|
|
173
|
-
|
|
176
|
+
total_count: @total_count,
|
|
177
|
+
empty_message: @filters.empty? ? "No finished jobs" : "No finished jobs matching filters"
|
|
174
178
|
)
|
|
175
179
|
|
|
176
180
|
table.render(frame, area, @table_state)
|
|
177
181
|
end
|
|
178
182
|
|
|
179
|
-
def render_filter_input(frame, area)
|
|
180
|
-
frame.render_widget(
|
|
181
|
-
@tui.paragraph(
|
|
182
|
-
text: @filter_input + "\u2588",
|
|
183
|
-
style: @tui.style(fg: :white),
|
|
184
|
-
block: @tui.block(
|
|
185
|
-
title: " Filter by class name ",
|
|
186
|
-
title_style: @tui.style(fg: :yellow),
|
|
187
|
-
borders: [:all],
|
|
188
|
-
border_type: :rounded,
|
|
189
|
-
border_style: @tui.style(fg: :cyan)
|
|
190
|
-
)
|
|
191
|
-
),
|
|
192
|
-
area
|
|
193
|
-
)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
183
|
def format_time(time)
|
|
197
184
|
return "n/a" unless time
|
|
198
185
|
time.strftime("%Y-%m-%d %H:%M:%S")
|
|
@@ -3,65 +3,72 @@
|
|
|
3
3
|
module SolidQueueTui
|
|
4
4
|
module Views
|
|
5
5
|
class InProgressView
|
|
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
|
|
19
|
+
init_filter
|
|
12
20
|
end
|
|
13
21
|
|
|
14
22
|
def update(jobs:)
|
|
15
23
|
@jobs = jobs
|
|
24
|
+
@all_loaded = jobs.size < SolidQueueTui.page_size
|
|
16
25
|
@selected_row = @selected_row.clamp(0, [@jobs.size - 1, 0].max)
|
|
17
26
|
@table_state.select(@selected_row)
|
|
18
27
|
end
|
|
19
28
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{ key: :class_name, label: "CLASS", width: :fill },
|
|
25
|
-
{ key: :priority, label: "PRI", width: 5 },
|
|
26
|
-
{ key: :worker_id, label: "WORKER", width: 8 },
|
|
27
|
-
{ key: :started_at, label: "STARTED", width: 12 }
|
|
28
|
-
]
|
|
29
|
+
def append(jobs:)
|
|
30
|
+
@jobs.concat(jobs)
|
|
31
|
+
@all_loaded = jobs.size < SolidQueueTui.page_size
|
|
32
|
+
end
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
queue_name: job.queue_name,
|
|
34
|
-
class_name: job.class_name,
|
|
35
|
-
priority: job.priority,
|
|
36
|
-
worker_id: job.worker_id || "n/a",
|
|
37
|
-
started_at: time_ago(job.started_at)
|
|
38
|
-
}
|
|
39
|
-
end
|
|
34
|
+
def total_count=(count)
|
|
35
|
+
@total_count = count
|
|
36
|
+
end
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
columns: columns,
|
|
45
|
-
rows: rows,
|
|
46
|
-
selected_row: @selected_row,
|
|
47
|
-
empty_message: "No jobs currently in progress"
|
|
48
|
-
)
|
|
38
|
+
def current_offset
|
|
39
|
+
@jobs.size
|
|
40
|
+
end
|
|
49
41
|
|
|
50
|
-
|
|
42
|
+
def reset_pagination!
|
|
43
|
+
@jobs = []
|
|
44
|
+
@total_count = nil
|
|
45
|
+
@all_loaded = false
|
|
46
|
+
@selected_row = 0
|
|
47
|
+
@table_state.select(0)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def render(frame, area)
|
|
51
|
+
if filter_mode?
|
|
52
|
+
filter_area, content_area = @tui.layout_split(
|
|
53
|
+
area,
|
|
54
|
+
direction: :vertical,
|
|
55
|
+
constraints: [
|
|
56
|
+
@tui.constraint_length(3),
|
|
57
|
+
@tui.constraint_fill(1)
|
|
58
|
+
]
|
|
59
|
+
)
|
|
60
|
+
render_filter_input(frame, filter_area)
|
|
61
|
+
render_table(frame, content_area)
|
|
62
|
+
else
|
|
63
|
+
render_table(frame, area)
|
|
64
|
+
end
|
|
51
65
|
end
|
|
52
66
|
|
|
53
67
|
def handle_input(event)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
move_selection(-1)
|
|
57
|
-
in { type: :key, code: "k" } | { type: :key, code: "down" }
|
|
58
|
-
move_selection(1)
|
|
59
|
-
in { type: :key, code: "g" }
|
|
60
|
-
jump_to_top
|
|
61
|
-
in { type: :key, code: "G" }
|
|
62
|
-
jump_to_bottom
|
|
68
|
+
if filter_mode?
|
|
69
|
+
handle_filter_input(event)
|
|
63
70
|
else
|
|
64
|
-
|
|
71
|
+
handle_normal_input(event)
|
|
65
72
|
end
|
|
66
73
|
end
|
|
67
74
|
|
|
@@ -71,21 +78,59 @@ module SolidQueueTui
|
|
|
71
78
|
end
|
|
72
79
|
|
|
73
80
|
def bindings
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
if filter_mode?
|
|
82
|
+
filter_bindings
|
|
83
|
+
else
|
|
84
|
+
[
|
|
85
|
+
{ key: "j/k", action: "Navigate" },
|
|
86
|
+
{ key: "Enter", action: "Detail" },
|
|
87
|
+
{ key: "/", action: "Filter" },
|
|
88
|
+
{ key: "G/g", action: "Bottom/Top" }
|
|
89
|
+
]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def capturing_input?
|
|
94
|
+
filter_mode?
|
|
79
95
|
end
|
|
80
96
|
|
|
81
|
-
def breadcrumb
|
|
97
|
+
def breadcrumb
|
|
98
|
+
@filters.empty? ? "in-progress" : "in-progress:filtered"
|
|
99
|
+
end
|
|
82
100
|
|
|
83
101
|
private
|
|
84
102
|
|
|
103
|
+
def needs_more?
|
|
104
|
+
!@all_loaded && @selected_row >= @jobs.size - LOAD_THRESHOLD
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def handle_normal_input(event)
|
|
108
|
+
case event
|
|
109
|
+
in { type: :key, code: "j" } | { type: :key, code: "up" }
|
|
110
|
+
move_selection(-1)
|
|
111
|
+
in { type: :key, code: "k" } | { type: :key, code: "down" }
|
|
112
|
+
result = move_selection(1)
|
|
113
|
+
return :load_more if result == :load_more
|
|
114
|
+
nil
|
|
115
|
+
in { type: :key, code: "g" }
|
|
116
|
+
jump_to_top
|
|
117
|
+
in { type: :key, code: "G" }
|
|
118
|
+
jump_to_bottom
|
|
119
|
+
in { type: :key, code: "/" }
|
|
120
|
+
enter_filter_mode
|
|
121
|
+
nil
|
|
122
|
+
in { type: :key, code: "esc" }
|
|
123
|
+
clear_filter
|
|
124
|
+
else
|
|
125
|
+
nil
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
85
129
|
def move_selection(delta)
|
|
86
130
|
return if @jobs.empty?
|
|
87
131
|
@selected_row = (@selected_row + delta).clamp(0, @jobs.size - 1)
|
|
88
132
|
@table_state.select(@selected_row)
|
|
133
|
+
:load_more if needs_more?
|
|
89
134
|
end
|
|
90
135
|
|
|
91
136
|
def jump_to_top
|
|
@@ -97,6 +142,41 @@ module SolidQueueTui
|
|
|
97
142
|
return if @jobs.empty?
|
|
98
143
|
@selected_row = @jobs.size - 1
|
|
99
144
|
@table_state.select(@selected_row)
|
|
145
|
+
return :load_more if needs_more?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def render_table(frame, area)
|
|
149
|
+
columns = [
|
|
150
|
+
{ key: :id, label: "ID", width: 8 },
|
|
151
|
+
{ key: :queue_name, label: "QUEUE", width: 14 },
|
|
152
|
+
{ key: :class_name, label: "CLASS", width: :fill },
|
|
153
|
+
{ key: :priority, label: "PRI", width: 5 },
|
|
154
|
+
{ key: :worker_id, label: "WORKER", width: 8 },
|
|
155
|
+
{ key: :started_at, label: "STARTED", width: 12 }
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
rows = @jobs.map do |job|
|
|
159
|
+
{
|
|
160
|
+
id: job.id,
|
|
161
|
+
queue_name: job.queue_name,
|
|
162
|
+
class_name: job.class_name,
|
|
163
|
+
priority: job.priority,
|
|
164
|
+
worker_id: job.worker_id || "n/a",
|
|
165
|
+
started_at: time_ago(job.started_at)
|
|
166
|
+
}
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
table = Components::JobTable.new(
|
|
170
|
+
@tui,
|
|
171
|
+
title: filter_title("In Progress"),
|
|
172
|
+
columns: columns,
|
|
173
|
+
rows: rows,
|
|
174
|
+
selected_row: @selected_row,
|
|
175
|
+
total_count: @total_count,
|
|
176
|
+
empty_message: @filters.empty? ? "No jobs currently in progress" : "No in-progress jobs matching filters"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
table.render(frame, area, @table_state)
|
|
100
180
|
end
|
|
101
181
|
|
|
102
182
|
def time_ago(time)
|
|
@@ -9,6 +9,7 @@ module SolidQueueTui
|
|
|
9
9
|
@table_state.select(0)
|
|
10
10
|
@selected_row = 0
|
|
11
11
|
@queues = []
|
|
12
|
+
@confirm_action = nil
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def update(queues:)
|
|
@@ -18,33 +19,59 @@ module SolidQueueTui
|
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def render(frame, area)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
26
37
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
38
|
+
def handle_input(event)
|
|
39
|
+
if @confirm_action
|
|
40
|
+
handle_confirm_input(event)
|
|
41
|
+
else
|
|
42
|
+
handle_normal_input(event)
|
|
33
43
|
end
|
|
44
|
+
end
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
rows: rows,
|
|
40
|
-
selected_row: @selected_row,
|
|
41
|
-
empty_message: "No queues found"
|
|
42
|
-
)
|
|
46
|
+
def selected_item
|
|
47
|
+
return nil if @queues.empty? || @selected_row >= @queues.size
|
|
48
|
+
@queues[@selected_row]
|
|
49
|
+
end
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
def capturing_input?
|
|
52
|
+
!!@confirm_action
|
|
45
53
|
end
|
|
46
54
|
|
|
47
|
-
def
|
|
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: "p", action: "Pause/Resume" },
|
|
65
|
+
{ key: "G/g", action: "Bottom/Top" }
|
|
66
|
+
]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def breadcrumb = "queues"
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def handle_normal_input(event)
|
|
48
75
|
case event
|
|
49
76
|
in { type: :key, code: "j" } | { type: :key, code: "up" }
|
|
50
77
|
move_selection(-1)
|
|
@@ -54,27 +81,33 @@ module SolidQueueTui
|
|
|
54
81
|
jump_to_top
|
|
55
82
|
in { type: :key, code: "G" }
|
|
56
83
|
jump_to_bottom
|
|
84
|
+
in { type: :key, code: "p" }
|
|
85
|
+
queue = selected_item
|
|
86
|
+
if queue
|
|
87
|
+
@confirm_action = queue.paused ? :resume : :pause
|
|
88
|
+
end
|
|
89
|
+
nil
|
|
57
90
|
else
|
|
58
91
|
nil
|
|
59
92
|
end
|
|
60
93
|
end
|
|
61
94
|
|
|
62
|
-
def
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
95
|
+
def handle_confirm_input(event)
|
|
96
|
+
case event
|
|
97
|
+
in { type: :key, code: "y" }
|
|
98
|
+
@confirm_action = nil
|
|
99
|
+
queue = selected_item
|
|
100
|
+
return nil unless queue
|
|
101
|
+
Actions::ToggleQueuePause.call(queue.name)
|
|
102
|
+
:refresh
|
|
103
|
+
in { type: :key, code: "n" } | { type: :key, code: "esc" }
|
|
104
|
+
@confirm_action = nil
|
|
105
|
+
nil
|
|
106
|
+
else
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
72
109
|
end
|
|
73
110
|
|
|
74
|
-
def breadcrumb = "queues"
|
|
75
|
-
|
|
76
|
-
private
|
|
77
|
-
|
|
78
111
|
def move_selection(delta)
|
|
79
112
|
return if @queues.empty?
|
|
80
113
|
@selected_row = (@selected_row + delta).clamp(0, @queues.size - 1)
|
|
@@ -91,6 +124,57 @@ module SolidQueueTui
|
|
|
91
124
|
@selected_row = @queues.size - 1
|
|
92
125
|
@table_state.select(@selected_row)
|
|
93
126
|
end
|
|
127
|
+
|
|
128
|
+
def render_table(frame, area)
|
|
129
|
+
columns = [
|
|
130
|
+
{ key: :name, label: "QUEUE", width: :fill },
|
|
131
|
+
{ key: :size, label: "SIZE", width: 10 },
|
|
132
|
+
{ key: :status, label: "STATUS", width: 10, color_by: :status }
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
rows = @queues.map do |q|
|
|
136
|
+
{
|
|
137
|
+
name: q.name,
|
|
138
|
+
size: q.size,
|
|
139
|
+
status: q.paused ? "paused" : "active"
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
table = Components::JobTable.new(
|
|
144
|
+
@tui,
|
|
145
|
+
title: "Queues",
|
|
146
|
+
columns: columns,
|
|
147
|
+
rows: rows,
|
|
148
|
+
selected_row: @selected_row,
|
|
149
|
+
empty_message: "No queues found"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
table.render(frame, area, @table_state)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def render_confirm(frame, area)
|
|
156
|
+
queue = selected_item
|
|
157
|
+
message = if @confirm_action == :pause
|
|
158
|
+
"Pause queue '#{queue&.name}'? Workers will stop picking up jobs from this queue. [y/n]"
|
|
159
|
+
else
|
|
160
|
+
"Resume queue '#{queue&.name}'? [y/n]"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
frame.render_widget(
|
|
164
|
+
@tui.paragraph(
|
|
165
|
+
text: " #{message}",
|
|
166
|
+
style: @tui.style(fg: :yellow, modifiers: [:bold]),
|
|
167
|
+
block: @tui.block(
|
|
168
|
+
title: " Confirm ",
|
|
169
|
+
title_style: @tui.style(fg: :red, modifiers: [:bold]),
|
|
170
|
+
borders: [:all],
|
|
171
|
+
border_type: :rounded,
|
|
172
|
+
border_style: @tui.style(fg: :red)
|
|
173
|
+
)
|
|
174
|
+
),
|
|
175
|
+
area
|
|
176
|
+
)
|
|
177
|
+
end
|
|
94
178
|
end
|
|
95
179
|
end
|
|
96
180
|
end
|