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
@@ -1,21 +1,21 @@
1
- <% content_for :page_title, "User Impact" %>
1
+ <% content_for :page_title, red_t("red.analytics.user_impact.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-people me-2"></i>
7
- User Impact
7
+ <%= red_t("red.analytics.user_impact.title") %>
8
8
  </h1>
9
9
 
10
10
  <div class="btn-group" role="group">
11
11
  <%= link_to user_impact_errors_path(days: 7), class: "btn btn-sm #{@days == 7 ? 'btn-primary' : 'btn-outline-primary'}" do %>
12
- 7 Days
12
+ <%= red_t("red.common.days_filter.7") %>
13
13
  <% end %>
14
14
  <%= link_to user_impact_errors_path(days: 30), class: "btn btn-sm #{@days == 30 ? 'btn-primary' : 'btn-outline-primary'}" do %>
15
- 30 Days
15
+ <%= red_t("red.common.days_filter.30") %>
16
16
  <% end %>
17
17
  <%= link_to user_impact_errors_path(days: 90), class: "btn btn-sm #{@days == 90 ? 'btn-primary' : 'btn-outline-primary'}" do %>
18
- 90 Days
18
+ <%= red_t("red.common.days_filter.90") %>
19
19
  <% end %>
20
20
  </div>
21
21
  </div>
@@ -23,17 +23,19 @@
23
23
  <% if @entries.empty? %>
24
24
  <div class="red-empty-state">
25
25
  <i class="bi bi-people display-1 text-muted mb-3"></i>
26
- <div class="red-empty-state-title">No User Impact Data</div>
26
+ <div class="red-empty-state-title"><%= red_t("red.analytics.user_impact.empty.title") %></div>
27
27
  <p class="text-muted">
28
- No errors with user attribution were found in the last <%= @days %> days.
28
+ <%= red_t("red.analytics.user_impact.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>How user impact is tracked:</h6>
32
+ <h6><%= red_t("red.analytics.user_impact.empty.how_tracked_title") %></h6>
33
33
  <ul class="mb-0">
34
- <li>Errors must have a <code>user_id</code> associated</li>
35
- <li>Auto-detected via <code>CurrentAttributes</code> or <code>current_user</code></li>
36
- <li>Or set <code>config.user_model = "User"</code> in your initializer</li>
34
+ <li><%= red_t("red.analytics.user_impact.empty.step_user_id_html", attribute: content_tag(:code, "user_id")) %></li>
35
+ <li><%= red_t("red.analytics.user_impact.empty.step_auto_html",
36
+ current_attributes: content_tag(:code, "CurrentAttributes"),
37
+ current_user: content_tag(:code, "current_user")) %></li>
38
+ <li><%= red_t("red.analytics.user_impact.empty.step_config_html", option: content_tag(:code, 'config.user_model = "User"')) %></li>
37
39
  </ul>
38
40
  </div>
39
41
  </div>
@@ -45,7 +47,7 @@
45
47
  <div class="card text-center">
46
48
  <div class="card-body">
47
49
  <div class="display-6 text-primary"><%= @summary[:total_error_types_with_users] %></div>
48
- <small class="text-muted">Error Types with Users</small>
50
+ <small class="text-muted"><%= red_t("red.analytics.user_impact.summary.error_types") %></small>
49
51
  </div>
50
52
  </div>
51
53
  </div>
@@ -53,23 +55,23 @@
53
55
  <div class="card text-center">
54
56
  <div class="card-body">
55
57
  <div class="display-6 text-danger"><%= @summary[:total_unique_users_affected] %></div>
56
- <small class="text-muted">Total Users Affected</small>
58
+ <small class="text-muted"><%= red_t("red.analytics.user_impact.summary.total_users_affected") %></small>
57
59
  </div>
58
60
  </div>
59
61
  </div>
60
62
  <div class="col-md-3">
61
63
  <div class="card text-center">
62
64
  <div class="card-body">
63
- <div class="display-6"><code><%= @summary[:most_impactful] || "N/A" %></code></div>
64
- <small class="text-muted">Most Impactful Error</small>
65
+ <div class="display-6"><code><%= @summary[:most_impactful] || red_t("red.common.not_available") %></code></div>
66
+ <small class="text-muted"><%= red_t("red.analytics.user_impact.summary.most_impactful") %></small>
65
67
  </div>
66
68
  </div>
67
69
  </div>
68
70
  <div class="col-md-3">
69
71
  <div class="card text-center">
70
72
  <div class="card-body">
71
- <div class="display-6 text-info"><%= @summary[:total_users] ? number_with_delimiter(@summary[:total_users]) : "N/A" %></div>
72
- <small class="text-muted">Total Users (for %)</small>
73
+ <div class="display-6 text-info"><%= @summary[:total_users] ? number_with_delimiter(@summary[:total_users]) : red_t("red.common.not_available") %></div>
74
+ <small class="text-muted"><%= red_t("red.analytics.user_impact.summary.total_users") %></small>
73
75
  </div>
74
76
  </div>
75
77
  </div>
@@ -80,7 +82,7 @@
80
82
  <div class="card-header d-flex justify-content-between align-items-center">
81
83
  <h5 class="mb-0">
82
84
  <i class="bi bi-bar-chart text-primary me-2"></i>
83
- Errors Ranked by User Impact
85
+ <%= red_t("red.analytics.user_impact.table.title") %>
84
86
  <span class="badge bg-primary"><%= @summary[:total_error_types_with_users] %></span>
85
87
  </h5>
86
88
  <small class="text-muted"><%== @pagy.info_tag %></small>
@@ -90,15 +92,15 @@
90
92
  <table class="table table-hover mb-0">
91
93
  <thead class="table-light">
92
94
  <tr>
93
- <th width="40">#</th>
94
- <th>Error Type</th>
95
- <th width="120">Unique Users</th>
96
- <th width="120">Occurrences</th>
95
+ <th width="40"><%= red_t("red.analytics.user_impact.table.column_rank") %></th>
96
+ <th><%= red_t("red.analytics.user_impact.table.column_error_type") %></th>
97
+ <th width="120"><%= red_t("red.analytics.user_impact.table.column_unique_users") %></th>
98
+ <th width="120"><%= red_t("red.analytics.user_impact.table.column_occurrences") %></th>
97
99
  <% if @summary[:total_users] %>
98
- <th width="150">User Impact %</th>
100
+ <th width="150"><%= red_t("red.analytics.user_impact.table.column_impact_percentage") %></th>
99
101
  <% end %>
100
- <th width="100">Severity</th>
101
- <th width="140">Last Seen</th>
102
+ <th width="100"><%= red_t("red.analytics.user_impact.table.column_severity") %></th>
103
+ <th width="140"><%= red_t("red.analytics.user_impact.table.column_last_seen") %></th>
102
104
  <th width="80"></th>
103
105
  </tr>
104
106
  </thead>
@@ -113,10 +115,10 @@
113
115
  <br><small class="text-muted"><%= entry[:message] %></small>
114
116
  </td>
115
117
  <td>
116
- <span class="badge bg-danger"><%= entry[:unique_users] %> users</span>
118
+ <span class="badge bg-danger"><%= red_tp("red.analytics.user_impact.table.users", count: entry[:unique_users]) %></span>
117
119
  </td>
118
120
  <td>
119
- <span class="badge bg-secondary"><%= entry[:total_occurrences] %>x</span>
121
+ <span class="badge bg-secondary"><%= red_tp("red.analytics.user_impact.table.occurrences", count: entry[:total_occurrences]) %></span>
120
122
  </td>
121
123
  <% if @summary[:total_users] && entry[:impact_percentage] %>
122
124
  <td>
@@ -143,7 +145,7 @@
143
145
  else "bg-secondary"
144
146
  end
145
147
  %>
146
- <span class="badge <%= sev_class %>"><%= sev.capitalize %></span>
148
+ <span class="badge <%= sev_class %>"><%= red_t("red.common.severity.#{sev}", default: sev) %></span>
147
149
  </td>
148
150
  <td><small><%= local_time_ago(entry[:last_seen]) %></small></td>
149
151
  <td>
@@ -162,8 +164,7 @@
162
164
  <div class="card-footer border-top d-flex justify-content-between align-items-center">
163
165
  <small class="text-muted">
164
166
  <i class="bi bi-info-circle"></i>
165
- Ranked by unique users affected, not occurrence count.
166
- An error hitting 1000 users once is worse than hitting 1 user 1000 times.
167
+ <%= red_t("red.analytics.user_impact.table.footer") %>
167
168
  </small>
168
169
  <div>
169
170
  <%== @pagy.series_nav(:bootstrap) if @pagy.pages > 1 %>