pgbus 0.2.5 → 0.2.6
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/README.md +21 -1
- data/app/controllers/pgbus/application_controller.rb +8 -2
- data/app/helpers/pgbus/application_helper.rb +10 -0
- data/app/views/layouts/pgbus/application.html.erb +104 -15
- data/app/views/pgbus/dashboard/_processes_table.html.erb +5 -5
- data/app/views/pgbus/dashboard/_queues_table.html.erb +6 -6
- data/app/views/pgbus/dashboard/_recent_failures.html.erb +4 -4
- data/app/views/pgbus/dead_letter/_messages_table.html.erb +1 -1
- data/app/views/pgbus/events/index.html.erb +8 -8
- data/app/views/pgbus/insights/show.html.erb +31 -29
- data/app/views/pgbus/jobs/_enqueued_table.html.erb +1 -1
- data/app/views/pgbus/jobs/_failed_table.html.erb +7 -7
- data/app/views/pgbus/locks/index.html.erb +7 -7
- data/app/views/pgbus/outbox/index.html.erb +7 -7
- data/app/views/pgbus/processes/_processes_table.html.erb +7 -7
- data/app/views/pgbus/queues/_queues_list.html.erb +8 -8
- data/app/views/pgbus/recurring_tasks/_tasks_table.html.erb +8 -8
- data/config/locales/da.yml +2 -0
- data/config/locales/de.yml +2 -0
- data/config/locales/en.yml +2 -0
- data/config/locales/es.yml +2 -0
- data/config/locales/fi.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/it.yml +2 -0
- data/config/locales/ja.yml +2 -0
- data/config/locales/nb.yml +2 -0
- data/config/locales/nl.yml +2 -0
- data/config/locales/pt.yml +2 -0
- data/config/locales/sv.yml +2 -0
- data/lib/pgbus/configuration.rb +3 -1
- data/lib/pgbus/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0d12150a0ea8aea034f08e626bfa2c553cf75349eb502d7a0fe0a50a867aa11b
|
|
4
|
+
data.tar.gz: 990216a4e6b7db7be81e888d90fe2d56ea536fa1e64a2507206dcd5524a255c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7e706c2824a4f00401027bd08df2c663502586a0a48fdd2e4150341a1e50fac520c50a503b2a6cff2d48d482d069ac66a605b9ce73a14513d9e65537da45f88
|
|
7
|
+
data.tar.gz: 64ad1a0978e42ddd271d50c224540bb3200e291912e3fde1bee72fe30eb74470b60833580a0a211785aa0830eb640dde463546c3bd748a33e9de0f903e79abad
|
data/README.md
CHANGED
|
@@ -211,7 +211,7 @@ mount Pgbus::Engine => "/pgbus"
|
|
|
211
211
|
|
|
212
212
|
The dashboard shows queues, jobs, processes, failures, dead letter messages, and event subscribers. It auto-refreshes via Turbo Frames with no WebSocket dependency.
|
|
213
213
|
|
|
214
|
-
Protect it in production:
|
|
214
|
+
Protect it in production with a simple auth lambda:
|
|
215
215
|
|
|
216
216
|
```ruby
|
|
217
217
|
Pgbus.configure do |config|
|
|
@@ -221,6 +221,24 @@ Pgbus.configure do |config|
|
|
|
221
221
|
end
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
+
Or inherit from your own authenticated controller (like mission_control-jobs):
|
|
225
|
+
|
|
226
|
+
```ruby
|
|
227
|
+
Pgbus.configure do |config|
|
|
228
|
+
config.base_controller_class = "Admin::BaseController"
|
|
229
|
+
end
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
When `base_controller_class` is set, all dashboard controllers inherit from that class instead of `ActionController::Base`. This is the recommended approach when mounting the dashboard inside an authenticated namespace -- your base controller's `before_action` filters, helper methods, and authentication logic apply automatically without monkey-patching.
|
|
233
|
+
|
|
234
|
+
Add a "back to app" button in the dashboard nav to return to your main application:
|
|
235
|
+
|
|
236
|
+
```ruby
|
|
237
|
+
Pgbus.configure do |config|
|
|
238
|
+
config.return_to_app_url = "/admin"
|
|
239
|
+
end
|
|
240
|
+
```
|
|
241
|
+
|
|
224
242
|
## Concurrency controls
|
|
225
243
|
|
|
226
244
|
Limit how many jobs with the same key can run concurrently:
|
|
@@ -624,6 +642,8 @@ The dispatcher runs archive compaction as part of its maintenance loop, deleting
|
|
|
624
642
|
| `outbox_batch_size` | `100` | Max entries per outbox poll cycle |
|
|
625
643
|
| `outbox_retention` | `86400` | Seconds to keep published outbox entries (1 day) |
|
|
626
644
|
| `idempotency_ttl` | `604800` | Seconds to keep processed event records (7 days, cleaned hourly) |
|
|
645
|
+
| `base_controller_class` | `"::ActionController::Base"` | Base class for dashboard controllers (string, constantized at load time) |
|
|
646
|
+
| `return_to_app_url` | `nil` | URL for "back to app" button in dashboard nav (nil hides the button) |
|
|
627
647
|
| `web_auth` | `nil` | Lambda for dashboard authentication |
|
|
628
648
|
| `web_refresh_interval` | `5000` | Dashboard auto-refresh interval in milliseconds |
|
|
629
649
|
| `web_live_updates` | `true` | Enable Turbo Frames auto-refresh on dashboard |
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Pgbus
|
|
4
|
-
class ApplicationController <
|
|
4
|
+
class ApplicationController < Pgbus.configuration.base_controller_class.constantize
|
|
5
|
+
# Ensure core ActionController modules are available even when the
|
|
6
|
+
# base controller is a slim subclass that may not include them all.
|
|
7
|
+
ActionController::Base::MODULES.each do |mod|
|
|
8
|
+
include mod unless self < mod
|
|
9
|
+
end
|
|
10
|
+
|
|
5
11
|
include Web::Authentication
|
|
6
12
|
|
|
7
13
|
protect_from_forgery with: :exception
|
|
@@ -10,7 +16,7 @@ module Pgbus
|
|
|
10
16
|
|
|
11
17
|
layout "pgbus/application"
|
|
12
18
|
|
|
13
|
-
helper Pgbus::ApplicationHelper
|
|
19
|
+
helper Pgbus::ApplicationHelper unless self < Pgbus::ApplicationHelper
|
|
14
20
|
|
|
15
21
|
# Make `pgbus` route proxy available in views (e.g. pgbus.root_path).
|
|
16
22
|
# With isolate_namespace, the non-prefixed helpers (root_path) work inside
|
|
@@ -158,6 +158,16 @@ module Pgbus
|
|
|
158
158
|
link_to label, path, class: css
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
+
def pgbus_mobile_nav_link(label, path)
|
|
162
|
+
active = request.path == path || (path != pgbus.root_path && request.path.start_with?(path))
|
|
163
|
+
css = if active
|
|
164
|
+
"block rounded-md px-3 py-2 text-base font-medium text-white bg-gray-800"
|
|
165
|
+
else
|
|
166
|
+
"block rounded-md px-3 py-2 text-base font-medium text-gray-300 hover:text-white hover:bg-gray-700"
|
|
167
|
+
end
|
|
168
|
+
link_to label, path, class: css
|
|
169
|
+
end
|
|
170
|
+
|
|
161
171
|
LOCALE_NAMES = {
|
|
162
172
|
da: "Dansk",
|
|
163
173
|
de: "Deutsch",
|
|
@@ -9,6 +9,43 @@
|
|
|
9
9
|
Applied before Tailwind CDN loads so the background is correct immediately. */
|
|
10
10
|
html.dark { background-color: #030712; } /* gray-950 */
|
|
11
11
|
html.dark body { background-color: #030712; }
|
|
12
|
+
|
|
13
|
+
/* Responsive tables: stack rows as cards on small screens */
|
|
14
|
+
@media (max-width: 1023px) {
|
|
15
|
+
.pgbus-table thead { display: none; }
|
|
16
|
+
.pgbus-table tbody tr {
|
|
17
|
+
display: block;
|
|
18
|
+
margin-bottom: 0.75rem;
|
|
19
|
+
border-radius: 0.5rem;
|
|
20
|
+
padding: 0.75rem;
|
|
21
|
+
border: 1px solid #e5e7eb;
|
|
22
|
+
}
|
|
23
|
+
html.dark .pgbus-table tbody tr { border-color: #374151; }
|
|
24
|
+
.pgbus-table tbody td {
|
|
25
|
+
display: flex;
|
|
26
|
+
justify-content: space-between;
|
|
27
|
+
align-items: baseline;
|
|
28
|
+
padding: 0.25rem 0;
|
|
29
|
+
border: none;
|
|
30
|
+
text-align: right;
|
|
31
|
+
}
|
|
32
|
+
.pgbus-table tbody td::before {
|
|
33
|
+
content: attr(data-label);
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
font-size: 0.75rem;
|
|
36
|
+
text-transform: uppercase;
|
|
37
|
+
color: #6b7280;
|
|
38
|
+
text-align: left;
|
|
39
|
+
margin-right: 1rem;
|
|
40
|
+
flex-shrink: 0;
|
|
41
|
+
}
|
|
42
|
+
html.dark .pgbus-table tbody td::before { color: #9ca3af; }
|
|
43
|
+
.pgbus-table tbody td[colspan] {
|
|
44
|
+
display: block;
|
|
45
|
+
text-align: center;
|
|
46
|
+
}
|
|
47
|
+
.pgbus-table tbody td[colspan]::before { display: none; }
|
|
48
|
+
}
|
|
12
49
|
</style>
|
|
13
50
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
14
51
|
<script>
|
|
@@ -23,6 +60,15 @@
|
|
|
23
60
|
var isDark = document.documentElement.classList.toggle('dark');
|
|
24
61
|
localStorage.setItem('pgbus-dark', isDark);
|
|
25
62
|
}
|
|
63
|
+
// Mobile menu toggle
|
|
64
|
+
function toggleMobileMenu() {
|
|
65
|
+
var menu = document.getElementById('pgbus-mobile-menu');
|
|
66
|
+
var openIcon = document.getElementById('pgbus-menu-open');
|
|
67
|
+
var closeIcon = document.getElementById('pgbus-menu-close');
|
|
68
|
+
menu.classList.toggle('hidden');
|
|
69
|
+
openIcon.classList.toggle('hidden');
|
|
70
|
+
closeIcon.classList.toggle('hidden');
|
|
71
|
+
}
|
|
26
72
|
// Close locale dropdown when clicking outside
|
|
27
73
|
document.addEventListener('click', function(e) {
|
|
28
74
|
var switcher = document.getElementById('pgbus-locale-switcher');
|
|
@@ -43,8 +89,10 @@
|
|
|
43
89
|
if (document.hidden) return;
|
|
44
90
|
document.querySelectorAll("turbo-frame[data-auto-refresh]")
|
|
45
91
|
.forEach(frame => {
|
|
46
|
-
|
|
47
|
-
|
|
92
|
+
try {
|
|
93
|
+
if (!frame.src && frame.dataset.src) frame.src = frame.dataset.src;
|
|
94
|
+
if (frame.src) frame.reload();
|
|
95
|
+
} catch (_) { /* Turbo may abort in-flight fetches during navigation */ }
|
|
48
96
|
});
|
|
49
97
|
}
|
|
50
98
|
function start() { timer = setInterval(refreshFrames, interval); }
|
|
@@ -61,13 +109,24 @@
|
|
|
61
109
|
<nav class="bg-gray-900 dark:bg-gray-950 border-b border-gray-800">
|
|
62
110
|
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
63
111
|
<div class="flex h-14 items-center justify-between">
|
|
112
|
+
<!-- Left: brand + desktop nav -->
|
|
64
113
|
<div class="flex items-center space-x-8">
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
114
|
+
<div class="flex items-center space-x-3">
|
|
115
|
+
<% if Pgbus.configuration.return_to_app_url %>
|
|
116
|
+
<a href="<%= Pgbus.configuration.return_to_app_url %>" class="rounded-md p-1.5 text-gray-400 hover:text-white hover:bg-gray-700" title="<%= t("pgbus.layout.return_to_app") %>">
|
|
117
|
+
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
|
118
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18"/>
|
|
119
|
+
</svg>
|
|
120
|
+
</a>
|
|
121
|
+
<% end %>
|
|
122
|
+
<%= link_to pgbus.root_path, class: "flex items-center space-x-2" do %>
|
|
123
|
+
<span class="text-lg font-bold text-white"><%= t("pgbus.layout.brand") %></span>
|
|
124
|
+
<span class="rounded bg-gray-700 px-1.5 py-0.5 text-xs text-gray-300"><%= Pgbus::VERSION %></span>
|
|
125
|
+
<% end %>
|
|
126
|
+
</div>
|
|
69
127
|
|
|
70
|
-
|
|
128
|
+
<!-- Desktop nav links (hidden on small screens) -->
|
|
129
|
+
<div class="hidden lg:flex space-x-1">
|
|
71
130
|
<%= pgbus_nav_link t("pgbus.layout.nav.dashboard"), pgbus.root_path %>
|
|
72
131
|
<%= pgbus_nav_link t("pgbus.layout.nav.queues"), pgbus.queues_path %>
|
|
73
132
|
<%= pgbus_nav_link t("pgbus.layout.nav.jobs"), pgbus.jobs_path %>
|
|
@@ -81,6 +140,7 @@
|
|
|
81
140
|
</div>
|
|
82
141
|
</div>
|
|
83
142
|
|
|
143
|
+
<!-- Right: locale, dark mode, hamburger -->
|
|
84
144
|
<div class="flex items-center space-x-2">
|
|
85
145
|
<!-- Locale switcher -->
|
|
86
146
|
<div class="relative" id="pgbus-locale-switcher">
|
|
@@ -98,17 +158,46 @@
|
|
|
98
158
|
</div>
|
|
99
159
|
</div>
|
|
100
160
|
|
|
101
|
-
|
|
102
|
-
<
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
161
|
+
<!-- Dark mode toggle -->
|
|
162
|
+
<button onclick="toggleDarkMode()" class="rounded-md p-2 text-gray-400 hover:text-white focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-900" aria-label="<%= t("pgbus.layout.toggle_dark_mode") %>">
|
|
163
|
+
<svg class="h-5 w-5 hidden dark:block" fill="currentColor" viewBox="0 0 20 20">
|
|
164
|
+
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"/>
|
|
165
|
+
</svg>
|
|
166
|
+
<svg class="h-5 w-5 block dark:hidden" fill="currentColor" viewBox="0 0 20 20">
|
|
167
|
+
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/>
|
|
168
|
+
</svg>
|
|
169
|
+
</button>
|
|
170
|
+
|
|
171
|
+
<!-- Mobile menu button (hidden on large screens) -->
|
|
172
|
+
<button onclick="toggleMobileMenu()" class="lg:hidden rounded-md p-2 text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500" aria-label="<%= t("pgbus.layout.toggle_menu") %>">
|
|
173
|
+
<!-- Hamburger icon -->
|
|
174
|
+
<svg id="pgbus-menu-open" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
|
175
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"/>
|
|
176
|
+
</svg>
|
|
177
|
+
<!-- Close icon (hidden by default) -->
|
|
178
|
+
<svg id="pgbus-menu-close" class="hidden h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
|
179
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
|
|
180
|
+
</svg>
|
|
181
|
+
</button>
|
|
109
182
|
</div>
|
|
110
183
|
</div>
|
|
111
184
|
</div>
|
|
185
|
+
|
|
186
|
+
<!-- Mobile menu (hidden by default, shown on small screens when toggled) -->
|
|
187
|
+
<div id="pgbus-mobile-menu" class="hidden lg:hidden border-t border-gray-800">
|
|
188
|
+
<div class="space-y-1 px-3 py-3">
|
|
189
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.dashboard"), pgbus.root_path %>
|
|
190
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.queues"), pgbus.queues_path %>
|
|
191
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.jobs"), pgbus.jobs_path %>
|
|
192
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.recurring"), pgbus.recurring_tasks_path %>
|
|
193
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.processes"), pgbus.processes_path %>
|
|
194
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.events"), pgbus.events_path %>
|
|
195
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.dlq"), pgbus.dead_letter_index_path %>
|
|
196
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.outbox"), pgbus.outbox_index_path %>
|
|
197
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.locks"), pgbus.locks_path %>
|
|
198
|
+
<%= pgbus_mobile_nav_link t("pgbus.layout.nav.insights"), pgbus.insights_path %>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
112
201
|
</nav>
|
|
113
202
|
|
|
114
203
|
<!-- Flash messages -->
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-3"><%= t("pgbus.dashboard.processes_table.title") %></h2>
|
|
4
4
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
5
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
5
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
6
6
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
7
7
|
<tr>
|
|
8
8
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.processes_table.headers.kind") %></th>
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
15
15
|
<% @processes.each do |p| %>
|
|
16
16
|
<tr>
|
|
17
|
-
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white"><%= p[:kind] %></td>
|
|
18
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= p[:hostname] %></td>
|
|
19
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= p[:pid] %></td>
|
|
20
|
-
<td class="px-4 py-3 text-sm"><%= pgbus_status_badge(p[:healthy]) %></td>
|
|
17
|
+
<td data-label="Kind" class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white"><%= p[:kind] %></td>
|
|
18
|
+
<td data-label="Host" class="px-4 py-3 text-sm text-gray-500"><%= p[:hostname] %></td>
|
|
19
|
+
<td data-label="PID" class="px-4 py-3 text-sm text-gray-500"><%= p[:pid] %></td>
|
|
20
|
+
<td data-label="Status" class="px-4 py-3 text-sm"><%= pgbus_status_badge(p[:healthy]) %></td>
|
|
21
21
|
</tr>
|
|
22
22
|
<% end %>
|
|
23
23
|
<% if @processes.empty? %>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
9
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
9
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
10
10
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
11
11
|
<tr>
|
|
12
12
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.queues_table.headers.queue") %></th>
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
20
20
|
<% @queues.each do |q| %>
|
|
21
21
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
22
|
-
<td class="px-4 py-3 text-sm">
|
|
22
|
+
<td data-label="Queue" class="px-4 py-3 text-sm">
|
|
23
23
|
<%= link_to q[:name], pgbus.queue_path(name: q[:name]), class: "font-medium text-indigo-600 hover:text-indigo-500", data: { turbo_frame: "_top" } %>
|
|
24
24
|
<%= pgbus_queue_badge(q[:name]) %>
|
|
25
25
|
</td>
|
|
26
|
-
<td class="px-4 py-3 text-sm text-right text-gray-700"><%= pgbus_number(q[:queue_length]) %></td>
|
|
27
|
-
<td class="px-4 py-3 text-sm text-right text-gray-700"><%= pgbus_number(q[:queue_visible_length]) %></td>
|
|
28
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500"><%= q[:oldest_msg_age_sec] || "—" %></td>
|
|
29
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500"><%= pgbus_number(q[:total_messages]) %></td>
|
|
26
|
+
<td data-label="Depth" class="px-4 py-3 text-sm text-right text-gray-700"><%= pgbus_number(q[:queue_length]) %></td>
|
|
27
|
+
<td data-label="Visible" class="px-4 py-3 text-sm text-right text-gray-700"><%= pgbus_number(q[:queue_visible_length]) %></td>
|
|
28
|
+
<td data-label="Oldest" class="px-4 py-3 text-sm text-right text-gray-500"><%= q[:oldest_msg_age_sec] || "—" %></td>
|
|
29
|
+
<td data-label="Total" class="px-4 py-3 text-sm text-right text-gray-500"><%= pgbus_number(q[:total_messages]) %></td>
|
|
30
30
|
</tr>
|
|
31
31
|
<% end %>
|
|
32
32
|
<% if @queues.empty? %>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<% end %>
|
|
8
8
|
</div>
|
|
9
9
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
10
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
10
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
11
11
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
12
12
|
<tr>
|
|
13
13
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.recent_failures.headers.queue") %></th>
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
19
19
|
<% @recent_failures.each do |f| %>
|
|
20
20
|
<tr>
|
|
21
|
-
<td class="px-4 py-3 text-sm text-gray-700"><%= f["queue_name"] %></td>
|
|
22
|
-
<td class="px-4 py-3 text-sm text-red-600 truncate max-w-xs"><%= f["error_class"] %>: <%= truncate(f["error_message"].to_s, length: 60) %></td>
|
|
23
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(f["failed_at"]) %></td>
|
|
21
|
+
<td data-label="Queue" class="px-4 py-3 text-sm text-gray-700"><%= f["queue_name"] %></td>
|
|
22
|
+
<td data-label="Error" class="px-4 py-3 text-sm text-red-600 truncate max-w-xs"><%= f["error_class"] %>: <%= truncate(f["error_message"].to_s, length: 60) %></td>
|
|
23
|
+
<td data-label="Time" class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(f["failed_at"]) %></td>
|
|
24
24
|
</tr>
|
|
25
25
|
<% end %>
|
|
26
26
|
<% if @recent_failures.empty? %>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<turbo-frame id="dlq-messages" data-auto-refresh data-src="<%= pgbus.dead_letter_index_path(frame: 'list') %>">
|
|
2
2
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
3
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
3
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
4
4
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
5
5
|
<tr>
|
|
6
6
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dead_letter.messages_table.headers.id") %></th>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<div class="mb-8">
|
|
5
5
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-3"><%= t("pgbus.events.index.subscribers_title") %></h2>
|
|
6
6
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
7
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
7
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
8
8
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
9
9
|
<tr>
|
|
10
10
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.events.index.subscribers_headers.pattern") %></th>
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
16
16
|
<% @subscribers.each do |s| %>
|
|
17
17
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
18
|
-
<td class="px-4 py-3 text-sm font-mono text-indigo-600"><%= s[:pattern] %></td>
|
|
19
|
-
<td class="px-4 py-3 text-sm text-gray-900 dark:text-white"><%= s[:handler_class] %></td>
|
|
20
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= s[:queue_name] %></td>
|
|
18
|
+
<td data-label="Pattern" class="px-4 py-3 text-sm font-mono text-indigo-600"><%= s[:pattern] %></td>
|
|
19
|
+
<td data-label="Handler" class="px-4 py-3 text-sm text-gray-900 dark:text-white"><%= s[:handler_class] %></td>
|
|
20
|
+
<td data-label="Queue" class="px-4 py-3 text-sm text-gray-500"><%= s[:queue_name] %></td>
|
|
21
21
|
</tr>
|
|
22
22
|
<% end %>
|
|
23
23
|
<% if @subscribers.empty? %>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<div>
|
|
33
33
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-3"><%= t("pgbus.events.index.processed_title") %></h2>
|
|
34
34
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
35
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
35
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
36
36
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
37
37
|
<tr>
|
|
38
38
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.events.index.processed_headers.event_id") %></th>
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
44
44
|
<% @events.each do |e| %>
|
|
45
45
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
46
|
-
<td class="px-4 py-3 text-sm font-mono text-gray-900 dark:text-white"><%= e["event_id"] %></td>
|
|
47
|
-
<td class="px-4 py-3 text-sm text-gray-700"><%= e["handler_class"] %></td>
|
|
48
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(e["processed_at"]) %></td>
|
|
46
|
+
<td data-label="Event ID" class="px-4 py-3 text-sm font-mono text-gray-900 dark:text-white"><%= e["event_id"] %></td>
|
|
47
|
+
<td data-label="Handler" class="px-4 py-3 text-sm text-gray-700"><%= e["handler_class"] %></td>
|
|
48
|
+
<td data-label="Processed At" class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(e["processed_at"]) %></td>
|
|
49
49
|
</tr>
|
|
50
50
|
<% end %>
|
|
51
51
|
<% if @events.empty? %>
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-700">
|
|
69
69
|
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300"><%= t("pgbus.insights.show.slowest.title") %></h3>
|
|
70
70
|
</div>
|
|
71
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
71
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
72
72
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
73
73
|
<tr>
|
|
74
74
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500 dark:text-gray-400"><%= t("pgbus.insights.show.slowest.headers.job_class") %></th>
|
|
@@ -80,10 +80,10 @@
|
|
|
80
80
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
81
81
|
<% @slowest.each do |row| %>
|
|
82
82
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50">
|
|
83
|
-
<td class="px-4 py-3 text-sm font-medium text-gray-700 dark:text-gray-300"><%= row[:job_class] %></td>
|
|
84
|
-
<td class="px-4 py-3 text-sm text-right font-mono text-gray-700 dark:text-gray-300"><%= pgbus_number(row[:count]) %></td>
|
|
85
|
-
<td class="px-4 py-3 text-sm text-right font-mono text-gray-700 dark:text-gray-300"><%= pgbus_ms_duration(row[:avg_ms]) %></td>
|
|
86
|
-
<td class="px-4 py-3 text-sm text-right font-mono text-gray-700 dark:text-gray-300"><%= pgbus_ms_duration(row[:max_ms]) %></td>
|
|
83
|
+
<td data-label="Job Class" class="px-4 py-3 text-sm font-medium text-gray-700 dark:text-gray-300"><%= row[:job_class] %></td>
|
|
84
|
+
<td data-label="Count" class="px-4 py-3 text-sm text-right font-mono text-gray-700 dark:text-gray-300"><%= pgbus_number(row[:count]) %></td>
|
|
85
|
+
<td data-label="Avg" class="px-4 py-3 text-sm text-right font-mono text-gray-700 dark:text-gray-300"><%= pgbus_ms_duration(row[:avg_ms]) %></td>
|
|
86
|
+
<td data-label="Max" class="px-4 py-3 text-sm text-right font-mono text-gray-700 dark:text-gray-300"><%= pgbus_ms_duration(row[:max_ms]) %></td>
|
|
87
87
|
</tr>
|
|
88
88
|
<% end %>
|
|
89
89
|
<% if @slowest.empty? %>
|
|
@@ -95,12 +95,14 @@
|
|
|
95
95
|
|
|
96
96
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts@4"></script>
|
|
97
97
|
<script>
|
|
98
|
-
|
|
98
|
+
(function() {
|
|
99
|
+
// IIFE prevents "redeclaration of let" when Turbo re-executes on navigation
|
|
100
|
+
var throughputChart, statusChart;
|
|
99
101
|
|
|
100
102
|
function getThemeColors() {
|
|
101
|
-
|
|
103
|
+
var isDark = document.documentElement.classList.contains('dark');
|
|
102
104
|
return {
|
|
103
|
-
isDark,
|
|
105
|
+
isDark: isDark,
|
|
104
106
|
text: isDark ? '#9ca3af' : '#6b7280',
|
|
105
107
|
grid: isDark ? '#374151' : '#e5e7eb',
|
|
106
108
|
tooltip: isDark ? 'dark' : 'light',
|
|
@@ -109,16 +111,14 @@
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
function renderCharts(data) {
|
|
112
|
-
|
|
114
|
+
var t = getThemeColors();
|
|
113
115
|
|
|
114
|
-
// Destroy existing charts before re-rendering
|
|
115
116
|
if (throughputChart) throughputChart.destroy();
|
|
116
117
|
if (statusChart) statusChart.destroy();
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}));
|
|
119
|
+
var throughputData = data.throughput.map(function(p) {
|
|
120
|
+
return { x: new Date(p.time).getTime(), y: p.count };
|
|
121
|
+
});
|
|
122
122
|
|
|
123
123
|
throughputChart = new ApexCharts(document.querySelector('#throughput-chart'), {
|
|
124
124
|
series: [{ name: '<%= j(t("pgbus.insights.show.charts.series_name")) %>', data: throughputData }],
|
|
@@ -134,10 +134,9 @@
|
|
|
134
134
|
});
|
|
135
135
|
throughputChart.render();
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const statusColors = statusLabels.map(s => {
|
|
137
|
+
var statusLabels = Object.keys(data.status_counts);
|
|
138
|
+
var statusValues = Object.values(data.status_counts);
|
|
139
|
+
var statusColors = statusLabels.map(function(s) {
|
|
141
140
|
if (s === 'success') return '#10b981';
|
|
142
141
|
if (s === 'failed') return '#ef4444';
|
|
143
142
|
if (s === 'dead_lettered') return '#f97316';
|
|
@@ -161,21 +160,24 @@
|
|
|
161
160
|
}
|
|
162
161
|
}
|
|
163
162
|
|
|
164
|
-
|
|
165
|
-
let chartData = null;
|
|
163
|
+
var chartData = null;
|
|
166
164
|
fetch('<%= pgbus.api_insights_path(minutes: @minutes) %>')
|
|
167
|
-
.then(r
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
165
|
+
.then(function(r) {
|
|
166
|
+
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
167
|
+
return r.json();
|
|
168
|
+
})
|
|
169
|
+
.then(function(data) { chartData = data; renderCharts(data); })
|
|
170
|
+
.catch(function(err) {
|
|
171
|
+
if (err.name === 'AbortError') return;
|
|
172
|
+
var msg = '<p class="text-center text-sm text-gray-400 dark:text-gray-500 pt-24"><%= j(t("pgbus.insights.show.charts.failed_to_load")) %></p>';
|
|
173
|
+
var el1 = document.querySelector('#throughput-chart');
|
|
174
|
+
var el2 = document.querySelector('#status-chart');
|
|
175
|
+
if (el1) el1.innerHTML = msg;
|
|
176
|
+
if (el2) el2.innerHTML = msg;
|
|
173
177
|
});
|
|
174
178
|
|
|
175
|
-
// Re-render charts when dark mode toggles.
|
|
176
|
-
// Listen for class changes on <html> instead of wrapping the toggle function,
|
|
177
|
-
// so it works regardless of script loading order.
|
|
178
179
|
new MutationObserver(function() {
|
|
179
180
|
if (chartData) renderCharts(chartData);
|
|
180
181
|
}).observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
|
|
182
|
+
})();
|
|
181
183
|
</script>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-3"><%= t("pgbus.jobs.enqueued_table.title") %></h2>
|
|
4
4
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
5
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
5
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
6
6
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
7
7
|
<tr>
|
|
8
8
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.jobs.enqueued_table.headers.id") %></th>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="mb-8">
|
|
3
3
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-3"><%= t("pgbus.jobs.failed_table.title") %></h2>
|
|
4
4
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
5
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
5
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
6
6
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
7
7
|
<tr>
|
|
8
8
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.jobs.failed_table.headers.id") %></th>
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
17
17
|
<% @failed.each do |f| %>
|
|
18
18
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
19
|
-
<td class="px-4 py-3 text-sm font-mono text-gray-900 dark:text-white">
|
|
19
|
+
<td data-label="ID" class="px-4 py-3 text-sm font-mono text-gray-900 dark:text-white">
|
|
20
20
|
<%= link_to f["id"], pgbus.job_path(f["id"]), class: "text-indigo-600 hover:text-indigo-500", data: { turbo_frame: "_top" } %>
|
|
21
21
|
</td>
|
|
22
|
-
<td class="px-4 py-3 text-sm text-gray-700"><%= f["queue_name"] %></td>
|
|
23
|
-
<td class="px-4 py-3 text-sm text-red-600 max-w-sm truncate">
|
|
22
|
+
<td data-label="Queue" class="px-4 py-3 text-sm text-gray-700"><%= f["queue_name"] %></td>
|
|
23
|
+
<td data-label="Error" class="px-4 py-3 text-sm text-red-600 max-w-sm truncate">
|
|
24
24
|
<span class="font-medium"><%= f["error_class"] %></span>: <%= truncate(f["error_message"].to_s, length: 80) %>
|
|
25
25
|
</td>
|
|
26
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= f["retry_count"] %></td>
|
|
27
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(f["failed_at"]) %></td>
|
|
28
|
-
<td class="px-4 py-3 text-sm text-right space-x-2">
|
|
26
|
+
<td data-label="Retries" class="px-4 py-3 text-sm text-gray-500"><%= f["retry_count"] %></td>
|
|
27
|
+
<td data-label="Failed" class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(f["failed_at"]) %></td>
|
|
28
|
+
<td data-label="Actions" class="px-4 py-3 text-sm text-right space-x-2">
|
|
29
29
|
<%= button_to t("pgbus.jobs.failed_table.retry"), pgbus.retry_job_path(f["id"]), method: :post,
|
|
30
30
|
class: "text-xs text-indigo-600 hover:text-indigo-800 font-medium",
|
|
31
31
|
data: { turbo_frame: "_top" } %>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
</div>
|
|
5
5
|
|
|
6
6
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
7
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
7
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
8
8
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
9
9
|
<tr>
|
|
10
10
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500 dark:text-gray-400"><%= t("pgbus.locks.index.headers.lock_key") %></th>
|
|
@@ -18,16 +18,16 @@
|
|
|
18
18
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
19
19
|
<% @locks.each do |lock| %>
|
|
20
20
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50">
|
|
21
|
-
<td class="px-4 py-3 text-sm font-mono text-gray-700 dark:text-gray-300 max-w-xs truncate"><%= lock[:lock_key] %></td>
|
|
22
|
-
<td class="px-4 py-3 text-sm text-gray-700 dark:text-gray-300"><%= lock[:job_class] %></td>
|
|
23
|
-
<td class="px-4 py-3 text-sm">
|
|
21
|
+
<td data-label="Lock Key" class="px-4 py-3 text-sm font-mono text-gray-700 dark:text-gray-300 max-w-xs truncate"><%= lock[:lock_key] %></td>
|
|
22
|
+
<td data-label="Job Class" class="px-4 py-3 text-sm text-gray-700 dark:text-gray-300"><%= lock[:job_class] %></td>
|
|
23
|
+
<td data-label="State" class="px-4 py-3 text-sm">
|
|
24
24
|
<% if lock[:state] == "executing" %>
|
|
25
25
|
<span class="inline-flex items-center rounded-full bg-blue-100 dark:bg-blue-900/50 px-2.5 py-0.5 text-xs font-medium text-blue-800 dark:text-blue-300"><%= t("pgbus.locks.index.executing") %></span>
|
|
26
26
|
<% else %>
|
|
27
27
|
<span class="inline-flex items-center rounded-full bg-yellow-100 dark:bg-yellow-900/50 px-2.5 py-0.5 text-xs font-medium text-yellow-800 dark:text-yellow-300"><%= t("pgbus.locks.index.queued") %></span>
|
|
28
28
|
<% end %>
|
|
29
29
|
</td>
|
|
30
|
-
<td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
|
|
30
|
+
<td data-label="Owner" class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
|
|
31
31
|
<% if lock[:owner_pid] %>
|
|
32
32
|
<span class="font-mono"><%= lock[:owner_pid] %></span>
|
|
33
33
|
<% if lock[:owner_hostname] %>
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
<span class="text-gray-400 dark:text-gray-500">—</span>
|
|
38
38
|
<% end %>
|
|
39
39
|
</td>
|
|
40
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500 dark:text-gray-400">
|
|
40
|
+
<td data-label="Age" class="px-4 py-3 text-sm text-right text-gray-500 dark:text-gray-400">
|
|
41
41
|
<% if lock[:age_seconds] %>
|
|
42
42
|
<%= pgbus_duration(lock[:age_seconds]) %>
|
|
43
43
|
<% end %>
|
|
44
44
|
</td>
|
|
45
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500 dark:text-gray-400"><%= pgbus_time_ago_future(lock[:expires_at]) %></td>
|
|
45
|
+
<td data-label="Expires" class="px-4 py-3 text-sm text-right text-gray-500 dark:text-gray-400"><%= pgbus_time_ago_future(lock[:expires_at]) %></td>
|
|
46
46
|
</tr>
|
|
47
47
|
<% end %>
|
|
48
48
|
<% if @locks.empty? %>
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
21
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
22
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
22
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
23
23
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
24
24
|
<tr>
|
|
25
25
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.outbox.index.headers.id") %></th>
|
|
@@ -33,18 +33,18 @@
|
|
|
33
33
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
34
34
|
<% @entries.each do |entry| %>
|
|
35
35
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
36
|
-
<td class="px-4 py-3 text-sm font-mono text-gray-700"><%= entry.id %></td>
|
|
37
|
-
<td class="px-4 py-3 text-sm text-gray-700"><%= entry.routing_key || entry.queue_name %></td>
|
|
38
|
-
<td class="px-4 py-3 text-sm text-gray-500 max-w-xs truncate"><%= pgbus_json_preview(entry.payload) %></td>
|
|
39
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500"><%= entry.priority %></td>
|
|
40
|
-
<td class="px-4 py-3 text-sm text-right">
|
|
36
|
+
<td data-label="ID" class="px-4 py-3 text-sm font-mono text-gray-700"><%= entry.id %></td>
|
|
37
|
+
<td data-label="Routing Key" class="px-4 py-3 text-sm text-gray-700"><%= entry.routing_key || entry.queue_name %></td>
|
|
38
|
+
<td data-label="Payload" class="px-4 py-3 text-sm text-gray-500 max-w-xs truncate"><%= pgbus_json_preview(entry.payload) %></td>
|
|
39
|
+
<td data-label="Priority" class="px-4 py-3 text-sm text-right text-gray-500"><%= entry.priority %></td>
|
|
40
|
+
<td data-label="Status" class="px-4 py-3 text-sm text-right">
|
|
41
41
|
<% if entry.published_at %>
|
|
42
42
|
<span class="inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800"><%= t("pgbus.outbox.index.published") %></span>
|
|
43
43
|
<% else %>
|
|
44
44
|
<span class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800"><%= t("pgbus.outbox.index.pending") %></span>
|
|
45
45
|
<% end %>
|
|
46
46
|
</td>
|
|
47
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500"><%= pgbus_time_ago(entry.created_at) %></td>
|
|
47
|
+
<td data-label="Created" class="px-4 py-3 text-sm text-right text-gray-500"><%= pgbus_time_ago(entry.created_at) %></td>
|
|
48
48
|
</tr>
|
|
49
49
|
<% end %>
|
|
50
50
|
<% if @entries.empty? %>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<turbo-frame id="processes-list" data-auto-refresh data-src="<%= pgbus.processes_path(frame: 'list') %>">
|
|
2
2
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
3
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
3
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
4
4
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
5
5
|
<tr>
|
|
6
6
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.processes.processes_table.headers.kind") %></th>
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
15
15
|
<% @processes.each do |p| %>
|
|
16
16
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
17
|
-
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white"><%= p[:kind] %></td>
|
|
18
|
-
<td class="px-4 py-3 text-sm text-gray-700"><%= p[:hostname] %></td>
|
|
19
|
-
<td class="px-4 py-3 text-sm font-mono text-gray-700"><%= p[:pid] %></td>
|
|
20
|
-
<td class="px-4 py-3 text-sm"><%= pgbus_status_badge(p[:healthy]) %></td>
|
|
21
|
-
<td class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(p[:last_heartbeat_at]) %></td>
|
|
22
|
-
<td class="px-4 py-3 text-sm text-gray-500 font-mono text-xs max-w-xs truncate">
|
|
17
|
+
<td data-label="Kind" class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white"><%= p[:kind] %></td>
|
|
18
|
+
<td data-label="Host" class="px-4 py-3 text-sm text-gray-700"><%= p[:hostname] %></td>
|
|
19
|
+
<td data-label="PID" class="px-4 py-3 text-sm font-mono text-gray-700"><%= p[:pid] %></td>
|
|
20
|
+
<td data-label="Status" class="px-4 py-3 text-sm"><%= pgbus_status_badge(p[:healthy]) %></td>
|
|
21
|
+
<td data-label="Last Heartbeat" class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(p[:last_heartbeat_at]) %></td>
|
|
22
|
+
<td data-label="Metadata" class="px-4 py-3 text-sm text-gray-500 font-mono text-xs max-w-xs truncate">
|
|
23
23
|
<% if p[:metadata].is_a?(Hash) %>
|
|
24
24
|
<% p[:metadata].each do |k, v| %>
|
|
25
25
|
<span class="inline-flex items-center rounded bg-gray-100 px-1.5 py-0.5 text-xs mr-1"><%= k %>: <%= v %></span>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<turbo-frame id="queues-list" data-auto-refresh data-src="<%= pgbus.queues_path(frame: 'list') %>">
|
|
2
2
|
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
3
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
3
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
4
4
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
5
5
|
<tr>
|
|
6
6
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.queues.queues_list.headers.queue") %></th>
|
|
@@ -15,19 +15,19 @@
|
|
|
15
15
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
16
16
|
<% @queues.each do |q| %>
|
|
17
17
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
18
|
-
<td class="px-4 py-3 text-sm">
|
|
18
|
+
<td data-label="Queue" class="px-4 py-3 text-sm">
|
|
19
19
|
<%= link_to q[:name], pgbus.queue_path(name: q[:name]), class: "font-medium text-indigo-600 hover:text-indigo-500", data: { turbo_frame: "_top" } %>
|
|
20
20
|
<%= pgbus_queue_badge(q[:name]) %>
|
|
21
21
|
<% if q[:paused] %>
|
|
22
22
|
<span class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800"><%= t("pgbus.queues.queues_list.paused") %></span>
|
|
23
23
|
<% end %>
|
|
24
24
|
</td>
|
|
25
|
-
<td class="px-4 py-3 text-sm text-right font-mono text-gray-700"><%= pgbus_number(q[:queue_length]) %></td>
|
|
26
|
-
<td class="px-4 py-3 text-sm text-right font-mono text-gray-700"><%= pgbus_number(q[:queue_visible_length]) %></td>
|
|
27
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500"><%= q[:oldest_msg_age_sec] || "—" %></td>
|
|
28
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500"><%= q[:newest_msg_age_sec] || "—" %></td>
|
|
29
|
-
<td class="px-4 py-3 text-sm text-right text-gray-500"><%= pgbus_number(q[:total_messages]) %></td>
|
|
30
|
-
<td class="px-4 py-3 text-sm text-right space-x-2">
|
|
25
|
+
<td data-label="Depth" class="px-4 py-3 text-sm text-right font-mono text-gray-700"><%= pgbus_number(q[:queue_length]) %></td>
|
|
26
|
+
<td data-label="Visible" class="px-4 py-3 text-sm text-right font-mono text-gray-700"><%= pgbus_number(q[:queue_visible_length]) %></td>
|
|
27
|
+
<td data-label="Oldest" class="px-4 py-3 text-sm text-right text-gray-500"><%= q[:oldest_msg_age_sec] || "—" %></td>
|
|
28
|
+
<td data-label="Newest" class="px-4 py-3 text-sm text-right text-gray-500"><%= q[:newest_msg_age_sec] || "—" %></td>
|
|
29
|
+
<td data-label="Total" class="px-4 py-3 text-sm text-right text-gray-500"><%= pgbus_number(q[:total_messages]) %></td>
|
|
30
|
+
<td data-label="Actions" class="px-4 py-3 text-sm text-right space-x-2">
|
|
31
31
|
<% if q[:paused] %>
|
|
32
32
|
<%= button_to t("pgbus.queues.queues_list.resume"), pgbus.resume_queue_path(name: q[:name]),
|
|
33
33
|
method: :post,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<p class="mt-1 text-sm"><%= t("pgbus.recurring_tasks.tasks_table.empty_hint") %></p>
|
|
7
7
|
</div>
|
|
8
8
|
<% else %>
|
|
9
|
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
9
|
+
<table class="pgbus-table min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
10
10
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
11
11
|
<tr>
|
|
12
12
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase"><%= t("pgbus.recurring_tasks.tasks_table.headers.task") %></th>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
|
22
22
|
<% @recurring_tasks.each do |task| %>
|
|
23
23
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
24
|
-
<td class="px-4 py-3">
|
|
24
|
+
<td data-label="Task" class="px-4 py-3">
|
|
25
25
|
<div>
|
|
26
26
|
<%= link_to task[:key], pgbus.recurring_task_path(task[:id]),
|
|
27
27
|
class: "text-sm font-medium text-blue-600 hover:text-blue-800" %>
|
|
@@ -31,26 +31,26 @@
|
|
|
31
31
|
<div class="text-xs text-gray-400 mt-0.5"><%= task[:description] %></div>
|
|
32
32
|
<% end %>
|
|
33
33
|
</td>
|
|
34
|
-
<td class="px-4 py-3">
|
|
34
|
+
<td data-label="Schedule" class="px-4 py-3">
|
|
35
35
|
<div class="text-sm text-gray-900 dark:text-white"><%= task[:schedule] %></div>
|
|
36
36
|
<% if task[:human_schedule] && task[:human_schedule] != task[:schedule] %>
|
|
37
37
|
<div class="text-xs text-gray-400"><%= task[:human_schedule] %></div>
|
|
38
38
|
<% end %>
|
|
39
39
|
</td>
|
|
40
|
-
<td class="px-4 py-3 text-sm text-gray-600">
|
|
40
|
+
<td data-label="Queue" class="px-4 py-3 text-sm text-gray-600">
|
|
41
41
|
<%= task[:queue_name] || t("pgbus.recurring_tasks.tasks_table.default_queue") %>
|
|
42
42
|
</td>
|
|
43
|
-
<td class="px-4 py-3 text-sm text-gray-600">
|
|
43
|
+
<td data-label="Last Run" class="px-4 py-3 text-sm text-gray-600">
|
|
44
44
|
<%= task[:last_run_at] ? pgbus_time_ago(task[:last_run_at]) : t("pgbus.recurring_tasks.tasks_table.never") %>
|
|
45
45
|
</td>
|
|
46
|
-
<td class="px-4 py-3 text-sm text-gray-600">
|
|
46
|
+
<td data-label="Next Run" class="px-4 py-3 text-sm text-gray-600">
|
|
47
47
|
<% if task[:enabled] && task[:next_run_at] %>
|
|
48
48
|
<%= pgbus_time_ago_future(task[:next_run_at]) %>
|
|
49
49
|
<% else %>
|
|
50
50
|
<span class="text-gray-400">—</span>
|
|
51
51
|
<% end %>
|
|
52
52
|
</td>
|
|
53
|
-
<td class="px-4 py-3">
|
|
53
|
+
<td data-label="Status" class="px-4 py-3">
|
|
54
54
|
<% if task[:enabled] %>
|
|
55
55
|
<%= pgbus_recurring_health_badge(task) %>
|
|
56
56
|
<% else %>
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
</span>
|
|
60
60
|
<% end %>
|
|
61
61
|
</td>
|
|
62
|
-
<td class="px-4 py-3 text-right space-x-1">
|
|
62
|
+
<td data-label="Actions" class="px-4 py-3 text-right space-x-1">
|
|
63
63
|
<%= button_to task[:enabled] ? t("pgbus.recurring_tasks.tasks_table.disable") : t("pgbus.recurring_tasks.tasks_table.enable"),
|
|
64
64
|
pgbus.toggle_recurring_task_path(task[:id]),
|
|
65
65
|
class: "inline-flex items-center rounded px-2 py-1 text-xs font-medium " \
|
data/config/locales/da.yml
CHANGED
|
@@ -217,8 +217,10 @@ da:
|
|
|
217
217
|
processes: Processer
|
|
218
218
|
queues: Køer
|
|
219
219
|
recurring: Gentagende
|
|
220
|
+
return_to_app: Tilbage til app
|
|
220
221
|
title: Pgbus Dashboard
|
|
221
222
|
toggle_dark_mode: Skift til mørk tilstand
|
|
223
|
+
toggle_menu: Skift menu
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Aktive unikke låse forhindrer duplikeret jobudførelse
|
data/config/locales/de.yml
CHANGED
|
@@ -217,8 +217,10 @@ de:
|
|
|
217
217
|
processes: Prozesse
|
|
218
218
|
queues: Warteschlangen
|
|
219
219
|
recurring: Wiederkehrend
|
|
220
|
+
return_to_app: Zurück zur App
|
|
220
221
|
title: Pgbus Dashboard
|
|
221
222
|
toggle_dark_mode: Dunkelmodus umschalten
|
|
223
|
+
toggle_menu: Menü umschalten
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Aktive Einzigartigkeitssperren verhindern doppelte Auftragserstellung
|
data/config/locales/en.yml
CHANGED
|
@@ -217,8 +217,10 @@ en:
|
|
|
217
217
|
processes: Processes
|
|
218
218
|
queues: Queues
|
|
219
219
|
recurring: Recurring
|
|
220
|
+
return_to_app: Back to app
|
|
220
221
|
title: Pgbus Dashboard
|
|
221
222
|
toggle_dark_mode: Toggle dark mode
|
|
223
|
+
toggle_menu: Toggle menu
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Active uniqueness locks preventing duplicate job execution
|
data/config/locales/es.yml
CHANGED
|
@@ -217,8 +217,10 @@ es:
|
|
|
217
217
|
processes: Procesos
|
|
218
218
|
queues: Colas
|
|
219
219
|
recurring: Recurrente
|
|
220
|
+
return_to_app: Volver a la app
|
|
220
221
|
title: Panel de Pgbus
|
|
221
222
|
toggle_dark_mode: Alternar modo oscuro
|
|
223
|
+
toggle_menu: Alternar menú
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Bloqueos de unicidad activos que impiden la ejecución duplicada del trabajo
|
data/config/locales/fi.yml
CHANGED
|
@@ -217,8 +217,10 @@ fi:
|
|
|
217
217
|
processes: Prosessit
|
|
218
218
|
queues: Jonot
|
|
219
219
|
recurring: Toistuva
|
|
220
|
+
return_to_app: Takaisin sovellukseen
|
|
220
221
|
title: Pgbus-hallintapaneeli
|
|
221
222
|
toggle_dark_mode: Vaihda tumma tila
|
|
223
|
+
toggle_menu: Vaihda valikko
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Aktiiviset ainutlaatuisuuden lukot estävät päällekkäisen työn suorittamisen
|
data/config/locales/fr.yml
CHANGED
|
@@ -217,8 +217,10 @@ fr:
|
|
|
217
217
|
processes: Processus
|
|
218
218
|
queues: Files d'attente
|
|
219
219
|
recurring: Récurrent
|
|
220
|
+
return_to_app: Retour à l'application
|
|
220
221
|
title: Tableau de bord Pgbus
|
|
221
222
|
toggle_dark_mode: Basculer en mode sombre
|
|
223
|
+
toggle_menu: Basculer le menu
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Verrous d'unicité actifs empêchant l'exécution de travaux en double
|
data/config/locales/it.yml
CHANGED
|
@@ -217,8 +217,10 @@ it:
|
|
|
217
217
|
processes: Processi
|
|
218
218
|
queues: Code
|
|
219
219
|
recurring: Ricorrente
|
|
220
|
+
return_to_app: Torna all'app
|
|
220
221
|
title: Cruscotto Pgbus
|
|
221
222
|
toggle_dark_mode: Attiva/disattiva modalità scura
|
|
223
|
+
toggle_menu: Attiva/disattiva menu
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Blocchi di unicità attivi che impediscono l'esecuzione duplicata del lavoro
|
data/config/locales/ja.yml
CHANGED
data/config/locales/nb.yml
CHANGED
|
@@ -217,8 +217,10 @@ nb:
|
|
|
217
217
|
processes: Prosesser
|
|
218
218
|
queues: Køer
|
|
219
219
|
recurring: Gjentakende
|
|
220
|
+
return_to_app: Tilbake til appen
|
|
220
221
|
title: Pgbus-dashbord
|
|
221
222
|
toggle_dark_mode: Bytt til mørk modus
|
|
223
|
+
toggle_menu: Veksle meny
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Aktive unike låser som forhindrer duplisert jobbkjøring
|
data/config/locales/nl.yml
CHANGED
|
@@ -217,8 +217,10 @@ nl:
|
|
|
217
217
|
processes: Processen
|
|
218
218
|
queues: Wachtrijen
|
|
219
219
|
recurring: Terugkerend
|
|
220
|
+
return_to_app: Terug naar app
|
|
220
221
|
title: Pgbus Dashboard
|
|
221
222
|
toggle_dark_mode: Donkere modus schakelen
|
|
223
|
+
toggle_menu: Menu wisselen
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Actieve uniekheidsvergrendelingen voorkomen dubbele taakuitvoering
|
data/config/locales/pt.yml
CHANGED
|
@@ -217,8 +217,10 @@ pt:
|
|
|
217
217
|
processes: Processos
|
|
218
218
|
queues: Filas
|
|
219
219
|
recurring: Recorrente
|
|
220
|
+
return_to_app: Voltar ao aplicativo
|
|
220
221
|
title: Painel Pgbus
|
|
221
222
|
toggle_dark_mode: Alternar modo escuro
|
|
223
|
+
toggle_menu: Alternar menu
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Bloqueios de exclusividade ativos impedindo a execução duplicada do trabalho
|
data/config/locales/sv.yml
CHANGED
|
@@ -217,8 +217,10 @@ sv:
|
|
|
217
217
|
processes: Processer
|
|
218
218
|
queues: Köer
|
|
219
219
|
recurring: Återkommande
|
|
220
|
+
return_to_app: Tillbaka till appen
|
|
220
221
|
title: Pgbus-instrumentpanel
|
|
221
222
|
toggle_dark_mode: Växla mörkt läge
|
|
223
|
+
toggle_menu: Växla meny
|
|
222
224
|
locks:
|
|
223
225
|
index:
|
|
224
226
|
description: Aktiva unika lås som förhindrar duplicerad jobbexekvering
|
data/lib/pgbus/configuration.rb
CHANGED
|
@@ -64,7 +64,7 @@ module Pgbus
|
|
|
64
64
|
|
|
65
65
|
# Web dashboard
|
|
66
66
|
attr_accessor :web_auth, :web_refresh_interval, :web_per_page, :web_live_updates, :web_data_source,
|
|
67
|
-
:insights_default_minutes
|
|
67
|
+
:insights_default_minutes, :base_controller_class, :return_to_app_url
|
|
68
68
|
|
|
69
69
|
def initialize
|
|
70
70
|
@database_url = nil
|
|
@@ -136,6 +136,8 @@ module Pgbus
|
|
|
136
136
|
@web_live_updates = true
|
|
137
137
|
@web_data_source = nil
|
|
138
138
|
@insights_default_minutes = 30 * 24 * 60 # 30 days
|
|
139
|
+
@base_controller_class = "::ActionController::Base"
|
|
140
|
+
@return_to_app_url = nil
|
|
139
141
|
end
|
|
140
142
|
|
|
141
143
|
def queue_name(name)
|
data/lib/pgbus/version.rb
CHANGED