rails_error_dashboard 0.5.15 → 0.6.1

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/rails_error_dashboard/application_controller.rb +37 -12
  3. data/app/controllers/rails_error_dashboard/errors_controller.rb +48 -26
  4. data/app/helpers/rails_error_dashboard/application_helper.rb +12 -5
  5. data/app/views/layouts/rails_error_dashboard.html.erb +1219 -1927
  6. data/app/views/rails_error_dashboard/errors/_breadcrumbs_group.html.erb +4 -4
  7. data/app/views/rails_error_dashboard/errors/_co_occurring_errors.html.erb +1 -1
  8. data/app/views/rails_error_dashboard/errors/_discussion.html.erb +3 -3
  9. data/app/views/rails_error_dashboard/errors/_error_cascades.html.erb +1 -1
  10. data/app/views/rails_error_dashboard/errors/_error_row.html.erb +69 -79
  11. data/app/views/rails_error_dashboard/errors/_instance_variables.html.erb +1 -1
  12. data/app/views/rails_error_dashboard/errors/_issue_section.html.erb +1 -1
  13. data/app/views/rails_error_dashboard/errors/_local_variables.html.erb +1 -1
  14. data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +2 -2
  15. data/app/views/rails_error_dashboard/errors/_request_context.html.erb +1 -1
  16. data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +1 -1
  17. data/app/views/rails_error_dashboard/errors/_similar_errors.html.erb +1 -1
  18. data/app/views/rails_error_dashboard/errors/_timeline.html.erb +4 -4
  19. data/app/views/rails_error_dashboard/errors/actioncable_health_summary.html.erb +6 -6
  20. data/app/views/rails_error_dashboard/errors/activestorage_health_summary.html.erb +6 -6
  21. data/app/views/rails_error_dashboard/errors/analytics.html.erb +34 -50
  22. data/app/views/rails_error_dashboard/errors/cache_health_summary.html.erb +7 -7
  23. data/app/views/rails_error_dashboard/errors/correlation.html.erb +11 -11
  24. data/app/views/rails_error_dashboard/errors/database_health_summary.html.erb +114 -172
  25. data/app/views/rails_error_dashboard/errors/deprecations.html.erb +7 -7
  26. data/app/views/rails_error_dashboard/errors/diagnostic_dumps.html.erb +6 -6
  27. data/app/views/rails_error_dashboard/errors/index.html.erb +311 -613
  28. data/app/views/rails_error_dashboard/errors/job_health_summary.html.erb +7 -7
  29. data/app/views/rails_error_dashboard/errors/n_plus_one_summary.html.erb +7 -7
  30. data/app/views/rails_error_dashboard/errors/overview.html.erb +192 -363
  31. data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +11 -11
  32. data/app/views/rails_error_dashboard/errors/rack_attack_summary.html.erb +6 -6
  33. data/app/views/rails_error_dashboard/errors/releases.html.erb +6 -6
  34. data/app/views/rails_error_dashboard/errors/settings.html.erb +53 -51
  35. data/app/views/rails_error_dashboard/errors/show.html.erb +200 -203
  36. data/app/views/rails_error_dashboard/errors/swallowed_exceptions.html.erb +19 -19
  37. data/app/views/rails_error_dashboard/errors/user_impact.html.erb +6 -6
  38. data/config/routes.rb +1 -0
  39. data/lib/rails_error_dashboard/configuration.rb +6 -0
  40. data/lib/rails_error_dashboard/services/error_broadcaster.rb +1 -1
  41. data/lib/rails_error_dashboard/services/system_health_snapshot.rb +1 -1
  42. data/lib/rails_error_dashboard/test_error.rb +7 -0
  43. data/lib/rails_error_dashboard/version.rb +1 -1
  44. data/lib/rails_error_dashboard.rb +1 -0
  45. metadata +3 -2
@@ -5,7 +5,7 @@
5
5
  <% deprecation_crumbs = breadcrumbs.select { |c| c["c"] == "deprecation" } %>
6
6
  <% if deprecation_crumbs.any? %>
7
7
  <div class="card mb-4" id="section-deprecation-warnings" style="border-color: var(--bs-danger);">
8
- <div class="card-header bg-white">
8
+ <div class="card-header">
9
9
  <h5 class="mb-0">
10
10
  <i class="bi bi-exclamation-triangle text-danger"></i> Deprecation Warnings
11
11
  <span class="badge bg-danger"><%= deprecation_crumbs.size %></span>
@@ -49,7 +49,7 @@
49
49
  <% n_plus_one_patterns = RailsErrorDashboard::Services::NplusOneDetector.call(breadcrumbs) %>
50
50
  <% if n_plus_one_patterns.any? %>
51
51
  <div class="card mb-4" id="section-n-plus-one" style="border-color: var(--bs-warning);">
52
- <div class="card-header bg-white">
52
+ <div class="card-header">
53
53
  <h5 class="mb-0">
54
54
  <i class="bi bi-arrow-repeat text-warning"></i> N+1 Query Detection
55
55
  <span class="badge bg-warning text-dark"><%= n_plus_one_patterns.size %> pattern<%= n_plus_one_patterns.size == 1 ? "" : "s" %></span>
@@ -108,7 +108,7 @@
108
108
  <% cache_analysis = RailsErrorDashboard::Services::CacheAnalyzer.call(breadcrumbs) %>
109
109
  <% if cache_analysis %>
110
110
  <div class="card mb-4" id="section-cache-health" style="border-color: var(--bs-info);">
111
- <div class="card-header bg-white">
111
+ <div class="card-header">
112
112
  <h5 class="mb-0">
113
113
  <i class="bi bi-lightning-charge text-info"></i> Cache Health
114
114
  <span class="badge bg-info text-dark"><%= cache_analysis[:reads] + cache_analysis[:writes] %> operations</span>
@@ -189,7 +189,7 @@
189
189
  <% end %>
190
190
 
191
191
  <div class="card mb-4" id="section-breadcrumbs">
192
- <div class="card-header bg-white">
192
+ <div class="card-header">
193
193
  <h5 class="mb-0">
194
194
  <i class="bi bi-signpost-2"></i> Breadcrumbs
195
195
  <span class="badge bg-secondary"><%= breadcrumbs.size %> events</span>
@@ -3,7 +3,7 @@
3
3
  <% co_occurring = error.co_occurring_errors(window_minutes: 5, min_frequency: 2, limit: 5) %>
4
4
  <% if co_occurring.any? %>
5
5
  <div class="card mb-4" id="section-co-occurring">
6
- <div class="card-header bg-white">
6
+ <div class="card-header">
7
7
  <h5 class="mb-0">
8
8
  <i class="bi bi-clock-history"></i> Co-occurring Errors
9
9
  <span class="badge bg-info text-dark">Time Patterns</span>
@@ -5,7 +5,7 @@
5
5
 
6
6
  <% if has_linked_issue && (platform_comments.any? || has_audit_comments) %>
7
7
  <div class="card mb-4" id="section-discussion">
8
- <div class="card-header bg-white d-flex justify-content-between align-items-center">
8
+ <div class="card-header d-flex justify-content-between align-items-center">
9
9
  <h5 class="mb-0">
10
10
  <i class="bi bi-chat-dots"></i> Discussion
11
11
  <% if platform_comments.any? %>
@@ -62,7 +62,7 @@
62
62
  <% elsif has_linked_issue %>
63
63
  <!-- Issue linked but no comments yet -->
64
64
  <div class="card mb-4" id="section-discussion">
65
- <div class="card-header bg-white d-flex justify-content-between align-items-center">
65
+ <div class="card-header d-flex justify-content-between align-items-center">
66
66
  <h5 class="mb-0">
67
67
  <i class="bi bi-chat-dots"></i> Discussion
68
68
  </h5>
@@ -77,7 +77,7 @@
77
77
  <% elsif has_audit_comments %>
78
78
  <!-- No issue linked, but has audit trail -->
79
79
  <div class="card mb-4" id="section-discussion">
80
- <div class="card-header bg-white">
80
+ <div class="card-header">
81
81
  <h5 class="mb-0">
82
82
  <i class="bi bi-clock-history"></i> Activity Log
83
83
  </h5>
@@ -3,7 +3,7 @@
3
3
  <% cascades = error.error_cascades %>
4
4
  <% if cascades[:parents].any? || cascades[:children].any? %>
5
5
  <div class="card" id="section-error-cascades">
6
- <div class="card-header bg-white">
6
+ <div class="card-header">
7
7
  <h5 class="mb-0">
8
8
  <i class="bi bi-diagram-3"></i> Error Cascades
9
9
  <small class="text-muted ms-2">Causal relationships between errors</small>
@@ -1,54 +1,83 @@
1
- <tr id="error_<%= error.id %>">
2
- <td onclick="event.stopPropagation();">
3
- <input type="checkbox" class="error-checkbox form-check-input" value="<%= error.id %>" data-error-id="<%= error.id %>">
1
+ <tr id="error_<%= error.id %>"
2
+ onclick="window.location='<%= error_path(error, **app_context) %>'"
3
+ style="border-bottom: 1px solid var(--border-primary); cursor: pointer; transition: background 0.1s ease;"
4
+ onmouseenter="this.style.background='var(--surface-hover)'; this.querySelector('.sev-bar').style.opacity='1';"
5
+ onmouseleave="this.style.background='transparent'; this.querySelector('.sev-bar').style.opacity='0';">
6
+ <td style="padding: var(--space-3) var(--space-4); text-align: center; position: relative;" onclick="event.stopPropagation(); var cb = this.querySelector('input'); cb.checked = !cb.checked; cb.dispatchEvent(new Event('change'));">
7
+ <span class="sev-bar" style="position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: <%= severity_color_var(error.severity) %>; opacity: 0; transition: opacity 0.1s ease; border-radius: 0 2px 2px 0;"></span>
8
+ <input type="checkbox" class="error-checkbox form-check-input" value="<%= error.id %>" data-error-id="<%= error.id %>" onclick="event.stopPropagation();" style="accent-color: var(--accent);">
4
9
  </td>
5
- <td onclick="window.location='<%= error_path(error) %>';">
6
- <% severity = error.severity %>
7
- <% if severity == :critical %>
8
- <span class="badge bg-danger" data-bs-toggle="tooltip" title="Critical severity - requires immediate attention">CRITICAL</span>
9
- <% elsif severity == :high %>
10
- <span class="badge bg-warning text-dark" data-bs-toggle="tooltip" title="High severity - should be fixed soon">HIGH</span>
11
- <% elsif severity == :medium %>
12
- <span class="badge bg-info text-dark" data-bs-toggle="tooltip" title="Medium severity - fix when possible">MEDIUM</span>
13
- <% else %>
14
- <span class="badge bg-secondary" data-bs-toggle="tooltip" title="Low severity - minor issue">LOW</span>
15
- <% end %>
16
- <% if error.respond_to?(:priority_score) && error.priority_score %>
17
- <br><small class="text-muted" data-bs-toggle="tooltip" title="Priority score (0-100) based on severity, frequency, recency, and user impact">P<%= error.priority_score %></small>
18
- <% end %>
10
+ <td style="padding: var(--space-3) var(--space-4);" onclick="window.location='<%= error_path(error, **app_context) %>'">
11
+ <div style="display: flex; align-items: center; gap: 8px;">
12
+ <span class="badge bg-<%= severity_color(error.severity) %>" style="display: inline-flex; align-items: center; gap: 4px;">
13
+ <span style="width: 6px; height: 6px; border-radius: 50%; background: currentColor;"></span>
14
+ <%= error.severity %>
15
+ </span>
16
+ <div style="min-width: 0;">
17
+ <div style="font-weight: 600; color: var(--text-primary); font-family: var(--font-mono); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
18
+ <%= error.error_type %>
19
+ <% if error.recent? %>
20
+ <span style="display: inline-block; padding: 1px 6px; font-size: 9px; font-weight: 600; border-radius: var(--radius-full); background: var(--status-success-bg); color: var(--status-success); margin-left: 4px; text-transform: uppercase;">NEW</span>
21
+ <% end %>
22
+ </div>
23
+ <div style="color: var(--text-tertiary); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="<%= error.message %>"><%= error.message %></div>
24
+ </div>
25
+ </div>
19
26
  </td>
20
- <td onclick="window.location='<%= error_path(error) %>';">
21
- <code class="text-danger" data-bs-toggle="tooltip" title="<%= error.error_type %>"><%= error.error_type.split('::').last %></code>
22
- <% if error.recent? %>
23
- <span class="badge bg-success ms-1" data-bs-toggle="tooltip" title="Error occurred within the last hour">NEW</span>
24
- <% end %>
25
- <% if error.respond_to?(:app_version) && error.app_version.present? %>
26
- <br><small class="badge bg-light text-dark" data-bs-toggle="tooltip" title="App version when error occurred">v<%= error.app_version %></small>
27
+ <td style="padding: var(--space-3) var(--space-4);" onclick="window.location='<%= error_path(error, **app_context) %>'">
28
+ <%
29
+ # Use the model's status field if it has a meaningful workflow status
30
+ raw_status = error.respond_to?(:status) ? error.status : nil
31
+ status_text = if error.respond_to?(:muted?) && error.muted?
32
+ 'muted'
33
+ elsif error.respond_to?(:snoozed?) && error.snoozed?
34
+ 'snoozed'
35
+ elsif raw_status.present? && raw_status != 'new'
36
+ raw_status.tr('_', ' ')
37
+ elsif error.resolved?
38
+ 'resolved'
39
+ else
40
+ 'unresolved'
41
+ end
42
+ status_colors = {
43
+ 'unresolved' => { bg: 'var(--status-critical-bg)', color: 'var(--status-critical)' },
44
+ 'resolved' => { bg: 'var(--status-success-bg)', color: 'var(--status-success)' },
45
+ 'in progress' => { bg: 'var(--status-info-bg)', color: 'var(--status-info)' },
46
+ 'investigating' => { bg: 'var(--status-caution-bg)', color: 'var(--status-caution)' },
47
+ 'wont fix' => { bg: 'var(--surface-tertiary)', color: 'var(--text-tertiary)' },
48
+ 'assigned' => { bg: 'var(--accent-subtle)', color: 'var(--accent)' },
49
+ 'snoozed' => { bg: 'var(--status-caution-bg)', color: 'var(--status-caution)' },
50
+ 'muted' => { bg: 'var(--surface-tertiary)', color: 'var(--text-tertiary)' },
51
+ }
52
+ sc = status_colors[status_text] || status_colors['unresolved']
53
+ %>
54
+ <span style="display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; font-size: 11px; font-weight: 600; border-radius: var(--radius-full); background: <%= sc[:bg] %>; color: <%= sc[:color] %>; text-transform: capitalize;">
55
+ <%= status_text %>
56
+ </span>
57
+ <% if error.reopened? %>
58
+ <i class="bi bi-arrow-counterclockwise" style="color: var(--status-warning); margin-left: 4px; font-size: 12px;" title="Reopened"></i>
27
59
  <% end %>
28
60
  </td>
29
- <td onclick="window.location='<%= error_path(error) %>';">
30
- <div class="text-truncate" style="max-width: 300px;" title="<%= error.message %>">
31
- <%= error.message %>
32
- </div>
61
+ <td style="padding: var(--space-3) var(--space-4); text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text-primary);" onclick="window.location='<%= error_path(error, **app_context) %>'">
62
+ <%= error.occurrence_count.to_s(:delimited) rescue error.occurrence_count %>
33
63
  </td>
34
- <td onclick="window.location='<%= error_path(error) %>';">
35
- <span class="badge bg-primary"><%= error.occurrence_count %>x</span>
64
+ <td style="padding: var(--space-3) var(--space-4); text-align: right; font-variant-numeric: tabular-nums; color: var(--text-secondary);" onclick="window.location='<%= error_path(error, **app_context) %>'">
65
+ <% if error.user_id %>
66
+ <%= error.user_id %>
67
+ <% else %>
68
+ <span style="color: var(--text-tertiary);">&mdash;</span>
69
+ <% end %>
36
70
  </td>
37
- <td onclick="window.location='<%= error_path(error) %>';">
38
- <small>
39
- <strong>First:</strong> <%= local_time(error.first_seen_at, format: :short) %><br>
40
- <strong>Last:</strong> <%= local_time(error.last_seen_at, format: :short) %>
41
- </small>
71
+ <td style="padding: var(--space-3) var(--space-4); text-align: right; color: var(--text-tertiary); font-size: 12px;" onclick="window.location='<%= error_path(error, **app_context) %>'">
72
+ <%= local_time_ago(error.last_seen_at) %>
42
73
  </td>
43
74
  <% if local_assigns[:show_application] %>
44
- <td onclick="window.location='<%= error_path(error) %>';">
45
- <span class="badge bg-info">
46
- <%= error.application&.name || 'Unknown' %>
47
- </span>
75
+ <td style="padding: var(--space-3) var(--space-4); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="<%= error.application&.name || 'Unknown' %>" onclick="window.location='<%= error_path(error, **app_context) %>'">
76
+ <span class="badge bg-info"><%= error.application&.name || 'Unknown' %></span>
48
77
  </td>
49
78
  <% end %>
50
79
  <% if local_assigns[:show_platform] %>
51
- <td onclick="window.location='<%= error_path(error) %>';">
80
+ <td style="padding: var(--space-3) var(--space-4); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="<%= error.platform || 'API' %>" onclick="window.location='<%= error_path(error, **app_context) %>'">
52
81
  <% if error.platform == 'iOS' %>
53
82
  <span class="badge badge-ios"><i class="bi bi-apple"></i> iOS</span>
54
83
  <% elsif error.platform == 'Android' %>
@@ -60,43 +89,4 @@
60
89
  <% end %>
61
90
  </td>
62
91
  <% end %>
63
- <td onclick="window.location='<%= error_path(error) %>';">
64
- <% if error.user_id %>
65
- <small data-bs-toggle="tooltip" title="User affected by this error">User #<%= error.user_id %></small>
66
- <% if error.respond_to?(:user_impact_percentage) %>
67
- <% impact = error.user_impact_percentage %>
68
- <% if impact > 0 %>
69
- <br><small class="badge bg-warning text-dark" data-bs-toggle="tooltip" title="Percentage of users affected by this error type"><%= impact %>% impact</small>
70
- <% end %>
71
- <% end %>
72
- <% else %>
73
- <small class="text-muted" data-bs-toggle="tooltip" title="No specific user affected">-</small>
74
- <% end %>
75
- </td>
76
- <td onclick="window.location='<%= error_path(error) %>';">
77
- <% if error.resolved? %>
78
- <i class="bi bi-check-circle-fill text-success"
79
- data-bs-toggle="tooltip"
80
- data-bs-placement="left"
81
- data-bs-html="true"
82
- title="<%= if error.resolution_comment.present?
83
- "<strong>Resolved</strong><br><em>#{error.resolution_comment.truncate(100).gsub('"', '&quot;').gsub("'", '&#39;')}</em>"
84
- else
85
- 'Resolved'
86
- end %>"></i>
87
- <% else %>
88
- <i class="bi bi-exclamation-circle-fill text-danger" data-bs-toggle="tooltip" title="Unresolved"></i>
89
- <% end %>
90
- <% if error.reopened? %>
91
- <i class="bi bi-arrow-counterclockwise text-warning ms-1" data-bs-toggle="tooltip" title="Reopened"></i>
92
- <% end %>
93
- <% if error.respond_to?(:muted?) && error.muted? %>
94
- <i class="bi bi-bell-slash text-secondary ms-1" data-bs-toggle="tooltip" title="Muted - notifications silenced"></i>
95
- <% end %>
96
- </td>
97
- <td onclick="event.stopPropagation();">
98
- <%= link_to error_path(error), class: "btn btn-sm btn-outline-primary" do %>
99
- <i class="bi bi-eye"></i>
100
- <% end %>
101
- </td>
102
92
  </tr>
@@ -4,7 +4,7 @@
4
4
  <% self_class = instance_vars.delete("_self_class") %>
5
5
  <% if instance_vars.any? %>
6
6
  <div class="card mb-4" id="section-instance-variables">
7
- <div class="card-header bg-white">
7
+ <div class="card-header">
8
8
  <h5 class="mb-0">
9
9
  <i class="bi bi-box"></i> Instance Variables
10
10
  <span class="badge bg-secondary"><%= instance_vars.size %> captured</span>
@@ -1,6 +1,6 @@
1
1
  <% if RailsErrorDashboard.configuration.enable_issue_tracking %>
2
2
  <div class="card mb-4" id="issue-tracking">
3
- <div class="card-header bg-white d-flex justify-content-between align-items-center">
3
+ <div class="card-header d-flex justify-content-between align-items-center">
4
4
  <h5 class="mb-0">
5
5
  <i class="bi bi-link-45deg me-2"></i>
6
6
  Issue Tracker
@@ -3,7 +3,7 @@
3
3
  <% local_vars = JSON.parse(error.local_variables) rescue {} %>
4
4
  <% if local_vars.any? %>
5
5
  <div class="card mb-4" id="section-local-variables">
6
- <div class="card-header bg-white">
6
+ <div class="card-header">
7
7
  <h5 class="mb-0">
8
8
  <i class="bi bi-braces"></i> Local Variables
9
9
  <span class="badge bg-secondary"><%= local_vars.size %> captured</span>
@@ -7,7 +7,7 @@
7
7
 
8
8
  <% if pattern_data.present? && pattern_data[:total_errors] > 0 %>
9
9
  <div class="card mb-4" id="section-occurrence-patterns">
10
- <div class="card-header bg-white">
10
+ <div class="card-header">
11
11
  <h5 class="mb-0">
12
12
  <i class="bi bi-graph-up"></i> Occurrence Patterns
13
13
  <small class="text-muted">(Last 30 days)</small>
@@ -128,7 +128,7 @@
128
128
  <!-- Error Bursts -->
129
129
  <% if bursts.present? && bursts.any? %>
130
130
  <div class="card mb-4">
131
- <div class="card-header bg-white">
131
+ <div class="card-header">
132
132
  <h5 class="mb-0">
133
133
  <i class="bi bi-lightning-charge-fill text-warning"></i> Error Bursts
134
134
  <span class="badge bg-warning text-dark"><%= bursts.count %></span>
@@ -1,7 +1,7 @@
1
1
  <!-- Request Context -->
2
2
  <% cache [error, 'request_context_v3'] do %>
3
3
  <div class="card mb-4" id="section-request-context">
4
- <div class="card-header bg-white">
4
+ <div class="card-header">
5
5
  <h5 class="mb-0"><i class="bi bi-globe"></i> Request Context</h5>
6
6
  </div>
7
7
  <div class="card-body">
@@ -1,6 +1,6 @@
1
1
  <!-- Metadata Card -->
2
2
  <div class="card mb-4">
3
- <div class="card-header bg-white">
3
+ <div class="card-header">
4
4
  <h5 class="mb-0"><i class="bi bi-info-circle"></i> Metadata</h5>
5
5
  </div>
6
6
  <div class="card-body">
@@ -4,7 +4,7 @@
4
4
  <% if similar.any? %>
5
5
  <% cache [error, 'similar_errors_v1', similar.map { |s| s[:error]&.updated_at }.compact.max] do %>
6
6
  <div class="card mb-4" id="section-similar-errors">
7
- <div class="card-header bg-white">
7
+ <div class="card-header">
8
8
  <h5 class="mb-0">
9
9
  <i class="bi bi-diagram-3"></i> Similar Errors
10
10
  <span class="badge bg-info text-dark">Fuzzy Matching</span>
@@ -1,7 +1,7 @@
1
1
  <%# Timeline view for related errors leading up to this error %>
2
2
  <% if @related_errors.any? %>
3
3
  <div class="card" id="section-timeline">
4
- <div class="card-header bg-white">
4
+ <div class="card-header">
5
5
  <h5 class="mb-0">
6
6
  <i class="bi bi-clock-history"></i> Timeline
7
7
  <small class="text-muted ms-2">Recent related errors</small>
@@ -87,11 +87,11 @@
87
87
  </div>
88
88
 
89
89
  <% if error.resolved? && error.resolution_comment.present? %>
90
- <div class="mt-2 p-2 bg-success bg-opacity-10 border border-success rounded">
91
- <small class="text-success fw-bold">
90
+ <div style="margin-top: var(--space-2); padding: var(--space-2) var(--space-3); background: var(--status-success-bg); border: 1px solid var(--status-success); border-radius: var(--radius-sm);">
91
+ <small style="color: var(--status-success); font-weight: 600;">
92
92
  <i class="bi bi-journal-text"></i> Resolution Notes:
93
93
  </small>
94
- <div class="mb-0 small text-muted mt-1">
94
+ <div style="font-size: 13px; color: var(--text-primary); margin-top: 4px;">
95
95
  <%= auto_link_urls(truncate(error.resolution_comment, length: 200), error: error).html_safe %>
96
96
  </div>
97
97
  </div>
@@ -1,8 +1,8 @@
1
1
  <% content_for :page_title, "ActionCable Health" %>
2
2
 
3
- <div class="container-fluid py-4">
3
+ <div>
4
4
  <div class="d-flex justify-content-between align-items-center mb-4">
5
- <h1 class="h3 mb-0">
5
+ <h1 style="font-size: 20px; font-weight: 700; margin: 0;">
6
6
  <i class="bi bi-broadcast me-2"></i>
7
7
  ActionCable Health
8
8
  </h1>
@@ -21,9 +21,9 @@
21
21
  </div>
22
22
 
23
23
  <% if @unique_channels == 0 %>
24
- <div class="text-center py-5">
24
+ <div class="red-empty-state">
25
25
  <i class="bi bi-broadcast display-1 text-success mb-3"></i>
26
- <h4 class="text-muted">No ActionCable Events Found</h4>
26
+ <div class="red-empty-state-title">No ActionCable Events Found</div>
27
27
  <p class="text-muted">
28
28
  No ActionCable channel actions, transmissions, or subscription events were detected in error breadcrumbs over the last <%= @days %> days.
29
29
  </p>
@@ -68,7 +68,7 @@
68
68
  </div>
69
69
 
70
70
  <div class="card mb-4">
71
- <div class="card-header bg-white d-flex justify-content-between align-items-center">
71
+ <div class="card-header d-flex justify-content-between align-items-center">
72
72
  <h5 class="mb-0">
73
73
  <i class="bi bi-broadcast text-primary me-2"></i>
74
74
  ActionCable Events by Channel
@@ -112,7 +112,7 @@
112
112
  </table>
113
113
  </div>
114
114
  </div>
115
- <div class="card-footer bg-white border-top d-flex justify-content-between align-items-center">
115
+ <div class="card-footer border-top d-flex justify-content-between align-items-center">
116
116
  <div>
117
117
  <small class="text-muted">
118
118
  <i class="bi bi-lightbulb text-warning"></i> ActionCable events are captured when they coincide with errors. High rejection counts may indicate authentication or authorization issues.
@@ -1,8 +1,8 @@
1
1
  <% content_for :page_title, "ActiveStorage Health" %>
2
2
 
3
- <div class="container-fluid py-4">
3
+ <div>
4
4
  <div class="d-flex justify-content-between align-items-center mb-4">
5
- <h1 class="h3 mb-0">
5
+ <h1 style="font-size: 20px; font-weight: 700; margin: 0;">
6
6
  <i class="bi bi-cloud-arrow-up me-2"></i>
7
7
  ActiveStorage Health
8
8
  </h1>
@@ -21,9 +21,9 @@
21
21
  </div>
22
22
 
23
23
  <% if @unique_services == 0 %>
24
- <div class="text-center py-5">
24
+ <div class="red-empty-state">
25
25
  <i class="bi bi-cloud-arrow-up display-1 text-success mb-3"></i>
26
- <h4 class="text-muted">No ActiveStorage Events Found</h4>
26
+ <div class="red-empty-state-title">No ActiveStorage Events Found</div>
27
27
  <p class="text-muted">
28
28
  No ActiveStorage service operations were detected in error breadcrumbs over the last <%= @days %> days.
29
29
  </p>
@@ -68,7 +68,7 @@
68
68
  </div>
69
69
 
70
70
  <div class="card mb-4">
71
- <div class="card-header bg-white d-flex justify-content-between align-items-center">
71
+ <div class="card-header d-flex justify-content-between align-items-center">
72
72
  <h5 class="mb-0">
73
73
  <i class="bi bi-cloud-arrow-up text-primary me-2"></i>
74
74
  Storage Operations by Service
@@ -128,7 +128,7 @@
128
128
  </table>
129
129
  </div>
130
130
  </div>
131
- <div class="card-footer bg-white border-top d-flex justify-content-between align-items-center">
131
+ <div class="card-footer border-top d-flex justify-content-between align-items-center">
132
132
  <div>
133
133
  <small class="text-muted">
134
134
  <i class="bi bi-lightbulb text-warning"></i> Slow storage operations may indicate network issues, large file sizes, or service provider throttling.