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
@@ -15,6 +15,9 @@ module RailsErrorDashboard
15
15
  # Association for tracking individual error occurrences
16
16
  has_many :error_occurrences, class_name: "RailsErrorDashboard::ErrorOccurrence", dependent: :destroy
17
17
 
18
+ # Association for comment threads (Phase 3: Workflow Integration)
19
+ has_many :comments, class_name: "RailsErrorDashboard::ErrorComment", foreign_key: :error_log_id, dependent: :destroy
20
+
18
21
  # Cascade pattern associations
19
22
  # parent_cascade_patterns: patterns where this error is the CHILD (errors that cause this error)
20
23
  has_many :parent_cascade_patterns, class_name: "RailsErrorDashboard::CascadePattern",
@@ -38,6 +41,15 @@ module RailsErrorDashboard
38
41
  scope :last_24_hours, -> { where("occurred_at >= ?", 24.hours.ago) }
39
42
  scope :last_week, -> { where("occurred_at >= ?", 1.week.ago) }
40
43
 
44
+ # Phase 3: Workflow Integration scopes
45
+ scope :active, -> { where("snoozed_until IS NULL OR snoozed_until < ?", Time.current) }
46
+ scope :snoozed, -> { where("snoozed_until IS NOT NULL AND snoozed_until >= ?", Time.current) }
47
+ scope :by_status, ->(status) { where(status: status) }
48
+ scope :assigned, -> { where.not(assigned_to: nil) }
49
+ scope :unassigned, -> { where(assigned_to: nil) }
50
+ scope :by_assignee, ->(name) { where(assigned_to: name) }
51
+ scope :by_priority, ->(level) { where(priority_level: level) }
52
+
41
53
  # Set defaults and tracking
42
54
  before_validation :set_defaults, on: :create
43
55
  before_create :set_tracking_fields
@@ -121,6 +133,11 @@ module RailsErrorDashboard
121
133
  SystemStackError
122
134
  SignalException
123
135
  ActiveRecord::StatementInvalid
136
+ LoadError
137
+ SyntaxError
138
+ ActiveRecord::ConnectionNotEstablished
139
+ Redis::ConnectionError
140
+ OpenSSL::SSL::SSLError
124
141
  ].freeze
125
142
 
126
143
  HIGH_SEVERITY_ERROR_TYPES = %w[
@@ -129,6 +146,11 @@ module RailsErrorDashboard
129
146
  TypeError
130
147
  NoMethodError
131
148
  NameError
149
+ ZeroDivisionError
150
+ FloatDomainError
151
+ IndexError
152
+ KeyError
153
+ RangeError
132
154
  ].freeze
133
155
 
134
156
  MEDIUM_SEVERITY_ERROR_TYPES = %w[
@@ -136,6 +158,10 @@ module RailsErrorDashboard
136
158
  Timeout::Error
137
159
  Net::ReadTimeout
138
160
  Net::OpenTimeout
161
+ ActiveRecord::RecordNotUnique
162
+ JSON::ParserError
163
+ CSV::MalformedCSVError
164
+ Errno::ECONNREFUSED
139
165
  ].freeze
140
166
 
141
167
  # Find existing error by hash or create new one
@@ -179,6 +205,139 @@ module RailsErrorDashboard
179
205
  Commands::ResolveError.call(id, resolution_data)
180
206
  end
181
207
 
208
+ # Phase 3: Workflow Integration methods
209
+
210
+ # Assignment methods
211
+ def assign_to!(assignee_name)
212
+ update!(
213
+ assigned_to: assignee_name,
214
+ assigned_at: Time.current,
215
+ status: "in_progress" # Auto-transition to in_progress when assigned
216
+ )
217
+ end
218
+
219
+ def unassign!
220
+ update!(
221
+ assigned_to: nil,
222
+ assigned_at: nil
223
+ )
224
+ end
225
+
226
+ def assigned?
227
+ assigned_to.present?
228
+ end
229
+
230
+ # Snooze methods
231
+ def snooze!(hours, reason: nil)
232
+ snooze_until = hours.hours.from_now
233
+ # Store snooze reason in comments if provided
234
+ if reason.present?
235
+ comments.create!(
236
+ author_name: assigned_to || "System",
237
+ body: "Snoozed for #{hours} hours: #{reason}"
238
+ )
239
+ end
240
+ update!(snoozed_until: snooze_until)
241
+ end
242
+
243
+ def unsnooze!
244
+ update!(snoozed_until: nil)
245
+ end
246
+
247
+ def snoozed?
248
+ snoozed_until.present? && snoozed_until >= Time.current
249
+ end
250
+
251
+ # Priority methods
252
+ def priority_label
253
+ case priority_level
254
+ when 3 then "Critical"
255
+ when 2 then "High"
256
+ when 1 then "Medium"
257
+ when 0 then "Low"
258
+ else "Unset"
259
+ end
260
+ end
261
+
262
+ def priority_color
263
+ case priority_level
264
+ when 3 then "danger" # Critical = red
265
+ when 2 then "warning" # High = orange
266
+ when 1 then "info" # Medium = blue
267
+ when 0 then "secondary" # Low = gray
268
+ else "light"
269
+ end
270
+ end
271
+
272
+ def calculate_priority
273
+ # Automatic priority calculation based on severity and frequency
274
+ severity_weight = case severity
275
+ when :critical then 3
276
+ when :high then 2
277
+ when :medium then 1
278
+ else 0
279
+ end
280
+
281
+ frequency_weight = if occurrence_count >= 100
282
+ 3
283
+ elsif occurrence_count >= 10
284
+ 2
285
+ elsif occurrence_count >= 5
286
+ 1
287
+ else
288
+ 0
289
+ end
290
+
291
+ # Take the higher of severity or frequency
292
+ [ severity_weight, frequency_weight ].max
293
+ end
294
+
295
+ # Status transition methods
296
+ def status_badge_color
297
+ case status
298
+ when "new" then "primary"
299
+ when "in_progress" then "info"
300
+ when "investigating" then "warning"
301
+ when "resolved" then "success"
302
+ when "wont_fix" then "secondary"
303
+ else "light"
304
+ end
305
+ end
306
+
307
+ def can_transition_to?(new_status)
308
+ # Define valid status transitions
309
+ valid_transitions = {
310
+ "new" => [ "in_progress", "investigating", "wont_fix" ],
311
+ "in_progress" => [ "investigating", "resolved", "new" ],
312
+ "investigating" => [ "resolved", "in_progress", "wont_fix" ],
313
+ "resolved" => [ "new" ], # Can reopen if error recurs
314
+ "wont_fix" => [ "new" ] # Can reopen
315
+ }
316
+
317
+ valid_transitions[status]&.include?(new_status) || false
318
+ end
319
+
320
+ def update_status!(new_status, comment: nil)
321
+ return false unless can_transition_to?(new_status)
322
+
323
+ transaction do
324
+ update!(status: new_status)
325
+
326
+ # Auto-resolve if status is "resolved"
327
+ update!(resolved: true) if new_status == "resolved"
328
+
329
+ # Add comment about status change
330
+ if comment.present?
331
+ comments.create!(
332
+ author_name: assigned_to || "System",
333
+ body: "Status changed to #{new_status}: #{comment}"
334
+ )
335
+ end
336
+ end
337
+
338
+ true
339
+ end
340
+
182
341
  # Get error statistics
183
342
  def self.statistics(days = 7)
184
343
  start_date = days.days.ago
@@ -1,16 +1,54 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <title>Rails error dashboard</title>
4
+ <title>Rails Error Dashboard</title>
5
5
  <%= csrf_meta_tags %>
6
6
  <%= csp_meta_tag %>
7
7
 
8
8
  <%= yield :head %>
9
9
 
10
10
  <%= stylesheet_link_tag "rails_error_dashboard/application", media: "all" %>
11
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
12
+ <script src="https://cdn.jsdelivr.net/npm/chartkick@5.0.1/dist/chartkick.min.js"></script>
11
13
  </head>
12
14
  <body>
13
15
 
16
+ <!-- Navigation -->
17
+ <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
18
+ <div class="container-fluid">
19
+ <%= link_to "Error Dashboard", root_path, class: "navbar-brand" %>
20
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
21
+ <span class="navbar-toggler-icon"></span>
22
+ </button>
23
+ <div class="collapse navbar-collapse" id="navbarNav">
24
+ <ul class="navbar-nav me-auto">
25
+ <li class="nav-item">
26
+ <%= link_to overview_path, class: "nav-link #{controller_name == 'errors' && action_name == 'overview' ? 'active' : ''}" do %>
27
+ <i class="bi bi-speedometer2"></i> Dashboard
28
+ <% end %>
29
+ </li>
30
+ <li class="nav-item">
31
+ <%= link_to errors_path, class: "nav-link #{controller_name == 'errors' && action_name == 'index' ? 'active' : ''}" do %>
32
+ <i class="bi bi-list-ul"></i> Errors
33
+ <% end %>
34
+ </li>
35
+ <li class="nav-item">
36
+ <%= link_to analytics_errors_path, class: "nav-link #{controller_name == 'errors' && action_name == 'analytics' ? 'active' : ''}" do %>
37
+ <i class="bi bi-graph-up"></i> Analytics
38
+ <% end %>
39
+ </li>
40
+ </ul>
41
+ <ul class="navbar-nav">
42
+ <li class="nav-item">
43
+ <a class="nav-link" href="#" id="theme-toggle">
44
+ <i class="bi bi-moon-stars"></i>
45
+ </a>
46
+ </li>
47
+ </ul>
48
+ </div>
49
+ </div>
50
+ </nav>
51
+
14
52
  <%= yield %>
15
53
 
16
54
  </body>