Show AS descriptions in AS path on prefix detail page
- Display AS descriptions alongside AS numbers in format: Description (ASN) - Truncate descriptions longer than 20 characters with ellipsis - Increase container max width to 1600px for better display - Enable word wrapping for AS path cells to handle long paths - Update mobile responsive styles for AS path display
This commit is contained in:
parent
a78e5c6e92
commit
dc3ceb8d94
@ -15,10 +15,16 @@ import (
|
||||
|
||||
"git.eeqj.de/sneak/routewatch/internal/database"
|
||||
"git.eeqj.de/sneak/routewatch/internal/templates"
|
||||
"git.eeqj.de/sneak/routewatch/pkg/asinfo"
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxASDescriptionLength is the maximum length for AS descriptions in the UI
|
||||
maxASDescriptionLength = 20
|
||||
)
|
||||
|
||||
// handleRoot returns a handler that redirects to /status
|
||||
func (s *Server) handleRoot() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
@ -645,12 +651,45 @@ func (s *Server) handlePrefixDetail() http.HandlerFunc {
|
||||
origins = append(origins, origin)
|
||||
}
|
||||
|
||||
// Create enhanced routes with AS path descriptions
|
||||
type ASPathEntry struct {
|
||||
Number int
|
||||
Description string
|
||||
}
|
||||
type EnhancedRoute struct {
|
||||
database.LiveRoute
|
||||
ASPathWithDesc []ASPathEntry
|
||||
}
|
||||
|
||||
enhancedRoutes := make([]EnhancedRoute, len(routes))
|
||||
for i, route := range routes {
|
||||
enhancedRoute := EnhancedRoute{
|
||||
LiveRoute: route,
|
||||
ASPathWithDesc: make([]ASPathEntry, len(route.ASPath)),
|
||||
}
|
||||
|
||||
// Look up description for each AS in the path
|
||||
for j, asn := range route.ASPath {
|
||||
desc := asinfo.GetDescription(asn)
|
||||
// Truncate description if longer than maxASDescriptionLength characters
|
||||
if len(desc) > maxASDescriptionLength {
|
||||
desc = desc[:maxASDescriptionLength] + "..."
|
||||
}
|
||||
enhancedRoute.ASPathWithDesc[j] = ASPathEntry{
|
||||
Number: asn,
|
||||
Description: desc,
|
||||
}
|
||||
}
|
||||
|
||||
enhancedRoutes[i] = enhancedRoute
|
||||
}
|
||||
|
||||
// Prepare template data
|
||||
data := struct {
|
||||
Prefix string
|
||||
MaskLength int
|
||||
IPVersion int
|
||||
Routes []database.LiveRoute
|
||||
Routes []EnhancedRoute
|
||||
Origins []*ASNInfo
|
||||
PeerCount int
|
||||
OriginCount int
|
||||
@ -658,7 +697,7 @@ func (s *Server) handlePrefixDetail() http.HandlerFunc {
|
||||
Prefix: prefix,
|
||||
MaskLength: maskLength,
|
||||
IPVersion: ipVersion,
|
||||
Routes: routes,
|
||||
Routes: enhancedRoutes,
|
||||
Origins: origins,
|
||||
PeerCount: len(routes),
|
||||
OriginCount: len(originMap),
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
@ -95,6 +96,9 @@ func (s *Streamer) RegisterHandler(handler MessageHandler) {
|
||||
info := &handlerInfo{
|
||||
handler: handler,
|
||||
queue: make(chan *ristypes.RISMessage, handler.QueueCapacity()),
|
||||
metrics: handlerMetrics{
|
||||
minTime: time.Duration(math.MaxInt64), // Initialize to max so first value sets the floor
|
||||
},
|
||||
}
|
||||
|
||||
s.handlers = append(s.handlers, info)
|
||||
@ -170,7 +174,7 @@ func (s *Streamer) runHandlerWorker(info *handlerInfo) {
|
||||
info.metrics.totalTime += elapsed
|
||||
|
||||
// Update min time
|
||||
if info.metrics.minTime == 0 || elapsed < info.metrics.minTime {
|
||||
if elapsed < info.metrics.minTime {
|
||||
info.metrics.minTime = elapsed
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,8 @@
|
||||
color: #333;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
width: 90%;
|
||||
max-width: 1600px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
@ -114,9 +115,10 @@
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
max-width: 300px;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
max-width: 600px;
|
||||
word-wrap: break-word;
|
||||
white-space: normal;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.age {
|
||||
color: #7f8c8d;
|
||||
@ -168,7 +170,7 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
.as-path {
|
||||
max-width: 150px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -234,7 +236,7 @@
|
||||
<a href="/as/{{.OriginASN}}" class="as-link">AS{{.OriginASN}}</a>
|
||||
</td>
|
||||
<td class="peer-ip">{{.PeerIP}}</td>
|
||||
<td class="as-path">{{range $i, $as := .ASPath}}{{if $i}} → {{end}}{{$as}}{{end}}</td>
|
||||
<td class="as-path">{{range $i, $as := .ASPathWithDesc}}{{if $i}} → {{end}}{{if $as.Description}}{{$as.Description}} ({{$as.Number}}){{else}}AS{{$as.Number}}{{end}}{{end}}</td>
|
||||
<td class="peer-ip">{{.NextHop}}</td>
|
||||
<td>{{.LastUpdated.Format "2006-01-02 15:04:05"}}</td>
|
||||
<td class="age">{{.LastUpdated | timeSince}}</td>
|
||||
|
Loading…
Reference in New Issue
Block a user