diff --git a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/ActiveUsersCard.razor b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/ActiveUsersCard.razor index 53bfb37e5..b0dfe4968 100644 --- a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/ActiveUsersCard.razor +++ b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/ActiveUsersCard.razor @@ -1,11 +1,6 @@

Total active users

-
@if (IsLoading) { @@ -16,63 +11,31 @@

Last 24 hours

-

@UserStats.Last24Hours

- @if (ShowUserNames) - { -
-
    - @foreach (var user in UserStats.Last24HourUsers) - { -
  • @user
  • - } -
-
- } +
+

@UserStats.Last24Hours

+ (@UserStats.ReturningLast24Hours) +

Last 3 days

-

@UserStats.Last3Days

- @if (ShowUserNames) - { -
-
    - @foreach (var user in UserStats.Last3DayUsers) - { -
  • @user
  • - } -
-
- } +
+

@UserStats.Last3Days

+ (@UserStats.ReturningLast3Days) +

Last 7 days

-

@UserStats.Last7Days

- @if (ShowUserNames) - { -
-
    - @foreach (var user in UserStats.Last7DayUsers) - { -
  • @user
  • - } -
-
- } +
+

@UserStats.Last7Days

+ (@UserStats.ReturningLast7Days) +
-

Last 14 days

-

@UserStats.Last14Days

- @if (ShowUserNames) - { -
-
    - @foreach (var user in UserStats.Last14DayUsers) - { -
  • @user
  • - } -
-
- } +

Last 30 days

+
+

@UserStats.Last30Days

+ (@UserStats.ReturningLast30Days) +
} @@ -81,7 +44,6 @@ @code { private bool IsLoading { get; set; } = true; private UserStatistics UserStats { get; set; } = new(); - private bool ShowUserNames { get; set; } /// /// Refreshes the data displayed on the card. @@ -95,50 +57,56 @@ var last24Hours = now.AddHours(-24); var last3Days = now.AddDays(-3); var last7Days = now.AddDays(-7); - var last14Days = now.AddDays(-14); + var last30Days = now.AddDays(-30); // Get user statistics - var (count24h, users24h) = await GetActiveUserCount(last24Hours); - var (count3d, users3d) = await GetActiveUserCount(last3Days); - var (count7d, users7d) = await GetActiveUserCount(last7Days); - var (count14d, users14d) = await GetActiveUserCount(last14Days); + var (count24h, returning24h) = await GetActiveUserCount(last24Hours); + var (count3d, returning3d) = await GetActiveUserCount(last3Days); + var (count7d, returning7d) = await GetActiveUserCount(last7Days); + var (count30d, returning30d) = await GetActiveUserCount(last30Days); UserStats = new UserStatistics { Last24Hours = count24h, Last3Days = count3d, Last7Days = count7d, - Last14Days = count14d, - Last24HourUsers = users24h, - Last3DayUsers = users3d, - Last7DayUsers = users7d, - Last14DayUsers = users14d + Last30Days = count30d, + ReturningLast24Hours = returning24h, + ReturningLast3Days = returning3d, + ReturningLast7Days = returning7d, + ReturningLast30Days = returning30d, }; IsLoading = false; StateHasChanged(); } - private async Task<(int count, List users)> GetActiveUserCount(DateTime since) + private async Task<(int totalCount, int returningCount)> GetActiveUserCount(DateTime since) { - // Get unique users who: - // 1. Have successful auth logs - // 2. Are not the admin user await using var dbContext = await DbContextFactory.CreateDbContextAsync(); + // Get all active users for the period var activeUsers = await dbContext.AuthLogs .Where(l => l.Timestamp >= since && l.IsSuccess && l.Username != "admin") .Select(l => l.Username) .Distinct() .ToListAsync(); - return (activeUsers.Count, activeUsers); - } + // Get returning users (those who have activity at least 24h after registration + var returningUsers = await dbContext.AuthLogs + .Where(l => l.Timestamp >= since && l.IsSuccess && l.Username != "admin") + .Join( + dbContext.AliasVaultUsers, + log => log.Username, + user => user.UserName, + (log, user) => new { log, user } + ) + .Where(x => x.log.Timestamp >= x.user.CreatedAt.AddHours(24)) + .Select(x => x.log.Username) + .Distinct() + .ToListAsync(); - private void ToggleUserNames() - { - ShowUserNames = !ShowUserNames; - StateHasChanged(); + return (activeUsers.Count, returningUsers.Count); } private sealed class UserStatistics @@ -146,10 +114,10 @@ public int Last24Hours { get; set; } public int Last3Days { get; set; } public int Last7Days { get; set; } - public int Last14Days { get; set; } - public List Last24HourUsers { get; set; } = new(); - public List Last3DayUsers { get; set; } = new(); - public List Last7DayUsers { get; set; } = new(); - public List Last14DayUsers { get; set; } = new(); + public int Last30Days { get; set; } + public int ReturningLast24Hours { get; set; } + public int ReturningLast3Days { get; set; } + public int ReturningLast7Days { get; set; } + public int ReturningLast30Days { get; set; } } } diff --git a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailClaimsCard.razor b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailClaimsCard.razor index 2764776c0..57942b8fd 100644 --- a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailClaimsCard.razor +++ b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailClaimsCard.razor @@ -27,8 +27,8 @@

@EmailClaimsStats.Days7.ToString("N0")

-

Last 14 days

-

@EmailClaimsStats.Days14.ToString("N0")

+

Last 30 days

+

@EmailClaimsStats.Days30.ToString("N0")

} @@ -95,7 +95,7 @@ var hours24 = now.AddHours(-24); var days3 = now.AddDays(-3); var days7 = now.AddDays(-7); - var days14 = now.AddDays(-14); + var days30 = now.AddDays(-30); // Get email claims statistics await using var dbContext = await DbContextFactory.CreateDbContextAsync(); @@ -105,7 +105,7 @@ Hours24 = await emailClaimsQuery.CountAsync(e => e.CreatedAt >= hours24), Days3 = await emailClaimsQuery.CountAsync(e => e.CreatedAt >= days3), Days7 = await emailClaimsQuery.CountAsync(e => e.CreatedAt >= days7), - Days14 = await emailClaimsQuery.CountAsync(e => e.CreatedAt >= days14) + Days30 = await emailClaimsQuery.CountAsync(e => e.CreatedAt >= days30) }; } @@ -142,6 +142,7 @@ claimCount => claimCount.Date, (date, claimCounts) => claimCounts.FirstOrDefault() ?? new DailyEmailClaimCount { Date = date, Count = 0 } ) + .OrderByDescending(e => e.Date) .ToList(); } } @@ -166,7 +167,7 @@ public int Hours24 { get; set; } public int Days3 { get; set; } public int Days7 { get; set; } - public int Days14 { get; set; } + public int Days30 { get; set; } } private sealed class DailyEmailClaimCount diff --git a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailStatisticsCard.razor b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailStatisticsCard.razor index 66ad0c140..7ef5cfb56 100644 --- a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailStatisticsCard.razor +++ b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/EmailStatisticsCard.razor @@ -27,8 +27,8 @@

@EmailStats.Days7.ToString("N0")

-

Last 14 days

-

@EmailStats.Days14.ToString("N0")

+

Last 30 days

+

@EmailStats.Days30.ToString("N0")

} @@ -95,7 +95,7 @@ var hours24 = now.AddHours(-24); var days3 = now.AddDays(-3); var days7 = now.AddDays(-7); - var days14 = now.AddDays(-14); + var days30 = now.AddDays(-30); // Get email statistics await using var dbContext = await DbContextFactory.CreateDbContextAsync(); @@ -105,7 +105,7 @@ Hours24 = await emailQuery.CountAsync(e => e.DateSystem >= hours24), Days3 = await emailQuery.CountAsync(e => e.DateSystem >= days3), Days7 = await emailQuery.CountAsync(e => e.DateSystem >= days7), - Days14 = await emailQuery.CountAsync(e => e.DateSystem >= days14) + Days30 = await emailQuery.CountAsync(e => e.DateSystem >= days30) }; } @@ -142,6 +142,7 @@ emailCount => emailCount.Date, (date, emailCounts) => emailCounts.FirstOrDefault() ?? new DailyEmailCount { Date = date, Count = 0 } ) + .OrderByDescending(e => e.Date) .ToList(); } } @@ -166,7 +167,7 @@ public int Hours24 { get; set; } public int Days3 { get; set; } public int Days7 { get; set; } - public int Days14 { get; set; } + public int Days30 { get; set; } } private sealed class DailyEmailCount diff --git a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/RegistrationStatisticsCard.razor b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/RegistrationStatisticsCard.razor index 973c5fa92..651b863c7 100644 --- a/src/AliasVault.Admin/Main/Pages/Dashboard/Components/RegistrationStatisticsCard.razor +++ b/src/AliasVault.Admin/Main/Pages/Dashboard/Components/RegistrationStatisticsCard.razor @@ -22,8 +22,8 @@

@RegistrationStats.Days7.ToString("N0")

-

Last 14 days

-

@RegistrationStats.Days14.ToString("N0")

+

Last 30 days

+

@RegistrationStats.Days30.ToString("N0")

} @@ -45,7 +45,7 @@ var hours24 = now.AddHours(-24); var days3 = now.AddDays(-3); var days7 = now.AddDays(-7); - var days14 = now.AddDays(-14); + var days30 = now.AddDays(-30); // Get registration statistics await using var dbContext = await DbContextFactory.CreateDbContextAsync(); @@ -55,7 +55,7 @@ Hours24 = await registrationQuery.CountAsync(u => u.CreatedAt >= hours24), Days3 = await registrationQuery.CountAsync(u => u.CreatedAt >= days3), Days7 = await registrationQuery.CountAsync(u => u.CreatedAt >= days7), - Days14 = await registrationQuery.CountAsync(u => u.CreatedAt >= days14) + Days30 = await registrationQuery.CountAsync(u => u.CreatedAt >= days30) }; IsLoading = false; @@ -67,6 +67,6 @@ public int Hours24 { get; set; } public int Days3 { get; set; } public int Days7 { get; set; } - public int Days14 { get; set; } + public int Days30 { get; set; } } } diff --git a/src/AliasVault.Admin/wwwroot/css/tailwind.css b/src/AliasVault.Admin/wwwroot/css/tailwind.css index 7a3386738..1db02e6dd 100644 --- a/src/AliasVault.Admin/wwwroot/css/tailwind.css +++ b/src/AliasVault.Admin/wwwroot/css/tailwind.css @@ -723,10 +723,6 @@ video { margin-inline-start: 0.25rem; } -.ms-2 { - margin-inline-start: 0.5rem; -} - .mt-0 { margin-top: 0px; } @@ -980,6 +976,10 @@ video { align-items: center; } +.items-baseline { + align-items: baseline; +} + .justify-start { justify-content: flex-start; } @@ -996,6 +996,10 @@ video { justify-content: space-between; } +.gap-2 { + gap: 0.5rem; +} + .gap-4 { gap: 1rem; } @@ -1004,10 +1008,6 @@ video { gap: 2rem; } -.gap-2 { - gap: 0.5rem; -} - .space-x-1 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.25rem * var(--tw-space-x-reverse));