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,21 +1,21 @@
|
|
|
1
1
|
<!-- Metadata Card -->
|
|
2
2
|
<div class="card mb-4">
|
|
3
3
|
<div class="card-header">
|
|
4
|
-
<h5 class="mb-0"><i class="bi bi-info-circle"></i>
|
|
4
|
+
<h5 class="mb-0"><i class="bi bi-info-circle"></i> <%= red_t("red.errors.sidebar.title") %></h5>
|
|
5
5
|
</div>
|
|
6
6
|
<div class="card-body">
|
|
7
7
|
<div class="mb-3">
|
|
8
|
-
<small class="metadata-label d-block mb-1"
|
|
8
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.occurrence_count") %></small>
|
|
9
9
|
<span class="badge bg-primary fs-5"><%= error.occurrence_count %>x</span>
|
|
10
10
|
<% if error.occurrence_count > 1 %>
|
|
11
|
-
<br><small class="text-muted"
|
|
11
|
+
<br><small class="text-muted"><%= red_tp("red.errors.sidebar.occurred_times", count: error.occurrence_count) %></small>
|
|
12
12
|
<% end %>
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
15
|
<div class="mb-3">
|
|
16
|
-
<small class="metadata-label d-block mb-1"
|
|
16
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.first_seen") %></small>
|
|
17
17
|
<% if related_errors.any? %>
|
|
18
|
-
<%= link_to "#section-timeline", class: "text-decoration-none", data: { bs_toggle: "tooltip" }, title: "
|
|
18
|
+
<%= link_to "#section-timeline", class: "text-decoration-none", data: { bs_toggle: "tooltip" }, title: red_t("red.errors.sidebar.jump_to_timeline") do %>
|
|
19
19
|
<strong><%= local_time(error.first_seen_at, format: :date_only) %></strong><br>
|
|
20
20
|
<small><%= local_time(error.first_seen_at, format: :time_only) %></small>
|
|
21
21
|
<i class="bi bi-arrow-down-circle ms-1"></i>
|
|
@@ -27,31 +27,34 @@
|
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
29
|
<div class="mb-3">
|
|
30
|
-
<small class="metadata-label d-block mb-1"
|
|
30
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.last_seen") %></small>
|
|
31
31
|
<strong><%= local_time(error.last_seen_at, format: :date_only) %></strong><br>
|
|
32
32
|
<small><%= local_time(error.last_seen_at, format: :time_only) %></small>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
35
35
|
<div class="mb-3">
|
|
36
|
-
<small class="metadata-label d-block mb-1"
|
|
37
|
-
<%
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.severity_level") %></small>
|
|
37
|
+
<%
|
|
38
|
+
severity = error.severity
|
|
39
|
+
# The badge class stays keyed on the machine value; only the label
|
|
40
|
+
# is translated. An unknown severity keeps the old "else" branch's
|
|
41
|
+
# secondary badge rather than falling through to nothing.
|
|
42
|
+
severity_badge_class = case severity
|
|
43
|
+
when :critical then "bg-danger"
|
|
44
|
+
when :high then "bg-warning text-dark"
|
|
45
|
+
when :medium then "bg-info text-dark"
|
|
46
|
+
else "bg-secondary"
|
|
47
|
+
end
|
|
48
|
+
%>
|
|
49
|
+
<%= link_to errors_path(severity: severity, unresolved: '0'), class: "text-decoration-none", title: red_t("red.errors.sidebar.view_all_severity", severity: red_t("red.common.severity.#{severity}", default: severity.to_s)) do %>
|
|
50
|
+
<span class="badge <%= severity_badge_class %> fs-6"><%= red_t("red.errors.sidebar.severity_badges.#{severity}", default: severity.to_s.upcase) %></span>
|
|
48
51
|
<% end %>
|
|
49
52
|
</div>
|
|
50
53
|
|
|
51
54
|
<div class="mb-3">
|
|
52
|
-
<small class="metadata-label d-block mb-1"
|
|
55
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.platform") %></small>
|
|
53
56
|
<% if error.platform.present? %>
|
|
54
|
-
<%= link_to errors_path(platform: error.platform, unresolved: '0'), class: "text-decoration-none", title: "
|
|
57
|
+
<%= link_to errors_path(platform: error.platform, unresolved: '0'), class: "text-decoration-none", title: red_t("red.errors.sidebar.view_all_platform", platform: error.platform) do %>
|
|
55
58
|
<% if error.platform == 'iOS' %>
|
|
56
59
|
<span class="badge badge-ios"><i class="bi bi-apple"></i> iOS</span>
|
|
57
60
|
<% elsif error.platform == 'Android' %>
|
|
@@ -68,18 +71,18 @@
|
|
|
68
71
|
</div>
|
|
69
72
|
|
|
70
73
|
<div class="mb-3">
|
|
71
|
-
<small class="metadata-label d-block mb-1"
|
|
74
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.user") %></small>
|
|
72
75
|
<% if error.respond_to?(:user) && error.user %>
|
|
73
|
-
<%= link_to errors_path(user_id: error.user_id, unresolved: '0'), class: "text-decoration-none", title: "
|
|
76
|
+
<%= link_to errors_path(user_id: error.user_id, unresolved: '0'), class: "text-decoration-none", title: red_t("red.errors.sidebar.view_user_errors") do %>
|
|
74
77
|
<strong><%= error.user.email %></strong><br>
|
|
75
|
-
<small class="text-muted"
|
|
78
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.user_id", id: error.user_id) %></small>
|
|
76
79
|
<% end %>
|
|
77
80
|
<% elsif error.user_id %>
|
|
78
|
-
<%= link_to errors_path(user_id: error.user_id, unresolved: '0'), class: "text-decoration-none text-muted", title: "
|
|
79
|
-
|
|
81
|
+
<%= link_to errors_path(user_id: error.user_id, unresolved: '0'), class: "text-decoration-none text-muted", title: red_t("red.errors.sidebar.view_user_errors") do %>
|
|
82
|
+
<%= red_t("red.errors.sidebar.user_id_label", id: error.user_id) %>
|
|
80
83
|
<% end %>
|
|
81
84
|
<% else %>
|
|
82
|
-
<span class="text-muted"
|
|
85
|
+
<span class="text-muted"><%= red_t("red.errors.sidebar.guest") %></span>
|
|
83
86
|
<% end %>
|
|
84
87
|
</div>
|
|
85
88
|
|
|
@@ -87,11 +90,21 @@
|
|
|
87
90
|
<div class="mb-3">
|
|
88
91
|
<small class="text-muted" style="font-size: 0.78em;">
|
|
89
92
|
<i class="bi bi-info-circle me-1"></i>
|
|
90
|
-
|
|
93
|
+
<%# Two whole sentences, not a shared stem plus two endings: the
|
|
94
|
+
link's position in the sentence is not the same in every
|
|
95
|
+
language.
|
|
96
|
+
|
|
97
|
+
The <a> is built here rather than living in the key. The key
|
|
98
|
+
is _html and therefore html_safe, so a raw URL interpolated
|
|
99
|
+
into an href inside it would not be escaped and a crafted
|
|
100
|
+
external_issue_url could inject an event handler. link_to
|
|
101
|
+
escapes the URL. %>
|
|
91
102
|
<% if error.respond_to?(:external_issue_url) && error.external_issue_url.present? %>
|
|
92
|
-
|
|
103
|
+
<%= red_t("red.errors.sidebar.issue_tracking_linked_html",
|
|
104
|
+
link: link_to(red_t("red.errors.sidebar.issue_tracking_link_text"),
|
|
105
|
+
error.external_issue_url, target: "_blank", rel: "noopener")) %>
|
|
93
106
|
<% else %>
|
|
94
|
-
|
|
107
|
+
<%= red_t("red.errors.sidebar.issue_tracking_unlinked") %>
|
|
95
108
|
<% end %>
|
|
96
109
|
</small>
|
|
97
110
|
</div>
|
|
@@ -99,16 +112,19 @@
|
|
|
99
112
|
<% unless RailsErrorDashboard.configuration.enable_issue_tracking %>
|
|
100
113
|
<!-- Workflow Status -->
|
|
101
114
|
<div class="mb-3">
|
|
102
|
-
<small class="metadata-label d-block mb-1"
|
|
115
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.workflow_status") %></small>
|
|
103
116
|
<% if error.respond_to?(:status) %>
|
|
104
117
|
<% badge_color = error.status_badge_color %>
|
|
105
118
|
<% text_dark = %w[info warning light].include?(badge_color) ? 'text-dark' : '' %>
|
|
106
119
|
<span class="badge bg-<%= badge_color %> <%= text_dark %> fs-6">
|
|
107
|
-
|
|
120
|
+
<%# titleize would apply English morphology to a machine value
|
|
121
|
+
("in_progress" -> "In Progress"). The status labels are the
|
|
122
|
+
ones the index and show pages already read. %>
|
|
123
|
+
<%= red_t("red.errors.row.status.#{error.status}", default: error.status.to_s.tr('_', ' ')) %>
|
|
108
124
|
</span>
|
|
109
125
|
<% elsif error.resolved? %>
|
|
110
126
|
<span class="badge bg-success">
|
|
111
|
-
<i class="bi bi-check-circle"></i>
|
|
127
|
+
<i class="bi bi-check-circle"></i> <%= red_t("red.errors.sidebar.resolved") %>
|
|
112
128
|
</span>
|
|
113
129
|
<% if error.resolved_at.present? %>
|
|
114
130
|
<br>
|
|
@@ -118,7 +134,7 @@
|
|
|
118
134
|
<% end %>
|
|
119
135
|
<% else %>
|
|
120
136
|
<span class="badge bg-danger">
|
|
121
|
-
<i class="bi bi-exclamation-circle"></i>
|
|
137
|
+
<i class="bi bi-exclamation-circle"></i> <%= red_t("red.errors.sidebar.unresolved") %>
|
|
122
138
|
</span>
|
|
123
139
|
<% end %>
|
|
124
140
|
</div>
|
|
@@ -126,9 +142,9 @@
|
|
|
126
142
|
<!-- Reopened indicator -->
|
|
127
143
|
<% if error.reopened? %>
|
|
128
144
|
<div class="mb-3">
|
|
129
|
-
<small class="metadata-label d-block mb-1"
|
|
145
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.reopened") %></small>
|
|
130
146
|
<span class="badge bg-warning text-dark">
|
|
131
|
-
<i class="bi bi-arrow-counterclockwise"></i>
|
|
147
|
+
<i class="bi bi-arrow-counterclockwise"></i> <%= red_t("red.errors.sidebar.reopened") %>
|
|
132
148
|
</span>
|
|
133
149
|
<br>
|
|
134
150
|
<small class="text-muted mt-1 d-block">
|
|
@@ -140,7 +156,7 @@
|
|
|
140
156
|
<!-- Assignment -->
|
|
141
157
|
<% if error.respond_to?(:assigned_to) %>
|
|
142
158
|
<div class="mb-3">
|
|
143
|
-
<small class="metadata-label d-block mb-1"
|
|
159
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.assigned_to") %></small>
|
|
144
160
|
<% if error.assigned? %>
|
|
145
161
|
<div class="d-flex align-items-center justify-content-between">
|
|
146
162
|
<div>
|
|
@@ -154,20 +170,22 @@
|
|
|
154
170
|
<% end %>
|
|
155
171
|
</div>
|
|
156
172
|
<%= button_to unassign_error_path(error), method: :post, class: "btn btn-sm btn-outline-secondary",
|
|
157
|
-
data: { turbo_confirm: "
|
|
173
|
+
data: { turbo_confirm: red_t("red.errors.sidebar.remove_assignment") } do %>
|
|
158
174
|
<i class="bi bi-x"></i>
|
|
159
175
|
<% end %>
|
|
160
176
|
</div>
|
|
161
177
|
<% else %>
|
|
162
178
|
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#assignModal">
|
|
163
|
-
<i class="bi bi-person-plus"></i>
|
|
179
|
+
<i class="bi bi-person-plus"></i> <%= red_t("red.errors.sidebar.assign") %>
|
|
164
180
|
</button>
|
|
165
181
|
<% end %>
|
|
166
182
|
</div>
|
|
167
183
|
|
|
168
184
|
<!-- Priority -->
|
|
169
185
|
<div class="mb-3">
|
|
170
|
-
|
|
186
|
+
<%# error.priority_label comes from PRIORITY_LEVELS in the model,
|
|
187
|
+
which P2-T11 covers; only the field label is extracted here. %>
|
|
188
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.priority") %></small>
|
|
171
189
|
<% if error.respond_to?(:priority_level) %>
|
|
172
190
|
<span class="badge bg-<%= error.priority_color %> fs-6">
|
|
173
191
|
<%= error.priority_label %>
|
|
@@ -183,19 +201,19 @@
|
|
|
183
201
|
<!-- Snooze (always visible — no platform equivalent) -->
|
|
184
202
|
<% if error.respond_to?(:assigned_to) %>
|
|
185
203
|
<div class="mb-3">
|
|
186
|
-
<small class="metadata-label d-block mb-1"
|
|
204
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.snooze") %></small>
|
|
187
205
|
<% if error.respond_to?(:snoozed?) && error.snoozed? %>
|
|
188
206
|
<div class="alert alert-warning py-2 mb-2">
|
|
189
207
|
<i class="bi bi-alarm"></i>
|
|
190
|
-
<strong
|
|
191
|
-
<small
|
|
208
|
+
<strong><%= red_t("red.errors.sidebar.snoozed") %></strong><br>
|
|
209
|
+
<small><%= red_t("red.errors.sidebar.snoozed_until_html", time: local_time(error.snoozed_until, format: :datetime)) %></small>
|
|
192
210
|
</div>
|
|
193
211
|
<%= button_to unsnooze_error_path(error), method: :post, class: "btn btn-sm btn-outline-warning" do %>
|
|
194
|
-
<i class="bi bi-alarm-fill"></i>
|
|
212
|
+
<i class="bi bi-alarm-fill"></i> <%= red_t("red.errors.sidebar.unsnooze") %>
|
|
195
213
|
<% end %>
|
|
196
214
|
<% else %>
|
|
197
215
|
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#snoozeModal">
|
|
198
|
-
<i class="bi bi-alarm"></i>
|
|
216
|
+
<i class="bi bi-alarm"></i> <%= red_t("red.errors.sidebar.snooze") %>
|
|
199
217
|
</button>
|
|
200
218
|
<% end %>
|
|
201
219
|
</div>
|
|
@@ -204,27 +222,27 @@
|
|
|
204
222
|
<!-- Mute Notifications -->
|
|
205
223
|
<% if error.respond_to?(:muted?) %>
|
|
206
224
|
<div class="mb-3">
|
|
207
|
-
<small class="metadata-label d-block mb-1"
|
|
225
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.notifications") %></small>
|
|
208
226
|
<% if error.muted? %>
|
|
209
227
|
<div class="alert alert-secondary py-2 mb-2">
|
|
210
228
|
<i class="bi bi-bell-slash"></i>
|
|
211
|
-
<strong
|
|
229
|
+
<strong><%= red_t("red.errors.sidebar.muted") %></strong><br>
|
|
212
230
|
<% if error.muted_by.present? %>
|
|
213
|
-
<small
|
|
231
|
+
<small><%= red_t("red.errors.sidebar.muted_by", name: error.muted_by) %></small><br>
|
|
214
232
|
<% end %>
|
|
215
233
|
<% if error.muted_reason.present? %>
|
|
216
234
|
<small><em><%= error.muted_reason %></em></small><br>
|
|
217
235
|
<% end %>
|
|
218
236
|
<% if error.muted_at.present? %>
|
|
219
|
-
<small
|
|
237
|
+
<small><%= red_t("red.errors.sidebar.muted_since_html", time: local_time(error.muted_at, format: :short)) %></small>
|
|
220
238
|
<% end %>
|
|
221
239
|
</div>
|
|
222
240
|
<%= button_to unmute_error_path(error), method: :post, class: "btn btn-sm btn-outline-primary" do %>
|
|
223
|
-
<i class="bi bi-bell"></i>
|
|
241
|
+
<i class="bi bi-bell"></i> <%= red_t("red.errors.sidebar.unmute") %>
|
|
224
242
|
<% end %>
|
|
225
243
|
<% else %>
|
|
226
244
|
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#muteModal">
|
|
227
|
-
<i class="bi bi-bell-slash"></i>
|
|
245
|
+
<i class="bi bi-bell-slash"></i> <%= red_t("red.errors.sidebar.mute") %>
|
|
228
246
|
</button>
|
|
229
247
|
<% end %>
|
|
230
248
|
</div>
|
|
@@ -232,21 +250,21 @@
|
|
|
232
250
|
|
|
233
251
|
<% if error.resolved? && error.resolved_by_name.present? %>
|
|
234
252
|
<div class="mb-3">
|
|
235
|
-
<small class="metadata-label d-block mb-1"
|
|
253
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.resolved_by") %></small>
|
|
236
254
|
<strong><%= error.resolved_by_name %></strong>
|
|
237
255
|
</div>
|
|
238
256
|
<% end %>
|
|
239
257
|
|
|
240
258
|
<% if error.resolved? && error.resolution_reference.present? %>
|
|
241
259
|
<div class="mb-3">
|
|
242
|
-
<small class="metadata-label d-block mb-1"
|
|
260
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.reference") %></small>
|
|
243
261
|
<code><%= error.resolution_reference %></code>
|
|
244
262
|
</div>
|
|
245
263
|
<% end %>
|
|
246
264
|
|
|
247
265
|
<% if error.resolved? && error.resolution_comment.present? %>
|
|
248
266
|
<div class="mb-3">
|
|
249
|
-
<small class="metadata-label d-block mb-1"
|
|
267
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.resolution_notes") %></small>
|
|
250
268
|
<div class="alert alert-success mb-0">
|
|
251
269
|
<%= auto_link_urls(error.resolution_comment, error: error).html_safe %>
|
|
252
270
|
</div>
|
|
@@ -255,13 +273,13 @@
|
|
|
255
273
|
|
|
256
274
|
<!-- Environment Information -->
|
|
257
275
|
<div class="sidebar-section sidebar-section-blue">
|
|
258
|
-
<div class="sidebar-section-title"><i class="bi bi-gear"></i>
|
|
259
|
-
<small class="sidebar-section-hint"
|
|
276
|
+
<div class="sidebar-section-title"><i class="bi bi-gear"></i> <%= red_t("red.errors.sidebar.environment.title") %></div>
|
|
277
|
+
<small class="sidebar-section-hint"><%= red_t("red.errors.sidebar.environment.hint") %></small>
|
|
260
278
|
<div class="sidebar-section-body">
|
|
261
279
|
<% if error.app_version.present? %>
|
|
262
280
|
<div class="mb-1">
|
|
263
|
-
<small class="text-muted"
|
|
264
|
-
<%= link_to errors_path(app_version: error.app_version, unresolved: '0'), class: "ms-1 text-decoration-none", title: "
|
|
281
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.environment.app_version") %></small>
|
|
282
|
+
<%= link_to errors_path(app_version: error.app_version, unresolved: '0'), class: "ms-1 text-decoration-none", title: red_t("red.errors.sidebar.environment.view_all_version", version: error.app_version) do %>
|
|
265
283
|
<code><%= error.app_version %></code>
|
|
266
284
|
<% end %>
|
|
267
285
|
</div>
|
|
@@ -269,7 +287,7 @@
|
|
|
269
287
|
|
|
270
288
|
<% if error.git_sha.present? %>
|
|
271
289
|
<div class="mb-1">
|
|
272
|
-
<small class="text-muted"
|
|
290
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.environment.git_sha") %></small>
|
|
273
291
|
<span class="ms-1"><%= git_commit_link(error.git_sha) %></span>
|
|
274
292
|
</div>
|
|
275
293
|
<% end %>
|
|
@@ -278,40 +296,47 @@
|
|
|
278
296
|
JSON.parse(error.environment_info, symbolize_names: true) : nil rescue nil %>
|
|
279
297
|
|
|
280
298
|
<div class="mb-1">
|
|
281
|
-
<small class="text-muted"
|
|
299
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.environment.rails") %></small>
|
|
282
300
|
<code class="ms-1"><%= env_info&.dig(:rails_version) || Rails.version %></code>
|
|
283
301
|
</div>
|
|
284
302
|
|
|
285
303
|
<div class="mb-1">
|
|
286
|
-
<small class="text-muted"
|
|
304
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.environment.ruby") %></small>
|
|
287
305
|
<code class="ms-1"><%= env_info&.dig(:ruby_version) || RUBY_VERSION %></code>
|
|
288
306
|
</div>
|
|
289
307
|
|
|
290
308
|
<div class="mb-1">
|
|
291
|
-
<small class="text-muted"
|
|
309
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.environment.environment") %></small>
|
|
292
310
|
<% env_name = env_info&.dig(:rails_env) || Rails.env.to_s %>
|
|
293
311
|
<span class="badge bg-<%= env_name == 'production' ? 'danger' : env_name == 'development' ? 'success' : 'warning' %> ms-1">
|
|
294
|
-
|
|
312
|
+
<%# A Rails environment name is a machine value the host app
|
|
313
|
+
chooses ("production", "staging_eu"). titleize applied
|
|
314
|
+
English morphology to it; it is shown verbatim instead.
|
|
315
|
+
The badge is text-transform: uppercase either way. %>
|
|
316
|
+
<%= env_name %>
|
|
295
317
|
</span>
|
|
296
318
|
</div>
|
|
297
319
|
|
|
298
320
|
<% if env_info&.dig(:server).present? && env_info[:server] != "unknown" %>
|
|
299
321
|
<div class="mb-1">
|
|
300
|
-
<small class="text-muted"
|
|
322
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.environment.server") %></small>
|
|
323
|
+
<%# A server name (puma, unicorn, passenger) is a product name
|
|
324
|
+
and stays English. capitalize is kept: it is cosmetic on a
|
|
325
|
+
known-ASCII value, not morphology applied to prose. %>
|
|
301
326
|
<code class="ms-1"><%= env_info[:server].capitalize %></code>
|
|
302
327
|
</div>
|
|
303
328
|
<% end %>
|
|
304
329
|
|
|
305
330
|
<% if env_info&.dig(:database_adapter).present? && env_info[:database_adapter] != "unknown" %>
|
|
306
331
|
<div class="mb-1">
|
|
307
|
-
<small class="text-muted"
|
|
332
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.environment.database") %></small>
|
|
308
333
|
<code class="ms-1"><%= env_info[:database_adapter] %></code>
|
|
309
334
|
</div>
|
|
310
335
|
<% end %>
|
|
311
336
|
|
|
312
337
|
<% if env_info&.dig(:gem_versions)&.any? %>
|
|
313
338
|
<div class="mb-1">
|
|
314
|
-
<small class="text-muted d-block"
|
|
339
|
+
<small class="text-muted d-block"><%= red_t("red.errors.sidebar.environment.key_gems") %></small>
|
|
315
340
|
<div class="ps-2">
|
|
316
341
|
<% env_info[:gem_versions].each do |name, version| %>
|
|
317
342
|
<small><code><%= name %> <%= version %></code></small><br>
|
|
@@ -327,13 +352,13 @@
|
|
|
327
352
|
<% health = begin; JSON.parse(error.system_health, symbolize_names: true); rescue; nil; end %>
|
|
328
353
|
<% if health %>
|
|
329
354
|
<div class="sidebar-section sidebar-section-red">
|
|
330
|
-
<div class="sidebar-section-title"><i class="bi bi-heart-pulse"></i>
|
|
331
|
-
<small class="sidebar-section-hint"
|
|
355
|
+
<div class="sidebar-section-title"><i class="bi bi-heart-pulse"></i> <%= red_t("red.errors.sidebar.health.title") %></div>
|
|
356
|
+
<small class="sidebar-section-hint"><%= red_t("red.errors.sidebar.health.hint") %></small>
|
|
332
357
|
<div class="sidebar-section-body">
|
|
333
358
|
<% if health[:process_memory] %>
|
|
334
359
|
<% pm = health[:process_memory] %>
|
|
335
360
|
<div class="mb-1">
|
|
336
|
-
<small class="text-muted"
|
|
361
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.memory_rss") %></small>
|
|
337
362
|
<% mem = pm[:rss_mb].to_f %>
|
|
338
363
|
<code class="ms-1 text-<%= mem > 1024 ? 'danger' : mem > 512 ? 'warning' : 'success' %>">
|
|
339
364
|
<%= mem %> MB
|
|
@@ -341,28 +366,28 @@
|
|
|
341
366
|
</div>
|
|
342
367
|
<% if pm[:swap_mb].to_f > 0 %>
|
|
343
368
|
<div class="mb-1">
|
|
344
|
-
<small class="text-muted"
|
|
369
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.process_swap") %></small>
|
|
345
370
|
<code class="ms-1 text-danger"><%= pm[:swap_mb] %> MB</code>
|
|
346
371
|
</div>
|
|
347
372
|
<% end %>
|
|
348
373
|
<% if pm[:rss_peak_mb] %>
|
|
349
374
|
<div class="mb-1">
|
|
350
|
-
<small class="text-muted"
|
|
375
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.peak_rss") %></small>
|
|
351
376
|
<code class="ms-1"><%= pm[:rss_peak_mb] %> MB</code>
|
|
352
377
|
</div>
|
|
353
378
|
<% end %>
|
|
354
379
|
<% if pm[:os_threads] %>
|
|
355
380
|
<div class="mb-1">
|
|
356
|
-
<small class="text-muted"
|
|
381
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.os_threads") %></small>
|
|
357
382
|
<code class="ms-1"><%= pm[:os_threads] %></code>
|
|
358
383
|
<% if health[:thread_count] %>
|
|
359
|
-
<small class="text-muted ms-1"
|
|
384
|
+
<small class="text-muted ms-1"><%= red_t("red.errors.sidebar.health.ruby_threads", count: health[:thread_count]) %></small>
|
|
360
385
|
<% end %>
|
|
361
386
|
</div>
|
|
362
387
|
<% end %>
|
|
363
388
|
<% elsif health[:process_memory_mb] %>
|
|
364
389
|
<div class="mb-1">
|
|
365
|
-
<small class="text-muted"
|
|
390
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.memory_rss") %></small>
|
|
366
391
|
<% mem = health[:process_memory_mb].to_f %>
|
|
367
392
|
<code class="ms-1 text-<%= mem > 1024 ? 'danger' : mem > 512 ? 'warning' : 'success' %>">
|
|
368
393
|
<%= mem %> MB
|
|
@@ -370,7 +395,7 @@
|
|
|
370
395
|
</div>
|
|
371
396
|
<% if health[:thread_count] %>
|
|
372
397
|
<div class="mb-1">
|
|
373
|
-
<small class="text-muted"
|
|
398
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.threads") %></small>
|
|
374
399
|
<code class="ms-1"><%= health[:thread_count] %></code>
|
|
375
400
|
</div>
|
|
376
401
|
<% end %>
|
|
@@ -379,7 +404,7 @@
|
|
|
379
404
|
<% if health[:file_descriptors] %>
|
|
380
405
|
<% fd = health[:file_descriptors] %>
|
|
381
406
|
<div class="mb-1">
|
|
382
|
-
<small class="text-muted"
|
|
407
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.file_descriptors") %></small>
|
|
383
408
|
<% fd_pct = fd[:utilization_pct].to_f %>
|
|
384
409
|
<code class="ms-1 text-<%= fd_pct > 80 ? 'danger' : fd_pct > 60 ? 'warning' : 'success' %>">
|
|
385
410
|
<%= fd[:open] %> / <%= fd[:limit] %> (<%= fd_pct %>%)
|
|
@@ -390,7 +415,7 @@
|
|
|
390
415
|
<% if health[:system_load] %>
|
|
391
416
|
<% sl = health[:system_load] %>
|
|
392
417
|
<div class="mb-1">
|
|
393
|
-
<small class="text-muted"
|
|
418
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.load_average") %></small>
|
|
394
419
|
<% lr = sl[:load_ratio].to_f %>
|
|
395
420
|
<code class="ms-1 text-<%= lr > 2.0 ? 'danger' : lr > 1.0 ? 'warning' : 'success' %>">
|
|
396
421
|
<%= sl[:load_1m] %><% if sl[:cpu_count] %> / <%= sl[:cpu_count] %> CPUs<% end %>
|
|
@@ -402,7 +427,7 @@
|
|
|
402
427
|
<% if health[:system_memory] %>
|
|
403
428
|
<% sm = health[:system_memory] %>
|
|
404
429
|
<div class="mb-1">
|
|
405
|
-
<small class="text-muted"
|
|
430
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.system_memory") %></small>
|
|
406
431
|
<% used_pct = sm[:used_pct].to_f %>
|
|
407
432
|
<code class="ms-1 text-<%= used_pct > 90 ? 'danger' : used_pct > 80 ? 'warning' : 'success' %>">
|
|
408
433
|
<%= sm[:available_mb] %> MB free / <%= sm[:total_mb] %> MB (<%= used_pct %>% used)
|
|
@@ -410,7 +435,7 @@
|
|
|
410
435
|
</div>
|
|
411
436
|
<% if sm[:swap_used_mb].to_i > 0 %>
|
|
412
437
|
<div class="mb-1">
|
|
413
|
-
<small class="text-muted"
|
|
438
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.system_swap") %></small>
|
|
414
439
|
<code class="ms-1 text-danger"><%= sm[:swap_used_mb] %> MB used</code>
|
|
415
440
|
</div>
|
|
416
441
|
<% end %>
|
|
@@ -419,7 +444,7 @@
|
|
|
419
444
|
<% if health[:tcp_connections] %>
|
|
420
445
|
<% tcp = health[:tcp_connections] %>
|
|
421
446
|
<div class="mb-1">
|
|
422
|
-
<small class="text-muted"
|
|
447
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.tcp_connections") %></small>
|
|
423
448
|
<code class="ms-1">
|
|
424
449
|
<%= tcp[:established] %> established<% if tcp[:close_wait].to_i > 0 %>, <span class="text-danger"><%= tcp[:close_wait] %> close_wait</span><% end %><% if tcp[:time_wait].to_i > 0 %>, <span class="text-warning"><%= tcp[:time_wait] %> time_wait</span><% end %>
|
|
425
450
|
</code>
|
|
@@ -428,11 +453,11 @@
|
|
|
428
453
|
|
|
429
454
|
<% if health[:gc] %>
|
|
430
455
|
<div class="mb-1">
|
|
431
|
-
<small class="text-muted"
|
|
456
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.gc_live_objects") %></small>
|
|
432
457
|
<code class="ms-1"><%= begin; number_with_delimiter(health[:gc][:heap_live_slots]); rescue; health[:gc][:heap_live_slots]; end %></code>
|
|
433
458
|
</div>
|
|
434
459
|
<div class="mb-1">
|
|
435
|
-
<small class="text-muted"
|
|
460
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.major_gc_runs") %></small>
|
|
436
461
|
<code class="ms-1"><%= health[:gc][:major_gc_count] %></code>
|
|
437
462
|
</div>
|
|
438
463
|
<% end %>
|
|
@@ -440,7 +465,7 @@
|
|
|
440
465
|
<% if health[:gc_latest] %>
|
|
441
466
|
<% gcl = health[:gc_latest] %>
|
|
442
467
|
<div class="mb-1">
|
|
443
|
-
<small class="text-muted"
|
|
468
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.last_gc") %></small>
|
|
444
469
|
<code class="ms-1">
|
|
445
470
|
<%= gcl[:major_by] ? "major (#{gcl[:major_by]})" : "minor" %> by <%= gcl[:gc_by] %><% if gcl[:state].to_s != "none" %>, <span class="text-warning">state: <%= gcl[:state] %></span><% end %>
|
|
446
471
|
</code>
|
|
@@ -450,7 +475,7 @@
|
|
|
450
475
|
<% if health[:connection_pool] %>
|
|
451
476
|
<% cp = health[:connection_pool] %>
|
|
452
477
|
<div class="mb-1">
|
|
453
|
-
<small class="text-muted"
|
|
478
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.connection_pool") %></small>
|
|
454
479
|
<code class="ms-1">
|
|
455
480
|
<%= cp[:busy] %>/<%= cp[:size] %> busy, <%= cp[:idle] %> idle<% if cp[:dead].to_i > 0 %>, <span class="text-danger"><%= cp[:dead] %> dead</span><% end %><% if cp[:waiting].to_i > 0 %>, <span class="text-warning"><%= cp[:waiting] %> waiting</span><% end %>
|
|
456
481
|
</code>
|
|
@@ -460,7 +485,7 @@
|
|
|
460
485
|
<% if health[:puma] %>
|
|
461
486
|
<% ps = health[:puma] %>
|
|
462
487
|
<div class="mb-1">
|
|
463
|
-
<small class="text-muted"
|
|
488
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.puma_threads") %></small>
|
|
464
489
|
<code class="ms-1">
|
|
465
490
|
<%= ps[:running] %>/<%= ps[:max_threads] %> running, <%= ps[:pool_capacity] %> capacity<% if ps[:backlog].to_i > 0 %>, <span class="text-warning"><%= ps[:backlog] %> backlog</span><% end %>
|
|
466
491
|
</code>
|
|
@@ -487,17 +512,17 @@
|
|
|
487
512
|
<% if health[:ruby_vm] %>
|
|
488
513
|
<% vm = health[:ruby_vm] %>
|
|
489
514
|
<div class="mb-1">
|
|
490
|
-
<small class="text-muted"
|
|
515
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.vm_cache_invalidations") %></small>
|
|
491
516
|
<% invals = vm[:constant_cache_invalidations].to_i %>
|
|
492
517
|
<code class="ms-1 <%= 'text-danger' if invals > 10_000 %>"><%= begin; number_with_delimiter(invals); rescue; invals; end %></code>
|
|
493
518
|
</div>
|
|
494
519
|
<div class="mb-1">
|
|
495
|
-
<small class="text-muted"
|
|
520
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.vm_cache_misses") %></small>
|
|
496
521
|
<code class="ms-1"><%= begin; number_with_delimiter(vm[:constant_cache_misses]); rescue; vm[:constant_cache_misses]; end %></code>
|
|
497
522
|
</div>
|
|
498
523
|
<% if vm[:shape_cache_size] %>
|
|
499
524
|
<div class="mb-1">
|
|
500
|
-
<small class="text-muted"
|
|
525
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.shape_cache_size") %></small>
|
|
501
526
|
<code class="ms-1"><%= begin; number_with_delimiter(vm[:shape_cache_size]); rescue; vm[:shape_cache_size]; end %></code>
|
|
502
527
|
</div>
|
|
503
528
|
<% end %>
|
|
@@ -507,26 +532,26 @@
|
|
|
507
532
|
<% yj = health[:yjit] %>
|
|
508
533
|
<% if yj[:compiled_iseq_count] || yj[:compiled_block_count] %>
|
|
509
534
|
<div class="mb-1">
|
|
510
|
-
<small class="text-muted"
|
|
535
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.yjit_compiled") %></small>
|
|
511
536
|
<code class="ms-1"><%= yj[:compiled_iseq_count] %> iseqs / <%= yj[:compiled_block_count] %> blocks</code>
|
|
512
537
|
</div>
|
|
513
538
|
<% end %>
|
|
514
539
|
<% if yj[:invalidation_count] %>
|
|
515
540
|
<div class="mb-1">
|
|
516
|
-
<small class="text-muted"
|
|
541
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.yjit_invalidations") %></small>
|
|
517
542
|
<% yj_invals = yj[:invalidation_count].to_i %>
|
|
518
543
|
<code class="ms-1 <%= 'text-danger' if yj_invals > 100 %>"><%= yj_invals %></code>
|
|
519
544
|
</div>
|
|
520
545
|
<% end %>
|
|
521
546
|
<% if yj[:code_region_size] %>
|
|
522
547
|
<div class="mb-1">
|
|
523
|
-
<small class="text-muted"
|
|
548
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.yjit_code_size") %></small>
|
|
524
549
|
<code class="ms-1"><%= (yj[:code_region_size].to_f / 1024).round(1) %> KB</code>
|
|
525
550
|
</div>
|
|
526
551
|
<% end %>
|
|
527
552
|
<% if yj[:compile_time_ns] %>
|
|
528
553
|
<div class="mb-1">
|
|
529
|
-
<small class="text-muted"
|
|
554
|
+
<small class="text-muted"><%= red_t("red.errors.sidebar.health.yjit_compile_time") %></small>
|
|
530
555
|
<code class="ms-1"><%= (yj[:compile_time_ns].to_f / 1_000_000).round(2) %> ms</code>
|
|
531
556
|
</div>
|
|
532
557
|
<% end %>
|
|
@@ -537,10 +562,10 @@
|
|
|
537
562
|
<% end %>
|
|
538
563
|
|
|
539
564
|
<div>
|
|
540
|
-
<small class="metadata-label d-block mb-1"
|
|
565
|
+
<small class="metadata-label d-block mb-1"><%= red_t("red.errors.sidebar.error_id") %></small>
|
|
541
566
|
<div class="d-flex align-items-center gap-2">
|
|
542
567
|
<code><%= error.id %></code>
|
|
543
|
-
<button type="button" class="btn btn-sm btn-outline-secondary" data-red-action="copy" data-red-copy-text="<%= error.id %>" title="
|
|
568
|
+
<button type="button" class="btn btn-sm btn-outline-secondary" data-red-action="copy" data-red-copy-text="<%= error.id %>" title="<%= red_t("red.errors.sidebar.copy_error_id") %>">
|
|
544
569
|
<i class="bi bi-clipboard"></i>
|
|
545
570
|
</button>
|
|
546
571
|
</div>
|