11export const dynamic = "force-dynamic"
2+
23import { redirect } from "next/navigation"
34import { promQuery , getScalar } from "@/lib/prometheus"
45import { getCurrentUser } from "@/lib/auth"
56import DashboardClient from "@/app/dashboard/dashboard-client"
67
8+ /* ---------------- Helpers ---------------- */
9+
10+ function parseTimeSeries ( data : unknown ) : [ number , string ] [ ] {
11+ if ( ! Array . isArray ( data ) ) return [ ]
12+
13+ return data
14+ . map ( ( item ) => {
15+ if (
16+ Array . isArray ( item ) &&
17+ item . length === 2 &&
18+ typeof item [ 0 ] === "number"
19+ ) {
20+ return [ item [ 0 ] , String ( item [ 1 ] ) ]
21+ }
22+ return null
23+ } )
24+ . filter ( Boolean ) as [ number , string ] [ ]
25+ }
26+
27+ /* ---------------- API ---------------- */
28+
729async function getRecentEvents ( ) {
8- const res = await fetch ( `${ process . env . NEXT_PUBLIC_API_URL } /events?limit=5` , {
9- credentials : "include" ,
10- cache : "no-store" ,
11- } )
12-
13- if ( ! res . ok ) return [ ]
14- const data = await res . json ( )
15- return data . items || [ ]
30+ try {
31+ const res = await fetch (
32+ `${ process . env . NEXT_PUBLIC_API_URL } /events?limit=5` ,
33+ { credentials : "include" , cache : "no-store" }
34+ )
35+
36+ if ( ! res . ok ) return [ ]
37+
38+ const data = await res . json ( )
39+ return data . items || [ ]
40+ } catch {
41+ return [ ]
42+ }
1643}
1744
1845async function getEndpoints ( ) {
19- const res = await fetch ( `${ process . env . NEXT_PUBLIC_API_URL } /routes` , {
20- credentials : "include" ,
21- cache : "no-store" ,
22- } )
46+ try {
47+ const res = await fetch (
48+ `${ process . env . NEXT_PUBLIC_API_URL } /routes` ,
49+ { credentials : "include" , cache : "no-store" }
50+ )
51+
52+ if ( ! res . ok ) return [ ]
53+
54+ const data = await res . json ( )
55+ return data . items || data || [ ]
56+ } catch {
57+ return [ ]
58+ }
59+ }
2360
24- if ( ! res . ok ) return [ ]
25- return res . json ( )
61+ async function getDLQCount ( ) {
62+ try {
63+ const res = await fetch (
64+ `${ process . env . NEXT_PUBLIC_API_URL } /events?status=dlq` ,
65+ { cache : "no-store" }
66+ )
67+
68+ if ( ! res . ok ) return 0
69+
70+ const data = await res . json ( )
71+ return data . items ?. length || 0
72+ } catch {
73+ return 0
74+ }
2675}
2776
77+ /* ---------------- PAGE ---------------- */
78+
2879export default async function Dashboard ( ) {
2980 const user = await getCurrentUser ( )
30-
3181 if ( ! user ) redirect ( "/login" )
3282
33- const [ totalEvents , delivered , failed , retries , events , endpoints ] =
34- await Promise . all ( [
83+ // ✅ Proper typing (FIXED)
84+ let totalEvents : unknown = [ ]
85+ let delivered : unknown = [ ]
86+ let failed : unknown = [ ]
87+ let retries : unknown = [ ]
88+ let successSeries : unknown = [ ]
89+ let failureSeries : unknown = [ ]
90+ let events : unknown = [ ]
91+ let endpoints : unknown = [ ]
92+ let dlqCount = 0
93+
94+ try {
95+ [
96+ totalEvents ,
97+ delivered ,
98+ failed ,
99+ retries ,
100+ successSeries ,
101+ failureSeries ,
102+ events ,
103+ endpoints ,
104+ dlqCount ,
105+ ] = await Promise . all ( [
35106 promQuery ( "sum(hooktrace_webhooks_received_total)" ) ,
36107 promQuery ( "sum(hooktrace_events_delivered_total)" ) ,
37108 promQuery ( "sum(hooktrace_events_failed_total)" ) ,
38109 promQuery ( "sum(hooktrace_events_retried_total)" ) ,
110+
111+ promQuery ( "rate(hooktrace_events_delivered_total[1m])" ) ,
112+ promQuery ( "rate(hooktrace_events_failed_total[1m])" ) ,
113+
39114 getRecentEvents ( ) ,
40115 getEndpoints ( ) ,
116+ getDLQCount ( ) ,
41117 ] )
118+ } catch ( err ) {
119+ console . error ( "Dashboard error:" , err )
120+ }
121+
122+ /* ---------------- Safe Parsing ---------------- */
42123
43124 const stats = [
44- { label : "Total Events" , value : getScalar ( totalEvents as unknown [ ] ) } ,
45- { label : "Delivered" , value : getScalar ( delivered as unknown [ ] ) } ,
46- { label : "Failed" , value : getScalar ( failed as unknown [ ] ) } ,
47- { label : "Retries" , value : getScalar ( retries as unknown [ ] ) } ,
125+ {
126+ label : "Total Events" ,
127+ value : Array . isArray ( totalEvents ) ? getScalar ( totalEvents ) || 0 : 0 ,
128+ } ,
129+ {
130+ label : "Delivered" ,
131+ value : Array . isArray ( delivered ) ? getScalar ( delivered ) || 0 : 0 ,
132+ } ,
133+ {
134+ label : "Failed" ,
135+ value : Array . isArray ( failed ) ? getScalar ( failed ) || 0 : 0 ,
136+ } ,
137+ {
138+ label : "Retries" ,
139+ value : Array . isArray ( retries ) ? getScalar ( retries ) || 0 : 0 ,
140+ } ,
48141 ]
49142
143+ const parsedSuccess = parseTimeSeries ( successSeries )
144+ const parsedFailure = parseTimeSeries ( failureSeries )
145+
146+ const safeEvents = Array . isArray ( events ) ? events : [ ]
147+ const safeEndpoints = Array . isArray ( endpoints ) ? endpoints : [ ]
148+
149+ /* ---------------- Render ---------------- */
150+
50151 return (
51152 < DashboardClient
52153 stats = { stats }
53154 user = { user }
54- recentEvents = { events }
55- endpoints = { endpoints }
155+ recentEvents = { safeEvents }
156+ endpoints = { safeEndpoints }
157+ successSeries = { parsedSuccess }
158+ failureSeries = { parsedFailure }
159+ dlqCount = { dlqCount }
56160 />
57161 )
58162}
0 commit comments