rails_error_dashboard 0.1.10 → 0.1.11
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/app/helpers/rails_error_dashboard/application_helper.rb +18 -0
- data/app/views/layouts/rails_error_dashboard.html.erb +128 -2
- data/app/views/rails_error_dashboard/errors/_error_row.html.erb +4 -4
- data/app/views/rails_error_dashboard/errors/_timeline.html.erb +5 -3
- data/app/views/rails_error_dashboard/errors/analytics.html.erb +2 -0
- data/app/views/rails_error_dashboard/errors/correlation.html.erb +21 -8
- data/app/views/rails_error_dashboard/errors/index.html.erb +46 -0
- data/app/views/rails_error_dashboard/errors/overview.html.erb +1 -0
- data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +11 -3
- data/app/views/rails_error_dashboard/errors/settings.html.erb +2 -0
- data/app/views/rails_error_dashboard/errors/show.html.erb +54 -20
- data/lib/rails_error_dashboard/version.rb +1 -1
- metadata +2 -3
- data/config/initializers/rails_error_dashboard.rb +0 -172
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f624e3d828c1bd13e2f98c7076096a45e448463c3ab46933ef41cdd568780abb
|
|
4
|
+
data.tar.gz: f3cb4c5ce26df2242fb023f295031ad19d0700bd37eda64caa8b6ee1725adbd1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e4f0277d96727d46667fe0d234986c10e612f0760f3bf7d15834b0491877843003a173ff20421981b60e989a95e996267ca3fd057091bd847df17873c8118e7e
|
|
7
|
+
data.tar.gz: 9710fd4639ba289f8ebac6f100c8abc32bbd4ba09309b6f80e2768f4eb520d2a80f23043d47d074e359ac73f8a25da3d8c1c4d66e118f728e0c8f7164e63e60d
|
|
@@ -56,6 +56,24 @@ module RailsErrorDashboard
|
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
# Returns platform icon
|
|
60
|
+
# @param platform [String] Platform name (ios, android, web, api)
|
|
61
|
+
# @return [String] Bootstrap icon class
|
|
62
|
+
def platform_icon(platform)
|
|
63
|
+
case platform&.downcase
|
|
64
|
+
when "ios"
|
|
65
|
+
"bi-apple"
|
|
66
|
+
when "android"
|
|
67
|
+
"bi-android2"
|
|
68
|
+
when "web"
|
|
69
|
+
"bi-globe"
|
|
70
|
+
when "api"
|
|
71
|
+
"bi-server"
|
|
72
|
+
else
|
|
73
|
+
"bi-question-circle"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
59
77
|
# Returns the current user name for filtering "My Errors"
|
|
60
78
|
# Uses configured dashboard username or system username
|
|
61
79
|
# @return [String] Current user identifier
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html>
|
|
3
3
|
<head>
|
|
4
|
-
<title><%= Rails.application.class.module_parent_name %> - Error Dashboard</title>
|
|
4
|
+
<title><%= content_for?(:page_title) ? "#{content_for(:page_title)} | " : "" %><%= Rails.application.class.module_parent_name %> - Error Dashboard</title>
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
6
|
<%= csrf_meta_tags %>
|
|
7
7
|
<%= csp_meta_tag %>
|
|
@@ -152,6 +152,17 @@
|
|
|
152
152
|
background-color: var(--ctp-surface1);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
/* Sticky table header for error list */
|
|
156
|
+
.table-responsive thead th {
|
|
157
|
+
position: sticky;
|
|
158
|
+
top: 0;
|
|
159
|
+
z-index: 10;
|
|
160
|
+
background-color: #f8f9fa;
|
|
161
|
+
}
|
|
162
|
+
body.dark-mode .table-responsive thead th {
|
|
163
|
+
background-color: var(--ctp-mantle);
|
|
164
|
+
}
|
|
165
|
+
|
|
155
166
|
/* Badges - Platform Colors */
|
|
156
167
|
.badge-ios {
|
|
157
168
|
background-color: #000;
|
|
@@ -724,10 +735,47 @@
|
|
|
724
735
|
body.dark-mode .card text {
|
|
725
736
|
fill: var(--ctp-text) !important;
|
|
726
737
|
}
|
|
738
|
+
|
|
739
|
+
/* Toast notifications */
|
|
740
|
+
.toast {
|
|
741
|
+
min-width: 250px;
|
|
742
|
+
}
|
|
743
|
+
.toast-container {
|
|
744
|
+
max-width: 350px;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* Filter pills */
|
|
748
|
+
.filter-pill {
|
|
749
|
+
display: inline-flex;
|
|
750
|
+
align-items: center;
|
|
751
|
+
padding: 0.5rem 0.75rem;
|
|
752
|
+
font-size: 0.875rem;
|
|
753
|
+
border-radius: 0.375rem;
|
|
754
|
+
transition: all 0.2s ease;
|
|
755
|
+
}
|
|
756
|
+
.filter-pill:hover {
|
|
757
|
+
opacity: 0.85;
|
|
758
|
+
transform: translateY(-1px);
|
|
759
|
+
}
|
|
760
|
+
.filter-pill .bi-x {
|
|
761
|
+
font-size: 1.1rem;
|
|
762
|
+
font-weight: bold;
|
|
763
|
+
}
|
|
764
|
+
body.dark-mode .filter-pill.bg-primary {
|
|
765
|
+
background-color: var(--ctp-mauve) !important;
|
|
766
|
+
}
|
|
767
|
+
body.dark-mode .filter-pill.bg-secondary {
|
|
768
|
+
background-color: var(--ctp-surface2) !important;
|
|
769
|
+
}
|
|
727
770
|
</style>
|
|
728
771
|
</head>
|
|
729
772
|
|
|
730
773
|
<body>
|
|
774
|
+
<!-- Toast Container -->
|
|
775
|
+
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 9999;">
|
|
776
|
+
<!-- Toasts will be dynamically inserted here -->
|
|
777
|
+
</div>
|
|
778
|
+
|
|
731
779
|
<!-- Top Navbar -->
|
|
732
780
|
<nav class="navbar navbar-dark">
|
|
733
781
|
<div class="container-fluid">
|
|
@@ -735,7 +783,7 @@
|
|
|
735
783
|
<button class="btn btn-link text-white d-md-none me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu">
|
|
736
784
|
<i class="bi bi-list fs-4"></i>
|
|
737
785
|
</button>
|
|
738
|
-
<a class="navbar-brand" href="<%= root_path %>">
|
|
786
|
+
<a class="navbar-brand" href="<%= main_app.root_path %>" title="Back to <%= Rails.application.class.module_parent_name %>">
|
|
739
787
|
<i class="bi bi-bug-fill"></i>
|
|
740
788
|
<span class="d-none d-sm-inline"><%= Rails.application.class.module_parent_name %></span>
|
|
741
789
|
<span class="d-none d-md-inline text-white-50 mx-2">|</span>
|
|
@@ -1001,6 +1049,84 @@
|
|
|
1001
1049
|
console.log('✅ Stopped force applying');
|
|
1002
1050
|
}
|
|
1003
1051
|
}, 500);
|
|
1052
|
+
|
|
1053
|
+
// Copy to clipboard functionality
|
|
1054
|
+
window.copyToClipboard = function(text, button) {
|
|
1055
|
+
navigator.clipboard.writeText(text).then(function() {
|
|
1056
|
+
// Store original button HTML
|
|
1057
|
+
const originalHTML = button.innerHTML;
|
|
1058
|
+
|
|
1059
|
+
// Show success state on button
|
|
1060
|
+
button.innerHTML = '<i class="bi bi-check"></i> Copied!';
|
|
1061
|
+
button.classList.remove('btn-outline-secondary');
|
|
1062
|
+
button.classList.add('btn-success');
|
|
1063
|
+
|
|
1064
|
+
// Show toast notification
|
|
1065
|
+
showToast('Copied to clipboard!', 'success');
|
|
1066
|
+
|
|
1067
|
+
// Reset button after 2 seconds
|
|
1068
|
+
setTimeout(function() {
|
|
1069
|
+
button.innerHTML = originalHTML;
|
|
1070
|
+
button.classList.remove('btn-success');
|
|
1071
|
+
button.classList.add('btn-outline-secondary');
|
|
1072
|
+
}, 2000);
|
|
1073
|
+
}).catch(function(err) {
|
|
1074
|
+
console.error('Failed to copy:', err);
|
|
1075
|
+
button.innerHTML = '<i class="bi bi-x"></i> Failed';
|
|
1076
|
+
showToast('Failed to copy to clipboard', 'danger');
|
|
1077
|
+
});
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
// Toast notification functionality
|
|
1081
|
+
window.showToast = function(message, type) {
|
|
1082
|
+
type = type || 'success';
|
|
1083
|
+
|
|
1084
|
+
const toastId = 'toast-' + Date.now();
|
|
1085
|
+
const iconClass = type === 'success' ? 'bi-check-circle-fill' :
|
|
1086
|
+
type === 'danger' ? 'bi-exclamation-circle-fill' :
|
|
1087
|
+
'bi-info-circle-fill';
|
|
1088
|
+
const bgClass = type === 'success' ? 'bg-success' :
|
|
1089
|
+
type === 'danger' ? 'bg-danger' :
|
|
1090
|
+
'bg-info';
|
|
1091
|
+
|
|
1092
|
+
const toastHTML = `
|
|
1093
|
+
<div id="${toastId}" class="toast align-items-center text-white ${bgClass} border-0" role="alert" aria-live="assertive" aria-atomic="true">
|
|
1094
|
+
<div class="d-flex">
|
|
1095
|
+
<div class="toast-body">
|
|
1096
|
+
<i class="bi ${iconClass} me-2"></i>
|
|
1097
|
+
${message}
|
|
1098
|
+
</div>
|
|
1099
|
+
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
1100
|
+
</div>
|
|
1101
|
+
</div>
|
|
1102
|
+
`;
|
|
1103
|
+
|
|
1104
|
+
const container = document.querySelector('.toast-container');
|
|
1105
|
+
container.insertAdjacentHTML('beforeend', toastHTML);
|
|
1106
|
+
|
|
1107
|
+
const toastElement = document.getElementById(toastId);
|
|
1108
|
+
const toast = new bootstrap.Toast(toastElement, { delay: 4000 });
|
|
1109
|
+
toast.show();
|
|
1110
|
+
|
|
1111
|
+
// Remove toast element after it's hidden
|
|
1112
|
+
toastElement.addEventListener('hidden.bs.toast', function() {
|
|
1113
|
+
toastElement.remove();
|
|
1114
|
+
});
|
|
1115
|
+
};
|
|
1116
|
+
|
|
1117
|
+
// Show flash messages as toasts
|
|
1118
|
+
<% if flash[:notice] %>
|
|
1119
|
+
showToast('<%= j flash[:notice] %>', 'success');
|
|
1120
|
+
<% end %>
|
|
1121
|
+
<% if flash[:alert] %>
|
|
1122
|
+
showToast('<%= j flash[:alert] %>', 'danger');
|
|
1123
|
+
<% end %>
|
|
1124
|
+
<% if flash[:success] %>
|
|
1125
|
+
showToast('<%= j flash[:success] %>', 'success');
|
|
1126
|
+
<% end %>
|
|
1127
|
+
<% if flash[:error] %>
|
|
1128
|
+
showToast('<%= j flash[:error] %>', 'danger');
|
|
1129
|
+
<% end %>
|
|
1004
1130
|
});
|
|
1005
1131
|
</script>
|
|
1006
1132
|
</body>
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
<% if local_assigns[:show_platform] %>
|
|
41
41
|
<td onclick="window.location='<%= error_path(error) %>';">
|
|
42
42
|
<% if error.platform == 'iOS' %>
|
|
43
|
-
<span class="badge badge-ios">iOS</span>
|
|
43
|
+
<span class="badge badge-ios"><i class="bi bi-apple"></i> iOS</span>
|
|
44
44
|
<% elsif error.platform == 'Android' %>
|
|
45
|
-
<span class="badge badge-android">Android</span>
|
|
45
|
+
<span class="badge badge-android"><i class="bi bi-android2"></i> Android</span>
|
|
46
46
|
<% elsif error.platform == 'Web' %>
|
|
47
|
-
<span class="badge badge-web">Web</span>
|
|
47
|
+
<span class="badge badge-web"><i class="bi bi-globe"></i> Web</span>
|
|
48
48
|
<% else %>
|
|
49
|
-
<span class="badge badge-api"
|
|
49
|
+
<span class="badge badge-api"><i class="bi bi-server"></i> <%= error.platform || 'API' %></span>
|
|
50
50
|
<% end %>
|
|
51
51
|
</td>
|
|
52
52
|
<% end %>
|
|
@@ -36,11 +36,13 @@
|
|
|
36
36
|
|
|
37
37
|
<% if error.platform.present? %>
|
|
38
38
|
<% if error.platform == 'iOS' %>
|
|
39
|
-
<span class="badge badge-ios ms-2">iOS</span>
|
|
39
|
+
<span class="badge badge-ios ms-2"><i class="bi bi-apple"></i> iOS</span>
|
|
40
40
|
<% elsif error.platform == 'Android' %>
|
|
41
|
-
<span class="badge badge-android ms-2">Android</span>
|
|
41
|
+
<span class="badge badge-android ms-2"><i class="bi bi-android2"></i> Android</span>
|
|
42
|
+
<% elsif error.platform == 'Web' %>
|
|
43
|
+
<span class="badge badge-web ms-2"><i class="bi bi-globe"></i> Web</span>
|
|
42
44
|
<% else %>
|
|
43
|
-
<span class="badge badge-api ms-2"
|
|
45
|
+
<span class="badge badge-api ms-2"><i class="bi bi-server"></i> <%= error.platform %></span>
|
|
44
46
|
<% end %>
|
|
45
47
|
<% end %>
|
|
46
48
|
</div>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<% content_for :page_title, "Error Correlation" %>
|
|
2
|
+
|
|
1
3
|
<div class="container-fluid py-4">
|
|
2
4
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
3
5
|
<h1 class="h3 mb-0">
|
|
@@ -368,14 +370,25 @@
|
|
|
368
370
|
|
|
369
371
|
<!-- Empty State -->
|
|
370
372
|
<% if @errors_by_version.blank? && @multi_error_users.blank? && @time_correlated_errors.blank? %>
|
|
371
|
-
<div class="
|
|
372
|
-
<i class="bi bi-
|
|
373
|
-
Not
|
|
374
|
-
<
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
373
|
+
<div class="text-center py-5">
|
|
374
|
+
<i class="bi bi-diagram-3 display-1 text-muted mb-3"></i>
|
|
375
|
+
<h4 class="text-muted">Not Enough Data for Correlation Analysis</h4>
|
|
376
|
+
<p class="text-muted">
|
|
377
|
+
Correlation analysis requires more error data to identify patterns.
|
|
378
|
+
</p>
|
|
379
|
+
<div class="card mx-auto" style="max-width: 500px;">
|
|
380
|
+
<div class="card-body text-start">
|
|
381
|
+
<h6>What's needed:</h6>
|
|
382
|
+
<ul class="mb-0">
|
|
383
|
+
<li>App version tracking for release correlation</li>
|
|
384
|
+
<li>User tracking for user correlation</li>
|
|
385
|
+
<li>Multiple error types for time correlation</li>
|
|
386
|
+
</ul>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
<small class="text-muted d-block mt-3">
|
|
390
|
+
<i class="bi bi-lightbulb"></i> Check back once more errors have been logged.
|
|
391
|
+
</small>
|
|
379
392
|
</div>
|
|
380
393
|
<% end %>
|
|
381
394
|
</div>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<% content_for :page_title, "Errors" %>
|
|
2
|
+
|
|
1
3
|
<!-- Subscribe to Turbo Stream updates (only if ActionCable is available) -->
|
|
2
4
|
<% if defined?(ActionCable) %>
|
|
3
5
|
<%= turbo_stream_from "error_list" %>
|
|
@@ -120,6 +122,50 @@
|
|
|
120
122
|
</div>
|
|
121
123
|
<% end %>
|
|
122
124
|
|
|
125
|
+
<!-- Active Filters Pills -->
|
|
126
|
+
<%
|
|
127
|
+
active_filters = []
|
|
128
|
+
active_filters << { label: "Search: #{params[:search]}", param: :search } if params[:search].present?
|
|
129
|
+
active_filters << { label: "Platform: #{params[:platform]}", param: :platform } if params[:platform].present?
|
|
130
|
+
active_filters << { label: "Type: #{params[:error_type]}", param: :error_type } if params[:error_type].present?
|
|
131
|
+
active_filters << { label: "Severity: #{params[:severity].titleize}", param: :severity } if params[:severity].present?
|
|
132
|
+
active_filters << { label: "Timeframe: #{params[:timeframe].humanize}", param: :timeframe } if params[:timeframe].present?
|
|
133
|
+
active_filters << { label: "Frequency: #{params[:frequency].humanize}", param: :frequency } if params[:frequency].present?
|
|
134
|
+
active_filters << { label: "Status: #{params[:status].humanize}", param: :status } if params[:status].present?
|
|
135
|
+
active_filters << { label: "Priority: P#{params[:priority_level]}", param: :priority_level } if params[:priority_level].present?
|
|
136
|
+
|
|
137
|
+
# Special handling for assigned_to
|
|
138
|
+
if params[:assigned_to].present? && params[:assigned_to] != '__unassigned__' && params[:assigned_to] != '__assigned__'
|
|
139
|
+
active_filters << { label: "Assigned to: #{params[:assigned_to]}", param: :assigned_to }
|
|
140
|
+
elsif params[:assigned_to] == '__unassigned__'
|
|
141
|
+
active_filters << { label: "Unassigned", param: :assigned_to }
|
|
142
|
+
elsif params[:assigned_to] == '__assigned__'
|
|
143
|
+
active_filters << { label: "Assigned", param: :assigned_to }
|
|
144
|
+
end
|
|
145
|
+
%>
|
|
146
|
+
|
|
147
|
+
<% if active_filters.any? %>
|
|
148
|
+
<div class="mb-3">
|
|
149
|
+
<div class="d-flex align-items-center gap-2 flex-wrap">
|
|
150
|
+
<small class="text-muted fw-bold">Active filters:</small>
|
|
151
|
+
<% active_filters.each do |filter| %>
|
|
152
|
+
<%
|
|
153
|
+
# Build URL without this specific filter
|
|
154
|
+
filter_params = params.permit!.except(:controller, :action, filter[:param])
|
|
155
|
+
%>
|
|
156
|
+
<%= link_to errors_path(filter_params), class: "badge bg-primary text-decoration-none filter-pill" do %>
|
|
157
|
+
<%= filter[:label] %>
|
|
158
|
+
<i class="bi bi-x ms-1"></i>
|
|
159
|
+
<% end %>
|
|
160
|
+
<% end %>
|
|
161
|
+
<%= link_to errors_path, class: "badge bg-secondary text-decoration-none filter-pill" do %>
|
|
162
|
+
<i class="bi bi-x-circle me-1"></i>
|
|
163
|
+
Clear All
|
|
164
|
+
<% end %>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
<% end %>
|
|
168
|
+
|
|
123
169
|
<!-- Filters -->
|
|
124
170
|
<div class="card mb-4" id="filters-section">
|
|
125
171
|
<div class="card-header bg-white">
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<% content_for :page_title, "Platform Comparison" %>
|
|
2
|
+
|
|
1
3
|
<div class="container-fluid py-4">
|
|
2
4
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
3
5
|
<h1 class="h3 mb-0">
|
|
@@ -19,9 +21,15 @@
|
|
|
19
21
|
</div>
|
|
20
22
|
|
|
21
23
|
<% if @platform_health.empty? %>
|
|
22
|
-
<div class="
|
|
23
|
-
<i class="bi bi-
|
|
24
|
-
No
|
|
24
|
+
<div class="text-center py-5">
|
|
25
|
+
<i class="bi bi-phone display-1 text-muted mb-3"></i>
|
|
26
|
+
<h4 class="text-muted">No Platform Data Available</h4>
|
|
27
|
+
<p class="text-muted">
|
|
28
|
+
No errors were logged for the selected time period (<%= @days %> days).
|
|
29
|
+
</p>
|
|
30
|
+
<small class="text-muted d-block mt-3">
|
|
31
|
+
<i class="bi bi-lightbulb"></i> Try selecting a longer time period or check back later.
|
|
32
|
+
</small>
|
|
25
33
|
</div>
|
|
26
34
|
<% else %>
|
|
27
35
|
<!-- Platform Health Summary Cards -->
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
<% content_for :page_title, "Error ##{@error.id}" %>
|
|
2
|
+
|
|
1
3
|
<div class="py-4">
|
|
4
|
+
<!-- Breadcrumbs -->
|
|
5
|
+
<nav aria-label="breadcrumb" class="mb-3">
|
|
6
|
+
<ol class="breadcrumb">
|
|
7
|
+
<li class="breadcrumb-item"><%= link_to root_path do %><i class="bi bi-house-door"></i> Dashboard<% end %></li>
|
|
8
|
+
<li class="breadcrumb-item"><%= link_to errors_path do %><i class="bi bi-bug"></i> Errors<% end %></li>
|
|
9
|
+
<li class="breadcrumb-item active" aria-current="page">Error #<%= @error.id %></li>
|
|
10
|
+
</ol>
|
|
11
|
+
</nav>
|
|
12
|
+
|
|
2
13
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
3
14
|
<div>
|
|
4
|
-
<%= link_to errors_path, class: "btn btn-outline-secondary btn-sm mb-2" do %>
|
|
5
|
-
<i class="bi bi-arrow-left"></i> Back to Errors
|
|
6
|
-
<% end %>
|
|
7
15
|
<h2 class="mb-0">
|
|
8
16
|
Error Details
|
|
9
17
|
<% severity = @error.severity %>
|
|
@@ -37,25 +45,42 @@
|
|
|
37
45
|
<% cache [@error, 'error_details_v1'] do %>
|
|
38
46
|
<div class="card mb-4">
|
|
39
47
|
<div class="card-header bg-danger text-white">
|
|
40
|
-
<
|
|
48
|
+
<div class="d-flex justify-content-between align-items-center">
|
|
49
|
+
<h5 class="mb-0"><i class="bi bi-bug-fill"></i> <%= @error.error_type %></h5>
|
|
50
|
+
<button class="btn btn-sm btn-outline-light" onclick="copyToClipboard('<%= j @error.error_type %>', this)" title="Copy error type">
|
|
51
|
+
<i class="bi bi-clipboard"></i>
|
|
52
|
+
</button>
|
|
53
|
+
</div>
|
|
41
54
|
</div>
|
|
42
55
|
<div class="card-body">
|
|
43
|
-
<
|
|
56
|
+
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
57
|
+
<h6 class="text-muted mb-0">Error Message:</h6>
|
|
58
|
+
<button class="btn btn-sm btn-outline-secondary" onclick="copyToClipboard('<%= j @error.message %>', this)" title="Copy error message">
|
|
59
|
+
<i class="bi bi-clipboard"></i> Copy
|
|
60
|
+
</button>
|
|
61
|
+
</div>
|
|
44
62
|
<div class="alert alert-danger">
|
|
45
63
|
<%= @error.message %>
|
|
46
64
|
</div>
|
|
47
65
|
|
|
48
|
-
<
|
|
49
|
-
|
|
66
|
+
<div class="d-flex justify-content-between align-items-center mb-2 mt-4">
|
|
67
|
+
<h6 class="text-muted mb-0">
|
|
68
|
+
Backtrace:
|
|
69
|
+
<% if @error.backtrace.present? %>
|
|
70
|
+
<% frames = parse_backtrace(@error.backtrace) %>
|
|
71
|
+
<% app_frames = filter_app_code(frames) %>
|
|
72
|
+
<% framework_frames = filter_framework_code(frames) %>
|
|
73
|
+
<small class="text-muted">
|
|
74
|
+
(<%= app_frames.count %> your code, <%= framework_frames.count %> framework/gems)
|
|
75
|
+
</small>
|
|
76
|
+
<% end %>
|
|
77
|
+
</h6>
|
|
50
78
|
<% if @error.backtrace.present? %>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<small class="text-muted">
|
|
55
|
-
(<%= app_frames.count %> your code, <%= framework_frames.count %> framework/gems)
|
|
56
|
-
</small>
|
|
79
|
+
<button class="btn btn-sm btn-outline-secondary" onclick="copyToClipboard(`<%= j @error.backtrace %>`, this)" title="Copy full backtrace">
|
|
80
|
+
<i class="bi bi-clipboard"></i> Copy Full Backtrace
|
|
81
|
+
</button>
|
|
57
82
|
<% end %>
|
|
58
|
-
</
|
|
83
|
+
</div>
|
|
59
84
|
<% if @error.backtrace.present? %>
|
|
60
85
|
<% frames = parse_backtrace(@error.backtrace) %>
|
|
61
86
|
<% app_frames = filter_app_code(frames) %>
|
|
@@ -226,11 +251,13 @@
|
|
|
226
251
|
</td>
|
|
227
252
|
<td>
|
|
228
253
|
<% if similar_error.platform == 'iOS' %>
|
|
229
|
-
<span class="badge badge-ios">iOS</span>
|
|
254
|
+
<span class="badge badge-ios"><i class="bi bi-apple"></i> iOS</span>
|
|
230
255
|
<% elsif similar_error.platform == 'Android' %>
|
|
231
|
-
<span class="badge badge-android">Android</span>
|
|
256
|
+
<span class="badge badge-android"><i class="bi bi-android2"></i> Android</span>
|
|
257
|
+
<% elsif similar_error.platform == 'Web' %>
|
|
258
|
+
<span class="badge badge-web"><i class="bi bi-globe"></i> Web</span>
|
|
232
259
|
<% else %>
|
|
233
|
-
<span class="badge badge-api"
|
|
260
|
+
<span class="badge badge-api"><i class="bi bi-server"></i> <%= similar_error.platform || 'API' %></span>
|
|
234
261
|
<% end %>
|
|
235
262
|
</td>
|
|
236
263
|
<td><span class="badge bg-primary"><%= similar_error.occurrence_count %>x</span></td>
|
|
@@ -572,9 +599,11 @@
|
|
|
572
599
|
<div class="mb-3">
|
|
573
600
|
<small class="text-muted d-block mb-1">Platform</small>
|
|
574
601
|
<% if @error.platform == 'iOS' %>
|
|
575
|
-
<span class="badge badge-ios"><i class="bi bi-
|
|
602
|
+
<span class="badge badge-ios"><i class="bi bi-apple"></i> iOS</span>
|
|
576
603
|
<% elsif @error.platform == 'Android' %>
|
|
577
|
-
<span class="badge badge-android"><i class="bi bi-
|
|
604
|
+
<span class="badge badge-android"><i class="bi bi-android2"></i> Android</span>
|
|
605
|
+
<% elsif @error.platform == 'Web' %>
|
|
606
|
+
<span class="badge badge-web"><i class="bi bi-globe"></i> Web</span>
|
|
578
607
|
<% else %>
|
|
579
608
|
<span class="badge badge-api"><i class="bi bi-server"></i> <%= @error.platform || 'API' %></span>
|
|
580
609
|
<% end %>
|
|
@@ -740,7 +769,12 @@
|
|
|
740
769
|
|
|
741
770
|
<div>
|
|
742
771
|
<small class="text-muted d-block mb-1">Error ID</small>
|
|
743
|
-
<
|
|
772
|
+
<div class="d-flex align-items-center gap-2">
|
|
773
|
+
<code><%= @error.id %></code>
|
|
774
|
+
<button class="btn btn-sm btn-outline-secondary" onclick="copyToClipboard('<%= @error.id %>', this)" title="Copy error ID">
|
|
775
|
+
<i class="bi bi-clipboard"></i>
|
|
776
|
+
</button>
|
|
777
|
+
</div>
|
|
744
778
|
</div>
|
|
745
779
|
</div>
|
|
746
780
|
</div>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_error_dashboard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anjan Jagirdar
|
|
@@ -311,7 +311,6 @@ files:
|
|
|
311
311
|
- app/views/rails_error_dashboard/errors/platform_comparison.html.erb
|
|
312
312
|
- app/views/rails_error_dashboard/errors/settings.html.erb
|
|
313
313
|
- app/views/rails_error_dashboard/errors/show.html.erb
|
|
314
|
-
- config/initializers/rails_error_dashboard.rb
|
|
315
314
|
- config/routes.rb
|
|
316
315
|
- db/migrate/20251224000001_create_rails_error_dashboard_error_logs.rb
|
|
317
316
|
- db/migrate/20251224081522_add_better_tracking_to_error_logs.rb
|
|
@@ -379,7 +378,7 @@ metadata:
|
|
|
379
378
|
source_code_uri: https://github.com/AnjanJ/rails_error_dashboard
|
|
380
379
|
changelog_uri: https://github.com/AnjanJ/rails_error_dashboard/blob/main/CHANGELOG.md
|
|
381
380
|
post_install_message: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n
|
|
382
|
-
\ Rails Error Dashboard v0.1.
|
|
381
|
+
\ Rails Error Dashboard v0.1.11 installed successfully!\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\U0001F4E6
|
|
383
382
|
Next steps to get started:\n\n 1. Run the installer:\n rails generate rails_error_dashboard:install\n\n
|
|
384
383
|
\ 2. Run migrations:\n rails db:migrate\n\n 3. Mount the engine in config/routes.rb:\n
|
|
385
384
|
\ mount RailsErrorDashboard::Engine => '/error_dashboard'\n\n 4. Start your
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RailsErrorDashboard.configure do |config|
|
|
4
|
-
# ============================================================================
|
|
5
|
-
# AUTHENTICATION (Always Required)
|
|
6
|
-
# ============================================================================
|
|
7
|
-
|
|
8
|
-
# Dashboard authentication credentials
|
|
9
|
-
# ⚠️ CHANGE THESE BEFORE PRODUCTION! ⚠️
|
|
10
|
-
config.dashboard_username = ENV.fetch("ERROR_DASHBOARD_USER", "gandalf")
|
|
11
|
-
config.dashboard_password = ENV.fetch("ERROR_DASHBOARD_PASSWORD", "youshallnotpass")
|
|
12
|
-
|
|
13
|
-
# Require authentication for dashboard access
|
|
14
|
-
config.require_authentication = true
|
|
15
|
-
|
|
16
|
-
# Require authentication even in development mode
|
|
17
|
-
config.require_authentication_in_development = false
|
|
18
|
-
|
|
19
|
-
# ============================================================================
|
|
20
|
-
# CORE FEATURES (Always Enabled)
|
|
21
|
-
# ============================================================================
|
|
22
|
-
|
|
23
|
-
# Error capture via middleware and Rails.error subscriber
|
|
24
|
-
config.enable_middleware = true
|
|
25
|
-
config.enable_error_subscriber = true
|
|
26
|
-
|
|
27
|
-
# User model for error associations
|
|
28
|
-
config.user_model = "User"
|
|
29
|
-
|
|
30
|
-
# Error retention policy (days to keep errors before auto-deletion)
|
|
31
|
-
config.retention_days = 90
|
|
32
|
-
|
|
33
|
-
# ============================================================================
|
|
34
|
-
# NOTIFICATION SETTINGS
|
|
35
|
-
# ============================================================================
|
|
36
|
-
# Configure which notification channels you want to use.
|
|
37
|
-
# You can enable/disable any of these at any time by changing true/false.
|
|
38
|
-
|
|
39
|
-
# Slack Notifications - DISABLED
|
|
40
|
-
# To enable: Set config.enable_slack_notifications = true and configure webhook URL
|
|
41
|
-
config.enable_slack_notifications = false
|
|
42
|
-
# config.slack_webhook_url = ENV["SLACK_WEBHOOK_URL"]
|
|
43
|
-
|
|
44
|
-
# Email Notifications - DISABLED
|
|
45
|
-
# To enable: Set config.enable_email_notifications = true and configure recipients
|
|
46
|
-
config.enable_email_notifications = false
|
|
47
|
-
# config.notification_email_recipients = ENV.fetch("ERROR_NOTIFICATION_EMAILS", "").split(",").map(&:strip)
|
|
48
|
-
# config.notification_email_from = ENV.fetch("ERROR_NOTIFICATION_FROM", "errors@example.com")
|
|
49
|
-
|
|
50
|
-
# Discord Notifications - DISABLED
|
|
51
|
-
# To enable: Set config.enable_discord_notifications = true and configure webhook URL
|
|
52
|
-
config.enable_discord_notifications = false
|
|
53
|
-
# config.discord_webhook_url = ENV["DISCORD_WEBHOOK_URL"]
|
|
54
|
-
|
|
55
|
-
# PagerDuty Integration - DISABLED
|
|
56
|
-
# To enable: Set config.enable_pagerduty_notifications = true and configure integration key
|
|
57
|
-
config.enable_pagerduty_notifications = false
|
|
58
|
-
# config.pagerduty_integration_key = ENV["PAGERDUTY_INTEGRATION_KEY"]
|
|
59
|
-
|
|
60
|
-
# Generic Webhook Notifications - DISABLED
|
|
61
|
-
# To enable: Set config.enable_webhook_notifications = true and configure webhook URLs
|
|
62
|
-
config.enable_webhook_notifications = false
|
|
63
|
-
# config.webhook_urls = ENV.fetch("WEBHOOK_URLS", "").split(",").map(&:strip).reject(&:empty?)
|
|
64
|
-
|
|
65
|
-
# Dashboard base URL (used in notification links)
|
|
66
|
-
config.dashboard_base_url = ENV["DASHBOARD_BASE_URL"]
|
|
67
|
-
|
|
68
|
-
# ============================================================================
|
|
69
|
-
# PERFORMANCE & SCALABILITY
|
|
70
|
-
# ============================================================================
|
|
71
|
-
|
|
72
|
-
# Async Error Logging - DISABLED
|
|
73
|
-
# Errors are logged synchronously (blocking)
|
|
74
|
-
# To enable: Set config.async_logging = true and configure adapter
|
|
75
|
-
config.async_logging = false
|
|
76
|
-
# config.async_adapter = :sidekiq # Options: :sidekiq, :solid_queue, :async
|
|
77
|
-
|
|
78
|
-
# Backtrace size limiting (reduces storage by ~80%)
|
|
79
|
-
config.max_backtrace_lines = 50
|
|
80
|
-
|
|
81
|
-
# Error Sampling - DISABLED
|
|
82
|
-
# All errors are logged (100% sampling rate)
|
|
83
|
-
# To enable: Set config.sampling_rate < 1.0 (e.g., 0.1 for 10%)
|
|
84
|
-
config.sampling_rate = 1.0
|
|
85
|
-
|
|
86
|
-
# Ignored exceptions (skip logging these)
|
|
87
|
-
# config.ignored_exceptions = [
|
|
88
|
-
# "ActionController::RoutingError",
|
|
89
|
-
# "ActionController::InvalidAuthenticityToken",
|
|
90
|
-
# /^ActiveRecord::RecordNotFound/
|
|
91
|
-
# ]
|
|
92
|
-
|
|
93
|
-
# ============================================================================
|
|
94
|
-
# DATABASE CONFIGURATION
|
|
95
|
-
# ============================================================================
|
|
96
|
-
|
|
97
|
-
# Separate Error Database - DISABLED
|
|
98
|
-
# Errors are stored in your main application database
|
|
99
|
-
# To enable: Set config.use_separate_database = true and configure database.yml
|
|
100
|
-
config.use_separate_database = false
|
|
101
|
-
|
|
102
|
-
# ============================================================================
|
|
103
|
-
# ADVANCED ANALYTICS
|
|
104
|
-
# ============================================================================
|
|
105
|
-
|
|
106
|
-
# Baseline Anomaly Alerts - DISABLED
|
|
107
|
-
# To enable: Set config.enable_baseline_alerts = true
|
|
108
|
-
config.enable_baseline_alerts = false
|
|
109
|
-
# config.baseline_alert_threshold_std_devs = 2.0
|
|
110
|
-
# config.baseline_alert_severities = [ :critical, :high ]
|
|
111
|
-
# config.baseline_alert_cooldown_minutes = 120
|
|
112
|
-
|
|
113
|
-
# Fuzzy Error Matching - DISABLED
|
|
114
|
-
# To enable: Set config.enable_similar_errors = true
|
|
115
|
-
config.enable_similar_errors = false
|
|
116
|
-
|
|
117
|
-
# Co-occurring Errors - DISABLED
|
|
118
|
-
# To enable: Set config.enable_co_occurring_errors = true
|
|
119
|
-
config.enable_co_occurring_errors = false
|
|
120
|
-
|
|
121
|
-
# Error Cascade Detection - DISABLED
|
|
122
|
-
# To enable: Set config.enable_error_cascades = true
|
|
123
|
-
config.enable_error_cascades = false
|
|
124
|
-
|
|
125
|
-
# Error Correlation Analysis - DISABLED
|
|
126
|
-
# To enable: Set config.enable_error_correlation = true
|
|
127
|
-
config.enable_error_correlation = false
|
|
128
|
-
|
|
129
|
-
# Platform Comparison - DISABLED
|
|
130
|
-
# To enable: Set config.enable_platform_comparison = true
|
|
131
|
-
config.enable_platform_comparison = false
|
|
132
|
-
|
|
133
|
-
# Occurrence Pattern Detection - DISABLED
|
|
134
|
-
# To enable: Set config.enable_occurrence_patterns = true
|
|
135
|
-
config.enable_occurrence_patterns = false
|
|
136
|
-
|
|
137
|
-
# ============================================================================
|
|
138
|
-
# INTERNAL LOGGING (Silent by Default)
|
|
139
|
-
# ============================================================================
|
|
140
|
-
# Rails Error Dashboard logging is SILENT by default to keep your logs clean.
|
|
141
|
-
# Enable only for debugging gem issues or troubleshooting setup.
|
|
142
|
-
|
|
143
|
-
# Enable internal logging (default: false - silent)
|
|
144
|
-
config.enable_internal_logging = false
|
|
145
|
-
|
|
146
|
-
# Log level (default: :silent)
|
|
147
|
-
# Options: :debug, :info, :warn, :error, :silent
|
|
148
|
-
config.log_level = :silent
|
|
149
|
-
|
|
150
|
-
# Example: Enable verbose logging for debugging
|
|
151
|
-
# config.enable_internal_logging = true
|
|
152
|
-
# config.log_level = :debug
|
|
153
|
-
|
|
154
|
-
# Example: Log only errors (troubleshooting)
|
|
155
|
-
# config.enable_internal_logging = true
|
|
156
|
-
# config.log_level = :error
|
|
157
|
-
|
|
158
|
-
# ============================================================================
|
|
159
|
-
# ADDITIONAL CONFIGURATION
|
|
160
|
-
# ============================================================================
|
|
161
|
-
|
|
162
|
-
# Custom severity rules (override automatic severity classification)
|
|
163
|
-
# config.custom_severity_rules = {
|
|
164
|
-
# "PaymentError" => :critical,
|
|
165
|
-
# "ValidationError" => :low
|
|
166
|
-
# }
|
|
167
|
-
|
|
168
|
-
# Enhanced metrics (optional)
|
|
169
|
-
config.app_version = ENV["APP_VERSION"]
|
|
170
|
-
config.git_sha = ENV["GIT_SHA"]
|
|
171
|
-
# config.total_users_for_impact = 10000 # For user impact % calculation
|
|
172
|
-
end
|