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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -0
  3. data/app/controllers/rails_error_dashboard/application_controller.rb +156 -0
  4. data/app/controllers/rails_error_dashboard/errors_controller.rb +95 -73
  5. data/app/controllers/rails_error_dashboard/locales_controller.rb +87 -0
  6. data/app/helpers/rails_error_dashboard/application_helper.rb +20 -14
  7. data/app/helpers/rails_error_dashboard/backtrace_helper.rb +15 -6
  8. data/app/helpers/rails_error_dashboard/i18n_helper.rb +154 -0
  9. data/app/helpers/rails_error_dashboard/mailer_i18n_helper.rb +69 -0
  10. data/app/helpers/rails_error_dashboard/overview_helper.rb +18 -6
  11. data/app/helpers/rails_error_dashboard/user_agent_helper.rb +25 -11
  12. data/app/jobs/rails_error_dashboard/application_job.rb +5 -0
  13. data/app/jobs/rails_error_dashboard/baseline_alert_job.rb +18 -16
  14. data/app/jobs/rails_error_dashboard/concerns/localized_job.rb +83 -0
  15. data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +4 -2
  16. data/app/jobs/rails_error_dashboard/email_error_notification_job.rb +4 -2
  17. data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +6 -2
  18. data/app/jobs/rails_error_dashboard/scheduled_digest_job.rb +8 -3
  19. data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +6 -4
  20. data/app/jobs/rails_error_dashboard/storm_notification_job.rb +26 -8
  21. data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +4 -2
  22. data/app/mailers/rails_error_dashboard/application_mailer.rb +14 -0
  23. data/app/mailers/rails_error_dashboard/digest_mailer.rb +18 -2
  24. data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +19 -2
  25. data/app/views/layouts/rails_error_dashboard.html.erb +255 -92
  26. data/app/views/rails_error_dashboard/digest_mailer/digest_summary.html.erb +23 -22
  27. data/app/views/rails_error_dashboard/digest_mailer/digest_summary.text.erb +30 -19
  28. data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +18 -16
  29. data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +21 -14
  30. data/app/views/rails_error_dashboard/errors/_ai_help_panel.html.erb +11 -7
  31. data/app/views/rails_error_dashboard/errors/_breadcrumbs_group.html.erb +45 -38
  32. data/app/views/rails_error_dashboard/errors/_co_occurring_errors.html.erb +17 -14
  33. data/app/views/rails_error_dashboard/errors/_discussion.html.erb +27 -9
  34. data/app/views/rails_error_dashboard/errors/_error_cascades.html.erb +25 -21
  35. data/app/views/rails_error_dashboard/errors/_error_info.html.erb +25 -22
  36. data/app/views/rails_error_dashboard/errors/_error_row.html.erb +24 -12
  37. data/app/views/rails_error_dashboard/errors/_instance_variables.html.erb +12 -11
  38. data/app/views/rails_error_dashboard/errors/_issue_section.html.erb +19 -13
  39. data/app/views/rails_error_dashboard/errors/_llm_summary.html.erb +14 -14
  40. data/app/views/rails_error_dashboard/errors/_local_variables.html.erb +8 -8
  41. data/app/views/rails_error_dashboard/errors/_modals.html.erb +60 -52
  42. data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +59 -49
  43. data/app/views/rails_error_dashboard/errors/_request_context.html.erb +23 -20
  44. data/app/views/rails_error_dashboard/errors/_show_scripts.html.erb +14 -14
  45. data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +118 -93
  46. data/app/views/rails_error_dashboard/errors/_similar_errors.html.erb +18 -12
  47. data/app/views/rails_error_dashboard/errors/_source_code.html.erb +20 -5
  48. data/app/views/rails_error_dashboard/errors/_stats.html.erb +5 -5
  49. data/app/views/rails_error_dashboard/errors/_timeline.html.erb +7 -7
  50. data/app/views/rails_error_dashboard/errors/_user_errors_table.html.erb +15 -12
  51. data/app/views/rails_error_dashboard/errors/actioncable_health_summary.html.erb +25 -25
  52. data/app/views/rails_error_dashboard/errors/activestorage_health_summary.html.erb +28 -28
  53. data/app/views/rails_error_dashboard/errors/analytics.html.erb +82 -82
  54. data/app/views/rails_error_dashboard/errors/cache_health_summary.html.erb +27 -27
  55. data/app/views/rails_error_dashboard/errors/correlation.html.erb +61 -57
  56. data/app/views/rails_error_dashboard/errors/database_health_summary.html.erb +64 -65
  57. data/app/views/rails_error_dashboard/errors/deprecations.html.erb +23 -23
  58. data/app/views/rails_error_dashboard/errors/diagnostic_dumps.html.erb +48 -36
  59. data/app/views/rails_error_dashboard/errors/index.html.erb +121 -70
  60. data/app/views/rails_error_dashboard/errors/job_health_summary.html.erb +30 -30
  61. data/app/views/rails_error_dashboard/errors/llm_health_summary.html.erb +38 -39
  62. data/app/views/rails_error_dashboard/errors/n_plus_one_summary.html.erb +28 -25
  63. data/app/views/rails_error_dashboard/errors/overview.html.erb +45 -39
  64. data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +45 -44
  65. data/app/views/rails_error_dashboard/errors/rack_attack_summary.html.erb +39 -28
  66. data/app/views/rails_error_dashboard/errors/releases.html.erb +46 -47
  67. data/app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb +48 -44
  68. data/app/views/rails_error_dashboard/errors/settings.html.erb +122 -112
  69. data/app/views/rails_error_dashboard/errors/show.html.erb +44 -37
  70. data/app/views/rails_error_dashboard/errors/storms.html.erb +30 -24
  71. data/app/views/rails_error_dashboard/errors/swallowed_exceptions.html.erb +26 -26
  72. data/app/views/rails_error_dashboard/errors/user_impact.html.erb +31 -30
  73. data/config/locales/de.yml +2007 -0
  74. data/config/locales/en.yml +2719 -0
  75. data/config/locales/es.yml +2079 -0
  76. data/config/locales/fr.yml +2082 -0
  77. data/config/locales/it.yml +2060 -0
  78. data/config/locales/ja.yml +1802 -0
  79. data/config/locales/pl.yml +2108 -0
  80. data/config/locales/pt-BR.yml +2064 -0
  81. data/config/locales/ru.yml +2109 -0
  82. data/config/locales/uk.yml +2106 -0
  83. data/config/locales/zh-CN.yml +1791 -0
  84. data/config/routes.rb +5 -0
  85. data/db/migrate/20260325000001_fix_swallowed_exceptions_index_for_mysql.rb +9 -3
  86. data/lib/rails_error_dashboard/commands/batch_delete_errors.rb +3 -1
  87. data/lib/rails_error_dashboard/commands/batch_mute_errors.rb +4 -2
  88. data/lib/rails_error_dashboard/commands/batch_resolve_errors.rb +4 -2
  89. data/lib/rails_error_dashboard/commands/batch_unmute_errors.rb +4 -2
  90. data/lib/rails_error_dashboard/commands/create_issue.rb +5 -3
  91. data/lib/rails_error_dashboard/commands/link_existing_issue.rb +4 -2
  92. data/lib/rails_error_dashboard/commands/log_error.rb +1 -1
  93. data/lib/rails_error_dashboard/configuration.rb +23 -0
  94. data/lib/rails_error_dashboard/current.rb +56 -0
  95. data/lib/rails_error_dashboard/i18n_store.rb +293 -0
  96. data/lib/rails_error_dashboard/private_backend.rb +213 -0
  97. data/lib/rails_error_dashboard/services/baseline_alert_payload_builder.rb +89 -22
  98. data/lib/rails_error_dashboard/services/digest_builder.rb +21 -7
  99. data/lib/rails_error_dashboard/services/discord_payload_builder.rb +27 -15
  100. data/lib/rails_error_dashboard/services/error_notification_dispatcher.rb +10 -5
  101. data/lib/rails_error_dashboard/services/localized_time_formatter.rb +117 -0
  102. data/lib/rails_error_dashboard/services/notification_helpers.rb +87 -4
  103. data/lib/rails_error_dashboard/services/pagerduty_payload_builder.rb +22 -5
  104. data/lib/rails_error_dashboard/services/slack_payload_builder.rb +48 -28
  105. data/lib/rails_error_dashboard/services/storm_protection/gate.rb +2 -1
  106. data/lib/rails_error_dashboard/services/webhook_payload_builder.rb +15 -1
  107. data/lib/rails_error_dashboard/translation.rb +39 -0
  108. data/lib/rails_error_dashboard/version.rb +1 -1
  109. data/lib/rails_error_dashboard.rb +4 -0
  110. data/lib/tasks/error_dashboard.rake +5 -1
  111. metadata +24 -4
@@ -5,13 +5,13 @@
5
5
  if value
6
6
  %>
7
7
  <span class="badge bg-success fs-6">
8
- <i class="bi bi-check-circle"></i> Enabled
8
+ <i class="bi bi-check-circle"></i> <%= red_t("red.settings.values.enabled") %>
9
9
  </span>
10
10
  <%
11
11
  else
12
12
  %>
13
13
  <span class="badge bg-secondary fs-6">
14
- <i class="bi bi-x-circle"></i> Disabled
14
+ <i class="bi bi-x-circle"></i> <%= red_t("red.settings.values.disabled") %>
15
15
  </span>
16
16
  <%
17
17
  end
@@ -19,22 +19,24 @@
19
19
  when :integer
20
20
  if value.present?
21
21
  %>
22
- <span class="badge bg-info fs-6"><%= value %><%= " #{unit}" if unit %></span>
22
+ <%# The unit is a plural key driven by the value, not an English word
23
+ appended to a number — position and form both vary by locale. %>
24
+ <span class="badge bg-info fs-6"><%= unit ? red_tp("red.settings.units.#{unit}", count: value) : value %></span>
23
25
  <%
24
26
  else
25
27
  %>
26
- <span class="badge bg-secondary fs-6">Not set</span>
28
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
27
29
  <%
28
30
  end
29
31
 
30
32
  when :float
31
33
  if value.present?
32
34
  %>
33
- <span class="badge bg-info fs-6"><%= value %><%= unit %></span>
35
+ <span class="badge bg-info fs-6"><%= unit ? red_tp("red.settings.units.#{unit}", count: value) : value %></span>
34
36
  <%
35
37
  else
36
38
  %>
37
- <span class="badge bg-secondary fs-6">Not set</span>
39
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
38
40
  <%
39
41
  end
40
42
 
@@ -45,7 +47,7 @@
45
47
  <%
46
48
  else
47
49
  %>
48
- <span class="badge bg-secondary fs-6">Not set</span>
50
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
49
51
  <%
50
52
  end
51
53
 
@@ -56,7 +58,7 @@
56
58
  <%
57
59
  else
58
60
  %>
59
- <span class="badge bg-secondary fs-6">Not set</span>
61
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
60
62
  <%
61
63
  end
62
64
 
@@ -67,7 +69,7 @@
67
69
  <%
68
70
  else
69
71
  %>
70
- <span class="badge bg-secondary fs-6">Not set</span>
72
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
71
73
  <%
72
74
  end
73
75
 
@@ -78,29 +80,29 @@
78
80
  <%
79
81
  else
80
82
  %>
81
- <span class="badge bg-secondary fs-6">Not set</span>
83
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
82
84
  <%
83
85
  end
84
86
 
85
87
  when :array
86
88
  if value.present? && value.any?
87
89
  %>
88
- <span class="badge bg-info fs-6"><%= value.count %> item<%= value.count != 1 ? 's' : '' %></span>
90
+ <span class="badge bg-info fs-6"><%= red_tp("red.settings.values.items", count: value.count) %></span>
89
91
  <%
90
92
  else
91
93
  %>
92
- <span class="badge bg-secondary fs-6">Empty</span>
94
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.empty") %></span>
93
95
  <%
94
96
  end
95
97
 
96
98
  when :hash
97
99
  if value.present? && value.any?
98
100
  %>
99
- <span class="badge bg-info fs-6"><%= value.count %> rule<%= value.count != 1 ? 's' : '' %></span>
101
+ <span class="badge bg-info fs-6"><%= red_tp("red.settings.values.rules", count: value.count) %></span>
100
102
  <%
101
103
  else
102
104
  %>
103
- <span class="badge bg-secondary fs-6">Empty</span>
105
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.empty") %></span>
104
106
  <%
105
107
  end
106
108
 
@@ -111,7 +113,7 @@
111
113
  <%
112
114
  else
113
115
  %>
114
- <span class="badge bg-secondary fs-6">Not set</span>
116
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
115
117
  <%
116
118
  end
117
119
 
@@ -128,18 +130,18 @@
128
130
  <code class="fs-6"><%= effective_value %></code>
129
131
  <% if is_auto_detected %>
130
132
  <small class="text-success d-block">
131
- <i class="bi bi-magic"></i> Auto-detected
133
+ <i class="bi bi-magic"></i> <%= red_t("red.settings.values.auto_detected") %>
132
134
  </small>
133
135
  <% else %>
134
- <small class="text-muted d-block">(Configured)</small>
136
+ <small class="text-muted d-block"><%= red_t("red.settings.values.configured") %></small>
135
137
  <% end %>
136
138
  </div>
137
139
  <%
138
140
  else
139
141
  %>
140
142
  <div>
141
- <span class="badge bg-secondary fs-6">Not set</span>
142
- <small class="text-muted d-block">Rails app name unavailable</small>
143
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
144
+ <small class="text-muted d-block"><%= red_t("red.settings.values.rails_app_name_unavailable") %></small>
143
145
  </div>
144
146
  <%
145
147
  end
@@ -154,11 +156,11 @@
154
156
  if db_config
155
157
  db_name = db_config.database
156
158
  status_badge = 'bg-success'
157
- status_text = "Separate DB: #{db_config_name}"
159
+ status_text = red_t("red.settings.values.separate_db", name: db_config_name)
158
160
  else
159
161
  db_name = db_config_name
160
162
  status_badge = 'bg-warning'
161
- status_text = "Configured but not found"
163
+ status_text = red_t("red.settings.values.configured_but_not_found")
162
164
  end
163
165
  else
164
166
  # Using primary database
@@ -166,12 +168,12 @@
166
168
  if db_config
167
169
  db_name = db_config.database
168
170
  status_badge = 'bg-info'
169
- status_text = "Shared DB (primary)"
171
+ status_text = red_t("red.settings.values.shared_db_primary")
170
172
  else
171
173
  # Fallback to current connection
172
- db_name = RailsErrorDashboard::ErrorLog.connection.current_database rescue 'Unknown'
174
+ db_name = RailsErrorDashboard::ErrorLog.connection.current_database rescue red_t("red.settings.values.unknown")
173
175
  status_badge = 'bg-info'
174
- status_text = "Shared DB"
176
+ status_text = red_t("red.settings.values.shared_db")
175
177
  end
176
178
  end
177
179
  %>
@@ -183,8 +185,8 @@
183
185
  rescue => e
184
186
  %>
185
187
  <div>
186
- <span class="badge bg-secondary fs-6">Unknown</span>
187
- <small class="text-muted d-block">Unable to detect</small>
188
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.unknown") %></span>
189
+ <small class="text-muted d-block"><%= red_t("red.settings.values.unable_to_detect") %></small>
188
190
  </div>
189
191
  <%
190
192
  end
@@ -201,18 +203,18 @@
201
203
  <code class="fs-6"><%= effective_value %></code>
202
204
  <% if is_auto_detected %>
203
205
  <small class="text-success d-block">
204
- <i class="bi bi-magic"></i> Auto-detected
206
+ <i class="bi bi-magic"></i> <%= red_t("red.settings.values.auto_detected") %>
205
207
  </small>
206
208
  <% else %>
207
- <small class="text-muted d-block">(Configured)</small>
209
+ <small class="text-muted d-block"><%= red_t("red.settings.values.configured") %></small>
208
210
  <% end %>
209
211
  </div>
210
212
  <%
211
213
  else
212
214
  %>
213
215
  <div>
214
- <span class="badge bg-secondary fs-6">Not found</span>
215
- <small class="text-muted d-block">No User model detected</small>
216
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_found") %></span>
217
+ <small class="text-muted d-block"><%= red_t("red.settings.values.no_user_model") %></small>
216
218
  </div>
217
219
  <%
218
220
  end
@@ -226,21 +228,23 @@
226
228
  if effective_value.present?
227
229
  %>
228
230
  <div>
229
- <span class="badge <%= is_auto_detected ? 'bg-success' : 'bg-info' %> fs-6"><%= number_with_delimiter(effective_value) %> users</span>
231
+ <span class="badge <%= is_auto_detected ? 'bg-success' : 'bg-info' %> fs-6"><%# count drives the plural form; the delimited number is what gets displayed,
232
+ so both are passed and the key interpolates %{formatted}. %>
233
+ <%= red_tp("red.settings.values.users", count: effective_value, formatted: number_with_delimiter(effective_value)) %></span>
230
234
  <% if is_auto_detected %>
231
235
  <small class="text-success d-block">
232
- <i class="bi bi-magic"></i> Auto-detected
236
+ <i class="bi bi-magic"></i> <%= red_t("red.settings.values.auto_detected") %>
233
237
  </small>
234
238
  <% else %>
235
- <small class="text-muted d-block">(Configured)</small>
239
+ <small class="text-muted d-block"><%= red_t("red.settings.values.configured") %></small>
236
240
  <% end %>
237
241
  </div>
238
242
  <%
239
243
  else
240
244
  %>
241
245
  <div>
242
- <span class="badge bg-secondary fs-6">Not available</span>
243
- <small class="text-muted d-block">Unable to query count</small>
246
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_available") %></span>
247
+ <small class="text-muted d-block"><%= red_t("red.settings.values.unable_to_query_count") %></small>
244
248
  </div>
245
249
  <%
246
250
  end
@@ -249,13 +253,13 @@
249
253
  if value.present?
250
254
  %>
251
255
  <span class="badge bg-success fs-6">
252
- <i class="bi bi-check-circle"></i> Set
256
+ <i class="bi bi-check-circle"></i> <%= red_t("red.settings.values.set") %>
253
257
  </span>
254
258
  <%
255
259
  else
256
260
  %>
257
261
  <span class="badge bg-warning text-dark fs-6">
258
- <i class="bi bi-exclamation-triangle"></i> Not set
262
+ <i class="bi bi-exclamation-triangle"></i> <%= red_t("red.settings.values.not_set") %>
259
263
  </span>
260
264
  <%
261
265
  end
@@ -265,22 +269,22 @@
265
269
  if value.present?
266
270
  %>
267
271
  <div>
268
- <span class="badge bg-warning text-dark fs-6"><%= value %> days</span>
272
+ <span class="badge bg-warning text-dark fs-6"><%= red_tp("red.settings.values.days", count: value) %></span>
269
273
  <small class="text-danger d-block">
270
- <i class="bi bi-exclamation-triangle"></i> Manual cleanup required
274
+ <i class="bi bi-exclamation-triangle"></i> <%= red_t("red.settings.values.manual_cleanup_required") %>
271
275
  </small>
272
276
  <small class="text-muted d-block mt-1">
273
- Run: <code class="small">rails error_dashboard:cleanup_resolved DAYS=<%= value %></code>
277
+ <%= red_t("red.settings.values.run_command") %> <code class="small">rails error_dashboard:cleanup_resolved DAYS=<%= value %></code>
274
278
  </small>
275
279
  </div>
276
280
  <%
277
281
  else
278
282
  %>
279
283
  <div>
280
- <span class="badge bg-success fs-6"><i class="bi bi-infinity"></i> Keep Forever</span>
281
- <small class="text-muted d-block">No automatic deletion</small>
284
+ <span class="badge bg-success fs-6"><i class="bi bi-infinity"></i> <%= red_t("red.settings.values.keep_forever") %></span>
285
+ <small class="text-muted d-block"><%= red_t("red.settings.values.no_automatic_deletion") %></small>
282
286
  <small class="text-muted d-block mt-1">
283
- To cleanup: <code class="small">rails error_dashboard:cleanup_resolved DAYS=90</code>
287
+ <%= red_t("red.settings.values.to_cleanup") %> <code class="small">rails error_dashboard:cleanup_resolved DAYS=90</code>
284
288
  </small>
285
289
  </div>
286
290
  <%
@@ -294,7 +298,7 @@
294
298
  <%
295
299
  else
296
300
  %>
297
- <span class="badge bg-secondary fs-6">Not set</span>
301
+ <span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
298
302
  <%
299
303
  end
300
304
  end