2

Refine the dashboard and requests log UX

This commit is contained in:
2026-03-12 17:40:13 +01:00
parent 0a14dd1df9
commit 0dfa30973e
8 changed files with 423 additions and 180 deletions

View File

@@ -236,6 +236,16 @@ func knownBotExistsClause(ipExpression string) string {
)`
}
func anyBotExistsClause(ipExpression string) string {
return `EXISTS (
SELECT 1
FROM ip_investigations i
WHERE i.ip = ` + ipExpression + `
AND json_valid(i.payload_json)
AND json_type(i.payload_json, '$.bot') IS NOT NULL
)`
}
func overviewFilterQueryParts(options model.OverviewOptions) (joins []string, clauses []string) {
if !options.ShowAllowed {
joins = append(joins, `LEFT JOIN ip_state s ON s.ip = e.client_ip`)
@@ -443,11 +453,27 @@ func (s *Store) GetOverview(ctx context.Context, since time.Time, limit int, opt
if err != nil {
return model.Overview{}, err
}
topIPsByEvents, err := s.listTopIPRows(ctx, since, limit, "events", options)
topIPsByEvents, err := s.listTopIPRows(ctx, since, limit, "events", options, "all")
if err != nil {
return model.Overview{}, err
}
topIPsByTraffic, err := s.listTopIPRows(ctx, since, limit, "traffic", options)
topBotIPsByEvents, err := s.listTopIPRows(ctx, since, limit, "events", options, "bots")
if err != nil {
return model.Overview{}, err
}
topNonBotIPsByEvents, err := s.listTopIPRows(ctx, since, limit, "events", options, "non-bots")
if err != nil {
return model.Overview{}, err
}
topIPsByTraffic, err := s.listTopIPRows(ctx, since, limit, "traffic", options, "all")
if err != nil {
return model.Overview{}, err
}
topBotIPsByTraffic, err := s.listTopIPRows(ctx, since, limit, "traffic", options, "bots")
if err != nil {
return model.Overview{}, err
}
topNonBotIPsByTraffic, err := s.listTopIPRows(ctx, since, limit, "traffic", options, "non-bots")
if err != nil {
return model.Overview{}, err
}
@@ -477,17 +503,27 @@ func (s *Store) GetOverview(ctx context.Context, since time.Time, limit int, opt
overview.Methods = methods
overview.Bots = bots
overview.TopIPsByEvents = topIPsByEvents
overview.TopBotIPsByEvents = topBotIPsByEvents
overview.TopNonBotIPsByEvents = topNonBotIPsByEvents
overview.TopIPsByTraffic = topIPsByTraffic
overview.TopBotIPsByTraffic = topBotIPsByTraffic
overview.TopNonBotIPsByTraffic = topNonBotIPsByTraffic
overview.TopSources = topSources
overview.TopURLs = topURLs
return overview, nil
}
func (s *Store) listTopIPRows(ctx context.Context, since time.Time, limit int, orderBy string, options model.OverviewOptions) ([]model.TopIPRow, error) {
func (s *Store) listTopIPRows(ctx context.Context, since time.Time, limit int, orderBy string, options model.OverviewOptions, botScope string) ([]model.TopIPRow, error) {
if limit <= 0 {
limit = 10
}
joins, clauses := overviewFilterQueryParts(options)
switch botScope {
case "bots":
clauses = append(clauses, anyBotExistsClause(`e.client_ip`))
case "non-bots":
clauses = append(clauses, `NOT `+anyBotExistsClause(`e.client_ip`))
}
query := fmt.Sprintf(`
SELECT e.client_ip,
COUNT(*) AS event_count,
@@ -797,6 +833,9 @@ func (s *Store) ListEvents(ctx context.Context, since time.Time, limit int, opti
if limit <= 0 {
limit = 100
}
if options.Offset < 0 {
options.Offset = 0
}
joins, clauses := eventFilterQueryParts(options)
query := `
SELECT e.id, e.source_name, e.profile_name, e.occurred_at, e.remote_ip, e.client_ip, e.host,
@@ -815,8 +854,8 @@ func (s *Store) ListEvents(ctx context.Context, since time.Time, limit int, opti
if len(clauses) > 0 {
query += ` WHERE ` + strings.Join(clauses, ` AND `)
}
query += ` ORDER BY e.occurred_at DESC, e.id DESC LIMIT ?`
args = append(args, limit)
query += ` ORDER BY e.occurred_at DESC, e.id DESC LIMIT ? OFFSET ?`
args = append(args, limit, options.Offset)
rows, err := s.db.QueryContext(ctx, query, args...)
if err != nil {