From ba6929629dfd95843649a0d069ffd6a86ada7764 Mon Sep 17 00:00:00 2001 From: Haelnorr Date: Wed, 11 Feb 2026 22:18:02 +1100 Subject: [PATCH] added pagination to audit logs --- internal/db/auditlog.go | 14 ++-- internal/db/getlist.go | 38 +++++++++-- internal/embedfs/web/css/output.css | 66 ------------------- .../view/adminview/audit_log_detail.templ | 2 +- internal/view/adminview/audit_logs_list.templ | 12 ++-- 5 files changed, 47 insertions(+), 85 deletions(-) diff --git a/internal/db/auditlog.go b/internal/db/auditlog.go index b2bd307..2a702d5 100644 --- a/internal/db/auditlog.go +++ b/internal/db/auditlog.go @@ -50,31 +50,31 @@ func NewAuditLogFilter() *AuditLogFilter { } func (a *AuditLogFilter) UserID(id int) *AuditLogFilter { - a.Add("al.user_id", "=", id) + a.Equals("al.user_id", id) return a } func (a *AuditLogFilter) Action(action string) *AuditLogFilter { - a.Add("al.action", "=", action) + a.Equals("al.action", action) return a } func (a *AuditLogFilter) ResourceType(resourceType string) *AuditLogFilter { - a.Add("al.resource_type", "=", resourceType) + a.Equals("al.resource_type", resourceType) return a } func (a *AuditLogFilter) Result(result string) *AuditLogFilter { - a.Add("al.result", "=", result) + a.Equals("al.result", result) return a } func (a *AuditLogFilter) DateRange(start, end int64) *AuditLogFilter { if start > 0 { - a.Add("al.created_at", ">=", start) + a.GreaterEqualThan("al.created_at", start) } if end > 0 { - a.Add("al.created_at", "<=", end) + a.LessEqualThan("al.created_at", end) } return a } @@ -83,7 +83,7 @@ func (a *AuditLogFilter) DateRange(start, end int64) *AuditLogFilter { func GetAuditLogs(ctx context.Context, tx bun.Tx, pageOpts *PageOpts, filters *AuditLogFilter) (*List[AuditLog], error) { defaultPageOpts := &PageOpts{ Page: 1, - PerPage: 50, + PerPage: 15, Order: bun.OrderDesc, OrderBy: "created_at", } diff --git a/internal/db/getlist.go b/internal/db/getlist.go index c583c4e..1768fde 100644 --- a/internal/db/getlist.go +++ b/internal/db/getlist.go @@ -20,11 +20,21 @@ type List[T any] struct { } type Filter struct { - Field string - Value any - Operator string + Field string + Value any + Comparator Comparator } +type Comparator string + +const ( + Equal Comparator = "=" + Less Comparator = "<" + LessEqual Comparator = "<=" + Greater Comparator = ">" + GreaterEqual Comparator = ">=" +) + type ListFilter struct { filters []Filter } @@ -33,8 +43,24 @@ func NewListFilter() *ListFilter { return &ListFilter{[]Filter{}} } -func (f *ListFilter) Add(field, operator string, value any) { - f.filters = append(f.filters, Filter{field, value, "="}) +func (f *ListFilter) Equals(field string, value any) { + f.filters = append(f.filters, Filter{field, value, Equal}) +} + +func (f *ListFilter) LessThan(field string, value any) { + f.filters = append(f.filters, Filter{field, value, Less}) +} + +func (f *ListFilter) LessEqualThan(field string, value any) { + f.filters = append(f.filters, Filter{field, value, LessEqual}) +} + +func (f *ListFilter) GreaterThan(field string, value any) { + f.filters = append(f.filters, Filter{field, value, Greater}) +} + +func (f *ListFilter) GreaterEqualThan(field string, value any) { + f.filters = append(f.filters, Filter{field, value, GreaterEqual}) } func GetList[T any](tx bun.Tx) *listgetter[T] { @@ -63,7 +89,7 @@ func (l *listgetter[T]) Relation(name string, apply ...func(*bun.SelectQuery) *b func (l *listgetter[T]) Filter(filters ...Filter) *listgetter[T] { for _, filter := range filters { - l.q = l.q.Where("? ? ?", bun.Ident(filter.Field), bun.Safe(filter.Operator), filter.Value) + l.q = l.q.Where("? ? ?", bun.Ident(filter.Field), bun.Safe(filter.Comparator), filter.Value) } return l } diff --git a/internal/embedfs/web/css/output.css b/internal/embedfs/web/css/output.css index 205716f..ea2cd13 100644 --- a/internal/embedfs/web/css/output.css +++ b/internal/embedfs/web/css/output.css @@ -45,7 +45,6 @@ --radius-xl: 0.75rem; --ease-in: cubic-bezier(0.4, 0, 1, 1); --ease-out: cubic-bezier(0, 0, 0.2, 1); - --blur-sm: 8px; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); @@ -1031,11 +1030,6 @@ .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } - .backdrop-blur-sm { - --tw-backdrop-blur: blur(var(--blur-sm)); - -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - } .transition { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); @@ -1170,16 +1164,6 @@ } } } - .hover\:bg-red\/80 { - &:hover { - @media (hover: hover) { - background-color: var(--red); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--red) 80%, transparent); - } - } - } - } .hover\:bg-sapphire\/75 { &:hover { @media (hover: hover) { @@ -1283,11 +1267,6 @@ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } } - .focus\:ring-blue { - &:focus { - --tw-ring-color: var(--blue); - } - } .focus\:ring-mauve { &:focus { --tw-ring-color: var(--mauve); @@ -1897,42 +1876,6 @@ syntax: "*"; inherits: false; } -@property --tw-backdrop-blur { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-brightness { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-contrast { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-grayscale { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-hue-rotate { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-invert { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-opacity { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-saturate { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-sepia { - syntax: "*"; - inherits: false; -} @property --tw-duration { syntax: "*"; inherits: false; @@ -1988,15 +1931,6 @@ --tw-drop-shadow-color: initial; --tw-drop-shadow-alpha: 100%; --tw-drop-shadow-size: initial; - --tw-backdrop-blur: initial; - --tw-backdrop-brightness: initial; - --tw-backdrop-contrast: initial; - --tw-backdrop-grayscale: initial; - --tw-backdrop-hue-rotate: initial; - --tw-backdrop-invert: initial; - --tw-backdrop-opacity: initial; - --tw-backdrop-saturate: initial; - --tw-backdrop-sepia: initial; --tw-duration: initial; --tw-ease: initial; } diff --git a/internal/view/adminview/audit_log_detail.templ b/internal/view/adminview/audit_log_detail.templ index de6aceb..49525fe 100644 --- a/internal/view/adminview/audit_log_detail.templ +++ b/internal/view/adminview/audit_log_detail.templ @@ -144,7 +144,7 @@ func formatJSON(raw []byte) string { return "No details available" } // Pretty print the JSON - var obj interface{} + var obj any if err := json.Unmarshal(raw, &obj); err != nil { return string(raw) } diff --git a/internal/view/adminview/audit_logs_list.templ b/internal/view/adminview/audit_logs_list.templ index 45d6c1c..be257ef 100644 --- a/internal/view/adminview/audit_logs_list.templ +++ b/internal/view/adminview/audit_logs_list.templ @@ -184,11 +184,12 @@ templ AuditLogsResults(logs *db.List[db.AuditLog]) { } }} if totalPages > 1 { -
+
if logs.PageOpts.Page > 1 {