@@ -77,6 +77,9 @@ const getProtocolName = (proto: number): string => {
7777
7878// Helper function to categorize IP addresses
7979const categorizeIP = ( ip : string ) : string [ ] => {
80+ // DERP servers
81+ if ( ip === '127.3.3.40' ) return [ 'derp' ]
82+
8083 // IPv4 Tailscale addresses
8184 if ( ip . startsWith ( '100.' ) ) return [ 'tailscale' ]
8285
@@ -128,7 +131,7 @@ const NetworkView: React.FC = () => {
128131 const [ trafficTypeFilters , setTrafficTypeFilters ] = useState < Set < string > > ( new Set ( ) )
129132 const [ ipCategoryFilters , setIpCategoryFilters ] = useState < Set < string > > ( new Set ( ) )
130133 const [ ipVersionFilter , setIpVersionFilter ] = useState < string > ( 'all' ) // IPv4/IPv6 filter
131- const [ timeRangeFilter , setTimeRangeFilter ] = useState < string > ( '1h ' )
134+ const [ timeRangeFilter , setTimeRangeFilter ] = useState < string > ( '5m ' )
132135 const [ minBandwidth , setMinBandwidth ] = useState < number > ( 0 )
133136 const [ maxBandwidth , setMaxBandwidth ] = useState < number > ( 1000000000 ) // 1GB
134137 const [ nodeCountFilter , setNodeCountFilter ] = useState < number > ( 0 ) // Minimum connections
@@ -180,7 +183,7 @@ const NetworkView: React.FC = () => {
180183 since = new Date ( now . getTime ( ) - 30 * 24 * 60 * 60 * 1000 )
181184 break
182185 default :
183- since = new Date ( now . getTime ( ) - 60 * 60 * 1000 ) // Default to last 1h
186+ since = new Date ( now . getTime ( ) - 5 * 60 * 1000 ) // Default to last 5m
184187 }
185188 params . append ( 'start' , since . toISOString ( ) )
186189 params . append ( 'end' , now . toISOString ( ) )
@@ -197,10 +200,10 @@ const NetworkView: React.FC = () => {
197200
198201 const networkLogs = ( Array . isArray ( networkLogsData ) && networkLogsData . length > 0 && 'logged' in networkLogsData [ 0 ] ) ? networkLogsData : [ ]
199202
200- // Set default date range to show most recent data (last 1 hour )
203+ // Set default date range to show most recent data (last 5 minutes )
201204 useEffect ( ( ) => {
202205 const now = new Date ( )
203- const oneHourAgo = new Date ( now . getTime ( ) - 60 * 60 * 1000 )
206+ const fiveMinutesAgo = new Date ( now . getTime ( ) - 5 * 60 * 1000 )
204207
205208 // Format for datetime-local input (YYYY-MM-DDTHH:mm)
206209 const formatForInput = ( date : Date ) => {
@@ -212,7 +215,7 @@ const NetworkView: React.FC = () => {
212215 return `${ year } -${ month } -${ day } T${ hours } :${ minutes } `
213216 }
214217
215- setStartDate ( formatForInput ( oneHourAgo ) )
218+ setStartDate ( formatForInput ( fiveMinutesAgo ) )
216219 setEndDate ( formatForInput ( now ) )
217220 setLoading ( false )
218221 } , [ ] )
@@ -457,46 +460,20 @@ const NetworkView: React.FC = () => {
457460
458461 svg . call ( zoom )
459462
460- // Group nodes by category for better clustering
461- const nodesByCategory = filteredData . nodes . reduce ( ( acc , node ) => {
462- const primaryTag = node . tags . find ( tag => ! tag . includes ( '+' ) ) || 'unknown'
463- if ( ! acc [ primaryTag ] ) acc [ primaryTag ] = [ ]
464- acc [ primaryTag ] . push ( node )
465- return acc
466- } , { } as Record < string , typeof filteredData . nodes > )
467-
468- // Calculate category centers in a grid pattern
469- const categories = Object . keys ( nodesByCategory )
470- const cols = Math . ceil ( Math . sqrt ( categories . length ) )
471- const categoryPositions = categories . reduce ( ( acc , category , index ) => {
472- const row = Math . floor ( index / cols )
473- const col = index % cols
474- const offsetX = ( width / cols ) * col + ( width / cols ) / 2
475- const offsetY = ( height / Math . ceil ( categories . length / cols ) ) * row + ( height / Math . ceil ( categories . length / cols ) ) / 2
476- acc [ category ] = { x : offsetX , y : offsetY }
477- return acc
478- } , { } as Record < string , { x : number ; y : number } > )
479-
480- // Create force simulation with better spacing and clustering
463+
464+
465+ // Create force simulation with no gravity - pure network topology layout
481466 const simulation = d3 . forceSimulation ( filteredData . nodes )
482- . force ( 'link' , d3 . forceLink ( filteredData . links ) . id ( ( d : any ) => d . id ) . distance ( 250 ) . strength ( 0.4 ) )
483- . force ( 'charge' , d3 . forceManyBody ( ) . strength ( - 800 ) . distanceMin ( 100 ) . distanceMax ( 1000 ) )
484- . force ( 'center ' , d3 . forceCenter ( width / 2 , height / 2 ) . strength ( 0.02 ) )
485- . force ( 'collision' , d3 . forceCollide ( ) . radius ( ( d : any ) => {
486- const maxTextLength = Math . max ( d . displayName . length , d . ip . length , 12 )
467+ . force ( 'link' , d3 . forceLink ( filteredData . links ) . id ( ( d : d3 . SimulationNodeDatum ) => ( d as NetworkNode ) . id ) . distance ( 200 ) . strength ( 0.5 ) )
468+ . force ( 'charge' , d3 . forceManyBody ( ) . strength ( - 800 ) . distanceMin ( 120 ) . distanceMax ( 600 ) )
469+ . force ( 'collision ' , d3 . forceCollide ( ) . radius ( ( d : d3 . SimulationNodeDatum ) => {
470+ const node = d as NetworkNode
471+ const maxTextLength = Math . max ( node . displayName . length , node . ip . length , 12 )
487472 const nodeWidth = Math . max ( 120 , Math . min ( maxTextLength * 8 + 20 , 200 ) )
488- return nodeWidth / 2 + 25 // More padding for better separation
473+ return nodeWidth / 2 + 35 // Good spacing for fan-out
489474 } ) . strength ( 1.0 ) . iterations ( 3 ) )
490- . force ( 'categoryX' , d3 . forceX ( ) . x ( ( d : any ) => {
491- const primaryTag = d . tags . find ( ( tag : string ) => ! tag . includes ( '+' ) ) || 'unknown'
492- return categoryPositions [ primaryTag ] ?. x || width / 2
493- } ) . strength ( 0.1 ) )
494- . force ( 'categoryY' , d3 . forceY ( ) . y ( ( d : any ) => {
495- const primaryTag = d . tags . find ( ( tag : string ) => ! tag . includes ( '+' ) ) || 'unknown'
496- return categoryPositions [ primaryTag ] ?. y || height / 2
497- } ) . strength ( 0.1 ) )
498- . alphaDecay ( 0.003 )
499- . velocityDecay ( 0.7 )
475+ . alphaDecay ( 0.01 ) // Quick settling
476+ . velocityDecay ( 0.85 ) // Moderate friction for natural movement
500477
501478 // Create links
502479 const link = g . append ( 'g' )
@@ -601,12 +578,14 @@ const NetworkView: React.FC = () => {
601578 . attr ( 'x' , ( d : NetworkNode ) => - getBoxDimensions ( d ) . width / 2 )
602579 . attr ( 'y' , ( d : NetworkNode ) => - getBoxDimensions ( d ) . height / 2 )
603580 . attr ( 'fill' , ( d : NetworkNode ) => {
581+ if ( d . tags . includes ( 'derp' ) ) return '#fecaca'
604582 if ( d . tags . includes ( 'tailscale' ) ) return '#dbeafe'
605583 if ( d . tags . includes ( 'private' ) ) return '#dcfce7'
606584 if ( d . tags . includes ( 'ipv6' ) ) return '#e9d5ff'
607585 return '#fef3c7'
608586 } )
609587 . attr ( 'stroke' , ( d : NetworkNode ) => {
588+ if ( d . tags . includes ( 'derp' ) ) return '#dc2626'
610589 if ( d . tags . includes ( 'tailscale' ) ) return '#3b82f6'
611590 if ( d . tags . includes ( 'private' ) ) return '#10b981'
612591 if ( d . tags . includes ( 'ipv6' ) ) return '#8b5cf6'
@@ -667,20 +646,20 @@ const NetworkView: React.FC = () => {
667646 connectedNodeIds . add ( d . id )
668647
669648 // Hide/show nodes
670- node . style ( 'opacity' , ( n : any ) => {
649+ node . style ( 'opacity' , ( n : NetworkNode ) => {
671650 return connectedNodeIds . has ( n . id ) ? 1 : 0.1
672651 } )
673652
674653 // Hide/show links
675- link . style ( 'opacity' , ( l : any ) => {
654+ link . style ( 'opacity' , ( l : NetworkLink ) => {
676655 const sourceId = typeof l . source === 'string' ? l . source : l . source . id
677656 const targetId = typeof l . target === 'string' ? l . target : l . target . id
678657 return sourceId === d . id || targetId === d . id ? 0.9 : 0.05
679658 } )
680659
681660 // Highlight selected node
682661 node . selectAll ( 'rect' )
683- . attr ( 'stroke-width' , ( n : any ) => n . id === d . id ? 4 : 2 )
662+ . attr ( 'stroke-width' , ( n : unknown ) => ( n as NetworkNode ) . id === d . id ? 4 : 2 )
684663 } )
685664
686665 // Handle link clicks with improved hiding
@@ -767,13 +746,13 @@ const NetworkView: React.FC = () => {
767746 setSearchQuery ( '' )
768747
769748 // Reset time range to default
770- setTimeRangeFilter ( '1h ' )
749+ setTimeRangeFilter ( '5m ' )
771750 setUseCustomTimeRange ( false )
772751
773752 // Reset all filter sets to include all options
774753 if ( uniqueProtocols . length > 0 ) setProtocolFilters ( new Set ( uniqueProtocols ) )
775754 if ( uniqueTrafficTypes . length > 0 ) setTrafficTypeFilters ( new Set ( uniqueTrafficTypes ) )
776- if ( uniqueIpCategories . length > 0 ) setIpCategoryFilters ( new Set ( uniqueIpCategories . filter ( cat => cat !== 'ipv6' ) ) )
755+ if ( uniqueIpCategories . length > 0 ) setIpCategoryFilters ( new Set ( uniqueIpCategories . filter ( cat => cat !== 'ipv6' && cat !== 'derp' ) ) ) // Keep derp hidden on reset
777756
778757 // Reset other filters
779758 setIpVersionFilter ( 'all' )
@@ -849,7 +828,7 @@ const NetworkView: React.FC = () => {
849828 // Get unique values for filters with common defaults
850829 const baseProtocols = [ 'TCP' , 'UDP' , 'ICMP' , 'Proto-255' , 'Proto-0' ] // Added Proto-0 to base protocols
851830 const baseTrafficTypes = [ 'virtual' , 'subnet' , 'physical' ] // All possible traffic types
852- const baseIpCategories = [ 'tailscale' , 'private' , 'public' ] // Common IP categories
831+ const baseIpCategories = [ 'tailscale' , 'private' , 'public' , 'derp' ] // Common IP categories
853832
854833 const dataProtocols = Array . from ( new Set ( links . map ( l => l . protocol ) ) )
855834 const dataTrafficTypes = Array . from ( new Set ( links . map ( l => l . trafficType ) ) )
@@ -866,7 +845,7 @@ const NetworkView: React.FC = () => {
866845 if ( ! filtersInitialized && uniqueProtocols . length > 0 && uniqueTrafficTypes . length > 0 && uniqueIpCategories . length > 0 ) {
867846 setProtocolFilters ( new Set ( uniqueProtocols ) )
868847 setTrafficTypeFilters ( new Set ( uniqueTrafficTypes ) )
869- setIpCategoryFilters ( new Set ( uniqueIpCategories . filter ( cat => cat !== 'ipv6' ) ) )
848+ setIpCategoryFilters ( new Set ( uniqueIpCategories . filter ( cat => cat !== 'ipv6' && cat !== 'derp' ) ) ) // Hide derp by default
870849 setFiltersInitialized ( true )
871850 }
872851 } , [ uniqueProtocols , uniqueTrafficTypes , uniqueIpCategories , filtersInitialized ] )
@@ -1412,6 +1391,10 @@ const NetworkView: React.FC = () => {
14121391 < div className = "w-3 h-3 border-2 border-yellow-500 bg-yellow-100 dark:bg-yellow-900 mr-2" > </ div >
14131392 < span > Public Internet</ span >
14141393 </ div >
1394+ < div className = "flex items-center" >
1395+ < div className = "w-3 h-3 border-2 border-red-600 bg-red-100 dark:bg-red-900 mr-2" > </ div >
1396+ < span > DERP Servers</ span >
1397+ </ div >
14151398 </ div >
14161399
14171400 < div className = "mt-4" >
0 commit comments