@page "/admin/audit" @attribute [Microsoft.AspNetCore.Authorization.Authorize] @inject IAuditService AuditService @inject IUserContextAccessor UserContext @inject NavigationManager Nav @rendermode InteractiveServer @using SharepointToolbox.Web.Core.Models @using SharepointToolbox.Web.Services.Audit @using SharepointToolbox.Web.Services.Session

Audit Logs

All technician and admin actions within the application.

@if (!UserContext.IsAuthenticated || UserContext.Role != UserRole.Admin) {
Access denied. Admin role required.
return; }
Export CSV
@if (_loading) {
Loading audit log...
} else if (_filtered.Count == 0) {
No audit entries found.
} else {
@foreach (var e in _filtered) { }
Timestamp User Role Action Client Sites Details
@e.Timestamp.ToString("yyyy-MM-dd HH:mm:ss") @e.UserDisplay
@e.UserEmail
@e.UserRole @e.Action @e.ClientName @string.Join(", ", e.Sites) @e.Details

Showing @_filtered.Count of @_entries.Count entries

} @code { private List _entries = new(); private List _filtered = new(); private bool _loading = true; private string _filterUser = string.Empty; private string _filterClient = string.Empty; private string _filterAction = string.Empty; protected override async Task OnInitializedAsync() { _entries = (await AuditService.GetAllAsync()) .OrderByDescending(e => e.Timestamp) .ToList(); _loading = false; ApplyFilters(); } private void ApplyFilters() { _filtered = _entries.Where(e => (string.IsNullOrEmpty(_filterUser) || e.UserEmail.Contains(_filterUser, StringComparison.OrdinalIgnoreCase) || e.UserDisplay.Contains(_filterUser, StringComparison.OrdinalIgnoreCase)) && (string.IsNullOrEmpty(_filterClient) || e.ClientName.Contains(_filterClient, StringComparison.OrdinalIgnoreCase)) && (string.IsNullOrEmpty(_filterAction) || e.Action.Contains(_filterAction, StringComparison.OrdinalIgnoreCase)) ).ToList(); } private static string RoleChipClass(UserRole role) => role switch { UserRole.Admin => "chip-red", UserRole.TechN1 => "chip-green", _ => "chip-blue" }; }