@@ -32,6 +32,17 @@ const TYPE_TEXT_COLORS = {
3232 "custom-event" : "text-white" ,
3333}
3434
35+ type EventType = "loader" | "client-loader" | "action" | "client-action" | "custom-event"
36+
37+ const EVENT_TYPE_FILTERS : { value : EventType | "all" ; label : string ; color : string } [ ] = [
38+ { value : "all" , label : "All Events" , color : "#ffffff" } ,
39+ { value : "loader" , label : "Loader" , color : "#4ade80" } ,
40+ { value : "client-loader" , label : "Client Loader" , color : "#60a5fa" } ,
41+ { value : "action" , label : "Action" , color : "#f59e0b" } ,
42+ { value : "client-action" , label : "Client Action" , color : "#ef4444" } ,
43+ { value : "custom-event" , label : "Custom Event" , color : "#ffffff" } ,
44+ ]
45+
3546const NetworkWaterfall : React . FC < Props > = ( { requests, width } ) => {
3647 const containerRef = useRef < HTMLDivElement > ( null )
3748 const { styles } = useStyles ( )
@@ -40,9 +51,14 @@ const NetworkWaterfall: React.FC<Props> = ({ requests, width }) => {
4051 const [ dragStart , setDragStart ] = useState ( { x : 0 , scrollLeft : 0 } )
4152 const [ selectedRequestIndex , setSelectedRequest ] = useState < number | null > ( null )
4253 const [ now , setNow ] = useState ( Date . now ( ) )
54+ const [ activeFilter , setActiveFilter ] = useState < EventType | "all" > ( "all" )
4355 const selectedRequest = selectedRequestIndex !== null ? requests [ selectedRequestIndex ] : null
56+
57+ // Filter requests based on active filter
58+ const filteredRequests = activeFilter === "all" ? requests : requests . filter ( ( req ) => req . type === activeFilter )
59+
4460 // Check if there are any active requests
45- const hasActiveRequests = requests . some (
61+ const hasActiveRequests = filteredRequests . some (
4662 ( req ) => ! req . endTime || ( req . endTime && now - req . endTime < INACTIVE_THRESHOLD )
4763 )
4864 useEffect ( ( ) => {
@@ -53,11 +69,11 @@ const NetworkWaterfall: React.FC<Props> = ({ requests, width }) => {
5369 return ( ) => clearInterval ( interval )
5470 } , [ hasActiveRequests ] )
5571
56- const minTime = Math . min ( ...requests . map ( ( r ) => r . startTime ) )
72+ const minTime = Math . min ( ...filteredRequests . map ( ( r ) => r . startTime ) )
5773 const maxTime = hasActiveRequests
5874 ? now + FUTURE_BUFFER
59- : requests . length > 0
60- ? Math . max ( ...requests . map ( ( r ) => r . endTime || r . startTime ) ) + 1000
75+ : filteredRequests . length > 0
76+ ? Math . max ( ...filteredRequests . map ( ( r ) => r . endTime || r . startTime ) ) + 1000
6177 : now
6278 const duration = maxTime - minTime
6379 const pixelsPerMs = scale
@@ -130,17 +146,49 @@ const NetworkWaterfall: React.FC<Props> = ({ requests, width }) => {
130146 if ( e . key === "ArrowLeft" && order > 0 ) {
131147 onChangeRequest ( order - 1 )
132148 }
133- if ( e . key === "ArrowRight" && order < requests . length - 1 ) {
149+ if ( e . key === "ArrowRight" && order < filteredRequests . length - 1 ) {
134150 onChangeRequest ( order + 1 )
135151 }
136152 } )
137153 return (
138154 < div className = { styles . network . waterfall . container } >
155+ { /* Filter Bar */ }
156+ < div className = { styles . network . waterfall . filterBar } >
157+ < div className = { styles . network . waterfall . filterLabel } > Filter:</ div >
158+ < div className = { styles . network . waterfall . filterButtons } >
159+ { EVENT_TYPE_FILTERS . map ( ( filter ) => (
160+ < button
161+ key = { filter . value }
162+ type = "button"
163+ className = { cx (
164+ styles . network . waterfall . filterButton ,
165+ activeFilter === filter . value && styles . network . waterfall . filterButtonActive
166+ ) }
167+ style = { {
168+ borderColor : activeFilter === filter . value ? filter . color : "transparent" ,
169+ color : activeFilter === filter . value ? filter . color : "#9ca3af" ,
170+ } }
171+ onClick = { ( ) => setActiveFilter ( filter . value ) }
172+ >
173+ { filter . label }
174+ { filter . value !== "all" && (
175+ < span className = { styles . network . waterfall . filterCount } >
176+ ({ requests . filter ( ( r ) => r . type === filter . value ) . length } )
177+ </ span >
178+ ) }
179+ { filter . value === "all" && (
180+ < span className = { styles . network . waterfall . filterCount } > ({ requests . length } )</ span >
181+ ) }
182+ </ button >
183+ ) ) }
184+ </ div >
185+ </ div >
186+
139187 < div className = { styles . network . waterfall . flexContainer } >
140188 < div >
141189 < div className = { styles . network . waterfall . requestsHeader } > Requests</ div >
142190 < div style = { { gap : BAR_PADDING } } className = { styles . network . waterfall . requestsList } >
143- { requests . map ( ( request , index ) => {
191+ { filteredRequests . map ( ( request , index ) => {
144192 const borderColorClass =
145193 request . type === "loader"
146194 ? styles . network . waterfall . requestButtonGreen
@@ -208,7 +256,7 @@ const NetworkWaterfall: React.FC<Props> = ({ requests, width }) => {
208256 isDragging ? styles . network . waterfall . scrollContainerGrabbing : styles . network . waterfall . scrollContainerGrab
209257 ) }
210258 style = { {
211- height : Math . min ( requests . length * ( BAR_HEIGHT + BAR_PADDING ) + 24 , window . innerHeight - 200 ) ,
259+ height : Math . min ( filteredRequests . length * ( BAR_HEIGHT + BAR_PADDING ) + 24 , window . innerHeight - 200 ) ,
212260 } }
213261 onMouseDown = { handleMouseDown }
214262 onMouseMove = { handleMouseMove }
@@ -229,14 +277,16 @@ const NetworkWaterfall: React.FC<Props> = ({ requests, width }) => {
229277 < span className = { styles . network . waterfall . timeLabel } > { i } s</ span >
230278 < div
231279 className = { styles . network . waterfall . timeDivider }
232- style = { { height : BAR_HEIGHT * requests . length + 1 + ( BAR_PADDING * requests . length + 1 ) } }
280+ style = { {
281+ height : BAR_HEIGHT * filteredRequests . length + 1 + ( BAR_PADDING * filteredRequests . length + 1 ) ,
282+ } }
233283 />
234284 </ div >
235285 ) ) }
236286 </ div >
237287
238288 < AnimatePresence mode = "popLayout" >
239- { requests . map ( ( request , index ) => (
289+ { filteredRequests . map ( ( request , index ) => (
240290 < NetworkBar
241291 key = { request . id + request . startTime }
242292 request = { request }
@@ -258,7 +308,7 @@ const NetworkWaterfall: React.FC<Props> = ({ requests, width }) => {
258308 < AnimatePresence mode = "wait" >
259309 < RequestDetails
260310 key = { selectedRequest . id + selectedRequest . startTime }
261- total = { requests . length }
311+ total = { filteredRequests . length }
262312 index = { selectedRequestIndex }
263313 request = { selectedRequest }
264314 onChangeRequest = { onChangeRequest }
0 commit comments