rails_error_dashboard 0.8.3 → 0.9.0
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 +35 -0
- data/app/controllers/rails_error_dashboard/application_controller.rb +156 -0
- data/app/controllers/rails_error_dashboard/errors_controller.rb +95 -73
- data/app/controllers/rails_error_dashboard/locales_controller.rb +87 -0
- data/app/helpers/rails_error_dashboard/application_helper.rb +20 -14
- data/app/helpers/rails_error_dashboard/backtrace_helper.rb +15 -6
- data/app/helpers/rails_error_dashboard/i18n_helper.rb +154 -0
- data/app/helpers/rails_error_dashboard/mailer_i18n_helper.rb +69 -0
- data/app/helpers/rails_error_dashboard/overview_helper.rb +18 -6
- data/app/helpers/rails_error_dashboard/user_agent_helper.rb +25 -11
- data/app/jobs/rails_error_dashboard/application_job.rb +5 -0
- data/app/jobs/rails_error_dashboard/baseline_alert_job.rb +18 -16
- data/app/jobs/rails_error_dashboard/concerns/localized_job.rb +83 -0
- data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +4 -2
- data/app/jobs/rails_error_dashboard/email_error_notification_job.rb +4 -2
- data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +6 -2
- data/app/jobs/rails_error_dashboard/scheduled_digest_job.rb +8 -3
- data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +6 -4
- data/app/jobs/rails_error_dashboard/storm_notification_job.rb +26 -8
- data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +4 -2
- data/app/mailers/rails_error_dashboard/application_mailer.rb +14 -0
- data/app/mailers/rails_error_dashboard/digest_mailer.rb +18 -2
- data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +19 -2
- data/app/views/layouts/rails_error_dashboard.html.erb +255 -92
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.html.erb +23 -22
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.text.erb +30 -19
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +18 -16
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +21 -14
- data/app/views/rails_error_dashboard/errors/_ai_help_panel.html.erb +11 -7
- data/app/views/rails_error_dashboard/errors/_breadcrumbs_group.html.erb +45 -38
- data/app/views/rails_error_dashboard/errors/_co_occurring_errors.html.erb +17 -14
- data/app/views/rails_error_dashboard/errors/_discussion.html.erb +27 -9
- data/app/views/rails_error_dashboard/errors/_error_cascades.html.erb +25 -21
- data/app/views/rails_error_dashboard/errors/_error_info.html.erb +25 -22
- data/app/views/rails_error_dashboard/errors/_error_row.html.erb +24 -12
- data/app/views/rails_error_dashboard/errors/_instance_variables.html.erb +12 -11
- data/app/views/rails_error_dashboard/errors/_issue_section.html.erb +19 -13
- data/app/views/rails_error_dashboard/errors/_llm_summary.html.erb +14 -14
- data/app/views/rails_error_dashboard/errors/_local_variables.html.erb +8 -8
- data/app/views/rails_error_dashboard/errors/_modals.html.erb +60 -52
- data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +59 -49
- data/app/views/rails_error_dashboard/errors/_request_context.html.erb +23 -20
- data/app/views/rails_error_dashboard/errors/_show_scripts.html.erb +14 -14
- data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +118 -93
- data/app/views/rails_error_dashboard/errors/_similar_errors.html.erb +18 -12
- data/app/views/rails_error_dashboard/errors/_source_code.html.erb +20 -5
- data/app/views/rails_error_dashboard/errors/_stats.html.erb +5 -5
- data/app/views/rails_error_dashboard/errors/_timeline.html.erb +7 -7
- data/app/views/rails_error_dashboard/errors/_user_errors_table.html.erb +15 -12
- data/app/views/rails_error_dashboard/errors/actioncable_health_summary.html.erb +25 -25
- data/app/views/rails_error_dashboard/errors/activestorage_health_summary.html.erb +28 -28
- data/app/views/rails_error_dashboard/errors/analytics.html.erb +82 -82
- data/app/views/rails_error_dashboard/errors/cache_health_summary.html.erb +27 -27
- data/app/views/rails_error_dashboard/errors/correlation.html.erb +61 -57
- data/app/views/rails_error_dashboard/errors/database_health_summary.html.erb +64 -65
- data/app/views/rails_error_dashboard/errors/deprecations.html.erb +23 -23
- data/app/views/rails_error_dashboard/errors/diagnostic_dumps.html.erb +48 -36
- data/app/views/rails_error_dashboard/errors/index.html.erb +121 -70
- data/app/views/rails_error_dashboard/errors/job_health_summary.html.erb +30 -30
- data/app/views/rails_error_dashboard/errors/llm_health_summary.html.erb +38 -39
- data/app/views/rails_error_dashboard/errors/n_plus_one_summary.html.erb +28 -25
- data/app/views/rails_error_dashboard/errors/overview.html.erb +45 -39
- data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +45 -44
- data/app/views/rails_error_dashboard/errors/rack_attack_summary.html.erb +39 -28
- data/app/views/rails_error_dashboard/errors/releases.html.erb +46 -47
- data/app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb +48 -44
- data/app/views/rails_error_dashboard/errors/settings.html.erb +122 -112
- data/app/views/rails_error_dashboard/errors/show.html.erb +44 -37
- data/app/views/rails_error_dashboard/errors/storms.html.erb +30 -24
- data/app/views/rails_error_dashboard/errors/swallowed_exceptions.html.erb +26 -26
- data/app/views/rails_error_dashboard/errors/user_impact.html.erb +31 -30
- data/config/locales/de.yml +2007 -0
- data/config/locales/en.yml +2719 -0
- data/config/locales/es.yml +2079 -0
- data/config/locales/fr.yml +2082 -0
- data/config/locales/it.yml +2060 -0
- data/config/locales/ja.yml +1802 -0
- data/config/locales/pl.yml +2108 -0
- data/config/locales/pt-BR.yml +2064 -0
- data/config/locales/ru.yml +2109 -0
- data/config/locales/uk.yml +2106 -0
- data/config/locales/zh-CN.yml +1791 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20260325000001_fix_swallowed_exceptions_index_for_mysql.rb +9 -3
- data/lib/rails_error_dashboard/commands/batch_delete_errors.rb +3 -1
- data/lib/rails_error_dashboard/commands/batch_mute_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/batch_resolve_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/batch_unmute_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/create_issue.rb +5 -3
- data/lib/rails_error_dashboard/commands/link_existing_issue.rb +4 -2
- data/lib/rails_error_dashboard/commands/log_error.rb +1 -1
- data/lib/rails_error_dashboard/configuration.rb +23 -0
- data/lib/rails_error_dashboard/current.rb +56 -0
- data/lib/rails_error_dashboard/i18n_store.rb +293 -0
- data/lib/rails_error_dashboard/private_backend.rb +213 -0
- data/lib/rails_error_dashboard/services/baseline_alert_payload_builder.rb +89 -22
- data/lib/rails_error_dashboard/services/digest_builder.rb +21 -7
- data/lib/rails_error_dashboard/services/discord_payload_builder.rb +27 -15
- data/lib/rails_error_dashboard/services/error_notification_dispatcher.rb +10 -5
- data/lib/rails_error_dashboard/services/localized_time_formatter.rb +117 -0
- data/lib/rails_error_dashboard/services/notification_helpers.rb +87 -4
- data/lib/rails_error_dashboard/services/pagerduty_payload_builder.rb +22 -5
- data/lib/rails_error_dashboard/services/slack_payload_builder.rb +48 -28
- data/lib/rails_error_dashboard/services/storm_protection/gate.rb +2 -1
- data/lib/rails_error_dashboard/services/webhook_payload_builder.rb +15 -1
- data/lib/rails_error_dashboard/translation.rb +39 -0
- data/lib/rails_error_dashboard/version.rb +1 -1
- data/lib/rails_error_dashboard.rb +4 -0
- data/lib/tasks/error_dashboard.rake +5 -1
- metadata +24 -4
|
@@ -1,18 +1,49 @@
|
|
|
1
|
-
<% content_for :page_title, "
|
|
1
|
+
<% content_for :page_title, red_t("red.errors.index.title") %>
|
|
2
2
|
|
|
3
3
|
<!-- Subscribe to Turbo Stream updates (only if Turbo Streams + ActionCable pubsub are available) -->
|
|
4
4
|
<% if defined?(Turbo::StreamsHelper) && defined?(ActionCable) && respond_to?(:turbo_stream_from) && RailsErrorDashboard::Services::ErrorBroadcaster.available? %>
|
|
5
5
|
<%= turbo_stream_from "error_list" %>
|
|
6
6
|
<% end %>
|
|
7
7
|
|
|
8
|
+
<%
|
|
9
|
+
# Value -> label lookups for the machine-valued filters.
|
|
10
|
+
#
|
|
11
|
+
# These previously went through humanize/titleize/capitalize, which apply
|
|
12
|
+
# English morphology to an identifier ("last_7_days" -> "Last 7 days") and
|
|
13
|
+
# produce nonsense in any other language. Each known value now has a key, and
|
|
14
|
+
# an unrecognised one falls back to its raw value rather than raising — a
|
|
15
|
+
# hand-edited query string must never break the page.
|
|
16
|
+
#
|
|
17
|
+
# They live here as lambdas because P2-T2's scope is this view and the row
|
|
18
|
+
# partial; the helpers are P2-T10's task, which can promote these as-is.
|
|
19
|
+
timeframe_label = ->(value) do
|
|
20
|
+
red_t("red.errors.index.filters.timeframes.#{value}", default: value.to_s)
|
|
21
|
+
end
|
|
22
|
+
frequency_label = ->(value) do
|
|
23
|
+
red_t("red.errors.index.filters.frequencies.#{value}", default: value.to_s)
|
|
24
|
+
end
|
|
25
|
+
severity_label = ->(value) do
|
|
26
|
+
red_t("red.common.severity.#{value}", default: value.to_s)
|
|
27
|
+
end
|
|
28
|
+
status_label = ->(value) do
|
|
29
|
+
red_t("red.errors.index.filters.status.#{value}", default: value.to_s)
|
|
30
|
+
end
|
|
31
|
+
%>
|
|
8
32
|
<div data-controller="loading">
|
|
9
|
-
|
|
10
|
-
|
|
33
|
+
<%# flex-wrap is load-bearing, not cosmetic: this row pairs the page title
|
|
34
|
+
with a fully-formatted timestamp, and every locale but English spells the
|
|
35
|
+
month out in full ("22 августа 2026, 14:05:03" against "August 22, 2026").
|
|
36
|
+
Without wrapping, the row is forced onto one line and overflows a 375px
|
|
37
|
+
viewport in de/fr/ru while fitting in English — measured at 406-469px in
|
|
38
|
+
spec/system/p7_layout_qa_spec.rb. Wrapping lets the timestamp drop below
|
|
39
|
+
the title instead of pushing the page wider. %>
|
|
40
|
+
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4);">
|
|
41
|
+
<h1 style="font-size: 20px; font-weight: 700; margin: 0;"><%= red_t("red.errors.index.title") %></h1>
|
|
11
42
|
<span style="font-size: 12px; color: var(--text-tertiary);">
|
|
12
|
-
|
|
43
|
+
<%= red_t("red.errors.index.last_updated_html", time: local_time(Time.current, format: :full)) %>
|
|
13
44
|
<% if defined?(Turbo::StreamsHelper) && defined?(ActionCable) && respond_to?(:turbo_stream_from) && RailsErrorDashboard::Services::ErrorBroadcaster.available? %>
|
|
14
45
|
<span style="display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; font-size: 10px; font-weight: 600; border-radius: var(--radius-full); background: var(--status-success-bg); color: var(--status-success); margin-left: 6px;">
|
|
15
|
-
<i class="bi bi-broadcast" style="font-size: 10px;"></i>
|
|
46
|
+
<i class="bi bi-broadcast" style="font-size: 10px;"></i> <%= red_t("red.errors.index.live") %>
|
|
16
47
|
</span>
|
|
17
48
|
<% end %>
|
|
18
49
|
</span>
|
|
@@ -30,14 +61,16 @@
|
|
|
30
61
|
<!-- Summary line + batch actions -->
|
|
31
62
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-4);">
|
|
32
63
|
<span style="font-size: 13px; color: var(--text-secondary);">
|
|
33
|
-
|
|
64
|
+
<%= red_tp("red.errors.index.summary.errors_html", count: @pagy.count,
|
|
65
|
+
value: tag.strong(@pagy.count, style: "color: var(--text-primary);")) %>
|
|
34
66
|
<span style="margin: 0 6px; color: var(--border-secondary);">·</span>
|
|
35
|
-
|
|
67
|
+
<%= red_t("red.errors.index.summary.unresolved_html",
|
|
68
|
+
value: tag.strong(@stats[:unresolved], style: "color: var(--status-critical);")) %>
|
|
36
69
|
<span style="margin: 0 6px; color: var(--border-secondary);">·</span>
|
|
37
70
|
<% if params[:timeframe].present? %>
|
|
38
|
-
<%= params[:timeframe]
|
|
71
|
+
<%= timeframe_label.call(params[:timeframe]) %>
|
|
39
72
|
<% else %>
|
|
40
|
-
|
|
73
|
+
<%= red_t("red.errors.index.summary.all_time") %>
|
|
41
74
|
<% end %>
|
|
42
75
|
</span>
|
|
43
76
|
</div>
|
|
@@ -50,17 +83,17 @@
|
|
|
50
83
|
<strong>
|
|
51
84
|
<% case @stats[:spike_info][:severity] %>
|
|
52
85
|
<% when :critical %>
|
|
53
|
-
|
|
86
|
+
<%= red_t("red.errors.index.spike.critical") %>
|
|
54
87
|
<% when :high %>
|
|
55
|
-
|
|
88
|
+
<%= red_t("red.errors.index.spike.high") %>
|
|
56
89
|
<% when :elevated %>
|
|
57
|
-
|
|
90
|
+
<%= red_t("red.errors.index.spike.elevated") %>
|
|
58
91
|
<% end %>
|
|
59
92
|
</strong>
|
|
60
93
|
<span style="color: var(--text-secondary);">
|
|
61
|
-
|
|
62
|
-
(
|
|
63
|
-
<strong><%= @stats[:spike_info][:multiplier]
|
|
94
|
+
<strong><%= red_tp("red.errors.index.spike.today", count: @stats[:spike_info][:today_count]) %></strong>
|
|
95
|
+
<%= red_t("red.errors.index.spike.average", avg: @stats[:spike_info][:avg_count]) %> —
|
|
96
|
+
<strong><%= red_t("red.errors.index.spike.multiplier", multiplier: @stats[:spike_info][:multiplier]) %></strong>
|
|
64
97
|
</span>
|
|
65
98
|
</div>
|
|
66
99
|
</div>
|
|
@@ -75,7 +108,7 @@
|
|
|
75
108
|
<!-- Search -->
|
|
76
109
|
<div style="position: relative; flex: 1 1 200px; min-width: 160px;">
|
|
77
110
|
<i class="bi bi-search" style="position: absolute; left: 10px; top: 50%; transform: translateY(-50%); font-size: 13px; color: var(--text-tertiary);"></i>
|
|
78
|
-
<%= text_field_tag :search, params[:search], placeholder: "
|
|
111
|
+
<%= text_field_tag :search, params[:search], placeholder: red_t("red.errors.index.filters.search_placeholder"), style: "width: 100%; padding: 6px 10px 6px 30px; font-size: 13px; border: 1px solid var(--border-primary); border-radius: var(--radius-sm); background: var(--surface-base); color: var(--text-primary); outline: none; font-family: var(--font-sans);" %>
|
|
79
112
|
</div>
|
|
80
113
|
|
|
81
114
|
<div style="width: 1px; height: 24px; background: var(--border-primary);"></div>
|
|
@@ -86,47 +119,60 @@
|
|
|
86
119
|
current_status = params[:status]
|
|
87
120
|
is_unresolved_only = params[:unresolved] != "false" && params[:unresolved] != "0"
|
|
88
121
|
%>
|
|
89
|
-
<%= link_to errors_path(app_context.merge(unresolved: '0')), class: "btn filter-pill #{current_status.blank? && !is_unresolved_only ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do
|
|
90
|
-
<%= link_to errors_path(app_context.merge(unresolved: '1')), class: "btn filter-pill #{is_unresolved_only && current_status.blank? ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do %>
|
|
91
|
-
<%= link_to errors_path(app_context.merge(status: 'resolved', unresolved: '0')), class: "btn filter-pill #{current_status == 'resolved' ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do
|
|
92
|
-
<%= link_to errors_path(app_context.merge(assigned_to: '__assigned__', unresolved: '0')), class: "btn filter-pill #{params[:assigned_to] == '__assigned__' ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do
|
|
93
|
-
<%= link_to errors_path(app_context.merge(reopened: 'true', unresolved: '0')), class: "btn filter-pill #{params[:reopened] == 'true' ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do
|
|
122
|
+
<%= link_to errors_path(app_context.merge(unresolved: '0')), class: "btn filter-pill #{current_status.blank? && !is_unresolved_only ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do %><%= red_t("red.errors.index.filters.status.all") %><% end %>
|
|
123
|
+
<%= link_to errors_path(app_context.merge(unresolved: '1')), class: "btn filter-pill #{is_unresolved_only && current_status.blank? ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do %><%= red_t("red.errors.index.filters.status.unresolved") %> <span style="font-size: 11px; opacity: 0.7;"><%= @stats[:unresolved] %></span><% end %>
|
|
124
|
+
<%= link_to errors_path(app_context.merge(status: 'resolved', unresolved: '0')), class: "btn filter-pill #{current_status == 'resolved' ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do %><%= red_t("red.errors.index.filters.status.resolved") %><% end %>
|
|
125
|
+
<%= link_to errors_path(app_context.merge(assigned_to: '__assigned__', unresolved: '0')), class: "btn filter-pill #{params[:assigned_to] == '__assigned__' ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do %><%= red_t("red.errors.index.filters.status.assigned") %><% end %>
|
|
126
|
+
<%= link_to errors_path(app_context.merge(reopened: 'true', unresolved: '0')), class: "btn filter-pill #{params[:reopened] == 'true' ? 'active btn-primary' : 'btn-outline-primary'}", style: "text-decoration: none;" do %><%= red_t("red.errors.index.filters.status.reopened") %><% end %>
|
|
94
127
|
</div>
|
|
95
128
|
|
|
96
129
|
<div style="width: 1px; height: 24px; background: var(--border-primary);"></div>
|
|
97
130
|
|
|
98
131
|
<!-- Severity pills -->
|
|
99
|
-
|
|
132
|
+
<%# flex-wrap matches the status-chip row above it. Five severity chips
|
|
133
|
+
fit one line in English ("Any Critical High Medium Low") but not in a
|
|
134
|
+
locale that expands: Russian renders "Любая важность Критическая
|
|
135
|
+
Высокая Средняя Низкая" and pushed this row to 426px inside a 375px
|
|
136
|
+
viewport. Pinned by spec/system/p7_layout_qa_spec.rb. %>
|
|
137
|
+
<div style="display: flex; gap: 4px; flex-wrap: wrap;">
|
|
100
138
|
<% current_severity = params[:severity] %>
|
|
101
|
-
<%= link_to errors_path(permitted_filter_params.except(:severity)), class: "filter-pill #{current_severity.blank? ? 'active' : ''}", style: "text-decoration: none;" do
|
|
139
|
+
<%= link_to errors_path(permitted_filter_params.except(:severity)), class: "filter-pill #{current_severity.blank? ? 'active' : ''}", style: "text-decoration: none;" do %><%= red_t("red.errors.index.filters.severity.any") %><% end %>
|
|
102
140
|
<% %w[critical high medium low].each do |sev| %>
|
|
103
|
-
<%= link_to errors_path(permitted_filter_params.merge(severity: sev)), class: "filter-pill #{current_severity == sev ? 'active' : ''}", style: "text-decoration: none;" do %><%= sev
|
|
141
|
+
<%= link_to errors_path(permitted_filter_params.merge(severity: sev)), class: "filter-pill #{current_severity == sev ? 'active' : ''}", style: "text-decoration: none;" do %><%= severity_label.call(sev) %><% end %>
|
|
104
142
|
<% end %>
|
|
105
143
|
</div>
|
|
106
144
|
|
|
107
145
|
<!-- Advanced filters toggle -->
|
|
108
146
|
<div style="width: 1px; height: 24px; background: var(--border-primary);"></div>
|
|
109
147
|
<button type="button" data-red-action="toggle-display" data-red-target="#advanced-filters" data-red-display="flex" class="filter-pill" style="border: none;">
|
|
110
|
-
<i class="bi bi-sliders"></i>
|
|
148
|
+
<i class="bi bi-sliders"></i> <%= red_t("red.errors.index.filters.more") %>
|
|
111
149
|
</button>
|
|
112
150
|
</div>
|
|
113
151
|
|
|
114
152
|
<!-- Advanced filters -->
|
|
115
153
|
<div id="advanced-filters" style="display: none; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-4); padding: var(--space-3) var(--space-4); background: var(--surface-primary); border-radius: var(--radius-md); border: 1px solid var(--border-primary);">
|
|
116
154
|
<% if @applications.size > 1 %>
|
|
117
|
-
<%= select_tag :application_id, options_for_select([[
|
|
155
|
+
<%= select_tag :application_id, options_for_select([[red_t("red.errors.index.filters.all_apps"), '']] + @applications, params[:application_id]), class: "form-select", style: "width: auto; min-width: 120px;" %>
|
|
118
156
|
<% end %>
|
|
119
157
|
<% if @platforms.size > 1 %>
|
|
120
|
-
<%= select_tag :platform, options_for_select([[
|
|
158
|
+
<%= select_tag :platform, options_for_select([[red_t("red.errors.index.filters.all_platforms"), '']] + @platforms.map { |p| [p, p] }, params[:platform]), class: "form-select", style: "width: auto; min-width: 120px;" %>
|
|
121
159
|
<% end %>
|
|
122
|
-
<%= select_tag :error_type, options_for_select([[
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
160
|
+
<%= select_tag :error_type, options_for_select([[red_t("red.errors.index.filters.all_types"), '']] + @error_types.map { |t| [t, t] }, params[:error_type]), class: "form-select", style: "width: auto; min-width: 120px;" %>
|
|
161
|
+
<%
|
|
162
|
+
# Built from the same keys the active chips read, so a label can never
|
|
163
|
+
# differ between the select and the chip it produces.
|
|
164
|
+
timeframe_options = %w[last_hour today yesterday last_7_days last_30_days last_90_days]
|
|
165
|
+
.map { |value| [ timeframe_label.call(value), value ] }
|
|
166
|
+
frequency_options = %w[once few frequent very_frequent recurring]
|
|
167
|
+
.map { |value| [ frequency_label.call(value), value ] }
|
|
168
|
+
%>
|
|
169
|
+
<%= select_tag :timeframe, options_for_select([[red_t("red.errors.index.filters.all_timeframes"), '']] + timeframe_options, params[:timeframe]), class: "form-select", style: "width: auto; min-width: 120px;" %>
|
|
170
|
+
<%= select_tag :frequency, options_for_select([[red_t("red.errors.index.filters.all_frequencies"), '']] + frequency_options, params[:frequency]), class: "form-select", style: "width: auto; min-width: 120px;" %>
|
|
171
|
+
<%= select_tag :priority_level, options_for_select([[red_t("red.errors.index.filters.all_priorities"), '']] + RailsErrorDashboard::ErrorLog.priority_options(include_emoji: true), params[:priority_level]), class: "form-select", style: "width: auto; min-width: 120px;" %>
|
|
172
|
+
<%= select_tag :assigned_to, options_for_select([[red_t("red.errors.index.filters.all_assignments"), ''], [red_t("red.errors.index.filters.unassigned"), '__unassigned__'], [red_t("red.errors.index.filters.assigned"), '__assigned__']], params[:assigned_to]), class: "form-select", id: "assigned_to_filter", style: "width: auto; min-width: 120px;" %>
|
|
127
173
|
<div id="assignee_name_filter" style="<%= params[:assigned_to] == '__assigned__' ? '' : 'display: none;' %>">
|
|
128
174
|
<% assignees = defined?(@assignees) ? @assignees : [] %>
|
|
129
|
-
<%= select_tag :assignee_name, options_for_select([[
|
|
175
|
+
<%= select_tag :assignee_name, options_for_select([[red_t("red.errors.index.filters.all_assignees"), '']] + assignees.map { |name| [name, name] }, params[:assignee_name]), class: "form-select", style: "width: auto; min-width: 120px;" %>
|
|
130
176
|
</div>
|
|
131
177
|
|
|
132
178
|
<div style="display: flex; align-items: center; gap: var(--space-4); font-size: 12px; color: var(--text-secondary);">
|
|
@@ -139,61 +185,66 @@
|
|
|
139
185
|
end
|
|
140
186
|
%>
|
|
141
187
|
<%= check_box_tag :unresolved, "1", is_checked, class: "form-check-input", id: "unresolved_checkbox", style: "width: 14px; height: 14px;" %>
|
|
142
|
-
|
|
188
|
+
<%= red_t("red.errors.index.filters.unresolved_only") %>
|
|
143
189
|
</label>
|
|
144
190
|
<label style="display: flex; align-items: center; gap: 4px; font-weight: 400;">
|
|
145
191
|
<%= check_box_tag :hide_snoozed, "1", params[:hide_snoozed] == "1", class: "form-check-input", style: "width: 14px; height: 14px;" %>
|
|
146
|
-
|
|
192
|
+
<%= red_t("red.errors.index.filters.hide_snoozed") %>
|
|
147
193
|
</label>
|
|
148
194
|
<label style="display: flex; align-items: center; gap: 4px; font-weight: 400;">
|
|
149
195
|
<%= check_box_tag :hide_muted, "1", params[:hide_muted] == "1", class: "form-check-input", style: "width: 14px; height: 14px;" %>
|
|
150
|
-
|
|
196
|
+
<%= red_t("red.errors.index.filters.hide_muted") %>
|
|
151
197
|
</label>
|
|
152
198
|
</div>
|
|
153
199
|
|
|
154
200
|
<div style="display: flex; gap: 6px; margin-left: auto;">
|
|
155
|
-
<%= submit_tag "
|
|
156
|
-
<%= link_to "
|
|
201
|
+
<%= submit_tag red_t("red.errors.index.filters.apply"), class: "btn btn-primary btn-sm", data: { loading_target: "submitButton" } %>
|
|
202
|
+
<%= link_to red_t("red.errors.index.filters.clear"), errors_path, class: "btn btn-sm", style: "font-size: 12px;" %>
|
|
157
203
|
</div>
|
|
158
204
|
</div>
|
|
159
205
|
<% end %>
|
|
160
206
|
|
|
161
207
|
<!-- Active Filter Pills -->
|
|
162
208
|
<%
|
|
209
|
+
# Each chip is an interpolated key, never a concatenation — the label and
|
|
210
|
+
# its value are not always in that order across languages. Search terms and
|
|
211
|
+
# application, platform and type names are free-form user data and are
|
|
212
|
+
# interpolated verbatim, never translated.
|
|
163
213
|
active_filters = []
|
|
164
|
-
active_filters << { label: "
|
|
214
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.search", value: params[:search]), param: :search } if params[:search].present?
|
|
165
215
|
if params[:application_id].present? && defined?(@applications)
|
|
166
216
|
app_name = @applications.find { |name, id| id.to_s == params[:application_id].to_s }&.first
|
|
167
|
-
active_filters << { label: "
|
|
217
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.application", value: app_name), param: :application_id } if app_name
|
|
168
218
|
end
|
|
169
|
-
active_filters << { label: "
|
|
170
|
-
active_filters << { label: "
|
|
171
|
-
active_filters << { label: "
|
|
172
|
-
active_filters << { label: "
|
|
173
|
-
active_filters << { label: "
|
|
174
|
-
active_filters << { label: "
|
|
219
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.platform", value: params[:platform]), param: :platform } if params[:platform].present?
|
|
220
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.error_type", value: params[:error_type]), param: :error_type } if params[:error_type].present?
|
|
221
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.severity", value: severity_label.call(params[:severity])), param: :severity } if params[:severity].present?
|
|
222
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.timeframe", value: timeframe_label.call(params[:timeframe])), param: :timeframe } if params[:timeframe].present?
|
|
223
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.frequency", value: frequency_label.call(params[:frequency])), param: :frequency } if params[:frequency].present?
|
|
224
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.status", value: status_label.call(params[:status])), param: :status } if params[:status].present?
|
|
175
225
|
if params[:priority_level].present?
|
|
176
226
|
# priority_level is the integer key (3=Critical/P0, 0=Low/P3); look up the short_label
|
|
177
227
|
# rather than interpolating the raw integer, which inverts the P-number.
|
|
228
|
+
# P0-P3 are identifiers, not words, and stay untranslated.
|
|
178
229
|
priority_data = RailsErrorDashboard::ErrorLog::PRIORITY_LEVELS[params[:priority_level].to_i]
|
|
179
230
|
priority_short = priority_data ? priority_data[:short_label] : "P?"
|
|
180
|
-
active_filters << { label: "
|
|
231
|
+
active_filters << { label: red_t("red.errors.index.filters.chips.priority", value: priority_short), param: :priority_level }
|
|
181
232
|
end
|
|
182
233
|
if params[:assigned_to] == '__unassigned__'
|
|
183
|
-
active_filters << { label: "
|
|
234
|
+
active_filters << { label: red_t("red.errors.index.filters.unassigned"), param: :assigned_to }
|
|
184
235
|
elsif params[:assigned_to] == '__assigned__'
|
|
185
|
-
active_filters << { label: "
|
|
236
|
+
active_filters << { label: red_t("red.errors.index.filters.assigned"), param: :assigned_to }
|
|
186
237
|
end
|
|
187
238
|
%>
|
|
188
239
|
<% if active_filters.any? %>
|
|
189
240
|
<div style="display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: var(--space-4); font-size: 12px;">
|
|
190
|
-
<span style="color: var(--text-tertiary); font-weight: 500;"
|
|
241
|
+
<span style="color: var(--text-tertiary); font-weight: 500;"><%= red_t("red.errors.index.filters.active_label") %></span>
|
|
191
242
|
<% active_filters.each do |filter| %>
|
|
192
|
-
<%= link_to errors_path(permitted_filter_params.except(filter[:param])), class: "filter-pill active", style: "text-decoration: none; font-size: 11px; padding: 3px 8px;" do %>
|
|
243
|
+
<%= link_to errors_path(permitted_filter_params.except(filter[:param])), class: "filter-pill active", style: "text-decoration: none; font-size: 11px; padding: 3px 8px;", "aria-label": red_t("red.errors.index.filters.chips.remove") do %>
|
|
193
244
|
<%= filter[:label] %> <i class="bi bi-x" style="font-size: 12px;"></i>
|
|
194
245
|
<% end %>
|
|
195
246
|
<% end %>
|
|
196
|
-
<%= link_to errors_path, style: "color: var(--text-tertiary); font-size: 11px;" do
|
|
247
|
+
<%= link_to errors_path, style: "color: var(--text-tertiary); font-size: 11px;" do %><%= red_t("red.errors.index.filters.clear_all") %><% end %>
|
|
197
248
|
</div>
|
|
198
249
|
<% end %>
|
|
199
250
|
|
|
@@ -210,10 +261,10 @@
|
|
|
210
261
|
<input type="checkbox" id="select-all-batch" class="form-check-input" style="accent-color: var(--accent); margin: 0;" checked>
|
|
211
262
|
<span id="selected-count" style="font-size: 13px; font-weight: 600; color: var(--text-primary); margin-right: var(--space-2);"></span>
|
|
212
263
|
<%= button_tag type: "submit", name: "action_type", value: "resolve", class: "btn btn-sm", style: "padding: 4px 12px; font-size: 12px;" do %>
|
|
213
|
-
<i class="bi bi-check-circle"></i>
|
|
264
|
+
<i class="bi bi-check-circle"></i> <%= red_t("red.errors.index.batch.resolve") %>
|
|
214
265
|
<% end %>
|
|
215
|
-
<%= button_tag type: "submit", name: "action_type", value: "delete", class: "btn btn-sm", style: "padding: 4px 12px; font-size: 12px; color: var(--status-critical);", data: { confirm: "
|
|
216
|
-
<i class="bi bi-trash"></i>
|
|
266
|
+
<%= button_tag type: "submit", name: "action_type", value: "delete", class: "btn btn-sm", style: "padding: 4px 12px; font-size: 12px; color: var(--status-critical);", data: { confirm: red_t("red.errors.index.batch.confirm_delete") } do %>
|
|
267
|
+
<i class="bi bi-trash"></i> <%= red_t("red.errors.index.batch.delete") %>
|
|
217
268
|
<% end %>
|
|
218
269
|
<% end %>
|
|
219
270
|
</div>
|
|
@@ -223,18 +274,18 @@
|
|
|
223
274
|
<thead>
|
|
224
275
|
<tr id="thead-columns" style="border-bottom: 1px solid var(--border-primary);">
|
|
225
276
|
<th style="width: 36px; padding: var(--space-3) var(--space-4); text-align: center;">
|
|
226
|
-
<input type="checkbox" id="select-all" class="form-check-input" style="accent-color: var(--accent);">
|
|
277
|
+
<input type="checkbox" id="select-all" class="form-check-input" style="accent-color: var(--accent);" aria-label="<%= red_t("red.errors.index.columns.select_all") %>">
|
|
227
278
|
</th>
|
|
228
|
-
<th style="padding: var(--space-3) var(--space-4); text-align: left;"
|
|
229
|
-
<th style="padding: var(--space-3) var(--space-4); text-align: left; width: 100px;"
|
|
230
|
-
<th style="padding: var(--space-3) var(--space-4); text-align: right; width: 70px;"
|
|
231
|
-
<th style="padding: var(--space-3) var(--space-4); text-align: right; width: 55px;"
|
|
232
|
-
<th style="padding: var(--space-3) var(--space-4); text-align: right; width: 85px;"
|
|
279
|
+
<th style="padding: var(--space-3) var(--space-4); text-align: left;"><%= red_t("red.errors.index.columns.error") %></th>
|
|
280
|
+
<th style="padding: var(--space-3) var(--space-4); text-align: left; width: 100px;"><%= red_t("red.errors.index.columns.status") %></th>
|
|
281
|
+
<th style="padding: var(--space-3) var(--space-4); text-align: right; width: 70px;"><%= red_t("red.errors.index.columns.events") %></th>
|
|
282
|
+
<th style="padding: var(--space-3) var(--space-4); text-align: right; width: 55px;"><%= red_t("red.errors.index.columns.users") %></th>
|
|
283
|
+
<th style="padding: var(--space-3) var(--space-4); text-align: right; width: 85px;"><%= red_t("red.errors.index.columns.last_seen") %></th>
|
|
233
284
|
<% if @applications.size > 1 && params[:application_id].blank? %>
|
|
234
|
-
<th style="padding: var(--space-3) var(--space-4); width: 100px;"
|
|
285
|
+
<th style="padding: var(--space-3) var(--space-4); width: 100px;"><%= red_t("red.errors.index.columns.application") %></th>
|
|
235
286
|
<% end %>
|
|
236
287
|
<% if @platforms.size > 1 %>
|
|
237
|
-
<th style="padding: var(--space-3) var(--space-4); width: 100px;"
|
|
288
|
+
<th style="padding: var(--space-3) var(--space-4); width: 100px;"><%= red_t("red.errors.index.columns.platform") %></th>
|
|
238
289
|
<% end %>
|
|
239
290
|
</tr>
|
|
240
291
|
</thead>
|
|
@@ -249,7 +300,7 @@
|
|
|
249
300
|
<!-- Pagination -->
|
|
250
301
|
<% if @pagy.pages > 1 %>
|
|
251
302
|
<div style="padding: var(--space-4); border-top: 1px solid var(--border-primary); display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3);">
|
|
252
|
-
<span style="font-size: 12px; color: var(--text-tertiary);"
|
|
303
|
+
<span style="font-size: 12px; color: var(--text-tertiary);"><%= red_t("red.errors.index.pagination", from: @pagy.from, to: @pagy.to, count: @pagy.count) %></span>
|
|
253
304
|
<div><%== @pagy.series_nav(:bootstrap) %></div>
|
|
254
305
|
</div>
|
|
255
306
|
<% end %>
|
|
@@ -267,13 +318,13 @@
|
|
|
267
318
|
<div class="red-empty-state">
|
|
268
319
|
<% if params[:search].present? || params[:error_type].present? || params[:severity].present? %>
|
|
269
320
|
<div class="red-empty-state-icon"><i class="bi bi-funnel"></i></div>
|
|
270
|
-
<div class="red-empty-state-title"
|
|
271
|
-
<div class="red-empty-state-message"
|
|
272
|
-
<%= link_to errors_path, class: "red-empty-state-cta" do %><i class="bi bi-x-circle"></i>
|
|
321
|
+
<div class="red-empty-state-title"><%= red_t("red.errors.index.empty.filtered_title") %></div>
|
|
322
|
+
<div class="red-empty-state-message"><%= red_t("red.errors.index.empty.filtered_message") %></div>
|
|
323
|
+
<%= link_to errors_path, class: "red-empty-state-cta" do %><i class="bi bi-x-circle"></i> <%= red_t("red.errors.index.empty.filtered_cta") %><% end %>
|
|
273
324
|
<% else %>
|
|
274
325
|
<div class="red-empty-state-icon" style="background: var(--status-success-bg); color: var(--status-success);"><i class="bi bi-check-lg"></i></div>
|
|
275
|
-
<div class="red-empty-state-title"
|
|
276
|
-
<div class="red-empty-state-message"
|
|
326
|
+
<div class="red-empty-state-title"><%= red_t("red.errors.index.empty.clear_title") %></div>
|
|
327
|
+
<div class="red-empty-state-message"><%= red_t("red.errors.index.empty.clear_message") %></div>
|
|
277
328
|
<% end %>
|
|
278
329
|
</div>
|
|
279
330
|
<% end %>
|
|
@@ -301,7 +352,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
301
352
|
|
|
302
353
|
if (count > 0) {
|
|
303
354
|
if (batchToolbar) batchToolbar.style.display = '';
|
|
304
|
-
if (selectedCountSpan) selectedCountSpan.textContent = count
|
|
355
|
+
if (selectedCountSpan) selectedCountSpan.textContent = window.redT('js.selected', { count: count });
|
|
305
356
|
if (selectAllBatchCheckbox) {
|
|
306
357
|
selectAllBatchCheckbox.checked = allChecked;
|
|
307
358
|
selectAllBatchCheckbox.indeterminate = someChecked && !allChecked;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
<% content_for :page_title, "
|
|
1
|
+
<% content_for :page_title, red_t("red.health.job.title") %>
|
|
2
2
|
|
|
3
3
|
<div>
|
|
4
4
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
5
5
|
<h1 style="font-size: 20px; font-weight: 700; margin: 0;">
|
|
6
6
|
<i class="bi bi-cpu me-2"></i>
|
|
7
|
-
|
|
7
|
+
<%= red_t("red.health.job.title") %>
|
|
8
8
|
</h1>
|
|
9
9
|
|
|
10
10
|
<div class="btn-group" role="group">
|
|
11
11
|
<%= link_to job_health_summary_errors_path(days: 7), class: "btn btn-sm #{@days == 7 ? 'btn-primary' : 'btn-outline-primary'}" do %>
|
|
12
|
-
7
|
|
12
|
+
<%= red_t("red.common.days_filter.7") %>
|
|
13
13
|
<% end %>
|
|
14
14
|
<%= link_to job_health_summary_errors_path(days: 30), class: "btn btn-sm #{@days == 30 ? 'btn-primary' : 'btn-outline-primary'}" do %>
|
|
15
|
-
30
|
|
15
|
+
<%= red_t("red.common.days_filter.30") %>
|
|
16
16
|
<% end %>
|
|
17
17
|
<%= link_to job_health_summary_errors_path(days: 90), class: "btn btn-sm #{@days == 90 ? 'btn-primary' : 'btn-outline-primary'}" do %>
|
|
18
|
-
90
|
|
18
|
+
<%= red_t("red.common.days_filter.90") %>
|
|
19
19
|
<% end %>
|
|
20
20
|
</div>
|
|
21
21
|
</div>
|
|
@@ -23,18 +23,18 @@
|
|
|
23
23
|
<% if @errors_with_jobs == 0 %>
|
|
24
24
|
<div class="red-empty-state">
|
|
25
25
|
<div class="red-empty-state-icon" style="background: var(--status-success-bg); color: var(--status-success);"><i class="bi bi-check-lg"></i></div>
|
|
26
|
-
<div class="red-empty-state-title"
|
|
26
|
+
<div class="red-empty-state-title"><%= red_t("red.health.job.empty.title") %></div>
|
|
27
27
|
<p class="text-muted">
|
|
28
|
-
|
|
28
|
+
<%= red_t("red.health.job.empty.message", days: @days) %>
|
|
29
29
|
</p>
|
|
30
30
|
<div class="card mx-auto" style="max-width: 500px;">
|
|
31
31
|
<div class="card-body text-start">
|
|
32
|
-
<h6
|
|
32
|
+
<h6><%= red_t("red.health.job.empty.how_it_works") %></h6>
|
|
33
33
|
<ul class="mb-0">
|
|
34
|
-
<li
|
|
35
|
-
<li
|
|
36
|
-
<li
|
|
37
|
-
<li
|
|
34
|
+
<li><%= red_t("red.health.job.empty.step_enable_html") %></li>
|
|
35
|
+
<li><%= red_t("red.health.job.empty.step_capture") %></li>
|
|
36
|
+
<li><%= red_t("red.health.job.empty.step_collected") %></li>
|
|
37
|
+
<li><%= red_t("red.health.job.empty.step_sort") %></li>
|
|
38
38
|
</ul>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
<div class="card text-center">
|
|
46
46
|
<div class="card-body">
|
|
47
47
|
<div class="display-6 text-info"><%= @errors_with_jobs %></div>
|
|
48
|
-
<small class="text-muted"
|
|
48
|
+
<small class="text-muted"><%= red_t("red.health.job.stats.errors_with_jobs") %></small>
|
|
49
49
|
</div>
|
|
50
50
|
</div>
|
|
51
51
|
</div>
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
<div class="card-body">
|
|
55
55
|
<% failed_color = @total_failed > 0 ? "danger" : "success" %>
|
|
56
56
|
<div class="display-6 text-<%= failed_color %>"><%= @total_failed %></div>
|
|
57
|
-
<small class="text-muted"
|
|
57
|
+
<small class="text-muted"><%= red_t("red.health.job.stats.total_failed") %></small>
|
|
58
58
|
</div>
|
|
59
59
|
</div>
|
|
60
60
|
</div>
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
<div class="card text-center">
|
|
63
63
|
<div class="card-body">
|
|
64
64
|
<div class="display-6 text-secondary"><%= @adapters_detected.size %></div>
|
|
65
|
-
<small class="text-muted"
|
|
65
|
+
<small class="text-muted"><%= red_t("red.health.job.stats.adapters_detected") %></small>
|
|
66
66
|
</div>
|
|
67
67
|
</div>
|
|
68
68
|
</div>
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
73
73
|
<h5 class="mb-0">
|
|
74
74
|
<i class="bi bi-cpu text-info me-2"></i>
|
|
75
|
-
|
|
75
|
+
<%= red_t("red.health.job.table.title") %>
|
|
76
76
|
<span class="badge bg-info"><%= @errors_with_jobs %></span>
|
|
77
77
|
</h5>
|
|
78
78
|
<small class="text-muted"><%== @pagy.info_tag %></small>
|
|
@@ -82,12 +82,12 @@
|
|
|
82
82
|
<table class="table table-hover mb-0">
|
|
83
83
|
<thead class="table-light">
|
|
84
84
|
<tr>
|
|
85
|
-
<th width="100"
|
|
86
|
-
<th width="120"
|
|
87
|
-
<th width="80"
|
|
88
|
-
<th width="120"
|
|
89
|
-
<th
|
|
90
|
-
<th width="140"
|
|
85
|
+
<th width="100"><%= red_t("red.health.job.table.column_error") %></th>
|
|
86
|
+
<th width="120"><%= red_t("red.health.job.table.column_adapter") %></th>
|
|
87
|
+
<th width="80"><%= red_t("red.health.job.table.column_failed") %></th>
|
|
88
|
+
<th width="120"><%= red_t("red.health.job.table.column_queued") %></th>
|
|
89
|
+
<th><%= red_t("red.health.job.table.column_other_stats") %></th>
|
|
90
|
+
<th width="140"><%= red_t("red.health.job.table.column_last_seen") %></th>
|
|
91
91
|
</tr>
|
|
92
92
|
</thead>
|
|
93
93
|
<tbody>
|
|
@@ -106,22 +106,22 @@
|
|
|
106
106
|
<td>
|
|
107
107
|
<% case entry[:adapter] %>
|
|
108
108
|
<% when "sidekiq" %>
|
|
109
|
-
<%= entry[:enqueued] %> enqueued
|
|
109
|
+
<%= entry[:enqueued] %> <%= red_t("red.health.job.table.enqueued") %>
|
|
110
110
|
<% when "solid_queue" %>
|
|
111
|
-
<%= entry[:ready] %> ready
|
|
111
|
+
<%= entry[:ready] %> <%= red_t("red.health.job.table.ready") %>
|
|
112
112
|
<% when "good_job" %>
|
|
113
|
-
<%= entry[:queued] %> queued
|
|
113
|
+
<%= entry[:queued] %> <%= red_t("red.health.job.table.queued") %>
|
|
114
114
|
<% end %>
|
|
115
115
|
</td>
|
|
116
116
|
<td>
|
|
117
117
|
<small class="text-muted">
|
|
118
118
|
<% case entry[:adapter] %>
|
|
119
119
|
<% when "sidekiq" %>
|
|
120
|
-
dead:
|
|
120
|
+
<%= red_t("red.health.job.table.other_stats_sidekiq", dead: entry[:dead], retry: entry[:retry], workers: entry[:workers]) %>
|
|
121
121
|
<% when "solid_queue" %>
|
|
122
|
-
claimed:
|
|
122
|
+
<%= red_t("red.health.job.table.other_stats_solid_queue", claimed: entry[:claimed], blocked: entry[:blocked], scheduled: entry[:scheduled]) %>
|
|
123
123
|
<% when "good_job" %>
|
|
124
|
-
finished:
|
|
124
|
+
<%= red_t("red.health.job.table.other_stats_good_job", finished: entry[:finished]) %>
|
|
125
125
|
<% end %>
|
|
126
126
|
</small>
|
|
127
127
|
</td>
|
|
@@ -135,11 +135,11 @@
|
|
|
135
135
|
<div class="card-footer border-top d-flex justify-content-between align-items-center">
|
|
136
136
|
<div>
|
|
137
137
|
<small class="text-muted">
|
|
138
|
-
<i class="bi bi-lightbulb text-warning"></i>
|
|
138
|
+
<i class="bi bi-lightbulb text-warning"></i> <%= red_t("red.health.job.table.tip") %>
|
|
139
139
|
</small>
|
|
140
140
|
<small class="ms-3">
|
|
141
141
|
<a href="https://guides.rubyonrails.org/active_job_basics.html" target="_blank" rel="noopener" class="text-decoration-none">
|
|
142
|
-
<i class="bi bi-book"></i>
|
|
142
|
+
<i class="bi bi-book"></i> <%= red_t("red.health.job.table.guide_link") %> <i class="bi bi-box-arrow-up-right" style="font-size: 0.7em;"></i>
|
|
143
143
|
</a>
|
|
144
144
|
</small>
|
|
145
145
|
</div>
|