1
1
import { subHours } from "date-fns" ;
2
2
import { AlertTriangleIcon , ClockIcon } from "lucide-react" ;
3
+ import { toast } from "sonner" ;
3
4
import {
4
5
getWebhookLatency ,
5
6
getWebhookRequests ,
@@ -12,9 +13,7 @@ import {
12
13
type Range ,
13
14
} from "@/components/analytics/date-range-selector" ;
14
15
import { RangeSelector } from "@/components/analytics/range-selector" ;
15
- import { ThirdwebBarChart } from "@/components/blocks/charts/bar-chart" ;
16
- import { Card , CardContent } from "@/components/ui/card" ;
17
- import type { ChartConfig } from "@/components/ui/chart" ;
16
+ import { StatCard } from "@/components/analytics/stat" ;
18
17
import type {
19
18
WebhookLatencyStats ,
20
19
WebhookRequestStats ,
@@ -23,16 +22,12 @@ import type {
23
22
import { LatencyChart } from "./latency-chart" ;
24
23
import { StatusCodesChart } from "./status-codes-chart" ;
25
24
import { WebhookSelector } from "./webhook-selector" ;
26
- import { toast } from "sonner" ;
27
- import { StatCard } from "@/components/analytics/stat" ;
28
-
29
-
30
25
31
26
type WebhookAnalyticsProps = {
32
27
interval : "day" | "week" ;
33
28
range : Range ;
34
29
selectedWebhookId : string | null ;
35
- webhooks : WebhookConfig [ ] ;
30
+ webhooksConfigs : WebhookConfig [ ] ;
36
31
requestStats : WebhookRequestStats [ ] ;
37
32
latencyStats : WebhookLatencyStats [ ] ;
38
33
summaryStats : WebhookSummaryStats [ ] ;
@@ -42,91 +37,67 @@ function WebhookAnalytics({
42
37
interval,
43
38
range,
44
39
selectedWebhookId,
45
- webhooks ,
40
+ webhooksConfigs ,
46
41
requestStats,
47
42
latencyStats,
48
43
summaryStats,
49
44
} : WebhookAnalyticsProps ) {
50
-
51
45
// Calculate overview metrics for the last 24 hours
52
- const last24HoursSummary = summaryStats . find (
53
- ( s ) => s . webhookId === selectedWebhookId ,
54
- ) ;
55
- const errorRate = 100 - ( last24HoursSummary ?. successRate || 0 ) ;
56
- const avgLatency = last24HoursSummary ?. avgLatencyMs || 0 ;
46
+ const errorRate = 100 - ( summaryStats [ 0 ] ?. successRate || 0 ) ;
47
+ const avgLatency = summaryStats [ 0 ] ?. avgLatencyMs || 0 ;
57
48
58
- // Transform request data for combined chart
49
+ // Transform request data for combined chart.
59
50
const allRequestsData = requestStats
60
- . filter (
61
- ( stat ) => ! selectedWebhookId || stat . webhookId === selectedWebhookId ,
62
- )
63
51
. reduce ( ( acc , stat ) => {
52
+ const statusCode = stat . httpStatusCode . toString ( ) ;
64
53
const existingEntry = acc . find ( ( entry ) => entry . time === stat . date ) ;
65
54
if ( existingEntry ) {
66
- existingEntry . totalRequests += stat . totalRequests ;
67
- existingEntry [ stat . httpStatusCode . toString ( ) ] =
68
- ( existingEntry [ stat . httpStatusCode . toString ( ) ] || 0 ) +
69
- stat . totalRequests ;
55
+ existingEntry [ statusCode ] =
56
+ ( existingEntry [ statusCode ] || 0 ) + stat . totalRequests ;
70
57
} else {
71
58
acc . push ( {
72
- time : stat . date , // Changed from 'date' to 'time'
73
- totalRequests : stat . totalRequests ,
74
- [ stat . httpStatusCode . toString ( ) ] : stat . totalRequests ,
59
+ time : stat . date ,
60
+ [ statusCode ] : stat . totalRequests ,
75
61
} ) ;
76
62
}
77
63
return acc ;
78
64
} , [ ] as any [ ] )
79
65
. sort ( ( a , b ) => new Date ( a . time ) . getTime ( ) - new Date ( b . time ) . getTime ( ) ) ;
80
66
81
- // Transform latency data for line chart
67
+ // Transform latency data for line chart.
82
68
const latencyData = latencyStats
83
- . filter (
84
- ( stat ) => ! selectedWebhookId || stat . webhookId === selectedWebhookId ,
85
- )
86
- . map ( ( stat ) => ( {
87
- p50LatencyMs : stat . p50LatencyMs , // Changed from 'date' to 'time'
88
- p90LatencyMs : stat . p90LatencyMs ,
89
- p99LatencyMs : stat . p99LatencyMs ,
90
- time : stat . date ,
91
- } ) )
69
+ . map ( ( stat ) => ( { ...stat , time : stat . date } ) )
92
70
. sort ( ( a , b ) => new Date ( a . time ) . getTime ( ) - new Date ( b . time ) . getTime ( ) ) ;
93
71
94
72
return (
95
73
< div className = "flex flex-col gap-6" >
96
- { /* Webhook Selector */ }
97
74
< WebhookSelector
98
75
selectedWebhookId = { selectedWebhookId }
99
- webhooks = { webhooks }
76
+ webhooks = { webhooksConfigs }
100
77
/>
101
78
102
- { /* Overview Cards */ }
103
79
< div className = "grid grid-cols-1 md:grid-cols-2 gap-6" >
104
80
< StatCard
81
+ formatter = { ( value ) => `${ value . toFixed ( 2 ) } %` }
105
82
icon = { AlertTriangleIcon }
106
83
isPending = { false }
107
84
label = "Error Rate (24h)"
108
85
value = { errorRate }
109
- formatter = { ( value ) => `${ value . toFixed ( 2 ) } %` }
110
86
/>
111
- < StatCard
87
+ < StatCard
88
+ formatter = { ( value ) => `${ value . toFixed ( 0 ) } ms` }
112
89
icon = { ClockIcon }
113
90
isPending = { false }
114
91
label = "P50 Latency (24h)"
115
92
value = { avgLatency }
116
- formatter = { ( value ) => `${ value . toFixed ( 0 ) } ms` }
117
93
/>
118
94
</ div >
119
95
120
96
< RangeSelector interval = { interval } range = { range } />
121
97
122
98
< div className = "flex flex-col gap-4 lg:gap-6" >
123
- { selectedWebhookId && (
124
- < StatusCodesChart data = { allRequestsData } isPending = { false } />
125
- ) }
126
-
127
- { selectedWebhookId && (
128
- < LatencyChart data = { latencyData } isPending = { false } />
129
- ) }
99
+ < StatusCodesChart data = { allRequestsData } isPending = { false } />
100
+ < LatencyChart data = { latencyData } isPending = { false } />
130
101
</ div >
131
102
</ div >
132
103
) ;
@@ -146,80 +117,53 @@ export async function AnalyticsPageContent({
146
117
} ) {
147
118
// Parse search params for filters
148
119
const selectedWebhookId = searchParams ?. webhookId as string | undefined ;
149
- const interval = ( searchParams ?. interval as "day" | "week" ) || DEFAULT_INTERVAL ;
120
+ const interval =
121
+ ( searchParams ?. interval as "day" | "week" ) || DEFAULT_INTERVAL ;
150
122
const range = DEFAULT_RANGE ; // Could be enhanced to parse from search params
151
123
152
- // Fetch webhooks
153
- const webhooksResponse = await getWebhookConfigs ( teamSlug , project . id ) ;
154
- if ( "error" in webhooksResponse ) {
155
- toast . error ( webhooksResponse . error ) ;
124
+ // Get webhook configs.
125
+ const webhooksConfigsResponse = await getWebhookConfigs ( teamSlug , project . id ) ;
126
+ if ( "error" in webhooksConfigsResponse ) {
127
+ toast . error ( webhooksConfigsResponse . error ) ;
156
128
return null ;
157
129
}
158
130
159
- const webhooks : WebhookConfig [ ] =
160
- webhooksResponse . data . length > 0
161
- ? webhooksResponse . data
162
- : [
163
- {
164
- id : "8582b449-551e-429f-99c4-5359f253dce1" ,
165
- description : "Webhook 2" ,
166
- createdAt : new Date ( ) ,
167
- updatedAt : new Date ( ) ,
168
- deletedAt : null ,
169
- teamId : 'team_clmb33q9w00gn1x0u2ri8z0k0' ,
170
- projectId : 'prj_cm6ibyah500bgxag5q7d79fps' ,
171
- destinationUrl : "https://example.com/webhook2" ,
172
- pausedAt : null ,
173
- webhookSecret : "secret" ,
174
- } ,
175
- ] ;
176
-
177
- // Fetch analytics data
131
+ // Get webhook analytics.
178
132
const [ requestStats , latencyStats , summaryStats ] = await Promise . all ( [
179
133
getWebhookRequests ( {
180
- teamId : 'team_clmb33q9w00gn1x0u2ri8z0k0' ,
181
- projectId : 'prj_cm6ibyah500bgxag5q7d79fps' ,
182
- // teamId: project.teamId,
183
- // projectId: project.id,
134
+ teamId : project . teamId ,
135
+ projectId : project . id ,
184
136
from : range . from ,
185
- to : range . to ,
186
137
period : interval ,
138
+ to : range . to ,
187
139
webhookId : selectedWebhookId || undefined ,
188
140
} ) . catch ( ( ) => [ ] ) ,
189
141
getWebhookLatency ( {
190
- teamId : 'team_clmb33q9w00gn1x0u2ri8z0k0' ,
191
- projectId : 'prj_cm6ibyah500bgxag5q7d79fps' ,
192
- // teamId: project.teamId,
193
- // projectId: project.id,
142
+ teamId : project . teamId ,
143
+ projectId : project . id ,
194
144
from : range . from ,
195
- to : range . to ,
196
145
period : interval ,
146
+ to : range . to ,
197
147
webhookId : selectedWebhookId || undefined ,
198
148
} ) . catch ( ( ) => [ ] ) ,
199
149
getWebhookSummary ( {
200
- teamId : 'team_clmb33q9w00gn1x0u2ri8z0k0' ,
201
- projectId : 'prj_cm6ibyah500bgxag5q7d79fps' ,
202
- // teamId: project.teamId,
203
- // projectId: project.id,
150
+ teamId : project . teamId ,
151
+ projectId : project . id ,
204
152
from : subHours ( new Date ( ) , 24 ) ,
205
153
to : new Date ( ) ,
206
154
webhookId : selectedWebhookId || undefined ,
207
155
} ) . catch ( ( ) => [ ] ) ,
208
156
] ) ;
209
157
210
- console . log ( "requestStats" , requestStats ) ;
211
- console . log ( "latencyStats" , latencyStats ) ;
212
- console . log ( "summaryStats" , summaryStats ) ;
213
-
214
158
return (
215
159
< WebhookAnalytics
216
160
interval = { interval }
161
+ latencyStats = { latencyStats }
217
162
range = { range }
218
- selectedWebhookId = { selectedWebhookId || null }
219
- webhooks = { webhooks }
220
163
requestStats = { requestStats }
221
- latencyStats = { latencyStats }
164
+ selectedWebhookId = { selectedWebhookId || null }
222
165
summaryStats = { summaryStats }
166
+ webhooksConfigs = { webhooksConfigsResponse . data }
223
167
/>
224
168
) ;
225
169
}
0 commit comments