rails_error_dashboard 0.8.4 → 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 +107 -4
- data/app/controllers/rails_error_dashboard/errors_controller.rb +91 -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 +30 -29
- 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 +10 -3
- 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,4 +1,4 @@
|
|
|
1
|
-
<% content_for :page_title, "
|
|
1
|
+
<% content_for :page_title, red_t("red.analytics.overview.title") %>
|
|
2
2
|
|
|
3
3
|
<script<%= " nonce=\"#{red_csp_nonce}\"".html_safe if red_csp_nonce %>>
|
|
4
4
|
// Dynamic chart colors based on theme
|
|
@@ -34,28 +34,28 @@
|
|
|
34
34
|
|
|
35
35
|
<div>
|
|
36
36
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-4);">
|
|
37
|
-
<h1 style="font-size: 20px; font-weight: 700; margin: 0;"
|
|
37
|
+
<h1 style="font-size: 20px; font-weight: 700; margin: 0;"><%= red_t("red.analytics.overview.title") %></h1>
|
|
38
38
|
</div>
|
|
39
39
|
|
|
40
40
|
<!-- Time range pills -->
|
|
41
41
|
<div style="display: flex; gap: 6px; margin-bottom: var(--space-6);">
|
|
42
|
-
<% [
|
|
43
|
-
<%= link_to analytics_errors_path(days: days), class: "filter-pill #{@days == days ? 'active' : ''}", style: "text-decoration: none;" do %><%=
|
|
42
|
+
<% [ 7, 14, 30, 60, 90 ].each do |days| %>
|
|
43
|
+
<%= link_to analytics_errors_path(days: days), class: "filter-pill #{@days == days ? 'active' : ''}", style: "text-decoration: none;" do %><%= red_t("red.analytics.days_pill.#{days}") %><% end %>
|
|
44
44
|
<% end %>
|
|
45
45
|
</div>
|
|
46
46
|
|
|
47
47
|
<!-- Summary Stats -->
|
|
48
48
|
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); margin-bottom: var(--space-6);">
|
|
49
49
|
<div class="card stat-card" style="border-left: 3px solid var(--accent); padding: var(--space-5) var(--space-6);">
|
|
50
|
-
<div class="stat-label" style="margin-bottom: 4px;"
|
|
50
|
+
<div class="stat-label" style="margin-bottom: 4px;"><%= red_t("red.analytics.overview.stats.total_errors") %></div>
|
|
51
51
|
<span class="stat-value"><%= @error_stats[:total] %></span>
|
|
52
52
|
</div>
|
|
53
53
|
<div class="card stat-card" style="border-left: 3px solid var(--status-critical); padding: var(--space-5) var(--space-6);">
|
|
54
|
-
<div class="stat-label" style="margin-bottom: 4px;"
|
|
54
|
+
<div class="stat-label" style="margin-bottom: 4px;"><%= red_t("red.analytics.overview.stats.unresolved") %></div>
|
|
55
55
|
<span class="stat-value" style="color: var(--status-critical);"><%= @error_stats[:unresolved] %></span>
|
|
56
56
|
</div>
|
|
57
57
|
<div class="card stat-card" style="border-left: 3px solid var(--status-success); padding: var(--space-5) var(--space-6);">
|
|
58
|
-
<div class="stat-label" style="margin-bottom: 4px;"
|
|
58
|
+
<div class="stat-label" style="margin-bottom: 4px;"><%= red_t("red.analytics.overview.stats.resolution_rate") %></div>
|
|
59
59
|
<span class="stat-value" style="color: var(--status-success);"><%= @resolution_rate %>%</span>
|
|
60
60
|
</div>
|
|
61
61
|
</div>
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
<!-- Error Trend Chart -->
|
|
64
64
|
<div class="card mb-4">
|
|
65
65
|
<div class="card-header">
|
|
66
|
-
<h5 class="mb-0"><i class="bi bi-graph-up"></i>
|
|
66
|
+
<h5 class="mb-0"><i class="bi bi-graph-up"></i> <%= red_t("red.analytics.overview.trend_chart.title", days: @days) %></h5>
|
|
67
67
|
</div>
|
|
68
68
|
<div class="card-body">
|
|
69
69
|
<div id="errors-over-time-chart"></div>
|
|
@@ -81,12 +81,12 @@
|
|
|
81
81
|
scales: {
|
|
82
82
|
x: {
|
|
83
83
|
ticks: { color: colors.textColor },
|
|
84
|
-
title: { color: colors.textColor, display: true, text: '
|
|
84
|
+
title: { color: colors.textColor, display: true, text: '<%= red_js_t("red.ui_js.charts.axis_date") %>' },
|
|
85
85
|
grid: { color: colors.gridColor }
|
|
86
86
|
},
|
|
87
87
|
y: {
|
|
88
88
|
ticks: { color: colors.textColor },
|
|
89
|
-
title: { color: colors.textColor, display: true, text: '
|
|
89
|
+
title: { color: colors.textColor, display: true, text: '<%= red_js_t("red.ui_js.charts.axis_number_of_errors") %>' },
|
|
90
90
|
grid: { color: colors.gridColor }
|
|
91
91
|
}
|
|
92
92
|
},
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
<div class="col-md-12">
|
|
109
109
|
<div class="card">
|
|
110
110
|
<div class="card-header">
|
|
111
|
-
<h5 class="mb-0"><i class="bi bi-phone"></i>
|
|
111
|
+
<h5 class="mb-0"><i class="bi bi-phone"></i> <%= red_t("red.analytics.overview.platform_chart.title") %></h5>
|
|
112
112
|
</div>
|
|
113
113
|
<div class="card-body">
|
|
114
114
|
<div id="errors-by-platform-chart"></div>
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
</div>
|
|
147
147
|
<div class="card-footer border-top-0">
|
|
148
148
|
<div class="d-flex gap-2 flex-wrap">
|
|
149
|
-
<small class="text-muted me-2"
|
|
149
|
+
<small class="text-muted me-2"><%= red_t("red.analytics.overview.platform_chart.quick_links") %></small>
|
|
150
150
|
<% @errors_by_platform.keys.each do |platform| %>
|
|
151
151
|
<%= link_to platform, errors_path(platform: platform, unresolved: '0'), class: "btn btn-sm btn-outline-secondary" %>
|
|
152
152
|
<% end %>
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
<div class="col-md-12">
|
|
163
163
|
<div class="card">
|
|
164
164
|
<div class="card-header">
|
|
165
|
-
<h5 class="mb-0"><i class="bi bi-bug"></i>
|
|
165
|
+
<h5 class="mb-0"><i class="bi bi-bug"></i> <%= red_t("red.analytics.overview.type_chart.title") %></h5>
|
|
166
166
|
</div>
|
|
167
167
|
<div class="card-body">
|
|
168
168
|
<div id="errors-by-type-chart"></div>
|
|
@@ -178,12 +178,12 @@
|
|
|
178
178
|
scales: {
|
|
179
179
|
x: {
|
|
180
180
|
ticks: { color: colors.textColor },
|
|
181
|
-
title: { color: colors.textColor, display: true, text: '
|
|
181
|
+
title: { color: colors.textColor, display: true, text: '<%= red_js_t("red.ui_js.charts.axis_error_type") %>' },
|
|
182
182
|
grid: { color: colors.gridColor }
|
|
183
183
|
},
|
|
184
184
|
y: {
|
|
185
185
|
ticks: { color: colors.textColor },
|
|
186
|
-
title: { color: colors.textColor, display: true, text: '
|
|
186
|
+
title: { color: colors.textColor, display: true, text: '<%= red_js_t("red.ui_js.charts.axis_count") %>' },
|
|
187
187
|
grid: { color: colors.gridColor }
|
|
188
188
|
}
|
|
189
189
|
},
|
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
<div class="col-md-12">
|
|
205
205
|
<div class="card">
|
|
206
206
|
<div class="card-header">
|
|
207
|
-
<h5 class="mb-0"><i class="bi bi-clock"></i>
|
|
207
|
+
<h5 class="mb-0"><i class="bi bi-clock"></i> <%= red_t("red.analytics.overview.hour_chart.title") %></h5>
|
|
208
208
|
</div>
|
|
209
209
|
<div class="card-body">
|
|
210
210
|
<div id="errors-by-hour-chart"></div>
|
|
@@ -220,12 +220,12 @@
|
|
|
220
220
|
scales: {
|
|
221
221
|
x: {
|
|
222
222
|
ticks: { color: colors.textColor },
|
|
223
|
-
title: { color: colors.textColor, display: true, text: '
|
|
223
|
+
title: { color: colors.textColor, display: true, text: '<%= red_js_t("red.ui_js.charts.axis_hour") %>' },
|
|
224
224
|
grid: { color: colors.gridColor }
|
|
225
225
|
},
|
|
226
226
|
y: {
|
|
227
227
|
ticks: { color: colors.textColor },
|
|
228
|
-
title: { color: colors.textColor, display: true, text: '
|
|
228
|
+
title: { color: colors.textColor, display: true, text: '<%= red_js_t("red.ui_js.charts.axis_number_of_errors") %>' },
|
|
229
229
|
grid: { color: colors.gridColor }
|
|
230
230
|
}
|
|
231
231
|
},
|
|
@@ -247,7 +247,7 @@
|
|
|
247
247
|
<div class="col-md-12">
|
|
248
248
|
<div class="card">
|
|
249
249
|
<div class="card-header">
|
|
250
|
-
<h5 class="mb-0"><i class="bi bi-people"></i>
|
|
250
|
+
<h5 class="mb-0"><i class="bi bi-people"></i> <%= red_t("red.analytics.overview.top_users.title") %></h5>
|
|
251
251
|
</div>
|
|
252
252
|
<div class="card-body p-0">
|
|
253
253
|
<%= render partial: 'user_errors_table',
|
|
@@ -270,19 +270,19 @@
|
|
|
270
270
|
<div class="col-md-12">
|
|
271
271
|
<div class="card">
|
|
272
272
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
273
|
-
<h5 class="mb-0"><i class="bi bi-list-check"></i>
|
|
274
|
-
<small class="text-muted"
|
|
273
|
+
<h5 class="mb-0"><i class="bi bi-list-check"></i> <%= red_t("red.analytics.overview.type_breakdown.title") %></h5>
|
|
274
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.type_breakdown.subtitle", days: @days) %></small>
|
|
275
275
|
</div>
|
|
276
276
|
<div class="card-body p-0">
|
|
277
277
|
<div class="table-responsive">
|
|
278
278
|
<table class="table table-hover mb-0">
|
|
279
279
|
<thead class="table-light">
|
|
280
280
|
<tr>
|
|
281
|
-
<th
|
|
282
|
-
<th
|
|
283
|
-
<th
|
|
284
|
-
<th
|
|
285
|
-
<th
|
|
281
|
+
<th><%= red_t("red.analytics.overview.type_breakdown.column_rank") %></th>
|
|
282
|
+
<th><%= red_t("red.analytics.overview.type_breakdown.column_error_type") %></th>
|
|
283
|
+
<th><%= red_t("red.analytics.overview.type_breakdown.column_count") %></th>
|
|
284
|
+
<th><%= red_t("red.analytics.overview.type_breakdown.column_percentage") %></th>
|
|
285
|
+
<th><%= red_t("red.analytics.overview.type_breakdown.column_actions") %></th>
|
|
286
286
|
</tr>
|
|
287
287
|
</thead>
|
|
288
288
|
<tbody>
|
|
@@ -304,7 +304,7 @@
|
|
|
304
304
|
</div>
|
|
305
305
|
</td>
|
|
306
306
|
<td>
|
|
307
|
-
<%= link_to "
|
|
307
|
+
<%= link_to red_t("red.analytics.overview.type_breakdown.view_errors"), errors_path(error_type: error_type, unresolved: '0'), class: "btn btn-sm btn-outline-primary" %>
|
|
308
308
|
</td>
|
|
309
309
|
</tr>
|
|
310
310
|
<% end %>
|
|
@@ -319,21 +319,21 @@
|
|
|
319
319
|
<!-- Recurring Issues Analysis -->
|
|
320
320
|
<div class="card mb-4">
|
|
321
321
|
<div class="card-header">
|
|
322
|
-
<h5 class="mb-0"><i class="bi bi-arrow-repeat"></i>
|
|
322
|
+
<h5 class="mb-0"><i class="bi bi-arrow-repeat"></i> <%= red_t("red.analytics.overview.recurring.title") %></h5>
|
|
323
323
|
</div>
|
|
324
324
|
<div class="card-body">
|
|
325
325
|
<% if @recurring_data[:high_frequency_errors].any? %>
|
|
326
|
-
<h6 class="text-muted mb-3"
|
|
326
|
+
<h6 class="text-muted mb-3"><%= red_t("red.analytics.overview.recurring.high_frequency_title") %></h6>
|
|
327
327
|
<div class="table-responsive mb-4">
|
|
328
328
|
<table class="table table-sm">
|
|
329
329
|
<thead>
|
|
330
330
|
<tr>
|
|
331
|
-
<th
|
|
332
|
-
<th
|
|
333
|
-
<th
|
|
334
|
-
<th
|
|
335
|
-
<th
|
|
336
|
-
<th
|
|
331
|
+
<th><%= red_t("red.analytics.overview.recurring.column_error_type") %></th>
|
|
332
|
+
<th><%= red_t("red.analytics.overview.recurring.column_total_occurrences") %></th>
|
|
333
|
+
<th><%= red_t("red.analytics.overview.recurring.column_duration") %></th>
|
|
334
|
+
<th><%= red_t("red.analytics.overview.recurring.column_first_seen") %></th>
|
|
335
|
+
<th><%= red_t("red.analytics.overview.recurring.column_last_seen") %></th>
|
|
336
|
+
<th><%= red_t("red.analytics.overview.recurring.column_status") %></th>
|
|
337
337
|
</tr>
|
|
338
338
|
</thead>
|
|
339
339
|
<tbody>
|
|
@@ -345,14 +345,14 @@
|
|
|
345
345
|
<% end %>
|
|
346
346
|
</td>
|
|
347
347
|
<td><span class="badge bg-danger"><%= error[:total_occurrences] %></span></td>
|
|
348
|
-
<td><%= error[:duration_days]
|
|
348
|
+
<td><%= red_t("red.analytics.overview.recurring.duration_days", days: error[:duration_days]) %></td>
|
|
349
349
|
<td><small class="text-muted"><%= local_time(error[:first_seen], format: :date_only) %></small></td>
|
|
350
350
|
<td><small class="text-muted"><%= local_time(error[:last_seen], format: :datetime) %></small></td>
|
|
351
351
|
<td>
|
|
352
352
|
<% if error[:still_active] %>
|
|
353
|
-
<span class="badge bg-warning"
|
|
353
|
+
<span class="badge bg-warning"><%= red_t("red.analytics.overview.recurring.active") %></span>
|
|
354
354
|
<% else %>
|
|
355
|
-
<span class="badge bg-secondary"
|
|
355
|
+
<span class="badge bg-secondary"><%= red_t("red.analytics.overview.recurring.inactive") %></span>
|
|
356
356
|
<% end %>
|
|
357
357
|
</td>
|
|
358
358
|
</tr>
|
|
@@ -361,24 +361,24 @@
|
|
|
361
361
|
</table>
|
|
362
362
|
</div>
|
|
363
363
|
<% else %>
|
|
364
|
-
<p class="text-muted"
|
|
364
|
+
<p class="text-muted"><%= red_t("red.analytics.overview.recurring.empty_high_frequency", days: @days) %></p>
|
|
365
365
|
<% end %>
|
|
366
366
|
|
|
367
367
|
<% if @recurring_data[:persistent_errors].any? %>
|
|
368
|
-
<h6 class="text-muted mb-3 mt-4"
|
|
368
|
+
<h6 class="text-muted mb-3 mt-4"><%= red_t("red.analytics.overview.recurring.persistent_title") %></h6>
|
|
369
369
|
<div class="alert alert-info">
|
|
370
|
-
<i class="bi bi-info-circle"></i>
|
|
370
|
+
<i class="bi bi-info-circle"></i> <%= red_t("red.analytics.overview.recurring.persistent_hint") %>
|
|
371
371
|
</div>
|
|
372
372
|
<div class="table-responsive">
|
|
373
373
|
<table class="table table-sm">
|
|
374
374
|
<thead>
|
|
375
375
|
<tr>
|
|
376
|
-
<th
|
|
377
|
-
<th
|
|
378
|
-
<th
|
|
379
|
-
<th
|
|
380
|
-
<th
|
|
381
|
-
<th
|
|
376
|
+
<th><%= red_t("red.analytics.overview.recurring.column_error_type") %></th>
|
|
377
|
+
<th><%= red_t("red.analytics.overview.recurring.column_message") %></th>
|
|
378
|
+
<th><%= red_t("red.analytics.overview.recurring.column_platform") %></th>
|
|
379
|
+
<th><%= red_t("red.analytics.overview.recurring.column_count") %></th>
|
|
380
|
+
<th><%= red_t("red.analytics.overview.recurring.column_age") %></th>
|
|
381
|
+
<th><%= red_t("red.analytics.overview.recurring.column_actions") %></th>
|
|
382
382
|
</tr>
|
|
383
383
|
</thead>
|
|
384
384
|
<tbody>
|
|
@@ -389,10 +389,10 @@
|
|
|
389
389
|
<td><%= error[:platform] %></td>
|
|
390
390
|
<td><span class="badge bg-secondary"><%= error[:occurrence_count] %>x</span></td>
|
|
391
391
|
<td>
|
|
392
|
-
<span class="badge bg-warning"><%= error[:age_days]
|
|
392
|
+
<span class="badge bg-warning"><%= red_t("red.analytics.overview.recurring.age_days", days: error[:age_days]) %></span>
|
|
393
393
|
</td>
|
|
394
394
|
<td>
|
|
395
|
-
<%= link_to "
|
|
395
|
+
<%= link_to red_t("red.analytics.overview.recurring.view"), error_path(error[:id]), class: "btn btn-sm btn-outline-primary" %>
|
|
396
396
|
</td>
|
|
397
397
|
</tr>
|
|
398
398
|
<% end %>
|
|
@@ -410,7 +410,7 @@
|
|
|
410
410
|
<div class="col-md-8">
|
|
411
411
|
<div class="card">
|
|
412
412
|
<div class="card-header">
|
|
413
|
-
<h5 class="mb-0"><i class="bi bi-git"></i>
|
|
413
|
+
<h5 class="mb-0"><i class="bi bi-git"></i> <%= red_t("red.analytics.overview.releases.version_chart_title") %></h5>
|
|
414
414
|
</div>
|
|
415
415
|
<div class="card-body">
|
|
416
416
|
<div id="errors-by-version-chart"></div>
|
|
@@ -436,40 +436,40 @@
|
|
|
436
436
|
<div class="col-md-4">
|
|
437
437
|
<div class="card">
|
|
438
438
|
<div class="card-header">
|
|
439
|
-
<h5 class="mb-0"
|
|
439
|
+
<h5 class="mb-0"><%= red_t("red.analytics.overview.releases.comparison_title") %></h5>
|
|
440
440
|
</div>
|
|
441
441
|
<div class="card-body">
|
|
442
442
|
<% if @release_comparison.present? %>
|
|
443
443
|
<div class="mb-3">
|
|
444
|
-
<small class="text-muted"
|
|
444
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.releases.latest_version") %></small>
|
|
445
445
|
<h4><%= @release_comparison[:latest_version] %></h4>
|
|
446
446
|
<p class="mb-0">
|
|
447
|
-
<span class="badge bg-danger"><%= @release_comparison[:latest_count]
|
|
447
|
+
<span class="badge bg-danger"><%= red_tp("red.analytics.overview.releases.latest_errors", count: @release_comparison[:latest_count]) %></span>
|
|
448
448
|
<% if @release_comparison[:latest_critical] > 0 %>
|
|
449
|
-
<span class="badge bg-dark ms-1"><%= @release_comparison[:latest_critical]
|
|
449
|
+
<span class="badge bg-dark ms-1"><%= red_tp("red.analytics.overview.releases.latest_critical", count: @release_comparison[:latest_critical]) %></span>
|
|
450
450
|
<% end %>
|
|
451
451
|
</p>
|
|
452
452
|
</div>
|
|
453
453
|
<div class="mb-3">
|
|
454
|
-
<small class="text-muted"
|
|
454
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.releases.previous_version") %></small>
|
|
455
455
|
<h4><%= @release_comparison[:previous_version] %></h4>
|
|
456
456
|
<p class="mb-0">
|
|
457
|
-
<span class="badge bg-secondary"><%= @release_comparison[:previous_count]
|
|
457
|
+
<span class="badge bg-secondary"><%= red_tp("red.analytics.overview.releases.previous_errors", count: @release_comparison[:previous_count]) %></span>
|
|
458
458
|
<% if @release_comparison[:previous_critical] > 0 %>
|
|
459
|
-
<span class="badge bg-secondary ms-1"><%= @release_comparison[:previous_critical]
|
|
459
|
+
<span class="badge bg-secondary ms-1"><%= red_tp("red.analytics.overview.releases.previous_critical", count: @release_comparison[:previous_critical]) %></span>
|
|
460
460
|
<% end %>
|
|
461
461
|
</p>
|
|
462
462
|
</div>
|
|
463
463
|
<hr>
|
|
464
464
|
<div>
|
|
465
|
-
<small class="text-muted"
|
|
465
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.releases.change") %></small>
|
|
466
466
|
<h4 class="<%= @release_comparison[:change_percentage] > 0 ? 'text-danger' : 'text-success' %>">
|
|
467
467
|
<%= @release_comparison[:change_percentage] > 0 ? '↑' : '↓' %>
|
|
468
468
|
<%= @release_comparison[:change_percentage].abs %>%
|
|
469
469
|
</h4>
|
|
470
470
|
</div>
|
|
471
471
|
<% else %>
|
|
472
|
-
<p class="text-muted"
|
|
472
|
+
<p class="text-muted"><%= red_t("red.analytics.overview.releases.empty") %></p>
|
|
473
473
|
<% end %>
|
|
474
474
|
</div>
|
|
475
475
|
</div>
|
|
@@ -479,15 +479,15 @@
|
|
|
479
479
|
<!-- Problematic Releases Alert -->
|
|
480
480
|
<% if @problematic_releases.any? %>
|
|
481
481
|
<div class="alert alert-warning mb-4">
|
|
482
|
-
<h5 class="alert-heading"><i class="bi bi-exclamation-triangle"></i>
|
|
483
|
-
<p
|
|
482
|
+
<h5 class="alert-heading"><i class="bi bi-exclamation-triangle"></i> <%= red_t("red.analytics.overview.releases.problematic_title") %></h5>
|
|
483
|
+
<p><%= red_t("red.analytics.overview.releases.problematic_hint_html", multiplier: 2) %></p>
|
|
484
484
|
<ul class="mb-0">
|
|
485
485
|
<% @problematic_releases.each do |release| %>
|
|
486
486
|
<li>
|
|
487
487
|
<strong><%= release[:version] %></strong>:
|
|
488
|
-
<%=
|
|
489
|
-
|
|
490
|
-
|
|
488
|
+
<%= red_t("red.analytics.overview.releases.problematic_entry",
|
|
489
|
+
count: release[:error_count], critical: release[:critical_count],
|
|
490
|
+
deviation: release[:deviation_from_avg]) %>
|
|
491
491
|
</li>
|
|
492
492
|
<% end %>
|
|
493
493
|
</ul>
|
|
@@ -499,7 +499,7 @@
|
|
|
499
499
|
<% if @mttr_stats[:total_resolved] > 0 %>
|
|
500
500
|
<div class="card mb-4">
|
|
501
501
|
<div class="card-header">
|
|
502
|
-
<h5 class="mb-0"><i class="bi bi-clock-history"></i>
|
|
502
|
+
<h5 class="mb-0"><i class="bi bi-clock-history"></i> <%= red_t("red.analytics.overview.mttr.title") %></h5>
|
|
503
503
|
</div>
|
|
504
504
|
<div class="card-body">
|
|
505
505
|
<div class="row g-3 mb-4">
|
|
@@ -507,9 +507,9 @@
|
|
|
507
507
|
<div class="col-md-3">
|
|
508
508
|
<div class="card border-info">
|
|
509
509
|
<div class="card-body text-center">
|
|
510
|
-
<small class="text-muted d-block"
|
|
510
|
+
<small class="text-muted d-block"><%= red_t("red.analytics.overview.mttr.overall_title") %></small>
|
|
511
511
|
<h3 class="text-info mb-0"><%= @mttr_stats[:overall_mttr] %>h</h3>
|
|
512
|
-
<small class="text-muted"
|
|
512
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.mttr.overall_hint") %></small>
|
|
513
513
|
</div>
|
|
514
514
|
</div>
|
|
515
515
|
</div>
|
|
@@ -518,9 +518,9 @@
|
|
|
518
518
|
<div class="col-md-3">
|
|
519
519
|
<div class="card border-success">
|
|
520
520
|
<div class="card-body text-center">
|
|
521
|
-
<small class="text-muted d-block"
|
|
521
|
+
<small class="text-muted d-block"><%= red_t("red.analytics.overview.mttr.fastest_title") %></small>
|
|
522
522
|
<h3 class="text-success mb-0"><%= @mttr_stats[:fastest_resolution] || 0 %>m</h3>
|
|
523
|
-
<small class="text-muted"
|
|
523
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.mttr.fastest_hint") %></small>
|
|
524
524
|
</div>
|
|
525
525
|
</div>
|
|
526
526
|
</div>
|
|
@@ -529,9 +529,9 @@
|
|
|
529
529
|
<div class="col-md-3">
|
|
530
530
|
<div class="card border-danger">
|
|
531
531
|
<div class="card-body text-center">
|
|
532
|
-
<small class="text-muted d-block"
|
|
532
|
+
<small class="text-muted d-block"><%= red_t("red.analytics.overview.mttr.slowest_title") %></small>
|
|
533
533
|
<h3 class="text-danger mb-0"><%= @mttr_stats[:slowest_resolution] || 0 %>h</h3>
|
|
534
|
-
<small class="text-muted"
|
|
534
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.mttr.slowest_hint") %></small>
|
|
535
535
|
</div>
|
|
536
536
|
</div>
|
|
537
537
|
</div>
|
|
@@ -540,9 +540,9 @@
|
|
|
540
540
|
<div class="col-md-3">
|
|
541
541
|
<div class="card border-secondary">
|
|
542
542
|
<div class="card-body text-center">
|
|
543
|
-
<small class="text-muted d-block"
|
|
543
|
+
<small class="text-muted d-block"><%= red_t("red.analytics.overview.mttr.total_resolved_title") %></small>
|
|
544
544
|
<h3 class="text-secondary mb-0"><%= @mttr_stats[:total_resolved] %></h3>
|
|
545
|
-
<small class="text-muted"
|
|
545
|
+
<small class="text-muted"><%= red_t("red.analytics.overview.mttr.total_resolved_hint", days: @days) %></small>
|
|
546
546
|
</div>
|
|
547
547
|
</div>
|
|
548
548
|
</div>
|
|
@@ -551,7 +551,7 @@
|
|
|
551
551
|
<!-- MTTR by Platform -->
|
|
552
552
|
<% if @mttr_by_platform.present? && @mttr_by_platform.any? %>
|
|
553
553
|
<div class="mt-4">
|
|
554
|
-
<h6 class="text-muted mb-3"
|
|
554
|
+
<h6 class="text-muted mb-3"><%= red_t("red.analytics.overview.mttr.by_platform_title") %></h6>
|
|
555
555
|
<div id="mttr-by-platform-chart"></div>
|
|
556
556
|
<script<%= " nonce=\"#{red_csp_nonce}\"".html_safe if red_csp_nonce %>>
|
|
557
557
|
document.addEventListener('DOMContentLoaded', function() {
|
|
@@ -571,14 +571,14 @@
|
|
|
571
571
|
<!-- MTTR by Severity -->
|
|
572
572
|
<% if @mttr_stats[:mttr_by_severity].present? && @mttr_stats[:mttr_by_severity].any? %>
|
|
573
573
|
<div class="mt-4">
|
|
574
|
-
<h6 class="text-muted mb-3"
|
|
574
|
+
<h6 class="text-muted mb-3"><%= red_t("red.analytics.overview.mttr.by_severity_title") %></h6>
|
|
575
575
|
<div class="table-responsive">
|
|
576
576
|
<table class="table table-sm">
|
|
577
577
|
<thead>
|
|
578
578
|
<tr>
|
|
579
|
-
<th
|
|
580
|
-
<th
|
|
581
|
-
<th
|
|
579
|
+
<th><%= red_t("red.analytics.overview.mttr.column_severity") %></th>
|
|
580
|
+
<th><%= red_t("red.analytics.overview.mttr.column_avg_time") %></th>
|
|
581
|
+
<th><%= red_t("red.analytics.overview.mttr.column_actions") %></th>
|
|
582
582
|
</tr>
|
|
583
583
|
</thead>
|
|
584
584
|
<tbody>
|
|
@@ -586,12 +586,12 @@
|
|
|
586
586
|
<tr>
|
|
587
587
|
<td>
|
|
588
588
|
<span class="badge bg-<%= severity_color(severity) %>">
|
|
589
|
-
<%= severity.to_s
|
|
589
|
+
<%= red_t("red.common.severity.#{severity}", default: severity.to_s) %>
|
|
590
590
|
</span>
|
|
591
591
|
</td>
|
|
592
|
-
<td><strong><%= hours
|
|
592
|
+
<td><strong><%= red_t("red.analytics.overview.mttr.hours", hours: hours) %></strong></td>
|
|
593
593
|
<td>
|
|
594
|
-
<%= link_to "
|
|
594
|
+
<%= link_to red_t("red.analytics.overview.mttr.view"), errors_path(severity: severity, unresolved: '0'), class: "btn btn-sm btn-outline-primary" %>
|
|
595
595
|
</td>
|
|
596
596
|
</tr>
|
|
597
597
|
<% end %>
|
|
@@ -604,7 +604,7 @@
|
|
|
604
604
|
<!-- MTTR Trend -->
|
|
605
605
|
<% if @mttr_stats[:mttr_trend].present? && @mttr_stats[:mttr_trend].any? %>
|
|
606
606
|
<div class="mt-4">
|
|
607
|
-
<h6 class="text-muted mb-3"
|
|
607
|
+
<h6 class="text-muted mb-3"><%= red_t("red.analytics.overview.mttr.trend_title") %></h6>
|
|
608
608
|
<div id="mttr-trend-chart"></div>
|
|
609
609
|
<script<%= " nonce=\"#{red_csp_nonce}\"".html_safe if red_csp_nonce %>>
|
|
610
610
|
document.addEventListener('DOMContentLoaded', function() {
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
<% content_for :page_title, "
|
|
1
|
+
<% content_for :page_title, red_t("red.health.cache.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-lightning-charge me-2"></i>
|
|
7
|
-
|
|
7
|
+
<%= red_t("red.health.cache.title") %>
|
|
8
8
|
</h1>
|
|
9
9
|
|
|
10
10
|
<div class="btn-group" role="group">
|
|
11
11
|
<%= link_to cache_health_summary_errors_path(days: 7), class: "btn btn-sm #{@days == 7 ? 'btn-primary' : 'btn-outline-primary'}" do %>
|
|
12
|
-
7
|
|
12
|
+
<%= red_t("red.common.days_filter.7") %>
|
|
13
13
|
<% end %>
|
|
14
14
|
<%= link_to cache_health_summary_errors_path(days: 30), class: "btn btn-sm #{@days == 30 ? 'btn-primary' : 'btn-outline-primary'}" do %>
|
|
15
|
-
30
|
|
15
|
+
<%= red_t("red.common.days_filter.30") %>
|
|
16
16
|
<% end %>
|
|
17
17
|
<%= link_to cache_health_summary_errors_path(days: 90), class: "btn btn-sm #{@days == 90 ? 'btn-primary' : 'btn-outline-primary'}" do %>
|
|
18
|
-
90
|
|
18
|
+
<%= red_t("red.common.days_filter.90") %>
|
|
19
19
|
<% end %>
|
|
20
20
|
</div>
|
|
21
21
|
</div>
|
|
@@ -23,18 +23,18 @@
|
|
|
23
23
|
<% if @errors_with_cache == 0 %>
|
|
24
24
|
<div class="red-empty-state">
|
|
25
25
|
<div class="red-empty-state-icon" style="background: var(--status-success-bg); color: var(--status-success);"><i class="bi bi-check-lg"></i></div>
|
|
26
|
-
<div class="red-empty-state-title"
|
|
26
|
+
<div class="red-empty-state-title"><%= red_t("red.health.cache.empty.title") %></div>
|
|
27
27
|
<p class="text-muted">
|
|
28
|
-
|
|
28
|
+
<%= red_t("red.health.cache.empty.message", days: @days) %>
|
|
29
29
|
</p>
|
|
30
30
|
<div class="card mx-auto" style="max-width: 500px;">
|
|
31
31
|
<div class="card-body text-start">
|
|
32
|
-
<h6
|
|
32
|
+
<h6><%= red_t("red.health.cache.empty.how_it_works") %></h6>
|
|
33
33
|
<ul class="mb-0">
|
|
34
|
-
<li
|
|
35
|
-
<li
|
|
36
|
-
<li
|
|
37
|
-
<li
|
|
34
|
+
<li><%= red_t("red.health.cache.empty.step_breadcrumbs_html") %></li>
|
|
35
|
+
<li><%= red_t("red.health.cache.empty.step_capture") %></li>
|
|
36
|
+
<li><%= red_t("red.health.cache.empty.step_hit_status") %></li>
|
|
37
|
+
<li><%= red_t("red.health.cache.empty.step_sort") %></li>
|
|
38
38
|
</ul>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
<div class="card text-center">
|
|
46
46
|
<div class="card-body">
|
|
47
47
|
<div class="display-6 text-info"><%= @errors_with_cache %></div>
|
|
48
|
-
<small class="text-muted"
|
|
48
|
+
<small class="text-muted"><%= red_t("red.health.cache.stats.errors_with_cache") %></small>
|
|
49
49
|
</div>
|
|
50
50
|
</div>
|
|
51
51
|
</div>
|
|
@@ -53,12 +53,12 @@
|
|
|
53
53
|
<div class="card text-center">
|
|
54
54
|
<div class="card-body">
|
|
55
55
|
<% if @avg_hit_rate.nil? %>
|
|
56
|
-
<div class="display-6 text-secondary"
|
|
56
|
+
<div class="display-6 text-secondary"><%= red_t("red.common.not_available") %></div>
|
|
57
57
|
<% else %>
|
|
58
58
|
<% hit_color = @avg_hit_rate >= 80 ? "success" : (@avg_hit_rate >= 50 ? "warning" : "danger") %>
|
|
59
59
|
<div class="display-6 text-<%= hit_color %>"><%= @avg_hit_rate %>%</div>
|
|
60
60
|
<% end %>
|
|
61
|
-
<small class="text-muted"
|
|
61
|
+
<small class="text-muted"><%= red_t("red.health.cache.stats.avg_hit_rate") %></small>
|
|
62
62
|
</div>
|
|
63
63
|
</div>
|
|
64
64
|
</div>
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
<div class="card text-center">
|
|
67
67
|
<div class="card-body">
|
|
68
68
|
<div class="display-6 text-secondary"><%= @total_cache_ops %></div>
|
|
69
|
-
<small class="text-muted"
|
|
69
|
+
<small class="text-muted"><%= red_t("red.health.cache.stats.total_ops") %></small>
|
|
70
70
|
</div>
|
|
71
71
|
</div>
|
|
72
72
|
</div>
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
77
77
|
<h5 class="mb-0">
|
|
78
78
|
<i class="bi bi-lightning-charge text-info me-2"></i>
|
|
79
|
-
|
|
79
|
+
<%= red_t("red.health.cache.table.title") %>
|
|
80
80
|
<span class="badge bg-info"><%= @errors_with_cache %></span>
|
|
81
81
|
</h5>
|
|
82
82
|
<small class="text-muted"><%== @pagy.info_tag %></small>
|
|
@@ -86,13 +86,13 @@
|
|
|
86
86
|
<table class="table table-hover mb-0">
|
|
87
87
|
<thead class="table-light">
|
|
88
88
|
<tr>
|
|
89
|
-
<th width="100"
|
|
90
|
-
<th width="80"
|
|
91
|
-
<th width="80"
|
|
92
|
-
<th width="120"
|
|
93
|
-
<th width="120"
|
|
94
|
-
<th
|
|
95
|
-
<th width="140"
|
|
89
|
+
<th width="100"><%= red_t("red.health.cache.table.column_error") %></th>
|
|
90
|
+
<th width="80"><%= red_t("red.health.cache.table.column_reads") %></th>
|
|
91
|
+
<th width="80"><%= red_t("red.health.cache.table.column_writes") %></th>
|
|
92
|
+
<th width="120"><%= red_t("red.health.cache.table.column_hit_rate") %></th>
|
|
93
|
+
<th width="120"><%= red_t("red.health.cache.table.column_total_time") %></th>
|
|
94
|
+
<th><%= red_t("red.health.cache.table.column_slowest_op") %></th>
|
|
95
|
+
<th width="140"><%= red_t("red.health.cache.table.column_last_seen") %></th>
|
|
96
96
|
</tr>
|
|
97
97
|
</thead>
|
|
98
98
|
<tbody>
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
<td><%= entry[:writes] %></td>
|
|
104
104
|
<td>
|
|
105
105
|
<% if entry[:hit_rate].nil? %>
|
|
106
|
-
<span class="badge bg-secondary"
|
|
106
|
+
<span class="badge bg-secondary"><%= red_t("red.common.not_available") %></span>
|
|
107
107
|
<% else %>
|
|
108
108
|
<% rate_color = entry[:hit_rate] >= 80 ? "success" : (entry[:hit_rate] >= 50 ? "warning" : "danger") %>
|
|
109
109
|
<span class="badge bg-<%= rate_color %>"><%= entry[:hit_rate] %>%</span>
|
|
@@ -126,11 +126,11 @@
|
|
|
126
126
|
<div class="card-footer border-top d-flex justify-content-between align-items-center">
|
|
127
127
|
<div>
|
|
128
128
|
<small class="text-muted">
|
|
129
|
-
<i class="bi bi-lightbulb text-warning"></i>
|
|
129
|
+
<i class="bi bi-lightbulb text-warning"></i> <%= red_t("red.health.cache.table.tip") %>
|
|
130
130
|
</small>
|
|
131
131
|
<small class="ms-3">
|
|
132
132
|
<a href="https://guides.rubyonrails.org/caching_with_rails.html" target="_blank" rel="noopener" class="text-decoration-none">
|
|
133
|
-
<i class="bi bi-book"></i>
|
|
133
|
+
<i class="bi bi-book"></i> <%= red_t("red.health.cache.table.guide_link") %> <i class="bi bi-box-arrow-up-right" style="font-size: 0.7em;"></i>
|
|
134
134
|
</a>
|
|
135
135
|
</small>
|
|
136
136
|
</div>
|