pgbus 0.2.1 → 0.2.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/app/controllers/pgbus/api/insights_controller.rb +5 -4
- data/app/controllers/pgbus/application_controller.rb +40 -0
- data/app/controllers/pgbus/insights_controller.rb +3 -2
- data/app/controllers/pgbus/locale_controller.rb +15 -0
- data/app/helpers/pgbus/application_helper.rb +67 -7
- data/app/views/layouts/pgbus/application.html.erb +50 -14
- data/app/views/pgbus/dashboard/_processes_table.html.erb +6 -6
- data/app/views/pgbus/dashboard/_queues_table.html.erb +8 -8
- data/app/views/pgbus/dashboard/_recent_failures.html.erb +6 -6
- data/app/views/pgbus/dashboard/_stats_cards.html.erb +9 -9
- data/app/views/pgbus/dashboard/show.html.erb +1 -1
- data/app/views/pgbus/dead_letter/_messages_table.html.erb +19 -19
- data/app/views/pgbus/dead_letter/index.html.erb +5 -5
- data/app/views/pgbus/dead_letter/show.html.erb +12 -12
- data/app/views/pgbus/events/index.html.erb +11 -11
- data/app/views/pgbus/events/show.html.erb +6 -6
- data/app/views/pgbus/insights/show.html.erb +41 -21
- data/app/views/pgbus/jobs/_enqueued_table.html.erb +19 -19
- data/app/views/pgbus/jobs/_failed_table.html.erb +11 -11
- data/app/views/pgbus/jobs/index.html.erb +5 -5
- data/app/views/pgbus/jobs/show.html.erb +13 -13
- data/app/views/pgbus/locks/index.html.erb +11 -11
- data/app/views/pgbus/outbox/index.html.erb +15 -15
- data/app/views/pgbus/processes/_processes_table.html.erb +7 -7
- data/app/views/pgbus/processes/index.html.erb +1 -1
- data/app/views/pgbus/queues/_queues_list.html.erb +14 -14
- data/app/views/pgbus/queues/index.html.erb +1 -1
- data/app/views/pgbus/queues/show.html.erb +11 -11
- data/app/views/pgbus/recurring_tasks/_tasks_table.html.erb +14 -14
- data/app/views/pgbus/recurring_tasks/index.html.erb +2 -2
- data/app/views/pgbus/recurring_tasks/show.html.erb +21 -21
- data/config/i18n-tasks.yml +41 -0
- data/config/locales/da.yml +348 -0
- data/config/locales/de.yml +348 -0
- data/config/locales/en.yml +348 -0
- data/config/locales/es.yml +348 -0
- data/config/locales/fi.yml +348 -0
- data/config/locales/fr.yml +348 -0
- data/config/locales/it.yml +348 -0
- data/config/locales/ja.yml +348 -0
- data/config/locales/nb.yml +348 -0
- data/config/locales/nl.yml +348 -0
- data/config/locales/pt.yml +348 -0
- data/config/locales/sv.yml +348 -0
- data/config/routes.rb +2 -0
- data/lib/pgbus/configuration.rb +8 -2
- data/lib/pgbus/engine.rb +4 -0
- data/lib/pgbus/version.rb +1 -1
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 11fc5e1aa1196d1332b426e72aab0364cc548925fe960ff6626a6cd8090b2de5
|
|
4
|
+
data.tar.gz: 52fd690b0a3afda834850f5fc0eb3a111fd18062af6b3ca7097fadc085abf1b9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f232df26f7a0122db40119b43bf0d03290ea583eaf889ac58c95bb81850c5f745603fa81b848be437f4298ffff5ed65c82c64b890da64bc663ef600a4d05fe0c
|
|
7
|
+
data.tar.gz: c2d5f381fa2e4cf4943fe9bd27815459faaf9f92c7bf40d97bb2ea93b5622dcb5a197d8ccdb63249fd2ee681d4c10961070e7016093bacda2ba81010939cd7aa
|
|
@@ -4,11 +4,12 @@ module Pgbus
|
|
|
4
4
|
module Api
|
|
5
5
|
class InsightsController < ApplicationController
|
|
6
6
|
def show
|
|
7
|
+
minutes = insights_minutes
|
|
7
8
|
render json: {
|
|
8
|
-
summary: data_source.job_stats_summary,
|
|
9
|
-
throughput: data_source.job_throughput,
|
|
10
|
-
status_counts: data_source.job_status_counts,
|
|
11
|
-
slowest: data_source.slowest_job_classes
|
|
9
|
+
summary: data_source.job_stats_summary(minutes: minutes),
|
|
10
|
+
throughput: data_source.job_throughput(minutes: minutes),
|
|
11
|
+
status_counts: data_source.job_status_counts(minutes: minutes),
|
|
12
|
+
slowest: data_source.slowest_job_classes(minutes: minutes)
|
|
12
13
|
}
|
|
13
14
|
end
|
|
14
15
|
end
|
|
@@ -5,6 +5,7 @@ module Pgbus
|
|
|
5
5
|
include Web::Authentication
|
|
6
6
|
|
|
7
7
|
protect_from_forgery with: :exception
|
|
8
|
+
before_action :set_locale
|
|
8
9
|
|
|
9
10
|
layout "pgbus/application"
|
|
10
11
|
|
|
@@ -20,6 +21,37 @@ module Pgbus
|
|
|
20
21
|
|
|
21
22
|
private
|
|
22
23
|
|
|
24
|
+
def set_locale
|
|
25
|
+
I18n.locale = extract_locale || I18n.default_locale
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def extract_locale
|
|
29
|
+
locale = params[:locale] || cookies[:pgbus_locale] || preferred_locale_from_header
|
|
30
|
+
locale if locale && available_locales.include?(locale.to_sym)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def preferred_locale_from_header
|
|
34
|
+
return unless request.env["HTTP_ACCEPT_LANGUAGE"]
|
|
35
|
+
|
|
36
|
+
request.env["HTTP_ACCEPT_LANGUAGE"]
|
|
37
|
+
.scan(/([a-z]{2}(?:-[A-Z]{2})?)\s*;?\s*(?:q=([0-9.]+))?/i)
|
|
38
|
+
.sort_by { |_, q| -(q&.to_f || 1.0) }
|
|
39
|
+
.each do |lang, _|
|
|
40
|
+
code = lang.downcase.to_sym
|
|
41
|
+
return code.to_s if available_locales.include?(code)
|
|
42
|
+
|
|
43
|
+
# Try base language (e.g., "de" from "de-AT")
|
|
44
|
+
base = lang.split("-").first.downcase.to_sym
|
|
45
|
+
return base.to_s if available_locales.include?(base)
|
|
46
|
+
end
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def available_locales
|
|
51
|
+
@available_locales ||= Dir[Pgbus::Engine.root.join("config", "locales", "*.yml")]
|
|
52
|
+
.map { |f| File.basename(f, ".yml").to_sym }
|
|
53
|
+
end
|
|
54
|
+
|
|
23
55
|
def data_source
|
|
24
56
|
@data_source ||= Pgbus.configuration.web_data_source || Web::DataSource.new
|
|
25
57
|
end
|
|
@@ -32,6 +64,14 @@ module Pgbus
|
|
|
32
64
|
Pgbus.configuration.web_per_page
|
|
33
65
|
end
|
|
34
66
|
|
|
67
|
+
def insights_minutes
|
|
68
|
+
config = Pgbus.configuration
|
|
69
|
+
default = config.insights_default_minutes.to_i
|
|
70
|
+
max = config.stats_retention.to_i / 60
|
|
71
|
+
value = (params[:minutes] || default).to_i
|
|
72
|
+
value.clamp(1, [max, 1].max)
|
|
73
|
+
end
|
|
74
|
+
|
|
35
75
|
def turbo_frame_request?
|
|
36
76
|
request.headers["Turbo-Frame"].present? || params[:frame].present?
|
|
37
77
|
end
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
module Pgbus
|
|
4
4
|
class InsightsController < ApplicationController
|
|
5
5
|
def show
|
|
6
|
-
@
|
|
7
|
-
@
|
|
6
|
+
@minutes = insights_minutes
|
|
7
|
+
@summary = data_source.job_stats_summary(minutes: @minutes)
|
|
8
|
+
@slowest = data_source.slowest_job_classes(minutes: @minutes)
|
|
8
9
|
end
|
|
9
10
|
end
|
|
10
11
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pgbus
|
|
4
|
+
class LocaleController < ApplicationController
|
|
5
|
+
def update
|
|
6
|
+
locale = params[:locale].to_s
|
|
7
|
+
if available_locales.include?(locale.to_sym)
|
|
8
|
+
cookies[:pgbus_locale] = { value: locale, expires: 1.year.from_now, path: "/" }
|
|
9
|
+
I18n.locale = locale
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
redirect_back fallback_location: pgbus.root_path
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -31,17 +31,21 @@ module Pgbus
|
|
|
31
31
|
|
|
32
32
|
def pgbus_status_badge(healthy)
|
|
33
33
|
if healthy
|
|
34
|
-
tag.span("
|
|
34
|
+
tag.span(I18n.t("pgbus.helpers.status_badge.healthy"),
|
|
35
|
+
class: "inline-flex items-center rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800")
|
|
35
36
|
else
|
|
36
|
-
tag.span("
|
|
37
|
+
tag.span(I18n.t("pgbus.helpers.status_badge.stale"),
|
|
38
|
+
class: "inline-flex items-center rounded-full bg-red-100 px-2.5 py-0.5 text-xs font-medium text-red-800")
|
|
37
39
|
end
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
def pgbus_queue_badge(name)
|
|
41
43
|
if name.to_s.end_with?("_dlq")
|
|
42
|
-
tag.span("
|
|
44
|
+
tag.span(I18n.t("pgbus.helpers.queue_badge.dlq"),
|
|
45
|
+
class: "inline-flex items-center rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-700")
|
|
43
46
|
else
|
|
44
|
-
tag.span("
|
|
47
|
+
tag.span(I18n.t("pgbus.helpers.queue_badge.queue"),
|
|
48
|
+
class: "inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-700")
|
|
45
49
|
end
|
|
46
50
|
end
|
|
47
51
|
|
|
@@ -76,7 +80,8 @@ module Pgbus
|
|
|
76
80
|
def pgbus_paused_badge(paused)
|
|
77
81
|
return unless paused
|
|
78
82
|
|
|
79
|
-
tag.span("
|
|
83
|
+
tag.span(I18n.t("pgbus.helpers.paused_badge"),
|
|
84
|
+
class: "inline-flex items-center rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800")
|
|
80
85
|
end
|
|
81
86
|
|
|
82
87
|
def pgbus_parse_message(message)
|
|
@@ -123,14 +128,26 @@ module Pgbus
|
|
|
123
128
|
|
|
124
129
|
def pgbus_recurring_health_badge(task)
|
|
125
130
|
if task[:last_run_at].nil?
|
|
126
|
-
tag.span("
|
|
131
|
+
tag.span(I18n.t("pgbus.helpers.recurring_health.pending"),
|
|
127
132
|
class: "inline-flex items-center rounded-full bg-yellow-100 px-2.5 py-0.5 text-xs font-medium text-yellow-800")
|
|
128
133
|
else
|
|
129
|
-
tag.span("
|
|
134
|
+
tag.span(I18n.t("pgbus.helpers.recurring_health.active"),
|
|
130
135
|
class: "inline-flex items-center rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800")
|
|
131
136
|
end
|
|
132
137
|
end
|
|
133
138
|
|
|
139
|
+
def pgbus_time_range_label(minutes)
|
|
140
|
+
minutes = [minutes.to_i, 1].max
|
|
141
|
+
|
|
142
|
+
if minutes > 1440 && (minutes % 1440).zero?
|
|
143
|
+
pgbus_pluralize_unit(minutes / 1440, "day")
|
|
144
|
+
elsif minutes >= 60 && (minutes % 60).zero?
|
|
145
|
+
pgbus_pluralize_unit(minutes / 60, "hour")
|
|
146
|
+
else
|
|
147
|
+
pgbus_pluralize_unit(minutes, "minute")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
134
151
|
def pgbus_nav_link(label, path)
|
|
135
152
|
active = request.path == path || (path != pgbus.root_path && request.path.start_with?(path))
|
|
136
153
|
css = if active
|
|
@@ -140,5 +157,48 @@ module Pgbus
|
|
|
140
157
|
end
|
|
141
158
|
link_to label, path, class: css
|
|
142
159
|
end
|
|
160
|
+
|
|
161
|
+
LOCALE_NAMES = {
|
|
162
|
+
da: "Dansk",
|
|
163
|
+
de: "Deutsch",
|
|
164
|
+
en: "English",
|
|
165
|
+
es: "Espa\u00f1ol",
|
|
166
|
+
fi: "Suomi",
|
|
167
|
+
fr: "Fran\u00e7ais",
|
|
168
|
+
it: "Italiano",
|
|
169
|
+
ja: "\u65E5\u672C\u8A9E",
|
|
170
|
+
nb: "Norsk",
|
|
171
|
+
nl: "Nederlands",
|
|
172
|
+
pt: "Portugu\u00eas",
|
|
173
|
+
sv: "Svenska"
|
|
174
|
+
}.freeze
|
|
175
|
+
|
|
176
|
+
def pgbus_locale_name(code)
|
|
177
|
+
LOCALE_NAMES[code.to_sym] || code.to_s.upcase
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def pgbus_locale_flag(code)
|
|
181
|
+
case code.to_sym
|
|
182
|
+
when :da then "\u{1F1E9}\u{1F1F0}"
|
|
183
|
+
when :de then "\u{1F1E9}\u{1F1EA}"
|
|
184
|
+
when :en then "\u{1F1EC}\u{1F1E7}"
|
|
185
|
+
when :es then "\u{1F1EA}\u{1F1F8}"
|
|
186
|
+
when :fi then "\u{1F1EB}\u{1F1EE}"
|
|
187
|
+
when :fr then "\u{1F1EB}\u{1F1F7}"
|
|
188
|
+
when :it then "\u{1F1EE}\u{1F1F9}"
|
|
189
|
+
when :ja then "\u{1F1EF}\u{1F1F5}"
|
|
190
|
+
when :nb then "\u{1F1F3}\u{1F1F4}"
|
|
191
|
+
when :nl then "\u{1F1F3}\u{1F1F1}"
|
|
192
|
+
when :pt then "\u{1F1F5}\u{1F1F9}"
|
|
193
|
+
when :sv then "\u{1F1F8}\u{1F1EA}"
|
|
194
|
+
else "\u{1F310}"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
private
|
|
199
|
+
|
|
200
|
+
def pgbus_pluralize_unit(count, unit)
|
|
201
|
+
count == 1 ? "1 #{unit}" : "#{count} #{unit}s"
|
|
202
|
+
end
|
|
143
203
|
end
|
|
144
204
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="
|
|
2
|
+
<html lang="<%= I18n.locale %>" class="h-full">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title
|
|
6
|
+
<title><%= t("pgbus.layout.title") %></title>
|
|
7
7
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
8
8
|
<script>
|
|
9
9
|
tailwind.config = { darkMode: 'class' };
|
|
@@ -17,6 +17,21 @@
|
|
|
17
17
|
var isDark = document.documentElement.classList.toggle('dark');
|
|
18
18
|
localStorage.setItem('pgbus-dark', isDark);
|
|
19
19
|
}
|
|
20
|
+
// Locale dropdown toggle
|
|
21
|
+
document.addEventListener('click', function(e) {
|
|
22
|
+
var btn = e.target.closest('[data-action="click->dropdown#toggle"]');
|
|
23
|
+
var menu = btn && btn.parentElement.querySelector('[data-dropdown-target="menu"]');
|
|
24
|
+
// Close all menus first
|
|
25
|
+
document.querySelectorAll('[data-dropdown-target="menu"]').forEach(function(m) {
|
|
26
|
+
if (m !== menu) m.classList.add('hidden');
|
|
27
|
+
});
|
|
28
|
+
if (menu) { menu.classList.toggle('hidden'); e.stopPropagation(); }
|
|
29
|
+
});
|
|
30
|
+
document.addEventListener('click', function() {
|
|
31
|
+
document.querySelectorAll('[data-dropdown-target="menu"]').forEach(function(m) {
|
|
32
|
+
m.classList.add('hidden');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
20
35
|
</script>
|
|
21
36
|
<script type="module">
|
|
22
37
|
import * as Turbo from "https://cdn.jsdelivr.net/npm/@hotwired/turbo@8/dist/turbo.es2017.esm.js";
|
|
@@ -46,25 +61,45 @@
|
|
|
46
61
|
<div class="flex h-14 items-center justify-between">
|
|
47
62
|
<div class="flex items-center space-x-8">
|
|
48
63
|
<%= link_to pgbus.root_path, class: "flex items-center space-x-2" do %>
|
|
49
|
-
<span class="text-lg font-bold text-white"
|
|
64
|
+
<span class="text-lg font-bold text-white"><%= t("pgbus.layout.brand") %></span>
|
|
50
65
|
<span class="rounded bg-gray-700 px-1.5 py-0.5 text-xs text-gray-300"><%= Pgbus::VERSION %></span>
|
|
51
66
|
<% end %>
|
|
52
67
|
|
|
53
68
|
<div class="flex space-x-1">
|
|
54
|
-
<%= pgbus_nav_link "
|
|
55
|
-
<%= pgbus_nav_link "
|
|
56
|
-
<%= pgbus_nav_link "
|
|
57
|
-
<%= pgbus_nav_link "
|
|
58
|
-
<%= pgbus_nav_link "
|
|
59
|
-
<%= pgbus_nav_link "
|
|
60
|
-
<%= pgbus_nav_link "
|
|
61
|
-
<%= pgbus_nav_link "
|
|
62
|
-
<%= pgbus_nav_link "
|
|
63
|
-
<%= pgbus_nav_link "
|
|
69
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.dashboard"), pgbus.root_path %>
|
|
70
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.queues"), pgbus.queues_path %>
|
|
71
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.jobs"), pgbus.jobs_path %>
|
|
72
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.recurring"), pgbus.recurring_tasks_path %>
|
|
73
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.processes"), pgbus.processes_path %>
|
|
74
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.events"), pgbus.events_path %>
|
|
75
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.dlq"), pgbus.dead_letter_index_path %>
|
|
76
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.outbox"), pgbus.outbox_index_path %>
|
|
77
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.locks"), pgbus.locks_path %>
|
|
78
|
+
<%= pgbus_nav_link t("pgbus.layout.nav.insights"), pgbus.insights_path %>
|
|
64
79
|
</div>
|
|
65
80
|
</div>
|
|
66
81
|
|
|
67
|
-
<
|
|
82
|
+
<div class="flex items-center space-x-2">
|
|
83
|
+
<!-- Locale switcher -->
|
|
84
|
+
<div class="relative" data-controller="dropdown">
|
|
85
|
+
<button type="button" data-action="click->dropdown#toggle" class="rounded-md px-2 py-1.5 text-sm text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
|
86
|
+
<%= pgbus_locale_flag(I18n.locale) %> <%= I18n.locale.to_s.upcase %>
|
|
87
|
+
</button>
|
|
88
|
+
<div data-dropdown-target="menu" class="hidden absolute right-0 z-50 mt-1 w-44 origin-top-right rounded-md bg-white dark:bg-gray-800 shadow-lg ring-1 ring-black/5 dark:ring-white/10">
|
|
89
|
+
<div class="py-1" role="menu">
|
|
90
|
+
<% controller.send(:available_locales).sort.each do |loc| %>
|
|
91
|
+
<%= form_tag pgbus.set_locale_path, method: :post, class: "contents" do %>
|
|
92
|
+
<%= hidden_field_tag :locale, loc %>
|
|
93
|
+
<button type="submit" role="menuitem" class="w-full text-left px-3 py-1.5 text-sm <%= loc == I18n.locale ? 'bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 font-medium' : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700' %>">
|
|
94
|
+
<%= pgbus_locale_flag(loc) %> <%= pgbus_locale_name(loc) %>
|
|
95
|
+
</button>
|
|
96
|
+
<% end %>
|
|
97
|
+
<% end %>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<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") %>">
|
|
68
103
|
<svg class="h-5 w-5 hidden dark:block" fill="currentColor" viewBox="0 0 20 20">
|
|
69
104
|
<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"/>
|
|
70
105
|
</svg>
|
|
@@ -72,6 +107,7 @@
|
|
|
72
107
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/>
|
|
73
108
|
</svg>
|
|
74
109
|
</button>
|
|
110
|
+
</div>
|
|
75
111
|
</div>
|
|
76
112
|
</div>
|
|
77
113
|
</nav>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<turbo-frame id="dashboard-processes" data-auto-refresh src="<%= pgbus.root_path(frame: 'processes') %>">
|
|
2
2
|
<div>
|
|
3
|
-
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-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
5
|
<table class="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
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
9
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
10
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
11
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
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>
|
|
9
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.processes_table.headers.host") %></th>
|
|
10
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.processes_table.headers.pid") %></th>
|
|
11
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.processes_table.headers.status") %></th>
|
|
12
12
|
</tr>
|
|
13
13
|
</thead>
|
|
14
14
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
</tr>
|
|
22
22
|
<% end %>
|
|
23
23
|
<% if @processes.empty? %>
|
|
24
|
-
<tr><td colspan="4" class="px-4 py-8 text-center text-sm text-gray-400"
|
|
24
|
+
<tr><td colspan="4" class="px-4 py-8 text-center text-sm text-gray-400"><%= t("pgbus.dashboard.processes_table.empty") %></td></tr>
|
|
25
25
|
<% end %>
|
|
26
26
|
</tbody>
|
|
27
27
|
</table>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<turbo-frame id="dashboard-queues" data-auto-refresh src="<%= pgbus.root_path(frame: 'queues') %>">
|
|
2
2
|
<div class="mb-8">
|
|
3
3
|
<div class="flex items-center justify-between mb-3">
|
|
4
|
-
<h2 class="text-lg font-semibold text-gray-900 dark:text-white"
|
|
5
|
-
<%= link_to "
|
|
4
|
+
<h2 class="text-lg font-semibold text-gray-900 dark:text-white"><%= t("pgbus.dashboard.queues_table.title") %></h2>
|
|
5
|
+
<%= link_to t("pgbus.dashboard.queues_table.view_all"), pgbus.queues_path, class: "text-sm text-indigo-600 hover:text-indigo-500", data: { turbo_frame: "_top" } %>
|
|
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
9
|
<table class="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
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
13
|
-
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"
|
|
14
|
-
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"
|
|
15
|
-
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"
|
|
16
|
-
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"
|
|
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>
|
|
13
|
+
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.queues_table.headers.depth") %></th>
|
|
14
|
+
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.queues_table.headers.visible") %></th>
|
|
15
|
+
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.queues_table.headers.oldest") %></th>
|
|
16
|
+
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.queues_table.headers.total") %></th>
|
|
17
17
|
</tr>
|
|
18
18
|
</thead>
|
|
19
19
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
</tr>
|
|
31
31
|
<% end %>
|
|
32
32
|
<% if @queues.empty? %>
|
|
33
|
-
<tr><td colspan="5" class="px-4 py-8 text-center text-sm text-gray-400"
|
|
33
|
+
<tr><td colspan="5" class="px-4 py-8 text-center text-sm text-gray-400"><%= t("pgbus.dashboard.queues_table.empty") %></td></tr>
|
|
34
34
|
<% end %>
|
|
35
35
|
</tbody>
|
|
36
36
|
</table>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<turbo-frame id="dashboard-failures" data-auto-refresh src="<%= pgbus.root_path(frame: 'failures') %>">
|
|
2
2
|
<div>
|
|
3
3
|
<div class="flex items-center justify-between mb-3">
|
|
4
|
-
<h2 class="text-lg font-semibold text-gray-900 dark:text-white"
|
|
4
|
+
<h2 class="text-lg font-semibold text-gray-900 dark:text-white"><%= t("pgbus.dashboard.recent_failures.title") %></h2>
|
|
5
5
|
<% if @recent_failures.any? %>
|
|
6
|
-
<%= link_to "
|
|
6
|
+
<%= link_to t("pgbus.dashboard.recent_failures.view_all"), pgbus.jobs_path(status: "failed"), class: "text-sm text-indigo-600 hover:text-indigo-500", data: { turbo_frame: "_top" } %>
|
|
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
10
|
<table class="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
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
14
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
15
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
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>
|
|
14
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.recent_failures.headers.error") %></th>
|
|
15
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dashboard.recent_failures.headers.when") %></th>
|
|
16
16
|
</tr>
|
|
17
17
|
</thead>
|
|
18
18
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
</tr>
|
|
25
25
|
<% end %>
|
|
26
26
|
<% if @recent_failures.empty? %>
|
|
27
|
-
<tr><td colspan="3" class="px-4 py-8 text-center text-sm text-gray-400"
|
|
27
|
+
<tr><td colspan="3" class="px-4 py-8 text-center text-sm text-gray-400"><%= t("pgbus.dashboard.recent_failures.empty") %></td></tr>
|
|
28
28
|
<% end %>
|
|
29
29
|
</tbody>
|
|
30
30
|
</table>
|
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
<turbo-frame id="dashboard-stats" data-auto-refresh src="<%= pgbus.root_path(frame: 'stats') %>">
|
|
2
2
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-6 mb-8">
|
|
3
3
|
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
4
|
-
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"
|
|
4
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"><%= t("pgbus.dashboard.stats_cards.queues") %></p>
|
|
5
5
|
<p class="mt-1 text-3xl font-semibold text-gray-900 dark:text-white"><%= @stats[:total_queues] %></p>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
9
|
-
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"
|
|
9
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"><%= t("pgbus.dashboard.stats_cards.enqueued") %></p>
|
|
10
10
|
<p class="mt-1 text-3xl font-semibold text-gray-900 dark:text-white"><%= pgbus_number(@stats[:total_depth]) %></p>
|
|
11
|
-
<p class="text-xs text-gray-400 dark:text-gray-500"><%= pgbus_number(@stats[:total_visible]) %> visible
|
|
11
|
+
<p class="text-xs text-gray-400 dark:text-gray-500"><%= pgbus_number(@stats[:total_visible]) %> <%= t("pgbus.dashboard.stats_cards.visible") %></p>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
14
|
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
15
|
-
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"
|
|
15
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"><%= t("pgbus.dashboard.stats_cards.processes") %></p>
|
|
16
16
|
<p class="mt-1 text-3xl font-semibold <%= @stats[:active_processes] > 0 ? 'text-green-600 dark:text-green-400' : 'text-gray-400' %>">
|
|
17
17
|
<%= @stats[:active_processes] %>
|
|
18
18
|
</p>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
21
|
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
22
|
-
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"
|
|
22
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"><%= t("pgbus.dashboard.stats_cards.recurring") %></p>
|
|
23
23
|
<p class="mt-1 text-3xl font-semibold text-gray-900 dark:text-white"><%= @stats[:recurring_count] %></p>
|
|
24
24
|
<p class="text-xs text-gray-400">
|
|
25
|
-
<%= link_to "
|
|
25
|
+
<%= link_to t("pgbus.dashboard.stats_cards.view_tasks"), pgbus.recurring_tasks_path, class: "text-blue-500 hover:text-blue-700 dark:text-blue-400" %>
|
|
26
26
|
</p>
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
29
|
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
30
|
-
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"
|
|
30
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"><%= t("pgbus.dashboard.stats_cards.failed_dlq") %></p>
|
|
31
31
|
<p class="mt-1 text-3xl font-semibold <%= (@stats[:failed_count] + @stats[:dlq_depth]) > 0 ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-white' %>">
|
|
32
32
|
<%= @stats[:failed_count] %> / <%= @stats[:dlq_depth] %>
|
|
33
33
|
</p>
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
36
|
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
37
|
-
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"
|
|
37
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400"><%= t("pgbus.dashboard.stats_cards.throughput") %></p>
|
|
38
38
|
<p class="mt-1 text-3xl font-semibold text-gray-900 dark:text-white"><%= @stats[:throughput_rate] %></p>
|
|
39
|
-
<p class="text-xs text-gray-400"
|
|
39
|
+
<p class="text-xs text-gray-400"><%= t("pgbus.dashboard.stats_cards.throughput_unit") %></p>
|
|
40
40
|
</div>
|
|
41
41
|
</div>
|
|
42
42
|
</turbo-frame>
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<table class="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
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
7
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
8
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
9
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
10
|
-
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"
|
|
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>
|
|
7
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dead_letter.messages_table.headers.job_class") %></th>
|
|
8
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dead_letter.messages_table.headers.source_queue") %></th>
|
|
9
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dead_letter.messages_table.headers.enqueued") %></th>
|
|
10
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500"><%= t("pgbus.dead_letter.messages_table.headers.reads") %></th>
|
|
11
11
|
</tr>
|
|
12
12
|
</thead>
|
|
13
13
|
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
@@ -27,39 +27,39 @@
|
|
|
27
27
|
</summary>
|
|
28
28
|
<div class="px-4 pb-4 bg-gray-50 dark:bg-gray-900 border-t border-gray-100">
|
|
29
29
|
<div class="flex items-center justify-between mt-3 mb-3">
|
|
30
|
-
<span class="text-xs font-mono text-gray-400"
|
|
30
|
+
<span class="text-xs font-mono text-gray-400"><%= t("pgbus.dead_letter.messages_table.job_id") %> <%= payload["job_id"] %></span>
|
|
31
31
|
<div class="flex space-x-2">
|
|
32
|
-
<%= button_to "
|
|
32
|
+
<%= button_to t("pgbus.dead_letter.messages_table.retry"), pgbus.retry_dead_letter_path(m[:msg_id], queue_name: m[:queue_name]), method: :post,
|
|
33
33
|
class: "rounded-md bg-indigo-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-indigo-500",
|
|
34
34
|
data: { turbo_frame: "_top" } %>
|
|
35
|
-
<%= button_to "
|
|
35
|
+
<%= button_to t("pgbus.dead_letter.messages_table.discard"), pgbus.discard_dead_letter_path(m[:msg_id], queue_name: m[:queue_name]), method: :post,
|
|
36
36
|
class: "rounded-md bg-red-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-red-500",
|
|
37
|
-
data: { turbo_confirm: "
|
|
37
|
+
data: { turbo_confirm: t("pgbus.dead_letter.messages_table.discard_confirm"), turbo_frame: "_top" } %>
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
40
40
|
<div class="grid grid-cols-2 gap-4 mb-3">
|
|
41
41
|
<div>
|
|
42
|
-
<span class="text-xs font-medium text-gray-500"
|
|
42
|
+
<span class="text-xs font-medium text-gray-500"><%= t("pgbus.dead_letter.messages_table.arguments") %></span>
|
|
43
43
|
<pre class="text-xs text-gray-700 bg-white dark:bg-gray-800 rounded p-2 mt-1 overflow-x-auto max-h-40"><%= JSON.pretty_generate(payload["arguments"] || []) rescue "—" %></pre>
|
|
44
44
|
</div>
|
|
45
45
|
<div>
|
|
46
|
-
<span class="text-xs font-medium text-gray-500"
|
|
46
|
+
<span class="text-xs font-medium text-gray-500"><%= t("pgbus.dead_letter.messages_table.metadata") %></span>
|
|
47
47
|
<div class="text-xs text-gray-600 bg-white dark:bg-gray-800 rounded p-2 mt-1 space-y-1">
|
|
48
|
-
<% if payload["queue_name"] %><p><strong
|
|
49
|
-
<% if payload["priority"] %><p><strong
|
|
50
|
-
<% if payload["executions"] %><p><strong
|
|
51
|
-
<% if m[:vt] %><p><strong
|
|
52
|
-
<% if m[:last_read_at] %><p><strong
|
|
48
|
+
<% if payload["queue_name"] %><p><strong><%= t("pgbus.dead_letter.messages_table.metadata_labels.queue") %></strong> <%= payload["queue_name"] %></p><% end %>
|
|
49
|
+
<% if payload["priority"] %><p><strong><%= t("pgbus.dead_letter.messages_table.metadata_labels.priority") %></strong> <%= payload["priority"] %></p><% end %>
|
|
50
|
+
<% if payload["executions"] %><p><strong><%= t("pgbus.dead_letter.messages_table.metadata_labels.executions") %></strong> <%= payload["executions"] %></p><% end %>
|
|
51
|
+
<% if m[:vt] %><p><strong><%= t("pgbus.dead_letter.messages_table.metadata_labels.visible_at") %></strong> <%= m[:vt] %></p><% end %>
|
|
52
|
+
<% if m[:last_read_at] %><p><strong><%= t("pgbus.dead_letter.messages_table.metadata_labels.last_read") %></strong> <%= m[:last_read_at] %></p><% end %>
|
|
53
53
|
</div>
|
|
54
54
|
</div>
|
|
55
55
|
</div>
|
|
56
56
|
<details class="mt-2">
|
|
57
|
-
<summary class="text-xs font-medium text-gray-500 cursor-pointer hover:text-gray-700"
|
|
57
|
+
<summary class="text-xs font-medium text-gray-500 cursor-pointer hover:text-gray-700"><%= t("pgbus.dead_letter.messages_table.full_json_payload") %></summary>
|
|
58
58
|
<pre class="text-xs text-gray-600 bg-white dark:bg-gray-800 rounded p-2 mt-1 overflow-x-auto max-h-96"><%= JSON.pretty_generate(payload) rescue m[:message] %></pre>
|
|
59
59
|
</details>
|
|
60
60
|
<% if m[:headers] %>
|
|
61
61
|
<details class="mt-2">
|
|
62
|
-
<summary class="text-xs font-medium text-gray-500 cursor-pointer hover:text-gray-700"
|
|
62
|
+
<summary class="text-xs font-medium text-gray-500 cursor-pointer hover:text-gray-700"><%= t("pgbus.dead_letter.messages_table.headers_section") %></summary>
|
|
63
63
|
<pre class="text-xs text-gray-600 bg-white dark:bg-gray-800 rounded p-2 mt-1 overflow-x-auto"><%= JSON.pretty_generate(JSON.parse(m[:headers])) rescue m[:headers] %></pre>
|
|
64
64
|
</details>
|
|
65
65
|
<% end %>
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
</tr>
|
|
70
70
|
<% end %>
|
|
71
71
|
<% if @messages.empty? %>
|
|
72
|
-
<tr><td colspan="5" class="px-4 py-8 text-center text-sm text-gray-400"
|
|
72
|
+
<tr><td colspan="5" class="px-4 py-8 text-center text-sm text-gray-400"><%= t("pgbus.dead_letter.messages_table.empty") %></td></tr>
|
|
73
73
|
<% end %>
|
|
74
74
|
</tbody>
|
|
75
75
|
</table>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<div class="flex items-center justify-between mb-6">
|
|
2
|
-
<h1 class="text-2xl font-bold text-gray-900 dark:text-white"
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white"><%= t("pgbus.dead_letter.index.title") %></h1>
|
|
3
3
|
<% if @messages.any? %>
|
|
4
4
|
<div class="flex space-x-2">
|
|
5
|
-
<%= button_to "
|
|
5
|
+
<%= button_to t("pgbus.dead_letter.index.retry_all"), pgbus.retry_all_dead_letter_index_path, method: :post,
|
|
6
6
|
class: "rounded-md bg-indigo-600 px-3 py-2 text-sm font-medium text-white hover:bg-indigo-500",
|
|
7
|
-
data: { turbo_confirm: "
|
|
8
|
-
<%= button_to "
|
|
7
|
+
data: { turbo_confirm: t("pgbus.dead_letter.index.retry_all_confirm") } %>
|
|
8
|
+
<%= button_to t("pgbus.dead_letter.index.discard_all"), pgbus.discard_all_dead_letter_index_path, method: :post,
|
|
9
9
|
class: "rounded-md bg-red-600 px-3 py-2 text-sm font-medium text-white hover:bg-red-500",
|
|
10
|
-
data: { turbo_confirm: "
|
|
10
|
+
data: { turbo_confirm: t("pgbus.dead_letter.index.discard_all_confirm") } %>
|
|
11
11
|
</div>
|
|
12
12
|
<% end %>
|
|
13
13
|
</div>
|