2

Refine requests log filter controls

This commit is contained in:
2026-03-12 18:52:21 +01:00
parent fef2237c49
commit 6b9330529c
3 changed files with 80 additions and 16 deletions

View File

@@ -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)
}

View File

@@ -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 = `<!doctype html>
<form class="filters-grid" id="controls-form" onsubmit="applyFilters(event)">
<div class="field">
<label for="source-filter">Source</label>
<input id="source-filter" type="text" placeholder="gitea">
<select id="source-filter">
<option value="">Any source</option>
{{ range .Sources }}<option value="{{ . }}">{{ . }}</option>{{ end }}
</select>
</div>
<div class="field">
<label for="method-filter">Method</label>
<input id="method-filter" type="text" list="method-options" placeholder="GET">
<datalist id="method-options">
<option value="GET"></option>
<option value="POST"></option>
<option value="HEAD"></option>
<option value="PUT"></option>
<option value="DELETE"></option>
<option value="PATCH"></option>
<option value="OPTIONS"></option>
<option value="OTHER"></option>
</datalist>
<select id="method-filter">
<option value="">Any method</option>
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="HEAD">HEAD</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
<option value="PATCH">PATCH</option>
<option value="OPTIONS">OPTIONS</option>
<option value="OTHER">OTHER</option>
</select>
</div>
<div class="field">
<label for="status-filter">HTTP status</label>
<input id="status-filter" type="text" placeholder="404 or 4xx">
<select id="status-filter">
<option value="">Any status</option>
<optgroup label="Status classes">
<option value="2xx">2xx</option>
<option value="3xx">3xx</option>
<option value="4xx">4xx</option>
<option value="5xx">5xx</option>
</optgroup>
<optgroup label="Common client errors">
<option value="400">400</option>
<option value="401">401</option>
<option value="403">403</option>
<option value="404">404</option>
<option value="405">405</option>
<option value="408">408</option>
<option value="410">410</option>
<option value="429">429</option>
</optgroup>
<optgroup label="Common server errors">
<option value="500">500</option>
<option value="502">502</option>
<option value="503">503</option>
<option value="504">504</option>
</optgroup>
</select>
</div>
<div class="field">
<label for="state-filter">State</label>

View File

@@ -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, `<select id="source-filter">`) || !strings.Contains(queryLogBody, `<option value="main">main</option>`) {
t.Fatalf("requests log page should expose a source dropdown with configured sources")
}
if !strings.Contains(queryLogBody, `<select id="method-filter">`) || !strings.Contains(queryLogBody, `<option value="POST">POST</option>`) {
t.Fatalf("requests log page should expose a method dropdown")
}
if !strings.Contains(queryLogBody, `<select id="status-filter">`) || !strings.Contains(queryLogBody, `<option value="4xx">4xx</option>`) {
t.Fatalf("requests log page should expose a structured HTTP status dropdown")
}
if !strings.Contains(queryLogBody, "Rows per page") {
t.Fatalf("requests log page should expose pagination settings")
}
@@ -224,6 +233,10 @@ type stubApp struct {
lastEventOptions model.EventListOptions
}
func (s *stubApp) ListSourceNames() []string {
return []string{"gitea", "main"}
}
func (s *stubApp) GetOverview(_ context.Context, _ time.Time, _ int, options model.OverviewOptions) (model.Overview, error) {
s.lastOverviewOptions = options
now := time.Now().UTC()