findbug 0.4.0 → 0.5.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 +45 -8
- data/app/models/findbug/error_event.rb +34 -6
- data/app/models/findbug/performance_event.rb +38 -16
- data/docs/docs.html +976 -0
- data/docs/index.html +594 -8
- data/lib/findbug/adapter_helper.rb +74 -0
- data/lib/findbug/version.rb +1 -1
- data/lib/findbug.rb +1 -0
- data/lib/generators/findbug/templates/create_findbug_error_events.rb +3 -3
- data/lib/generators/findbug/templates/create_findbug_performance_events.rb +3 -3
- metadata +8 -3
data/docs/index.html
CHANGED
|
@@ -961,6 +961,150 @@
|
|
|
961
961
|
.demo-grid-2 { grid-template-columns: 1fr; }
|
|
962
962
|
}
|
|
963
963
|
|
|
964
|
+
/* Demo Badge Info */
|
|
965
|
+
.demo-badge-info {
|
|
966
|
+
background-color: hsl(var(--info) / 0.15);
|
|
967
|
+
color: hsl(var(--info));
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/* Demo Toggle */
|
|
971
|
+
.demo-toggle {
|
|
972
|
+
position: relative;
|
|
973
|
+
display: inline-block;
|
|
974
|
+
width: 2rem;
|
|
975
|
+
height: 1.125rem;
|
|
976
|
+
}
|
|
977
|
+
.demo-toggle input { display: none; }
|
|
978
|
+
.demo-toggle-slider {
|
|
979
|
+
position: absolute;
|
|
980
|
+
inset: 0;
|
|
981
|
+
border-radius: 9999px;
|
|
982
|
+
background-color: hsl(0 62.8% 30.6%);
|
|
983
|
+
transition: background-color 0.2s;
|
|
984
|
+
}
|
|
985
|
+
.demo-toggle-slider::before {
|
|
986
|
+
content: '';
|
|
987
|
+
position: absolute;
|
|
988
|
+
width: 0.875rem;
|
|
989
|
+
height: 0.875rem;
|
|
990
|
+
left: 0.125rem;
|
|
991
|
+
top: 50%;
|
|
992
|
+
transform: translateY(-50%);
|
|
993
|
+
border-radius: 50%;
|
|
994
|
+
background: white;
|
|
995
|
+
transition: transform 0.2s;
|
|
996
|
+
}
|
|
997
|
+
.demo-toggle input:checked + .demo-toggle-slider {
|
|
998
|
+
background-color: hsl(var(--success));
|
|
999
|
+
}
|
|
1000
|
+
.demo-toggle input:checked + .demo-toggle-slider::before {
|
|
1001
|
+
transform: translateY(-50%) translateX(0.875rem);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/* Demo Icon Button */
|
|
1005
|
+
.demo-btn-icon {
|
|
1006
|
+
display: inline-flex;
|
|
1007
|
+
align-items: center;
|
|
1008
|
+
justify-content: center;
|
|
1009
|
+
width: 1.75rem;
|
|
1010
|
+
height: 1.75rem;
|
|
1011
|
+
border-radius: var(--radius);
|
|
1012
|
+
color: hsl(var(--muted-foreground));
|
|
1013
|
+
background: transparent;
|
|
1014
|
+
border: none;
|
|
1015
|
+
cursor: pointer;
|
|
1016
|
+
transition: all 0.15s;
|
|
1017
|
+
}
|
|
1018
|
+
.demo-btn-icon:hover {
|
|
1019
|
+
background-color: hsl(var(--muted));
|
|
1020
|
+
color: hsl(var(--foreground));
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/* Demo Tab Content */
|
|
1024
|
+
.demo-tab-content { display: none; }
|
|
1025
|
+
.demo-tab-content.active { display: block; }
|
|
1026
|
+
|
|
1027
|
+
/* Demo Filter Bar */
|
|
1028
|
+
.demo-filter-bar {
|
|
1029
|
+
display: flex;
|
|
1030
|
+
justify-content: space-between;
|
|
1031
|
+
align-items: center;
|
|
1032
|
+
gap: 0.75rem;
|
|
1033
|
+
margin-bottom: 0.75rem;
|
|
1034
|
+
flex-wrap: wrap;
|
|
1035
|
+
}
|
|
1036
|
+
.demo-filter-bar-filters {
|
|
1037
|
+
display: flex;
|
|
1038
|
+
gap: 0.5rem;
|
|
1039
|
+
flex-wrap: wrap;
|
|
1040
|
+
}
|
|
1041
|
+
.demo-select {
|
|
1042
|
+
appearance: none;
|
|
1043
|
+
background-color: hsl(var(--secondary));
|
|
1044
|
+
color: hsl(var(--foreground));
|
|
1045
|
+
border: 1px solid hsl(var(--border));
|
|
1046
|
+
border-radius: var(--radius);
|
|
1047
|
+
padding: 0.375rem 1.75rem 0.375rem 0.625rem;
|
|
1048
|
+
font-size: 0.75rem;
|
|
1049
|
+
cursor: pointer;
|
|
1050
|
+
background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23999' fill='none' stroke-width='1.5'/%3E%3C/svg%3E");
|
|
1051
|
+
background-repeat: no-repeat;
|
|
1052
|
+
background-position: right 0.5rem center;
|
|
1053
|
+
}
|
|
1054
|
+
.demo-search-input {
|
|
1055
|
+
background-color: hsl(var(--secondary));
|
|
1056
|
+
color: hsl(var(--foreground));
|
|
1057
|
+
border: 1px solid hsl(var(--border));
|
|
1058
|
+
border-radius: var(--radius);
|
|
1059
|
+
padding: 0.375rem 0.625rem;
|
|
1060
|
+
font-size: 0.75rem;
|
|
1061
|
+
width: 160px;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/* Demo Chart */
|
|
1065
|
+
.demo-chart-container {
|
|
1066
|
+
display: flex;
|
|
1067
|
+
align-items: flex-end;
|
|
1068
|
+
gap: 3px;
|
|
1069
|
+
height: 80px;
|
|
1070
|
+
padding: 1rem 1.25rem 0.25rem;
|
|
1071
|
+
}
|
|
1072
|
+
.demo-chart-bar {
|
|
1073
|
+
flex: 1;
|
|
1074
|
+
background: hsl(var(--info) / 0.6);
|
|
1075
|
+
border-radius: 2px 2px 0 0;
|
|
1076
|
+
min-width: 4px;
|
|
1077
|
+
transition: background 0.15s;
|
|
1078
|
+
}
|
|
1079
|
+
.demo-chart-bar:hover {
|
|
1080
|
+
background: hsl(var(--info));
|
|
1081
|
+
}
|
|
1082
|
+
.demo-chart-labels {
|
|
1083
|
+
display: flex;
|
|
1084
|
+
justify-content: space-between;
|
|
1085
|
+
padding: 0.375rem 1.25rem 0.75rem;
|
|
1086
|
+
font-size: 0.625rem;
|
|
1087
|
+
color: hsl(var(--muted-foreground));
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/* Demo Action Buttons (Resolve/Ignore) */
|
|
1091
|
+
.demo-btn-sm {
|
|
1092
|
+
display: inline-flex;
|
|
1093
|
+
align-items: center;
|
|
1094
|
+
padding: 0.1875rem 0.5rem;
|
|
1095
|
+
font-size: 0.6875rem;
|
|
1096
|
+
font-weight: 500;
|
|
1097
|
+
border-radius: var(--radius);
|
|
1098
|
+
border: 1px solid hsl(var(--border));
|
|
1099
|
+
background: transparent;
|
|
1100
|
+
color: hsl(var(--foreground));
|
|
1101
|
+
cursor: pointer;
|
|
1102
|
+
}
|
|
1103
|
+
.demo-btn-sm.ghost {
|
|
1104
|
+
border-color: transparent;
|
|
1105
|
+
color: hsl(var(--muted-foreground));
|
|
1106
|
+
}
|
|
1107
|
+
|
|
964
1108
|
@media (max-width: 640px) {
|
|
965
1109
|
.demo-stats-grid { grid-template-columns: 1fr; }
|
|
966
1110
|
.demo-app-nav { display: none; }
|
|
@@ -1699,6 +1843,7 @@
|
|
|
1699
1843
|
<a href="#comparison">Compare</a>
|
|
1700
1844
|
<a href="#architecture">Architecture</a>
|
|
1701
1845
|
<a href="#demo">Demo</a>
|
|
1846
|
+
<a href="/docs">Docs</a>
|
|
1702
1847
|
</div>
|
|
1703
1848
|
<div class="nav-right">
|
|
1704
1849
|
<a href="#demo" class="btn btn-primary btn-sm">
|
|
@@ -1717,7 +1862,7 @@
|
|
|
1717
1862
|
<div class="container">
|
|
1718
1863
|
<div class="hero-badge">
|
|
1719
1864
|
<span>NEW</span>
|
|
1720
|
-
v0.
|
|
1865
|
+
v0.5.0 — now database-agnostic (PostgreSQL · MySQL · SQLite) with full test coverage
|
|
1721
1866
|
</div>
|
|
1722
1867
|
<h1>Catch bugs<br>before your users do</h1>
|
|
1723
1868
|
<p>
|
|
@@ -1735,7 +1880,7 @@
|
|
|
1735
1880
|
</div>
|
|
1736
1881
|
<div class="hero-code">
|
|
1737
1882
|
<span class="comment"># Add to your Gemfile:</span><br>
|
|
1738
|
-
<span class="keyword">gem</span> <span class="string">"findbug", "~> 0.
|
|
1883
|
+
<span class="keyword">gem</span> <span class="string">"findbug", "~> 0.5.0"</span><br><br>
|
|
1739
1884
|
<span class="comment"># Install and you're done!</span><br>
|
|
1740
1885
|
$ rails generate findbug:install<br>
|
|
1741
1886
|
$ rails db:migrate<br><br>
|
|
@@ -1793,7 +1938,7 @@
|
|
|
1793
1938
|
<!-- Self-Hosted - Narrow Card with Privacy Visual -->
|
|
1794
1939
|
<div class="bento-card bento-narrow">
|
|
1795
1940
|
<h3>Self-Hosted</h3>
|
|
1796
|
-
<p>Your data stays on your infrastructure.
|
|
1941
|
+
<p>Your data stays on your infrastructure. Database-agnostic — works with PostgreSQL, MySQL, or SQLite.</p>
|
|
1797
1942
|
<div class="visual">
|
|
1798
1943
|
<div class="privacy-visual">
|
|
1799
1944
|
<div class="server-icon">
|
|
@@ -2109,6 +2254,10 @@
|
|
|
2109
2254
|
<div class="comparison-highlight-value">2 min</div>
|
|
2110
2255
|
<div class="comparison-highlight-label">Setup time</div>
|
|
2111
2256
|
</div>
|
|
2257
|
+
<div class="comparison-highlight-item">
|
|
2258
|
+
<div class="comparison-highlight-value">79</div>
|
|
2259
|
+
<div class="comparison-highlight-label">Passing specs</div>
|
|
2260
|
+
</div>
|
|
2112
2261
|
</div>
|
|
2113
2262
|
</div>
|
|
2114
2263
|
</div>
|
|
@@ -2206,7 +2355,7 @@
|
|
|
2206
2355
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>
|
|
2207
2356
|
</div>
|
|
2208
2357
|
<div class="flow-node-title">Your Database</div>
|
|
2209
|
-
<div class="flow-node-desc">PostgreSQL
|
|
2358
|
+
<div class="flow-node-desc">PostgreSQL · MySQL · SQLite</div>
|
|
2210
2359
|
</div>
|
|
2211
2360
|
|
|
2212
2361
|
<div class="flow-arrow">
|
|
@@ -2286,9 +2435,10 @@
|
|
|
2286
2435
|
<span>FindBug</span>
|
|
2287
2436
|
</div>
|
|
2288
2437
|
<nav class="demo-app-nav">
|
|
2289
|
-
<a class="active">Dashboard</a>
|
|
2290
|
-
<a>Errors</a>
|
|
2291
|
-
<a>Performance</a>
|
|
2438
|
+
<a class="active" onclick="switchDemoTab('dashboard', this)">Dashboard</a>
|
|
2439
|
+
<a onclick="switchDemoTab('errors', this)">Errors</a>
|
|
2440
|
+
<a onclick="switchDemoTab('performance', this)">Performance</a>
|
|
2441
|
+
<a onclick="switchDemoTab('alerts', this)">Alerts</a>
|
|
2292
2442
|
</nav>
|
|
2293
2443
|
<div class="demo-header-right">
|
|
2294
2444
|
<div class="demo-health-indicator">
|
|
@@ -2298,8 +2448,10 @@
|
|
|
2298
2448
|
</div>
|
|
2299
2449
|
</div>
|
|
2300
2450
|
|
|
2301
|
-
<!-- Main Content
|
|
2451
|
+
<!-- Main Content -->
|
|
2302
2452
|
<div class="demo-main">
|
|
2453
|
+
<!-- Dashboard Tab -->
|
|
2454
|
+
<div class="demo-tab-content active" id="demo-tab-dashboard">
|
|
2303
2455
|
<h1 class="demo-page-title">Dashboard</h1>
|
|
2304
2456
|
<p class="demo-page-description">Monitor errors and performance across your application.</p>
|
|
2305
2457
|
|
|
@@ -2412,6 +2564,422 @@
|
|
|
2412
2564
|
</table>
|
|
2413
2565
|
</div>
|
|
2414
2566
|
</div>
|
|
2567
|
+
</div><!-- /demo-tab-dashboard -->
|
|
2568
|
+
|
|
2569
|
+
<!-- Errors Tab -->
|
|
2570
|
+
<div class="demo-tab-content" id="demo-tab-errors">
|
|
2571
|
+
<h1 class="demo-page-title">Errors</h1>
|
|
2572
|
+
<p class="demo-page-description">Track and manage application errors.</p>
|
|
2573
|
+
|
|
2574
|
+
<!-- Filter Bar -->
|
|
2575
|
+
<div class="demo-filter-bar">
|
|
2576
|
+
<div class="demo-filter-bar-filters">
|
|
2577
|
+
<select class="demo-select"><option>Unresolved</option><option>Resolved</option><option>Ignored</option><option>All Statuses</option></select>
|
|
2578
|
+
<select class="demo-select"><option>All Severities</option><option>Error</option><option>Warning</option><option>Info</option></select>
|
|
2579
|
+
<select class="demo-select"><option>All Time</option><option>Last Hour</option><option>Last 24 Hours</option><option>Last 7 Days</option></select>
|
|
2580
|
+
<select class="demo-select"><option>Most Recent</option><option>Most Occurrences</option><option>Oldest</option></select>
|
|
2581
|
+
</div>
|
|
2582
|
+
<input type="text" class="demo-search-input" placeholder="Search errors...">
|
|
2583
|
+
</div>
|
|
2584
|
+
|
|
2585
|
+
<p class="demo-text-muted demo-text-xs" style="margin-bottom: 0.75rem;">Showing 5 of 12 errors</p>
|
|
2586
|
+
|
|
2587
|
+
<!-- Errors Table -->
|
|
2588
|
+
<div class="demo-card">
|
|
2589
|
+
<table class="demo-table">
|
|
2590
|
+
<thead>
|
|
2591
|
+
<tr>
|
|
2592
|
+
<th style="width: 45%;">Error</th>
|
|
2593
|
+
<th>Status</th>
|
|
2594
|
+
<th>Count</th>
|
|
2595
|
+
<th>Last Seen</th>
|
|
2596
|
+
<th>Actions</th>
|
|
2597
|
+
</tr>
|
|
2598
|
+
</thead>
|
|
2599
|
+
<tbody>
|
|
2600
|
+
<tr>
|
|
2601
|
+
<td>
|
|
2602
|
+
<a href="#" class="demo-font-mono" style="font-weight: 600;">Stripe::CardError</a><br>
|
|
2603
|
+
<span class="demo-text-muted demo-text-sm">Your card was declined</span>
|
|
2604
|
+
<div style="margin-top: 0.25rem;">
|
|
2605
|
+
<span class="demo-badge demo-badge-error">error</span>
|
|
2606
|
+
<span class="demo-text-muted demo-text-xs" style="margin-left: 0.5rem;">production</span>
|
|
2607
|
+
</div>
|
|
2608
|
+
</td>
|
|
2609
|
+
<td><span class="demo-badge demo-badge-error">unresolved</span></td>
|
|
2610
|
+
<td><strong>142</strong></td>
|
|
2611
|
+
<td class="demo-text-muted demo-text-sm">2 minutes ago</td>
|
|
2612
|
+
<td>
|
|
2613
|
+
<button class="demo-btn-sm">Resolve</button>
|
|
2614
|
+
<button class="demo-btn-sm ghost">Ignore</button>
|
|
2615
|
+
</td>
|
|
2616
|
+
</tr>
|
|
2617
|
+
<tr>
|
|
2618
|
+
<td>
|
|
2619
|
+
<a href="#" class="demo-font-mono" style="font-weight: 600;">ActiveRecord::RecordInvalid</a><br>
|
|
2620
|
+
<span class="demo-text-muted demo-text-sm">Validation failed: Email has already been taken</span>
|
|
2621
|
+
<div style="margin-top: 0.25rem;">
|
|
2622
|
+
<span class="demo-badge demo-badge-error">error</span>
|
|
2623
|
+
<span class="demo-text-muted demo-text-xs" style="margin-left: 0.5rem;">production</span>
|
|
2624
|
+
</div>
|
|
2625
|
+
</td>
|
|
2626
|
+
<td><span class="demo-badge demo-badge-error">unresolved</span></td>
|
|
2627
|
+
<td><strong>89</strong></td>
|
|
2628
|
+
<td class="demo-text-muted demo-text-sm">5 minutes ago</td>
|
|
2629
|
+
<td>
|
|
2630
|
+
<button class="demo-btn-sm">Resolve</button>
|
|
2631
|
+
<button class="demo-btn-sm ghost">Ignore</button>
|
|
2632
|
+
</td>
|
|
2633
|
+
</tr>
|
|
2634
|
+
<tr>
|
|
2635
|
+
<td>
|
|
2636
|
+
<a href="#" class="demo-font-mono" style="font-weight: 600;">Net::ReadTimeout</a><br>
|
|
2637
|
+
<span class="demo-text-muted demo-text-sm">Request to api.example.com timed out</span>
|
|
2638
|
+
<div style="margin-top: 0.25rem;">
|
|
2639
|
+
<span class="demo-badge demo-badge-warning">warning</span>
|
|
2640
|
+
<span class="demo-text-muted demo-text-xs" style="margin-left: 0.5rem;">production</span>
|
|
2641
|
+
</div>
|
|
2642
|
+
</td>
|
|
2643
|
+
<td><span class="demo-badge demo-badge-error">unresolved</span></td>
|
|
2644
|
+
<td><strong>23</strong></td>
|
|
2645
|
+
<td class="demo-text-muted demo-text-sm">12 minutes ago</td>
|
|
2646
|
+
<td>
|
|
2647
|
+
<button class="demo-btn-sm">Resolve</button>
|
|
2648
|
+
<button class="demo-btn-sm ghost">Ignore</button>
|
|
2649
|
+
</td>
|
|
2650
|
+
</tr>
|
|
2651
|
+
<tr>
|
|
2652
|
+
<td>
|
|
2653
|
+
<a href="#" class="demo-font-mono" style="font-weight: 600;">NoMethodError</a><br>
|
|
2654
|
+
<span class="demo-text-muted demo-text-sm">undefined method 'name' for nil</span>
|
|
2655
|
+
<div style="margin-top: 0.25rem;">
|
|
2656
|
+
<span class="demo-badge demo-badge-error">error</span>
|
|
2657
|
+
<span class="demo-text-muted demo-text-xs" style="margin-left: 0.5rem;">staging</span>
|
|
2658
|
+
</div>
|
|
2659
|
+
</td>
|
|
2660
|
+
<td><span class="demo-badge demo-badge-error">unresolved</span></td>
|
|
2661
|
+
<td><strong>8</strong></td>
|
|
2662
|
+
<td class="demo-text-muted demo-text-sm">34 minutes ago</td>
|
|
2663
|
+
<td>
|
|
2664
|
+
<button class="demo-btn-sm">Resolve</button>
|
|
2665
|
+
<button class="demo-btn-sm ghost">Ignore</button>
|
|
2666
|
+
</td>
|
|
2667
|
+
</tr>
|
|
2668
|
+
<tr>
|
|
2669
|
+
<td>
|
|
2670
|
+
<a href="#" class="demo-font-mono" style="font-weight: 600;">ActionController::ParameterMissing</a><br>
|
|
2671
|
+
<span class="demo-text-muted demo-text-sm">param is missing or the value is empty: user</span>
|
|
2672
|
+
<div style="margin-top: 0.25rem;">
|
|
2673
|
+
<span class="demo-badge demo-badge-error">error</span>
|
|
2674
|
+
<span class="demo-text-muted demo-text-xs" style="margin-left: 0.5rem;">production</span>
|
|
2675
|
+
</div>
|
|
2676
|
+
</td>
|
|
2677
|
+
<td><span class="demo-badge demo-badge-error">unresolved</span></td>
|
|
2678
|
+
<td><strong>3</strong></td>
|
|
2679
|
+
<td class="demo-text-muted demo-text-sm">1 hour ago</td>
|
|
2680
|
+
<td>
|
|
2681
|
+
<button class="demo-btn-sm">Resolve</button>
|
|
2682
|
+
<button class="demo-btn-sm ghost">Ignore</button>
|
|
2683
|
+
</td>
|
|
2684
|
+
</tr>
|
|
2685
|
+
</tbody>
|
|
2686
|
+
</table>
|
|
2687
|
+
</div>
|
|
2688
|
+
</div><!-- /demo-tab-errors -->
|
|
2689
|
+
|
|
2690
|
+
<!-- Performance Tab -->
|
|
2691
|
+
<div class="demo-tab-content" id="demo-tab-performance">
|
|
2692
|
+
<h1 class="demo-page-title">Performance</h1>
|
|
2693
|
+
|
|
2694
|
+
<!-- Time filter -->
|
|
2695
|
+
<div style="margin-bottom: 1.5rem;">
|
|
2696
|
+
<select class="demo-select"><option>Last 24 Hours</option><option>Last Hour</option><option>Last 7 Days</option><option>Last 30 Days</option></select>
|
|
2697
|
+
</div>
|
|
2698
|
+
|
|
2699
|
+
<!-- Stats Grid -->
|
|
2700
|
+
<div class="demo-stats-grid">
|
|
2701
|
+
<div class="demo-stat-card">
|
|
2702
|
+
<div class="demo-stat-label">Total Requests</div>
|
|
2703
|
+
<div class="demo-stat-value">1,847</div>
|
|
2704
|
+
</div>
|
|
2705
|
+
<div class="demo-stat-card">
|
|
2706
|
+
<div class="demo-stat-label">Avg Duration</div>
|
|
2707
|
+
<div class="demo-stat-value warning">142<span class="unit">ms</span></div>
|
|
2708
|
+
</div>
|
|
2709
|
+
<div class="demo-stat-card">
|
|
2710
|
+
<div class="demo-stat-label">Max Duration</div>
|
|
2711
|
+
<div class="demo-stat-value">1,245<span class="unit">ms</span></div>
|
|
2712
|
+
</div>
|
|
2713
|
+
<div class="demo-stat-card">
|
|
2714
|
+
<div class="demo-stat-label">N+1 Rate</div>
|
|
2715
|
+
<div class="demo-stat-value warning">12%</div>
|
|
2716
|
+
</div>
|
|
2717
|
+
</div>
|
|
2718
|
+
|
|
2719
|
+
<div class="demo-grid-2">
|
|
2720
|
+
<!-- Slowest Endpoints -->
|
|
2721
|
+
<div class="demo-card">
|
|
2722
|
+
<div class="demo-card-header">
|
|
2723
|
+
<div><h2 class="demo-card-title">Slowest Endpoints</h2></div>
|
|
2724
|
+
</div>
|
|
2725
|
+
<table class="demo-table">
|
|
2726
|
+
<thead>
|
|
2727
|
+
<tr>
|
|
2728
|
+
<th>Endpoint</th>
|
|
2729
|
+
<th>Avg</th>
|
|
2730
|
+
<th>Max</th>
|
|
2731
|
+
<th>Count</th>
|
|
2732
|
+
</tr>
|
|
2733
|
+
</thead>
|
|
2734
|
+
<tbody>
|
|
2735
|
+
<tr>
|
|
2736
|
+
<td><a href="#" class="demo-font-mono demo-text-sm">OrdersController#create</a></td>
|
|
2737
|
+
<td><span class="demo-badge demo-badge-warning">847ms</span></td>
|
|
2738
|
+
<td class="demo-text-muted demo-text-sm">1,245ms</td>
|
|
2739
|
+
<td>312</td>
|
|
2740
|
+
</tr>
|
|
2741
|
+
<tr>
|
|
2742
|
+
<td><a href="#" class="demo-font-mono demo-text-sm">ReportsController#index</a></td>
|
|
2743
|
+
<td><span class="demo-badge demo-badge-warning">623ms</span></td>
|
|
2744
|
+
<td class="demo-text-muted demo-text-sm">982ms</td>
|
|
2745
|
+
<td>156</td>
|
|
2746
|
+
</tr>
|
|
2747
|
+
<tr>
|
|
2748
|
+
<td><a href="#" class="demo-font-mono demo-text-sm">UsersController#show</a></td>
|
|
2749
|
+
<td><span class="demo-badge demo-badge-muted">156ms</span></td>
|
|
2750
|
+
<td class="demo-text-muted demo-text-sm">298ms</td>
|
|
2751
|
+
<td>847</td>
|
|
2752
|
+
</tr>
|
|
2753
|
+
<tr>
|
|
2754
|
+
<td><a href="#" class="demo-font-mono demo-text-sm">Api::V1::ProductsController#index</a></td>
|
|
2755
|
+
<td><span class="demo-badge demo-badge-muted">89ms</span></td>
|
|
2756
|
+
<td class="demo-text-muted demo-text-sm">201ms</td>
|
|
2757
|
+
<td>1,203</td>
|
|
2758
|
+
</tr>
|
|
2759
|
+
</tbody>
|
|
2760
|
+
</table>
|
|
2761
|
+
</div>
|
|
2762
|
+
|
|
2763
|
+
<!-- N+1 Hotspots -->
|
|
2764
|
+
<div class="demo-card">
|
|
2765
|
+
<div class="demo-card-header">
|
|
2766
|
+
<div><h2 class="demo-card-title">N+1 Hotspots</h2></div>
|
|
2767
|
+
</div>
|
|
2768
|
+
<table class="demo-table">
|
|
2769
|
+
<thead>
|
|
2770
|
+
<tr>
|
|
2771
|
+
<th>Endpoint</th>
|
|
2772
|
+
<th>N+1 Count</th>
|
|
2773
|
+
<th>Avg Queries</th>
|
|
2774
|
+
</tr>
|
|
2775
|
+
</thead>
|
|
2776
|
+
<tbody>
|
|
2777
|
+
<tr>
|
|
2778
|
+
<td><a href="#" class="demo-font-mono demo-text-sm">OrdersController#create</a></td>
|
|
2779
|
+
<td><span class="demo-badge demo-badge-warning">47</span></td>
|
|
2780
|
+
<td>18</td>
|
|
2781
|
+
</tr>
|
|
2782
|
+
<tr>
|
|
2783
|
+
<td><a href="#" class="demo-font-mono demo-text-sm">ReportsController#index</a></td>
|
|
2784
|
+
<td><span class="demo-badge demo-badge-warning">23</span></td>
|
|
2785
|
+
<td>12</td>
|
|
2786
|
+
</tr>
|
|
2787
|
+
<tr>
|
|
2788
|
+
<td><a href="#" class="demo-font-mono demo-text-sm">UsersController#show</a></td>
|
|
2789
|
+
<td><span class="demo-badge demo-badge-muted">5</span></td>
|
|
2790
|
+
<td>4</td>
|
|
2791
|
+
</tr>
|
|
2792
|
+
</tbody>
|
|
2793
|
+
</table>
|
|
2794
|
+
</div>
|
|
2795
|
+
</div>
|
|
2796
|
+
|
|
2797
|
+
<!-- Throughput Chart -->
|
|
2798
|
+
<div class="demo-card">
|
|
2799
|
+
<div class="demo-card-header">
|
|
2800
|
+
<div>
|
|
2801
|
+
<h2 class="demo-card-title">Throughput Over Time</h2>
|
|
2802
|
+
<p class="demo-card-description">Requests per interval</p>
|
|
2803
|
+
</div>
|
|
2804
|
+
</div>
|
|
2805
|
+
<div class="demo-chart-container">
|
|
2806
|
+
<div class="demo-chart-bar" style="height: 25%;"></div>
|
|
2807
|
+
<div class="demo-chart-bar" style="height: 18%;"></div>
|
|
2808
|
+
<div class="demo-chart-bar" style="height: 30%;"></div>
|
|
2809
|
+
<div class="demo-chart-bar" style="height: 45%;"></div>
|
|
2810
|
+
<div class="demo-chart-bar" style="height: 38%;"></div>
|
|
2811
|
+
<div class="demo-chart-bar" style="height: 52%;"></div>
|
|
2812
|
+
<div class="demo-chart-bar" style="height: 68%;"></div>
|
|
2813
|
+
<div class="demo-chart-bar" style="height: 85%;"></div>
|
|
2814
|
+
<div class="demo-chart-bar" style="height: 100%;"></div>
|
|
2815
|
+
<div class="demo-chart-bar" style="height: 92%;"></div>
|
|
2816
|
+
<div class="demo-chart-bar" style="height: 78%;"></div>
|
|
2817
|
+
<div class="demo-chart-bar" style="height: 65%;"></div>
|
|
2818
|
+
<div class="demo-chart-bar" style="height: 55%;"></div>
|
|
2819
|
+
<div class="demo-chart-bar" style="height: 48%;"></div>
|
|
2820
|
+
<div class="demo-chart-bar" style="height: 60%;"></div>
|
|
2821
|
+
<div class="demo-chart-bar" style="height: 72%;"></div>
|
|
2822
|
+
<div class="demo-chart-bar" style="height: 80%;"></div>
|
|
2823
|
+
<div class="demo-chart-bar" style="height: 75%;"></div>
|
|
2824
|
+
<div class="demo-chart-bar" style="height: 58%;"></div>
|
|
2825
|
+
<div class="demo-chart-bar" style="height: 42%;"></div>
|
|
2826
|
+
<div class="demo-chart-bar" style="height: 35%;"></div>
|
|
2827
|
+
<div class="demo-chart-bar" style="height: 28%;"></div>
|
|
2828
|
+
<div class="demo-chart-bar" style="height: 22%;"></div>
|
|
2829
|
+
<div class="demo-chart-bar" style="height: 15%;"></div>
|
|
2830
|
+
</div>
|
|
2831
|
+
<div class="demo-chart-labels">
|
|
2832
|
+
<span>00:00</span>
|
|
2833
|
+
<span>23:00</span>
|
|
2834
|
+
</div>
|
|
2835
|
+
</div>
|
|
2836
|
+
</div><!-- /demo-tab-performance -->
|
|
2837
|
+
|
|
2838
|
+
<!-- Alerts Tab -->
|
|
2839
|
+
<div class="demo-tab-content" id="demo-tab-alerts">
|
|
2840
|
+
<h1 class="demo-page-title">Alerts</h1>
|
|
2841
|
+
<p class="demo-page-description">Manage alert channels and send test notifications.</p>
|
|
2842
|
+
|
|
2843
|
+
<!-- Stats Grid -->
|
|
2844
|
+
<div class="demo-stats-grid" style="grid-template-columns: repeat(3, 1fr);">
|
|
2845
|
+
<div class="demo-stat-card">
|
|
2846
|
+
<div class="demo-stat-label">Total Channels</div>
|
|
2847
|
+
<div class="demo-stat-value" style="font-size: 1.5rem;">3</div>
|
|
2848
|
+
<div class="demo-stat-change">2 enabled</div>
|
|
2849
|
+
</div>
|
|
2850
|
+
<div class="demo-stat-card">
|
|
2851
|
+
<div class="demo-stat-label">Throttle Period</div>
|
|
2852
|
+
<div class="demo-stat-value" style="font-size: 1.5rem;">300s</div>
|
|
2853
|
+
<div class="demo-stat-change">5 minutes between alerts per error</div>
|
|
2854
|
+
</div>
|
|
2855
|
+
<div class="demo-stat-card">
|
|
2856
|
+
<div class="demo-stat-label">Alert Status</div>
|
|
2857
|
+
<div style="margin-top: 0.5rem;">
|
|
2858
|
+
<span class="demo-health-dot" style="display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50; vertical-align: middle;"></span>
|
|
2859
|
+
<span class="demo-text-sm">Active</span>
|
|
2860
|
+
</div>
|
|
2861
|
+
<div class="demo-stat-change">Alerts will be sent when errors occur</div>
|
|
2862
|
+
</div>
|
|
2863
|
+
</div>
|
|
2864
|
+
|
|
2865
|
+
<!-- Add Channel Button -->
|
|
2866
|
+
<div style="display: flex; justify-content: flex-end; margin-bottom: 1rem;">
|
|
2867
|
+
<button class="demo-btn-outline" style="gap: 0.375rem; display: inline-flex; align-items: center;">
|
|
2868
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2869
|
+
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
|
|
2870
|
+
</svg>
|
|
2871
|
+
Add Alert Channel
|
|
2872
|
+
</button>
|
|
2873
|
+
</div>
|
|
2874
|
+
|
|
2875
|
+
<!-- Channels Table -->
|
|
2876
|
+
<div class="demo-card">
|
|
2877
|
+
<table class="demo-table">
|
|
2878
|
+
<thead>
|
|
2879
|
+
<tr>
|
|
2880
|
+
<th>Channel</th>
|
|
2881
|
+
<th>Config</th>
|
|
2882
|
+
<th style="text-align: center;">Status</th>
|
|
2883
|
+
<th style="text-align: right;">Actions</th>
|
|
2884
|
+
</tr>
|
|
2885
|
+
</thead>
|
|
2886
|
+
<tbody>
|
|
2887
|
+
<tr>
|
|
2888
|
+
<td>
|
|
2889
|
+
<strong>Production Slack</strong>
|
|
2890
|
+
<span class="demo-badge demo-badge-info" style="margin-left: 0.5rem;">Slack</span>
|
|
2891
|
+
</td>
|
|
2892
|
+
<td class="demo-text-muted demo-text-sm demo-font-mono">https://hooks.slack.com/service********</td>
|
|
2893
|
+
<td style="text-align: center;">
|
|
2894
|
+
<label class="demo-toggle">
|
|
2895
|
+
<input type="checkbox" checked>
|
|
2896
|
+
<span class="demo-toggle-slider"></span>
|
|
2897
|
+
</label>
|
|
2898
|
+
</td>
|
|
2899
|
+
<td>
|
|
2900
|
+
<div style="display: flex; gap: 0.25rem; justify-content: flex-end; align-items: center;">
|
|
2901
|
+
<button class="demo-btn-icon" title="Send test alert">
|
|
2902
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2903
|
+
<path d="M22 2 11 13"/><path d="m22 2-7 20-4-9-9-4 20-7z"/>
|
|
2904
|
+
</svg>
|
|
2905
|
+
</button>
|
|
2906
|
+
<button class="demo-btn-icon" title="Edit">
|
|
2907
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2908
|
+
<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/>
|
|
2909
|
+
</svg>
|
|
2910
|
+
</button>
|
|
2911
|
+
<button class="demo-btn-icon" title="Delete" style="color: hsl(var(--error) / 0.7);">
|
|
2912
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2913
|
+
<path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
|
|
2914
|
+
</svg>
|
|
2915
|
+
</button>
|
|
2916
|
+
</div>
|
|
2917
|
+
</td>
|
|
2918
|
+
</tr>
|
|
2919
|
+
<tr>
|
|
2920
|
+
<td>
|
|
2921
|
+
<strong>Dev Team Email</strong>
|
|
2922
|
+
<span class="demo-badge demo-badge-info" style="margin-left: 0.5rem;">Email</span>
|
|
2923
|
+
</td>
|
|
2924
|
+
<td class="demo-text-muted demo-text-sm demo-font-mono">team@example.com, oncall@example.com</td>
|
|
2925
|
+
<td style="text-align: center;">
|
|
2926
|
+
<label class="demo-toggle">
|
|
2927
|
+
<input type="checkbox" checked>
|
|
2928
|
+
<span class="demo-toggle-slider"></span>
|
|
2929
|
+
</label>
|
|
2930
|
+
</td>
|
|
2931
|
+
<td>
|
|
2932
|
+
<div style="display: flex; gap: 0.25rem; justify-content: flex-end; align-items: center;">
|
|
2933
|
+
<button class="demo-btn-icon" title="Send test alert">
|
|
2934
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2935
|
+
<path d="M22 2 11 13"/><path d="m22 2-7 20-4-9-9-4 20-7z"/>
|
|
2936
|
+
</svg>
|
|
2937
|
+
</button>
|
|
2938
|
+
<button class="demo-btn-icon" title="Edit">
|
|
2939
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2940
|
+
<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/>
|
|
2941
|
+
</svg>
|
|
2942
|
+
</button>
|
|
2943
|
+
<button class="demo-btn-icon" title="Delete" style="color: hsl(var(--error) / 0.7);">
|
|
2944
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2945
|
+
<path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
|
|
2946
|
+
</svg>
|
|
2947
|
+
</button>
|
|
2948
|
+
</div>
|
|
2949
|
+
</td>
|
|
2950
|
+
</tr>
|
|
2951
|
+
<tr>
|
|
2952
|
+
<td>
|
|
2953
|
+
<strong>Discord Staging</strong>
|
|
2954
|
+
<span class="demo-badge demo-badge-info" style="margin-left: 0.5rem;">Discord</span>
|
|
2955
|
+
</td>
|
|
2956
|
+
<td class="demo-text-muted demo-text-sm demo-font-mono">https://discord.com/api/web********</td>
|
|
2957
|
+
<td style="text-align: center;">
|
|
2958
|
+
<label class="demo-toggle">
|
|
2959
|
+
<input type="checkbox">
|
|
2960
|
+
<span class="demo-toggle-slider"></span>
|
|
2961
|
+
</label>
|
|
2962
|
+
</td>
|
|
2963
|
+
<td>
|
|
2964
|
+
<div style="display: flex; gap: 0.25rem; justify-content: flex-end; align-items: center;">
|
|
2965
|
+
<button class="demo-btn-icon" title="Edit">
|
|
2966
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2967
|
+
<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/>
|
|
2968
|
+
</svg>
|
|
2969
|
+
</button>
|
|
2970
|
+
<button class="demo-btn-icon" title="Delete" style="color: hsl(var(--error) / 0.7);">
|
|
2971
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2972
|
+
<path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
|
|
2973
|
+
</svg>
|
|
2974
|
+
</button>
|
|
2975
|
+
</div>
|
|
2976
|
+
</td>
|
|
2977
|
+
</tr>
|
|
2978
|
+
</tbody>
|
|
2979
|
+
</table>
|
|
2980
|
+
</div>
|
|
2981
|
+
</div><!-- /demo-tab-alerts -->
|
|
2982
|
+
|
|
2415
2983
|
</div>
|
|
2416
2984
|
</div>
|
|
2417
2985
|
</div>
|
|
@@ -2492,5 +3060,23 @@
|
|
|
2492
3060
|
</div>
|
|
2493
3061
|
</footer>
|
|
2494
3062
|
|
|
3063
|
+
<script>
|
|
3064
|
+
function switchDemoTab(tab, navLink) {
|
|
3065
|
+
// Update nav
|
|
3066
|
+
document.querySelectorAll('.demo-app-nav a').forEach(function(a) { a.classList.remove('active'); });
|
|
3067
|
+
navLink.classList.add('active');
|
|
3068
|
+
|
|
3069
|
+
// Update content
|
|
3070
|
+
document.querySelectorAll('.demo-tab-content').forEach(function(el) { el.classList.remove('active'); });
|
|
3071
|
+
var target = document.getElementById('demo-tab-' + tab);
|
|
3072
|
+
if (target) target.classList.add('active');
|
|
3073
|
+
|
|
3074
|
+
// Update URL bar
|
|
3075
|
+
var urls = { dashboard: 'localhost:3010/findbug', errors: 'localhost:3010/findbug/errors', performance: 'localhost:3010/findbug/performance', alerts: 'localhost:3010/findbug/alerts' };
|
|
3076
|
+
var urlBar = document.querySelector('.demo-titlebar .url');
|
|
3077
|
+
if (urlBar && urls[tab]) urlBar.textContent = urls[tab];
|
|
3078
|
+
}
|
|
3079
|
+
</script>
|
|
3080
|
+
|
|
2495
3081
|
</body>
|
|
2496
3082
|
</html>
|