diff --git a/internal/service/service.go b/internal/service/service.go index 49460e2..88e2554 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -9,6 +9,7 @@ import ( "log" "net" "os" + "sort" "strings" "sync" "syscall" @@ -113,6 +114,27 @@ func (s *Service) ListEvents(ctx context.Context, since time.Time, limit int, op return items, nil } +func (s *Service) ListSourceNames() []string { + if s == nil || s.cfg == nil || len(s.cfg.Sources) == 0 { + return nil + } + seen := make(map[string]struct{}, len(s.cfg.Sources)) + items := make([]string, 0, len(s.cfg.Sources)) + for _, source := range s.cfg.Sources { + name := strings.TrimSpace(source.Name) + if name == "" { + continue + } + if _, ok := seen[name]; ok { + continue + } + seen[name] = struct{}{} + items = append(items, name) + } + sort.Strings(items) + return items +} + func (s *Service) ListIPs(ctx context.Context, limit int, state string) ([]model.IPState, error) { return s.store.ListIPStates(ctx, limit, state) } diff --git a/internal/web/handler.go b/internal/web/handler.go index 98a86af..8545293 100644 --- a/internal/web/handler.go +++ b/internal/web/handler.go @@ -19,6 +19,7 @@ import ( type App interface { GetOverview(ctx context.Context, since time.Time, limit int, options model.OverviewOptions) (model.Overview, error) ListEvents(ctx context.Context, since time.Time, limit int, options model.EventListOptions) ([]model.Event, error) + ListSourceNames() []string ListIPs(ctx context.Context, limit int, state string) ([]model.IPState, error) ListRecentIPs(ctx context.Context, since time.Time, limit int) ([]model.RecentIPRow, error) GetIPDetails(ctx context.Context, ip string) (model.IPDetails, error) @@ -36,8 +37,9 @@ type handler struct { } type pageData struct { - Title string - IP string + Title string + IP string + Sources []string } type actionPayload struct { @@ -92,7 +94,7 @@ func (h *handler) handleQueryLogPage(w http.ResponseWriter, r *http.Request) { methodNotAllowed(w) return } - renderTemplate(w, h.queryLogPage, pageData{Title: "Requests Log"}) + renderTemplate(w, h.queryLogPage, pageData{Title: "Requests Log", Sources: h.app.ListSourceNames()}) } func (h *handler) handleIPPage(w http.ResponseWriter, r *http.Request) { @@ -1020,25 +1022,52 @@ const queryLogHTML = `
- +
- - - - - - - - - - - +
- +
diff --git a/internal/web/handler_test.go b/internal/web/handler_test.go index 0b60b48..1f94e74 100644 --- a/internal/web/handler_test.go +++ b/internal/web/handler_test.go @@ -169,6 +169,15 @@ func TestHandlerServesOverviewAndManualActions(t *testing.T) { if !strings.Contains(queryLogBody, "Filters, sorting, and pagination") { t.Fatalf("requests log page should expose the collapsible controls panel") } + if !strings.Contains(queryLogBody, ``) || !strings.Contains(queryLogBody, ``) { + t.Fatalf("requests log page should expose a method dropdown") + } + if !strings.Contains(queryLogBody, `