rails_error_dashboard 0.1.1 → 0.1.4

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +92 -21
  3. data/app/assets/stylesheets/rails_error_dashboard/_catppuccin_mocha.scss +107 -0
  4. data/app/assets/stylesheets/rails_error_dashboard/_components.scss +625 -0
  5. data/app/assets/stylesheets/rails_error_dashboard/_layout.scss +257 -0
  6. data/app/assets/stylesheets/rails_error_dashboard/_theme_variables.scss +203 -0
  7. data/app/assets/stylesheets/rails_error_dashboard/application.css.map +7 -0
  8. data/app/assets/stylesheets/rails_error_dashboard/application.scss +61 -0
  9. data/app/controllers/rails_error_dashboard/errors_controller.rb +135 -1
  10. data/app/helpers/rails_error_dashboard/application_helper.rb +80 -4
  11. data/app/helpers/rails_error_dashboard/backtrace_helper.rb +91 -0
  12. data/app/helpers/rails_error_dashboard/overview_helper.rb +78 -0
  13. data/app/helpers/rails_error_dashboard/user_agent_helper.rb +118 -0
  14. data/app/models/rails_error_dashboard/error_comment.rb +27 -0
  15. data/app/models/rails_error_dashboard/error_log.rb +159 -0
  16. data/app/views/layouts/rails_error_dashboard/application.html.erb +39 -1
  17. data/app/views/layouts/rails_error_dashboard.html.erb +796 -299
  18. data/app/views/layouts/rails_error_dashboard_old_backup.html.erb +383 -0
  19. data/app/views/rails_error_dashboard/errors/_error_row.html.erb +2 -0
  20. data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +4 -4
  21. data/app/views/rails_error_dashboard/errors/_timeline.html.erb +167 -0
  22. data/app/views/rails_error_dashboard/errors/analytics.html.erb +439 -22
  23. data/app/views/rails_error_dashboard/errors/index.html.erb +127 -11
  24. data/app/views/rails_error_dashboard/errors/overview.html.erb +253 -0
  25. data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +29 -18
  26. data/app/views/rails_error_dashboard/errors/show.html.erb +353 -54
  27. data/config/routes.rb +11 -1
  28. data/db/migrate/20251226020000_add_workflow_fields_to_error_logs.rb +27 -0
  29. data/db/migrate/20251226020100_create_error_comments.rb +18 -0
  30. data/lib/generators/rails_error_dashboard/install/install_generator.rb +8 -2
  31. data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +21 -0
  32. data/lib/generators/rails_error_dashboard/uninstall/uninstall_generator.rb +317 -0
  33. data/lib/rails_error_dashboard/commands/batch_delete_errors.rb +1 -1
  34. data/lib/rails_error_dashboard/commands/batch_resolve_errors.rb +2 -2
  35. data/lib/rails_error_dashboard/commands/log_error.rb +47 -9
  36. data/lib/rails_error_dashboard/commands/resolve_error.rb +1 -1
  37. data/lib/rails_error_dashboard/configuration.rb +8 -0
  38. data/lib/rails_error_dashboard/error_reporter.rb +4 -4
  39. data/lib/rails_error_dashboard/logger.rb +105 -0
  40. data/lib/rails_error_dashboard/middleware/error_catcher.rb +2 -2
  41. data/lib/rails_error_dashboard/plugin.rb +3 -3
  42. data/lib/rails_error_dashboard/plugin_registry.rb +2 -2
  43. data/lib/rails_error_dashboard/plugins/jira_integration_plugin.rb +1 -1
  44. data/lib/rails_error_dashboard/plugins/metrics_plugin.rb +1 -1
  45. data/lib/rails_error_dashboard/queries/dashboard_stats.rb +109 -1
  46. data/lib/rails_error_dashboard/queries/errors_list.rb +134 -7
  47. data/lib/rails_error_dashboard/queries/mttr_stats.rb +111 -0
  48. data/lib/rails_error_dashboard/queries/recurring_issues.rb +97 -0
  49. data/lib/rails_error_dashboard/services/backtrace_parser.rb +113 -0
  50. data/lib/rails_error_dashboard/version.rb +1 -1
  51. data/lib/rails_error_dashboard.rb +5 -0
  52. data/lib/tasks/rails_error_dashboard_tasks.rake +85 -4
  53. metadata +36 -2
@@ -0,0 +1,253 @@
1
+ <div class="container-fluid py-4">
2
+ <!-- Page Header -->
3
+ <div class="d-flex justify-content-between align-items-center mb-4">
4
+ <h1 class="h3 mb-0">
5
+ <i class="bi bi-speedometer2 me-2"></i>
6
+ Dashboard Overview
7
+ </h1>
8
+ <div class="text-muted">
9
+ <small>
10
+ Last updated: <%= Time.current.strftime("%B %d, %Y %I:%M %p") %>
11
+ </small>
12
+ </div>
13
+ </div>
14
+
15
+ <!-- Key Metrics Cards (Mobile-first: stack on mobile, 3 columns on desktop) -->
16
+ <div class="row g-3 mb-4">
17
+ <!-- Error Rate Card -->
18
+ <div class="col-12 col-md-6 col-lg-4">
19
+ <div class="card stat-card h-100 <%= error_rate_border_class(@stats[:error_rate]) %>">
20
+ <div class="card-body text-center">
21
+ <div class="stat-label mb-2">ERROR RATE</div>
22
+ <div class="stat-value <%= error_rate_text_class(@stats[:error_rate]) %>">
23
+ <%= @stats[:error_rate] %>%
24
+ </div>
25
+ <small class="text-muted">Errors per hour today</small>
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Affected Users Card -->
31
+ <div class="col-12 col-md-6 col-lg-4">
32
+ <div class="card stat-card h-100">
33
+ <div class="card-body text-center">
34
+ <div class="stat-label mb-2">AFFECTED USERS</div>
35
+ <div class="stat-value text-primary">
36
+ <%= @stats[:affected_users_today] %>
37
+ </div>
38
+ <small class="<%= trend_color_class(@stats[:affected_users_change]) %>">
39
+ <%= trend_arrow(@stats[:affected_users_change]) %>
40
+ <%= @stats[:affected_users_change].abs %>
41
+ from yesterday
42
+ </small>
43
+ </div>
44
+ </div>
45
+ </div>
46
+
47
+ <!-- Trend Card -->
48
+ <div class="col-12 col-lg-4">
49
+ <div class="card stat-card h-100">
50
+ <div class="card-body text-center">
51
+ <div class="stat-label mb-2">ERROR TREND</div>
52
+ <div class="stat-value <%= trend_color_class(@stats[:trend_percentage]) %>">
53
+ <%= trend_arrow(@stats[:trend_percentage]) %>
54
+ <%= @stats[:trend_percentage].abs %>%
55
+ </div>
56
+ <small class="text-muted">
57
+ <%= trend_text(@stats[:trend_direction]) %>
58
+ </small>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </div>
63
+
64
+ <!-- Top 5 Errors by Impact (Mobile: stack, Desktop: 2 columns) -->
65
+ <% if @stats[:top_errors_by_impact].any? %>
66
+ <div class="card mb-4">
67
+ <div class="card-header bg-white d-flex justify-content-between align-items-center">
68
+ <h5 class="mb-0">
69
+ <i class="bi bi-exclamation-triangle me-2"></i>
70
+ Top 5 Errors by Impact
71
+ </h5>
72
+ <%= link_to "View All Errors →", errors_path, class: "btn btn-sm btn-outline-primary" %>
73
+ </div>
74
+ <div class="card-body">
75
+ <div class="row g-3">
76
+ <% @stats[:top_errors_by_impact].each do |error| %>
77
+ <div class="col-12 col-lg-6">
78
+ <%= link_to error_path(error[:id]), class: "text-decoration-none" do %>
79
+ <div class="card h-100 border-start border-<%= severity_color(error[:severity]) %> border-3">
80
+ <div class="card-body">
81
+ <div class="d-flex justify-content-between align-items-start mb-2">
82
+ <div class="flex-grow-1">
83
+ <h6 class="mb-1">
84
+ <span class="badge bg-<%= severity_color(error[:severity]) %> me-2">
85
+ <%= severity_icon(error[:severity]) %> <%= error[:severity].to_s.titleize %>
86
+ </span>
87
+ <code class="small"><%= error[:error_type] %></code>
88
+ </h6>
89
+ <p class="small text-muted mb-2"><%= error[:message] %></p>
90
+ </div>
91
+ </div>
92
+ <div class="d-flex justify-content-between align-items-center small">
93
+ <span class="text-muted">
94
+ <i class="bi bi-people-fill me-1"></i>
95
+ <%= error[:affected_users] %> user<%= error[:affected_users] != 1 ? 's' : '' %>
96
+ </span>
97
+ <span class="text-muted">
98
+ <i class="bi bi-arrow-repeat me-1"></i>
99
+ <%= error[:occurrence_count] %> occurrence<%= error[:occurrence_count] != 1 ? 's' : '' %>
100
+ </span>
101
+ <span class="fw-bold text-danger">
102
+ Impact: <%= error[:impact_score] %>
103
+ </span>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ <% end %>
108
+ </div>
109
+ <% end %>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ <% end %>
114
+
115
+ <!-- Platform Health Summary (Mobile: stack, Desktop: 3 columns) -->
116
+ <% if @platform_health.any? %>
117
+ <div class="card mb-4">
118
+ <div class="card-header bg-white d-flex justify-content-between align-items-center">
119
+ <h5 class="mb-0">
120
+ <i class="bi bi-phone me-2"></i>
121
+ Platform Health
122
+ </h5>
123
+ <% if RailsErrorDashboard.configuration.enable_platform_comparison %>
124
+ <%= link_to "Full Comparison →", platform_comparison_errors_path, class: "btn btn-sm btn-outline-primary" %>
125
+ <% end %>
126
+ </div>
127
+ <div class="card-body">
128
+ <div class="row g-3">
129
+ <% @platform_health.each do |platform, health| %>
130
+ <div class="col-12 col-md-4">
131
+ <div class="card h-100 border-<%= health_status_color(health[:health_status]) %>">
132
+ <div class="card-body">
133
+ <div class="d-flex justify-content-between align-items-start mb-3">
134
+ <h6 class="text-capitalize mb-0"><%= platform %></h6>
135
+ <span class="badge bg-<%= health_status_color(health[:health_status]) %>">
136
+ <%= health_status_text(health[:health_status]) %>
137
+ </span>
138
+ </div>
139
+
140
+ <div class="mb-2">
141
+ <small class="text-muted">Stability Score</small>
142
+ <div class="d-flex align-items-center">
143
+ <h4 class="mb-0 me-2"><%= health[:stability_score] %>/100</h4>
144
+ <div class="progress flex-grow-1" style="height: 8px;">
145
+ <div class="progress-bar bg-<%= health_status_color(health[:health_status]) %>"
146
+ role="progressbar"
147
+ style="width: <%= health[:stability_score] %>%">
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+
153
+ <div class="small">
154
+ <div class="d-flex justify-content-between mb-1">
155
+ <span class="text-muted">Total Errors:</span>
156
+ <strong><%= health[:total_errors] %></strong>
157
+ </div>
158
+ <div class="d-flex justify-content-between mb-1">
159
+ <span class="text-muted">Critical:</span>
160
+ <strong class="text-danger"><%= health[:critical_errors] %></strong>
161
+ </div>
162
+ <div class="d-flex justify-content-between">
163
+ <span class="text-muted">Unresolved:</span>
164
+ <strong><%= health[:unresolved_errors] %></strong>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ </div>
170
+ <% end %>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ <% end %>
175
+
176
+ <!-- Critical Alerts (Last hour) -->
177
+ <% if @critical_alerts.any? %>
178
+ <div class="alert alert-danger border-danger mb-4" role="alert">
179
+ <div class="d-flex align-items-center mb-2">
180
+ <i class="bi bi-exclamation-triangle-fill fs-3 me-3"></i>
181
+ <div>
182
+ <h5 class="alert-heading mb-0">
183
+ 🚨 <%= @critical_alerts.count %> Critical/High Error<%= @critical_alerts.count != 1 ? 's' : '' %> in Last Hour
184
+ </h5>
185
+ </div>
186
+ </div>
187
+ <div class="list-group list-group-flush">
188
+ <% @critical_alerts.first(5).each do |error| %>
189
+ <%= link_to error_path(error), class: "list-group-item list-group-item-action" do %>
190
+ <div class="d-flex justify-content-between align-items-start">
191
+ <div class="flex-grow-1">
192
+ <div class="d-flex align-items-center mb-1">
193
+ <span class="badge bg-<%= severity_color(error.severity) %> me-2">
194
+ <%= severity_icon(error.severity) %>
195
+ </span>
196
+ <code class="small"><%= error.error_type %></code>
197
+ </div>
198
+ <p class="mb-1 small"><%= error.message&.truncate(100) %></p>
199
+ <small class="text-muted">
200
+ <i class="bi bi-clock me-1"></i>
201
+ <%= time_ago_in_words(error.occurred_at) %> ago
202
+
203
+ <i class="bi bi-arrow-repeat me-1"></i>
204
+ <%= error.occurrence_count %> occurrence<%= error.occurrence_count != 1 ? 's' : '' %>
205
+ </small>
206
+ </div>
207
+ <i class="bi bi-chevron-right"></i>
208
+ </div>
209
+ <% end %>
210
+ <% end %>
211
+ </div>
212
+ <% if @critical_alerts.count > 5 %>
213
+ <div class="mt-2">
214
+ <%= link_to "View all #{@critical_alerts.count} critical errors →",
215
+ errors_path(severity: 'critical'),
216
+ class: "btn btn-sm btn-outline-danger" %>
217
+ </div>
218
+ <% end %>
219
+ </div>
220
+ <% end %>
221
+
222
+ <!-- Quick Actions -->
223
+ <div class="row g-3">
224
+ <div class="col-12 col-md-6 col-lg-3">
225
+ <%= link_to errors_path, class: "btn btn-lg btn-outline-primary w-100" do %>
226
+ <i class="bi bi-list-ul d-block fs-3 mb-2"></i>
227
+ View All Errors
228
+ <% end %>
229
+ </div>
230
+ <div class="col-12 col-md-6 col-lg-3">
231
+ <%= link_to analytics_errors_path, class: "btn btn-lg btn-outline-primary w-100" do %>
232
+ <i class="bi bi-graph-up d-block fs-3 mb-2"></i>
233
+ Analytics
234
+ <% end %>
235
+ </div>
236
+ <% if RailsErrorDashboard.configuration.enable_platform_comparison %>
237
+ <div class="col-12 col-md-6 col-lg-3">
238
+ <%= link_to platform_comparison_errors_path, class: "btn btn-lg btn-outline-primary w-100" do %>
239
+ <i class="bi bi-phone d-block fs-3 mb-2"></i>
240
+ Platform Health
241
+ <% end %>
242
+ </div>
243
+ <% end %>
244
+ <% if RailsErrorDashboard.configuration.enable_error_correlation %>
245
+ <div class="col-12 col-md-6 col-lg-3">
246
+ <%= link_to correlation_errors_path, class: "btn btn-lg btn-outline-primary w-100" do %>
247
+ <i class="bi bi-diagram-3 d-block fs-3 mb-2"></i>
248
+ Correlation
249
+ <% end %>
250
+ </div>
251
+ <% end %>
252
+ </div>
253
+ </div>
@@ -290,8 +290,16 @@
290
290
  datasets: [{
291
291
  label: 'Total Errors',
292
292
  data: <%= raw @error_rate_by_platform.values.to_json %>,
293
- backgroundColor: 'rgba(54, 162, 235, 0.5)',
294
- borderColor: 'rgba(54, 162, 235, 1)',
293
+ backgroundColor: (function() {
294
+ const isDark = document.body.classList.contains('dark-mode');
295
+ const config = getCatppuccinChartConfig(isDark);
296
+ return config.colors.blue.replace('rgb', 'rgba').replace(')', ', 0.5)');
297
+ })(),
298
+ borderColor: (function() {
299
+ const isDark = document.body.classList.contains('dark-mode');
300
+ const config = getCatppuccinChartConfig(isDark);
301
+ return config.colors.blue;
302
+ })(),
295
303
  borderWidth: 1
296
304
  }]
297
305
  },
@@ -311,29 +319,24 @@
311
319
  // Daily Trend Chart
312
320
  const dailyTrendCtx = document.getElementById('dailyTrendChart');
313
321
  if (dailyTrendCtx) {
314
- const colors = {
315
- ios: 'rgba(255, 99, 132, 1)',
316
- android: 'rgba(75, 192, 192, 1)',
317
- api: 'rgba(255, 206, 86, 1)',
318
- web: 'rgba(153, 102, 255, 1)',
319
- unknown: 'rgba(201, 203, 207, 1)'
320
- };
322
+ // Use Catppuccin colors from global theme config
323
+ const isDark = document.body.classList.contains('dark-mode');
321
324
 
322
325
  const datasets = <%= raw @daily_trends.map { |platform, data|
323
326
  {
324
327
  label: platform.to_s.capitalize,
325
328
  data: data.values,
326
- borderColor: "colors['#{platform}'] || 'rgba(75, 192, 192, 1)'",
327
- backgroundColor: "colors['#{platform}'] ? colors['#{platform}'].replace('1)', '0.1)') : 'rgba(75, 192, 192, 0.1)'",
328
- tension: 0.1
329
+ platform: platform.to_s.downcase,
330
+ tension: 0.4
329
331
  }
330
332
  }.to_json %>;
331
333
 
332
- // Replace string placeholders with actual colors
334
+ // Apply Catppuccin platform colors
333
335
  datasets.forEach(ds => {
334
- const platform = ds.label.toLowerCase();
335
- ds.borderColor = colors[platform] || 'rgba(75, 192, 192, 1)';
336
- ds.backgroundColor = colors[platform] ? colors[platform].replace('1)', '0.1)') : 'rgba(75, 192, 192, 0.1)';
336
+ const color = getPlatformColor(ds.platform, isDark);
337
+ ds.borderColor = color;
338
+ // Add transparency for background
339
+ ds.backgroundColor = color.replace('rgb', 'rgba').replace(')', ', 0.1)');
337
340
  });
338
341
 
339
342
  new Chart(dailyTrendCtx, {
@@ -368,8 +371,16 @@
368
371
  datasets: [{
369
372
  label: 'Hours to Resolve',
370
373
  data: times,
371
- backgroundColor: 'rgba(255, 159, 64, 0.5)',
372
- borderColor: 'rgba(255, 159, 64, 1)',
374
+ backgroundColor: (function() {
375
+ const isDark = document.body.classList.contains('dark-mode');
376
+ const config = getCatppuccinChartConfig(isDark);
377
+ return config.colors.orange.replace('rgb', 'rgba').replace(')', ', 0.5)');
378
+ })(),
379
+ borderColor: (function() {
380
+ const isDark = document.body.classList.contains('dark-mode');
381
+ const config = getCatppuccinChartConfig(isDark);
382
+ return config.colors.orange;
383
+ })(),
373
384
  borderWidth: 1
374
385
  }]
375
386
  },