Skip to content

Commit 72abaf5

Browse files
committed
feat(target-allocator): Improve web UI with modern design and interactivity
Replaces the basic HTML UI with a modern, responsive interface that includes: - Dashboard with stat cards showing scrape configs, jobs, targets, and collectors - Interactive search and table sorting - Auto-refresh toggle for live updates - Keyboard shortcuts (/, r, a, h, ?) - Bar chart visualization of target distribution across collectors - Responsive design with mobile support The UI uses vanilla JavaScript and embedded CSS/JS files - no external dependencies. Static assets are served via /static and embedded in the binary using Go's embed.FS. Also adds a complete production-ready example setup in examples/target-allocator-setup/ with RBAC, collector configuration, and sample applications.
1 parent aa012eb commit 72abaf5

33 files changed

+4278
-1070
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ ci: generate fmt vet test ensure-update-is-noop
179179
.PHONY: update
180180
update: generate manifests bundle api-docs reset
181181

182+
.PHONY: update-golden-files
183+
update-golden-files:
184+
CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(ARCH) ./scripts/update-golden-files.sh
185+
182186
# Build manager binary
183187
.PHONY: manager
184188
manager: generate

cmd/otel-allocator/internal/server/server.go

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"crypto/tls"
99
"fmt"
10+
"io/fs"
1011
"net/http"
1112
"net/http/pprof"
1213
"net/url"
@@ -81,6 +82,14 @@ func (s *Server) setRouter(router *gin.Engine) {
8182
router.UnescapePathValues = false
8283
router.Use(s.PrometheusMiddleware)
8384

85+
// Serve static files - need to create a sub-filesystem to strip the "static/" prefix
86+
staticFS, err := fs.Sub(StaticFiles, "static")
87+
if err != nil {
88+
s.logger.Error(err, "Failed to create static file sub-filesystem")
89+
} else {
90+
router.StaticFS("/static", http.FS(staticFS))
91+
}
92+
8493
router.GET("/", s.IndexHandler)
8594
router.GET("/debug/collector", s.CollectorHTMLHandler)
8695
router.GET("/debug/job", s.JobHTMLHandler)
@@ -294,35 +303,34 @@ func (s *Server) PrometheusMiddleware(c *gin.Context) {
294303
func (s *Server) IndexHandler(c *gin.Context) {
295304
c.Writer.Header().Set("Content-Type", "text/html")
296305
WriteHTMLPageHeader(c.Writer, HeaderData{
297-
Title: "OpenTelemetry Target Allocator",
306+
Title: "Dashboard",
298307
})
299308

300-
WriteHTMLPropertiesTable(c.Writer, PropertiesTableData{
301-
Headers: []string{"Category", "Count"},
302-
Rows: [][]Cell{
303-
{scrapeConfigAnchorLink(), Text(strconv.Itoa(s.getScrapeConfigCount()))},
304-
{jobsAnchorLink(), Text(strconv.Itoa(s.getJobCount()))},
305-
{targetsAnchorLink(), Text(strconv.Itoa(len(s.allocator.TargetItems())))},
306-
},
307-
})
308-
WriteHTMLPropertiesTable(c.Writer, PropertiesTableData{
309-
Headers: []string{"Collector", "Job Count", "Target Count"},
310-
Rows: func() [][]Cell {
311-
var rows [][]Cell
312-
collectorNames := []string{}
313-
for k := range s.allocator.Collectors() {
314-
collectorNames = append(collectorNames, k)
315-
}
316-
sort.Strings(collectorNames)
309+
// Prepare collector data
310+
collectorNames := []string{}
311+
for k := range s.allocator.Collectors() {
312+
collectorNames = append(collectorNames, k)
313+
}
314+
sort.Strings(collectorNames)
317315

318-
for _, colName := range collectorNames {
319-
jobCount := strconv.Itoa(s.getJobCountForCollector(colName))
320-
targetCount := strconv.Itoa(s.getTargetCountForCollector(colName))
321-
rows = append(rows, []Cell{collectorAnchorLink(colName), NewCell(jobCount), NewCell(targetCount)})
322-
}
323-
return rows
324-
}(),
316+
collectorData := []CollectorInfo{}
317+
for _, colName := range collectorNames {
318+
collectorData = append(collectorData, CollectorInfo{
319+
Name: colName,
320+
JobCount: s.getJobCountForCollector(colName),
321+
TargetCount: s.getTargetCountForCollector(colName),
322+
})
323+
}
324+
325+
// Write dashboard
326+
WriteHTMLDashboard(c.Writer, DashboardData{
327+
ScrapeConfigCount: s.getScrapeConfigCount(),
328+
JobCount: s.getJobCount(),
329+
TargetCount: len(s.allocator.TargetItems()),
330+
CollectorCount: len(s.allocator.Collectors()),
331+
CollectorData: collectorData,
325332
})
333+
326334
WriteHTMLPageFooter(c.Writer)
327335
}
328336

0 commit comments

Comments
 (0)