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
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
<div class="container">
|
|
37
37
|
<!-- Header -->
|
|
38
38
|
<div class="header">
|
|
39
|
-
<h1
|
|
40
|
-
<div class="subtitle"><%= @digest[:period_label] %> — <%= @digest[:generated_at]
|
|
39
|
+
<h1><%= red_t("red.mailers.digest.heading") %></h1>
|
|
40
|
+
<div class="subtitle"><%= @digest[:period_label] %> — <%= red_mail_time(@digest[:generated_at], format: :date_only) %></div>
|
|
41
41
|
</div>
|
|
42
42
|
|
|
43
43
|
<!-- Summary Stats -->
|
|
@@ -45,27 +45,27 @@
|
|
|
45
45
|
<div class="stat-grid">
|
|
46
46
|
<div class="stat-box">
|
|
47
47
|
<div class="stat-value text-primary"><%= @digest[:stats][:new_errors] %></div>
|
|
48
|
-
<div class="stat-label"
|
|
48
|
+
<div class="stat-label"><%= red_t("red.mailers.digest.stats.new_errors") %></div>
|
|
49
49
|
</div>
|
|
50
50
|
<div class="stat-box">
|
|
51
51
|
<div class="stat-value"><%= @digest[:stats][:total_occurrences] %></div>
|
|
52
|
-
<div class="stat-label"
|
|
52
|
+
<div class="stat-label"><%= red_t("red.mailers.digest.stats.total_occurrences") %></div>
|
|
53
53
|
</div>
|
|
54
54
|
<div class="stat-box">
|
|
55
55
|
<div class="stat-value text-success"><%= @digest[:stats][:resolved] %></div>
|
|
56
|
-
<div class="stat-label"
|
|
56
|
+
<div class="stat-label"><%= red_t("red.mailers.digest.stats.resolved") %></div>
|
|
57
57
|
</div>
|
|
58
58
|
<div class="stat-box">
|
|
59
59
|
<div class="stat-value text-warning"><%= @digest[:stats][:unresolved] %></div>
|
|
60
|
-
<div class="stat-label"
|
|
60
|
+
<div class="stat-label"><%= red_t("red.mailers.digest.stats.unresolved") %></div>
|
|
61
61
|
</div>
|
|
62
62
|
<div class="stat-box">
|
|
63
63
|
<div class="stat-value text-danger"><%= @digest[:stats][:critical_high] %></div>
|
|
64
|
-
<div class="stat-label"
|
|
64
|
+
<div class="stat-label"><%= red_t("red.mailers.digest.stats.critical_high") %></div>
|
|
65
65
|
</div>
|
|
66
66
|
<div class="stat-box">
|
|
67
67
|
<div class="stat-value"><%= @digest[:stats][:resolution_rate] %>%</div>
|
|
68
|
-
<div class="stat-label"
|
|
68
|
+
<div class="stat-label"><%= red_t("red.mailers.digest.stats.resolution_rate") %></div>
|
|
69
69
|
</div>
|
|
70
70
|
</div>
|
|
71
71
|
</div>
|
|
@@ -81,10 +81,10 @@
|
|
|
81
81
|
%>
|
|
82
82
|
<div class="comparison">
|
|
83
83
|
<div>
|
|
84
|
-
<span class="text-muted"
|
|
84
|
+
<span class="text-muted"><%= red_t("red.mailers.digest.comparison.versus", period: @digest[:period]) %></span>
|
|
85
85
|
</div>
|
|
86
86
|
<div class="delta <%= delta_class %>">
|
|
87
|
-
<%== arrow %> <%= delta > 0 ? "+#{delta}" : delta %>
|
|
87
|
+
<%== arrow %> <%= red_tp("red.mailers.digest.comparison.delta", count: delta.abs, delta: delta > 0 ? "+#{delta}" : delta) %>
|
|
88
88
|
(<%= pct > 0 ? "+#{pct}" : pct %>%)
|
|
89
89
|
</div>
|
|
90
90
|
</div>
|
|
@@ -94,12 +94,12 @@
|
|
|
94
94
|
<!-- Critical / High Unresolved -->
|
|
95
95
|
<% if @digest[:critical_unresolved].any? %>
|
|
96
96
|
<div class="card">
|
|
97
|
-
<h3 style="margin: 0 0 12px 0; font-size: 16px;"
|
|
97
|
+
<h3 style="margin: 0 0 12px 0; font-size: 16px;"><%= red_t("red.mailers.digest.critical_unresolved") %></h3>
|
|
98
98
|
<table>
|
|
99
99
|
<thead>
|
|
100
100
|
<tr>
|
|
101
|
-
<th
|
|
102
|
-
<th
|
|
101
|
+
<th><%= red_t("red.mailers.digest.columns.severity") %></th>
|
|
102
|
+
<th><%= red_t("red.mailers.digest.columns.error") %></th>
|
|
103
103
|
<th></th>
|
|
104
104
|
</tr>
|
|
105
105
|
</thead>
|
|
@@ -107,14 +107,15 @@
|
|
|
107
107
|
<% @digest[:critical_unresolved].each do |error| %>
|
|
108
108
|
<tr>
|
|
109
109
|
<td>
|
|
110
|
-
|
|
110
|
+
<%# Severity is a machine value; its label comes from red.common. %>
|
|
111
|
+
<span class="badge badge-<%= error[:severity].to_s.downcase %>"><%= red_t("red.common.severity.#{error[:severity].to_s.downcase}") %></span>
|
|
111
112
|
</td>
|
|
112
113
|
<td>
|
|
113
114
|
<strong><%= error[:error_type] %></strong><br>
|
|
114
115
|
<small class="text-muted"><%= error[:message] %></small>
|
|
115
116
|
</td>
|
|
116
117
|
<td>
|
|
117
|
-
<a href="<%= @dashboard_url %>/errors/<%= error[:id] %>"
|
|
118
|
+
<a href="<%= @dashboard_url %>/errors/<%= error[:id] %>"><%= red_t("red.mailers.digest.view") %></a>
|
|
118
119
|
</td>
|
|
119
120
|
</tr>
|
|
120
121
|
<% end %>
|
|
@@ -126,12 +127,12 @@
|
|
|
126
127
|
<!-- Top Errors -->
|
|
127
128
|
<% if @digest[:top_errors].any? %>
|
|
128
129
|
<div class="card">
|
|
129
|
-
<h3 style="margin: 0 0 12px 0; font-size: 16px;"
|
|
130
|
+
<h3 style="margin: 0 0 12px 0; font-size: 16px;"><%= red_t("red.mailers.digest.top_errors") %></h3>
|
|
130
131
|
<table>
|
|
131
132
|
<thead>
|
|
132
133
|
<tr>
|
|
133
|
-
<th
|
|
134
|
-
<th
|
|
134
|
+
<th><%= red_t("red.mailers.digest.columns.error_type") %></th>
|
|
135
|
+
<th><%= red_t("red.mailers.digest.columns.count") %></th>
|
|
135
136
|
<th></th>
|
|
136
137
|
</tr>
|
|
137
138
|
</thead>
|
|
@@ -145,7 +146,7 @@
|
|
|
145
146
|
<td><%= error[:count] %></td>
|
|
146
147
|
<td>
|
|
147
148
|
<% if error[:id] %>
|
|
148
|
-
<a href="<%= @dashboard_url %>/errors/<%= error[:id] %>"
|
|
149
|
+
<a href="<%= @dashboard_url %>/errors/<%= error[:id] %>"><%= red_t("red.mailers.digest.view") %></a>
|
|
149
150
|
<% end %>
|
|
150
151
|
</td>
|
|
151
152
|
</tr>
|
|
@@ -158,14 +159,14 @@
|
|
|
158
159
|
<!-- CTA -->
|
|
159
160
|
<div class="card" style="text-align: center;">
|
|
160
161
|
<a href="<%= @dashboard_url %>" style="display: inline-block; padding: 10px 24px; background: #3b82f6; color: #ffffff; border-radius: 6px; font-weight: 600; text-decoration: none;">
|
|
161
|
-
|
|
162
|
+
<%= red_t("red.mailers.digest.open_dashboard") %>
|
|
162
163
|
</a>
|
|
163
164
|
</div>
|
|
164
165
|
|
|
165
166
|
<!-- Footer -->
|
|
166
167
|
<div class="footer">
|
|
167
|
-
|
|
168
|
-
<a href="<%= @dashboard_url %>/settings"
|
|
168
|
+
<%= red_t("red.mailers.digest.footer", product: red_t("red.mailers.shared.product_name")) %><br>
|
|
169
|
+
<a href="<%= @dashboard_url %>/settings"><%= red_t("red.mailers.digest.manage_settings") %></a>
|
|
169
170
|
</div>
|
|
170
171
|
</div>
|
|
171
172
|
</body>
|
|
@@ -1,40 +1,51 @@
|
|
|
1
|
+
<%# Stat labels are NOT padded to a column. The English version aligned values %>
|
|
2
|
+
<%# at column 20 ("New Errors: 12"), which only works while every label %>
|
|
3
|
+
<%# is shorter than that. "Gesamtvorkommen" and friends are not. Label, space, %>
|
|
4
|
+
<%# value. (P4-T2 REQ-3) %>
|
|
1
5
|
==========================================
|
|
2
|
-
|
|
6
|
+
<%= red_mail_t("red.mailers.digest.heading") %> (<%= @digest[:period_label] %>)
|
|
3
7
|
==========================================
|
|
4
|
-
|
|
8
|
+
<%= red_mail_t("red.mailers.digest.generated_at") %>: <%= red_mail_time(@digest[:generated_at]) %>
|
|
5
9
|
|
|
6
10
|
------------------------------------------
|
|
7
|
-
|
|
11
|
+
<%= red_mail_t("red.mailers.digest.summary") %>
|
|
8
12
|
------------------------------------------
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
<%= red_mail_t("red.mailers.digest.stats.new_errors") %>: <%= @digest[:stats][:new_errors] %>
|
|
14
|
+
<%= red_mail_t("red.mailers.digest.stats.total_occurrences_text") %>: <%= @digest[:stats][:total_occurrences] %>
|
|
15
|
+
<%= red_mail_t("red.mailers.digest.stats.resolved") %>: <%= @digest[:stats][:resolved] %>
|
|
16
|
+
<%= red_mail_t("red.mailers.digest.stats.unresolved") %>: <%= @digest[:stats][:unresolved] %>
|
|
17
|
+
<%= red_mail_t("red.mailers.digest.stats.critical_high") %>: <%= @digest[:stats][:critical_high] %>
|
|
18
|
+
<%= red_mail_t("red.mailers.digest.stats.resolution_rate") %>: <%= @digest[:stats][:resolution_rate] %>%
|
|
15
19
|
|
|
16
20
|
<% if @digest[:comparison][:error_delta_percentage] %>
|
|
17
21
|
------------------------------------------
|
|
18
|
-
|
|
19
|
-
------------------------------------------
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
<%= red_mail_t("red.mailers.digest.comparison.heading") %>
|
|
23
|
+
------------------------------------------
|
|
24
|
+
<%
|
|
25
|
+
delta = @digest[:comparison][:error_delta]
|
|
26
|
+
pct = @digest[:comparison][:error_delta_percentage]
|
|
27
|
+
signed_delta = delta > 0 ? "+#{delta}" : delta.to_s
|
|
28
|
+
signed_pct = pct > 0 ? "+#{pct}" : pct.to_s
|
|
29
|
+
%>
|
|
30
|
+
<%= red_mail_t("red.mailers.digest.comparison.current") %>: <%= red_mail_tp("red.mailers.digest.comparison.delta", count: @digest[:comparison][:current_count], delta: @digest[:comparison][:current_count]) %>
|
|
31
|
+
<%= red_mail_t("red.mailers.digest.comparison.previous") %>: <%= red_mail_tp("red.mailers.digest.comparison.delta", count: @digest[:comparison][:previous_count], delta: @digest[:comparison][:previous_count]) %>
|
|
32
|
+
<%= red_mail_t("red.mailers.digest.comparison.change") %>: <%= signed_delta %> (<%= signed_pct %>%)
|
|
23
33
|
<% end %>
|
|
24
34
|
|
|
25
35
|
<% if @digest[:critical_unresolved].any? %>
|
|
26
36
|
------------------------------------------
|
|
27
|
-
|
|
37
|
+
<%= red_mail_t("red.mailers.digest.critical_unresolved") %>
|
|
28
38
|
------------------------------------------
|
|
29
39
|
<% @digest[:critical_unresolved].each do |error| %>
|
|
30
|
-
|
|
40
|
+
<%# Severity is a machine value; its display label comes from red.common. %>
|
|
41
|
+
[<%= red_mail_t("red.common.severity.#{error[:severity].to_s.downcase}") %>] <%= error[:error_type] %>: <%= error[:message] %>
|
|
31
42
|
→ <%= @dashboard_url %>/errors/<%= error[:id] %>
|
|
32
43
|
<% end %>
|
|
33
44
|
<% end %>
|
|
34
45
|
|
|
35
46
|
<% if @digest[:top_errors].any? %>
|
|
36
47
|
------------------------------------------
|
|
37
|
-
|
|
48
|
+
<%= red_mail_t("red.mailers.digest.top_errors") %>
|
|
38
49
|
------------------------------------------
|
|
39
50
|
<% @digest[:top_errors].each_with_index do |error, i| %>
|
|
40
51
|
<%= i + 1 %>. <%= error[:error_type] %> (<%= error[:count] %>x): <%= error[:message] %>
|
|
@@ -44,6 +55,6 @@ TOP ERRORS BY COUNT
|
|
|
44
55
|
|
|
45
56
|
------------------------------------------
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
<%= red_mail_t("red.mailers.digest.view_dashboard_text") %>
|
|
48
59
|
<%= @dashboard_url %>
|
|
49
|
-
|
|
60
|
+
<%= red_mail_t("red.mailers.digest.footer", product: red_mail_t("red.mailers.shared.product_name")) %>
|
|
@@ -128,19 +128,19 @@
|
|
|
128
128
|
</head>
|
|
129
129
|
<body>
|
|
130
130
|
<div class="header">
|
|
131
|
-
<h1
|
|
131
|
+
<h1><%= red_t("red.mailers.error_alert.heading") %></h1>
|
|
132
132
|
</div>
|
|
133
133
|
|
|
134
134
|
<div class="content">
|
|
135
135
|
<div class="info-grid">
|
|
136
|
-
<div class="label"
|
|
137
|
-
<div class="value"><strong><%= @error_log.application&.name ||
|
|
136
|
+
<div class="label"><%= red_t("red.mailers.error_alert.labels.application") %>:</div>
|
|
137
|
+
<div class="value"><strong><%= @error_log.application&.name || red_t("red.mailers.shared.unknown_application") %></strong></div>
|
|
138
138
|
|
|
139
|
-
<div class="label"
|
|
139
|
+
<div class="label"><%= red_t("red.mailers.error_alert.labels.error_type") %>:</div>
|
|
140
140
|
<div class="value"><code><%= @error_log.error_type %></code></div>
|
|
141
141
|
|
|
142
142
|
<% if @error_log.platform.present? %>
|
|
143
|
-
<div class="label"
|
|
143
|
+
<div class="label"><%= red_t("red.mailers.error_alert.labels.platform") %>:</div>
|
|
144
144
|
<div class="value">
|
|
145
145
|
<span class="badge badge-<%= @error_log.platform.downcase %>">
|
|
146
146
|
<%= @error_log.platform %>
|
|
@@ -148,47 +148,49 @@
|
|
|
148
148
|
</div>
|
|
149
149
|
<% end %>
|
|
150
150
|
|
|
151
|
-
<div class="label"
|
|
152
|
-
<div class="value"><%= @error_log.occurred_at
|
|
151
|
+
<div class="label"><%= red_t("red.mailers.error_alert.labels.occurred_at") %>:</div>
|
|
152
|
+
<div class="value"><%= red_mail_time(@error_log.occurred_at) %></div>
|
|
153
153
|
|
|
154
154
|
<% if @error_log.user_id.present? %>
|
|
155
|
-
<div class="label"
|
|
155
|
+
<div class="label"><%= red_t("red.mailers.error_alert.labels.user_id") %>:</div>
|
|
156
156
|
<div class="value"><%= @error_log.user_id %></div>
|
|
157
157
|
<% end %>
|
|
158
158
|
|
|
159
159
|
<% if @error_log.ip_address.present? %>
|
|
160
|
-
<div class="label"
|
|
160
|
+
<div class="label"><%= red_t("red.mailers.error_alert.labels.ip_address") %>:</div>
|
|
161
161
|
<div class="value"><%= @error_log.ip_address %></div>
|
|
162
162
|
<% end %>
|
|
163
163
|
|
|
164
164
|
<% if @error_log.request_url.present? %>
|
|
165
|
-
<div class="label"
|
|
165
|
+
<div class="label"><%= red_t("red.mailers.error_alert.labels.request_url") %>:</div>
|
|
166
166
|
<div class="value"><%= @error_log.request_url %></div>
|
|
167
167
|
<% end %>
|
|
168
168
|
</div>
|
|
169
169
|
|
|
170
170
|
<div class="error-message">
|
|
171
|
-
<strong
|
|
171
|
+
<strong><%= red_t("red.mailers.error_alert.labels.message") %>:</strong><br/>
|
|
172
172
|
<code><%= @error_log.message %></code>
|
|
173
173
|
</div>
|
|
174
174
|
|
|
175
175
|
<% if @error_log.backtrace.present? %>
|
|
176
|
+
<% backtrace_lines = @error_log.backtrace.split("\n").first(10) %>
|
|
176
177
|
<div class="backtrace">
|
|
177
|
-
<strong
|
|
178
|
-
|
|
178
|
+
<strong><%= red_tp("red.mailers.error_alert.stack_trace", count: backtrace_lines.length) %>:</strong>
|
|
179
|
+
<%# Backtrace content is diagnostic output and is never translated. %>
|
|
180
|
+
<pre><%= backtrace_lines.join("\n") %></pre>
|
|
179
181
|
</div>
|
|
180
182
|
<% end %>
|
|
181
183
|
|
|
182
184
|
<div style="text-align: center;">
|
|
183
185
|
<a href="<%= @dashboard_url %>" class="button">
|
|
184
|
-
|
|
186
|
+
<%= red_t("red.mailers.error_alert.view_details") %>
|
|
185
187
|
</a>
|
|
186
188
|
</div>
|
|
187
189
|
|
|
188
190
|
<div class="footer">
|
|
189
191
|
<p>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
<%= red_t("red.mailers.error_alert.footer", product: red_t("red.mailers.shared.product_name")) %><br/>
|
|
193
|
+
<%= red_t("red.mailers.error_alert.labels.error_id") %>: <%= @error_log.id %>
|
|
192
194
|
</p>
|
|
193
195
|
</div>
|
|
194
196
|
</div>
|
|
@@ -1,32 +1,39 @@
|
|
|
1
|
+
<%# Separators are fixed-width but LABELS ARE NOT ALIGNED TO A COLUMN. %>
|
|
2
|
+
<%# Padding "Application:" to a column assumes every translation is about as %>
|
|
3
|
+
<%# long as the English one; German runs ~30% longer and would push values %>
|
|
4
|
+
<%# past 80 characters or force translators to abbreviate. Label, space, %>
|
|
5
|
+
<%# value — nothing to break. (P4-T2 REQ-3) %>
|
|
1
6
|
==========================================
|
|
2
|
-
|
|
7
|
+
<%= red_mail_t("red.mailers.error_alert.heading") %>
|
|
3
8
|
==========================================
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<% if @error_log.platform.present?
|
|
8
|
-
|
|
9
|
-
<% if @error_log.user_id.present?
|
|
10
|
-
<% if @error_log.ip_address.present?
|
|
11
|
-
<% if @error_log.request_url.present?
|
|
10
|
+
<%= red_mail_t("red.mailers.error_alert.labels.application") %>: <%= @error_log.application&.name || red_mail_t("red.mailers.shared.unknown_application") %>
|
|
11
|
+
<%= red_mail_t("red.mailers.error_alert.labels.error_type") %>: <%= @error_log.error_type %>
|
|
12
|
+
<% if @error_log.platform.present? %><%= red_mail_t("red.mailers.error_alert.labels.platform") %>: <%= @error_log.platform %><% end %>
|
|
13
|
+
<%= red_mail_t("red.mailers.error_alert.labels.occurred_at") %>: <%= red_mail_time(@error_log.occurred_at) %>
|
|
14
|
+
<% if @error_log.user_id.present? %><%= red_mail_t("red.mailers.error_alert.labels.user_id") %>: <%= @error_log.user_id %><% end %>
|
|
15
|
+
<% if @error_log.ip_address.present? %><%= red_mail_t("red.mailers.error_alert.labels.ip_address") %>: <%= @error_log.ip_address %><% end %>
|
|
16
|
+
<% if @error_log.request_url.present? %><%= red_mail_t("red.mailers.error_alert.labels.request_url") %>: <%= @error_log.request_url %><% end %>
|
|
12
17
|
|
|
13
18
|
------------------------------------------
|
|
14
|
-
|
|
19
|
+
<%= red_mail_t("red.mailers.error_alert.labels.message") %>
|
|
15
20
|
------------------------------------------
|
|
21
|
+
<%# Error content is diagnostic output and is never translated. %>
|
|
16
22
|
<%= @error_log.message %>
|
|
17
23
|
|
|
18
24
|
<% if @error_log.backtrace.present? %>
|
|
25
|
+
<% backtrace_lines = @error_log.backtrace.split("\n").first(10) %>
|
|
19
26
|
------------------------------------------
|
|
20
|
-
|
|
27
|
+
<%= red_mail_tp("red.mailers.error_alert.stack_trace", count: backtrace_lines.length) %>
|
|
21
28
|
------------------------------------------
|
|
22
|
-
<%=
|
|
29
|
+
<%= backtrace_lines.join("\n") %>
|
|
23
30
|
<% end %>
|
|
24
31
|
|
|
25
32
|
------------------------------------------
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
<%= red_mail_t("red.mailers.error_alert.view_details_text") %>
|
|
28
35
|
<%= @dashboard_url %>
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
<%= red_mail_t("red.mailers.error_alert.labels.error_id") %>: <%= @error_log.id %>
|
|
31
38
|
|
|
32
|
-
|
|
39
|
+
<%= red_mail_t("red.mailers.error_alert.footer", product: red_mail_t("red.mailers.shared.product_name")) %>
|
|
@@ -5,31 +5,35 @@
|
|
|
5
5
|
<div>
|
|
6
6
|
<div id="red-ai-help-title" class="red-ai-help-title">
|
|
7
7
|
<i class="bi bi-stars"></i>
|
|
8
|
-
|
|
8
|
+
<%= red_t("red.errors.ai_help.title") %>
|
|
9
9
|
</div>
|
|
10
10
|
<div class="red-ai-help-subtitle">
|
|
11
|
-
|
|
11
|
+
<%# Brand name, identical in every locale, but looked up rather than
|
|
12
|
+
titleized: "openai".titleize is "Openai", which is not how the
|
|
13
|
+
company writes it. An unknown provider falls back to its raw value. %>
|
|
14
|
+
<% llm_provider = RailsErrorDashboard.configuration.effective_llm_provider %>
|
|
15
|
+
<%= red_t("red.errors.ai_help.providers.#{llm_provider}", default: llm_provider.to_s) %>
|
|
12
16
|
·
|
|
13
17
|
<%= RailsErrorDashboard.configuration.effective_llm_model %>
|
|
14
18
|
</div>
|
|
15
19
|
</div>
|
|
16
|
-
<button type="button" class="btn-close" data-red-action="close-ai-help" aria-label="
|
|
20
|
+
<button type="button" class="btn-close" data-red-action="close-ai-help" aria-label="<%= red_t("red.errors.ai_help.close") %>"></button>
|
|
17
21
|
</div>
|
|
18
22
|
|
|
19
23
|
<div id="red-ai-help-messages" class="red-ai-help-messages" aria-live="polite">
|
|
20
24
|
<div class="red-ai-help-empty">
|
|
21
|
-
|
|
25
|
+
<%= red_t("red.errors.ai_help.empty") %>
|
|
22
26
|
</div>
|
|
23
27
|
</div>
|
|
24
28
|
|
|
25
29
|
<form id="red-ai-help-form" class="red-ai-help-form" data-ai-help-url="<%= ai_help_error_path(error, **app_context) %>">
|
|
26
|
-
<label for="red-ai-help-question"
|
|
27
|
-
<textarea id="red-ai-help-question" name="question" rows="4" maxlength="4000" placeholder="
|
|
30
|
+
<label for="red-ai-help-question"><%= red_t("red.errors.ai_help.question_label") %></label>
|
|
31
|
+
<textarea id="red-ai-help-question" name="question" rows="4" maxlength="4000" placeholder="<%= red_t("red.errors.ai_help.question_placeholder") %>"></textarea>
|
|
28
32
|
<div class="red-ai-help-footer">
|
|
29
33
|
<span id="red-ai-help-status" class="red-ai-help-status"></span>
|
|
30
34
|
<button type="submit" class="btn btn-primary">
|
|
31
35
|
<i class="bi bi-send"></i>
|
|
32
|
-
|
|
36
|
+
<%= red_t("red.errors.ai_help.ask") %>
|
|
33
37
|
</button>
|
|
34
38
|
</div>
|
|
35
39
|
</form>
|