package adminview import ( "fmt" "git.haelnorr.com/h/oslstats/internal/db" "time" ) templ AuditLogsList(logs *db.List[db.AuditLog], users []*db.User, actions []string, resourceTypes []string) {

Audit Logs

@multiSelectDropdown("user_id", "Users", userOptions(users)) @multiSelectDropdown("action", "Actions", stringOptions(actions)) @multiSelectDropdown("resource_type", "Resource Types", stringOptions(resourceTypes)) @multiSelectDropdown("result", "Results", []selectOption{ {Value: "success", Label: "Success"}, {Value: "denied", Label: "Denied"}, {Value: "error", Label: "Error"}, })
@AuditLogsResults(logs)
} templ AuditLogsResults(logs *db.List[db.AuditLog]) {
if len(logs.Items) == 0 {

No audit logs found

} else {
@auditTableHeader("created_at", "Timestamp", logs.PageOpts.OrderBy, string(logs.PageOpts.Order)) @auditTableHeader("user_id", "User", logs.PageOpts.OrderBy, string(logs.PageOpts.Order)) @auditTableHeader("action", "Action", logs.PageOpts.OrderBy, string(logs.PageOpts.Order)) @auditTableHeader("resource_type", "Resource", logs.PageOpts.OrderBy, string(logs.PageOpts.Order)) @auditTableHeader("resource_id", "Resource ID", logs.PageOpts.OrderBy, string(logs.PageOpts.Order)) @auditTableHeader("result", "Result", logs.PageOpts.OrderBy, string(logs.PageOpts.Order)) for _, log := range logs.Items { }
Actions
{ formatFullTimestamp(log.CreatedAt) } if log.User != nil { { log.User.Username } } else { Unknown } { log.Action } { log.ResourceType } if log.ResourceID != nil { { *log.ResourceID } } else { } @resultBadge(log.Result)
if logs.Total > 0 { Showing { fmt.Sprintf("%d", logs.PageOpts.StartItem()) } - { fmt.Sprintf("%d", logs.PageOpts.EndItem(logs.Total)) } of { fmt.Sprintf("%d", logs.Total) } results } else { No results }
if logs.Total > 0 && logs.PageOpts.TotalPages(logs.Total) > 1 {
for _, pageNum := range logs.PageOpts.GetPageRange(logs.Total, 7) { }
}
}
} templ auditTableHeader(field string, label string, currentField string, currentOrder string) { {{ isActive := currentField == field baseClasses := "px-4 py-3 text-left text-sm font-semibold text-text cursor-pointer select-none hover:text-blue transition-colors" arrow := "" if isActive { if currentOrder == "ASC" { arrow = " ↑" } else { arrow = " ↓" } } }} { label } if arrow != "" { { arrow } } } type selectOption struct { Value string Label string } func userOptions(users []*db.User) []selectOption { opts := make([]selectOption, len(users)) for i, u := range users { opts[i] = selectOption{Value: fmt.Sprintf("%d", u.ID), Label: u.Username} } return opts } func stringOptions(strs []string) []selectOption { opts := make([]selectOption, len(strs)) for i, s := range strs { opts[i] = selectOption{Value: s, Label: s} } return opts } templ multiSelectDropdown(name string, label string, options []selectOption) { {{ containerId := name + "-container" }}
} templ resultBadge(result string) { {{ var classes string switch result { case "success": classes = "px-2 py-0.5 bg-green/20 text-green rounded text-xs font-medium" case "denied": classes = "px-2 py-0.5 bg-yellow/20 text-yellow rounded text-xs font-medium" case "error": classes = "px-2 py-0.5 bg-red/20 text-red rounded text-xs font-medium" default: classes = "px-2 py-0.5 bg-surface1 text-subtext0 rounded text-xs font-medium" } }} { result } } func formatFullTimestamp(unixTime int64) string { t := time.Unix(unixTime, 0) return t.Format("Jan 2, 2006 15:04:05") }