File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ import { StreamsWorkspace } from "@/components/streams/streams-workspace"
2+
3+ export default function StreamsPage ( ) {
4+ return (
5+ < StreamsWorkspace />
6+ )
7+ }
Original file line number Diff line number Diff line change 1+ "use client"
2+
3+ import { StreamRow } from "./stream-row"
4+
5+ type Row = {
6+ provider : string
7+ route : string
8+ status : string
9+ latency : string
10+ timestamp : string
11+ eventType : string
12+ }
13+
14+ type Props = {
15+ rows : Row [ ]
16+ selected : Row | null
17+ onSelect : ( row : Row ) => void
18+ }
19+
20+ export function LiveStreamTable ( {
21+ rows,
22+ selected,
23+ onSelect,
24+ } : Props ) {
25+ return (
26+ < div className = "h-full overflow-auto" >
27+
28+ < div
29+ className = "
30+ sticky top-0 z-10
31+ grid
32+ grid-cols-[120px_1fr_180px_120px_120px_140px]
33+ border-b border-border
34+ bg-background/95
35+ px-5 py-3
36+ text-xs uppercase tracking-wide
37+ text-muted-foreground
38+ backdrop-blur
39+ "
40+ >
41+
42+ < div > Provider</ div >
43+ < div > Route</ div >
44+ < div > Event</ div >
45+ < div > Status</ div >
46+ < div > Latency</ div >
47+ < div > Time</ div >
48+
49+ </ div >
50+
51+ { rows . map ( ( row , i ) => (
52+ < StreamRow
53+ key = { i }
54+ { ...row }
55+ selected = {
56+ selected === row
57+ }
58+ onClick = { ( ) =>
59+ onSelect ( row )
60+ }
61+ />
62+ ) ) }
63+
64+ </ div >
65+ )
66+ }
Original file line number Diff line number Diff line change 1+ "use client"
2+
3+ import { useMemo , useState } from "react"
4+
5+ import {
6+ Panel ,
7+ PanelGroup ,
8+ PanelResizeHandle ,
9+ } from "react-resizable-panels"
10+
11+ import { LiveStreamTable } from "./live-stream-table"
12+
13+ import { StreamInspector } from "./stream-inspector"
14+
15+ const rows = Array . from ( {
16+ length : 30 ,
17+ } ) . map ( ( _ , i ) => ( {
18+ provider :
19+ i % 2 === 0
20+ ? "stripe"
21+ : "github" ,
22+
23+ route :
24+ i % 2 === 0
25+ ? "/webhooks/stripe"
26+ : "/webhooks/github" ,
27+
28+ eventType :
29+ i % 2 === 0
30+ ? "payment.succeeded"
31+ : "repo.push" ,
32+
33+ status :
34+ i % 4 === 0
35+ ? "failed"
36+ : "success" ,
37+
38+ latency : `${ 40 + i } ms` ,
39+
40+ timestamp : `${ i + 1 } s ago` ,
41+ } ) )
42+
43+ type Props = {
44+ query : string
45+ }
46+
47+ export function LiveStream ( {
48+ query,
49+ } : Props ) {
50+
51+ const [ selected , setSelected ] =
52+ useState <
53+ ( typeof rows ) [ number ] | null
54+ > ( null )
55+
56+ const filtered =
57+ useMemo ( ( ) => {
58+
59+ return rows . filter ( ( row ) =>
60+ `
61+ ${ row . provider }
62+ ${ row . route }
63+ ${ row . eventType }
64+ `
65+ . toLowerCase ( )
66+ . includes ( query . toLowerCase ( ) )
67+ )
68+
69+ } , [ query ] )
70+
71+ return (
72+ < PanelGroup direction = "horizontal" >
73+
74+ < Panel
75+ defaultSize = { 72 }
76+ minSize = { 45 }
77+ >
78+
79+ < LiveStreamTable
80+ rows = { filtered }
81+ selected = { selected }
82+ onSelect = { setSelected }
83+ />
84+
85+ </ Panel >
86+
87+ < PanelResizeHandle className = "w-2 bg-border/40" />
88+
89+ < Panel
90+ defaultSize = { 28 }
91+ minSize = { 20 }
92+ >
93+
94+ < div className = "h-full border-l border-border bg-background/20" >
95+
96+ < StreamInspector
97+ event = { selected }
98+ />
99+
100+ </ div >
101+
102+ </ Panel >
103+
104+ </ PanelGroup >
105+ )
106+ }
Original file line number Diff line number Diff line change 1+ "use client"
2+
3+ import {
4+ Clock3 ,
5+ FileJson ,
6+ Globe ,
7+ Radio ,
8+ } from "lucide-react"
9+
10+ import { StreamJson } from "./stream-json"
11+
12+ type StreamEvent = {
13+ provider : string
14+ route : string
15+ status : string
16+ latency : string
17+ timestamp : string
18+ eventType : string
19+ }
20+
21+ type Props = {
22+ event : StreamEvent | null
23+ }
24+
25+ export function StreamInspector ( {
26+ event,
27+ } : Props ) {
28+
29+ if ( ! event ) {
30+ return (
31+ < div className = "flex h-full items-center justify-center text-sm text-muted-foreground" >
32+ Select a stream event
33+ </ div >
34+ )
35+ }
36+
37+ return (
38+ < div className = "flex h-full flex-col" >
39+
40+ { /* Header */ }
41+ < div className = "border-b border-border p-5" >
42+
43+ < div className = "flex items-center gap-3" >
44+
45+ < div
46+ className = "
47+ flex h-11 w-11 items-center justify-center
48+ rounded-xl border border-border
49+ bg-background/40
50+ "
51+ >
52+ < Radio className = "h-5 w-5 text-orange-400" />
53+ </ div >
54+
55+ < div >
56+
57+ < h2 className = "text-lg font-semibold" >
58+ Stream Inspector
59+ </ h2 >
60+
61+ < p className = "mt-1 text-sm text-muted-foreground" >
62+ live webhook payload
63+ </ p >
64+
65+ </ div >
66+
67+ </ div >
68+
69+ </ div >
70+
71+ { /* Meta */ }
72+ < div className = "space-y-3 border-b border-border p-5" >
73+
74+ < MetaRow
75+ icon = { Globe }
76+ label = "Provider"
77+ value = { event . provider }
78+ />
79+
80+ < MetaRow
81+ icon = { FileJson }
82+ label = "Event Type"
83+ value = { event . eventType }
84+ />
85+
86+ < MetaRow
87+ icon = { Clock3 }
88+ label = "Latency"
89+ value = { event . latency }
90+ />
91+
92+ </ div >
93+
94+ { /* Payload */ }
95+ < div className = "flex-1 overflow-auto p-5" >
96+
97+ < div className = "mb-4" >
98+
99+ < h3 className = "text-sm font-semibold" >
100+ Payload
101+ </ h3 >
102+
103+ </ div >
104+
105+ < StreamJson
106+ payload = { {
107+ id : "evt_12345" ,
108+ route : event . route ,
109+ provider : event . provider ,
110+ type : event . eventType ,
111+ latency : event . latency ,
112+ metadata : {
113+ retries : 1 ,
114+ region : "eu-west" ,
115+ worker : "worker-02" ,
116+ } ,
117+ } }
118+ />
119+
120+ </ div >
121+
122+ </ div >
123+ )
124+ }
125+
126+ function MetaRow ( {
127+ icon : Icon ,
128+ label,
129+ value,
130+ } : {
131+ icon : React . ElementType
132+ label : string
133+ value : string
134+ } ) {
135+ return (
136+ < div className = "flex items-center justify-between" >
137+
138+ < div className = "flex items-center gap-2 text-sm text-muted-foreground" >
139+
140+ < Icon className = "h-4 w-4" />
141+
142+ { label }
143+
144+ </ div >
145+
146+ < div className = "text-sm font-medium" >
147+ { value }
148+ </ div >
149+
150+ </ div >
151+ )
152+ }
Original file line number Diff line number Diff line change 1+ "use client"
2+
3+ import JsonView from "@uiw/react-json-view"
4+
5+ type Props = {
6+ payload : Record < string , unknown > | undefined
7+ }
8+
9+ export function StreamJson ( {
10+ payload,
11+ } : Props ) {
12+ return (
13+ < div
14+ className = "
15+ overflow-hidden rounded-xl
16+ border border-border
17+ bg-background/40
18+ p-4
19+ "
20+ >
21+
22+ < JsonView
23+ value = { payload }
24+ displayDataTypes = { false }
25+ displayObjectSize = { false }
26+ enableClipboard
27+ />
28+
29+ </ div >
30+ )
31+ }
You can’t perform that action at this time.
0 commit comments