diff --git a/crowdsec-dashy b/crowdsec-dashy index 7e12264..8b22d91 100755 Binary files a/crowdsec-dashy and b/crowdsec-dashy differ diff --git a/internal/crowdsec/cli.go b/internal/crowdsec/cli.go index ace4444..95d0405 100644 --- a/internal/crowdsec/cli.go +++ b/internal/crowdsec/cli.go @@ -28,18 +28,24 @@ func NewCLIClient(cscliPath string) *CLIClient { // ----------------------------------------------------------------------- // ListDecisions returns decisions via cscli, applying filter options. -// cscli does not support offset, so pagination is handled in Go by fetching -// enough rows and slicing. Maximum fetch = page * limit + 1. +// cscli decisions list -o json returns alert objects with nested decisions — +// not a flat decision list. We extract and flatten the nested decisions. +// cscli does not support offset, so pagination is Go-side. func (c *CLIClient) ListDecisions(ctx context.Context, f DecisionFilter) ([]Decision, error) { + // Fetch enough alerts to cover offset+limit decisions. + // Since --limit is per-alert and each alert typically has one decision, + // multiply by a small factor; minimum fetch covers the full page range. fetchLimit := f.Limit if f.Offset > 0 { fetchLimit = f.Offset + f.Limit } + // Always fetch at least 500 so small offsets don't under-fetch. + if fetchLimit < 500 { + fetchLimit = 500 + } args := []string{"decisions", "list", "-o", "json"} - if fetchLimit > 0 { - args = append(args, "--limit", fmt.Sprintf("%d", fetchLimit)) - } + args = append(args, "--limit", fmt.Sprintf("%d", fetchLimit)) if f.Type != "" && safeArg.MatchString(f.Type) { args = append(args, "--type", f.Type) } @@ -63,12 +69,19 @@ func (c *CLIClient) ListDecisions(ctx context.Context, f DecisionFilter) ([]Deci return []Decision{}, nil } - var decisions []Decision - if err := json.Unmarshal(out, &decisions); err != nil { + // cscli decisions list -o json returns alert objects, each containing + // a "decisions" array. Extract and flatten those nested decisions. + var alerts []Alert + if err := json.Unmarshal(out, &alerts); err != nil { return nil, fmt.Errorf("parse decisions: %w\noutput: %s", err, string(out)) } - // apply Go-side offset slice + var decisions []Decision + for _, a := range alerts { + decisions = append(decisions, a.Decisions...) + } + + // Apply Go-side offset slice. if f.Offset > 0 { if f.Offset >= len(decisions) { return []Decision{}, nil diff --git a/web/static/css/app.css b/web/static/css/app.css index 0525fad..d127bde 100644 --- a/web/static/css/app.css +++ b/web/static/css/app.css @@ -287,19 +287,23 @@ body { background: var(--s-800); border: 1px solid var(--border); border-radius: 10px; - padding: 18px 20px; + padding: 12px 16px; border-top: 2px solid transparent; - transition: border-color 0.2s; + transition: border-color 0.2s, background 0.15s; + display: block; + text-decoration: none; + color: inherit; } +a.stat-card:hover { background: var(--s-700); cursor: pointer; } .stat-card--threat { border-top-color: var(--threat); } .stat-card--warn { border-top-color: var(--warn); } .stat-card--accent { border-top-color: var(--accent); } .stat-card--safe { border-top-color: var(--safe); } -.stat-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 6px; } -.stat-value { font-family: 'JetBrains Mono', monospace; font-size: 32px; font-weight: 600; line-height: 1; color: #e6edf3; margin-bottom: 4px; } -.stat-sub { font-size: 11px; color: var(--muted); } +.stat-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 4px; } +.stat-value { font-family: 'JetBrains Mono', monospace; font-size: 26px; font-weight: 600; line-height: 1; color: #e6edf3; margin-bottom: 2px; } +.stat-sub { font-size: 10px; color: var(--muted); } /* --------------------------------------------------------------- Panels diff --git a/web/templates/pages/dashboard.html b/web/templates/pages/dashboard.html index 9b45942..35c99c8 100644 --- a/web/templates/pages/dashboard.html +++ b/web/templates/pages/dashboard.html @@ -2,32 +2,32 @@ {{define "content"}}
-
-
@@ -53,7 +53,7 @@ {{.Value}} {{.Type}} {{.Origin}} - {{truncate .Until 16}} + {{if .Until}}{{truncate .Until 16}}{{else}}{{.Duration}}{{end}} {{end}} diff --git a/web/templates/pages/decisions.html b/web/templates/pages/decisions.html index bd78dc8..24af3b1 100644 --- a/web/templates/pages/decisions.html +++ b/web/templates/pages/decisions.html @@ -117,7 +117,7 @@ {{.Origin}} {{truncate .Scenario 24}} {{.Duration}} - {{truncate .Until 16}} + {{if .Until}}{{truncate .Until 16}}{{else}}{{.Duration}}{{end}}