+
+ @user.UserName
@if (user.IsInactive)
{
@@ -75,13 +72,15 @@ else
}
@if (user.TwoFactorEnabled)
{
-
+
}
-
-
-
+
@RelativeTimeFormatter.Format(user.LastActivityDate)
+
@user.CredentialCount
+
@user.EmailClaimCount
+
@user.VaultCount
+
@Math.Round((double)user.VaultStorageInKb / 1024, 1) MB
}
@@ -92,13 +91,11 @@ else
private readonly List
_tableColumns = [
new TableColumn { Title = "Registered", PropertyName = "CreatedAt" },
new TableColumn { Title = "Username", PropertyName = "UserName" },
- new TableColumn { Title = "# Vaults", PropertyName = "VaultCount" },
+ new TableColumn { Title = "Last Activity", PropertyName = "LastActivityDate" },
new TableColumn { Title = "# Credentials", PropertyName = "CredentialCount" },
new TableColumn { Title = "# Email claims", PropertyName = "EmailClaimCount" },
+ new TableColumn { Title = "# Vaults", PropertyName = "VaultCount" },
new TableColumn { Title = "Storage", PropertyName = "VaultStorageInKb" },
- new TableColumn { Title = "Last Activity", PropertyName = "LastActivityDate" },
- new TableColumn { Title = "Status", Sortable = false },
- new TableColumn { Title = "Actions", Sortable = false},
];
private List UserList { get; set; } = [];
@@ -158,6 +155,11 @@ else
await RefreshData(CancellationToken.None);
}
+ private void NavigateToUser(string userId)
+ {
+ NavigationManager.NavigateTo($"users/{userId}");
+ }
+
///
protected override async Task OnInitializedAsync()
{
diff --git a/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTable.razor b/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTable.razor
index e9da25b53..3e6c81519 100644
--- a/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTable.razor
+++ b/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTable.razor
@@ -1,5 +1,5 @@
-
-
+
+
@foreach (var column in Columns)
diff --git a/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTableRow.razor b/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTableRow.razor
index 1bbdc2a02..d3b67dd28 100644
--- a/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTableRow.razor
+++ b/apps/server/Shared/AliasVault.RazorComponents/Tables/SortableTableRow.razor
@@ -1,4 +1,4 @@
-
+
@ChildContent
diff --git a/apps/server/Shared/AliasVault.RazorComponents/Utilities/RelativeTimeFormatter.cs b/apps/server/Shared/AliasVault.RazorComponents/Utilities/RelativeTimeFormatter.cs
new file mode 100644
index 000000000..3a785b9cc
--- /dev/null
+++ b/apps/server/Shared/AliasVault.RazorComponents/Utilities/RelativeTimeFormatter.cs
@@ -0,0 +1,74 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) aliasvault. All rights reserved.
+// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
+//
+//-----------------------------------------------------------------------
+
+namespace AliasVault.RazorComponents.Utilities;
+
+///
+/// Utility for formatting DateTime values as relative time strings (e.g., "5 minutes ago", "2 days ago").
+///
+public static class RelativeTimeFormatter
+{
+ ///
+ /// Formats a DateTime as a relative time string.
+ ///
+ /// The DateTime to format (assumed to be UTC).
+ /// A human-readable relative time string.
+ public static string Format(DateTime dateTime)
+ {
+ var now = DateTime.UtcNow;
+ var timeSpan = now - dateTime;
+
+ if (timeSpan.TotalSeconds < 0)
+ {
+ return "just now";
+ }
+
+ if (timeSpan.TotalSeconds < 60)
+ {
+ var seconds = (int)timeSpan.TotalSeconds;
+ return seconds <= 5 ? "just now" : $"{seconds} sec ago";
+ }
+
+ if (timeSpan.TotalMinutes < 60)
+ {
+ var minutes = (int)timeSpan.TotalMinutes;
+ return minutes == 1 ? "1 min ago" : $"{minutes} min ago";
+ }
+
+ if (timeSpan.TotalHours < 24)
+ {
+ var hours = (int)timeSpan.TotalHours;
+ return hours == 1 ? "1 hour ago" : $"{hours} hours ago";
+ }
+
+ if (timeSpan.TotalDays < 30)
+ {
+ var days = (int)timeSpan.TotalDays;
+ return days == 1 ? "1 day ago" : $"{days} days ago";
+ }
+
+ if (timeSpan.TotalDays < 365)
+ {
+ var months = (int)(timeSpan.TotalDays / 30);
+ return months == 1 ? "1 month ago" : $"{months} months ago";
+ }
+
+ var years = (int)(timeSpan.TotalDays / 365);
+ return years == 1 ? "1 year ago" : $"{years} years ago";
+ }
+
+ ///
+ /// Formats a nullable DateTime as a relative time string.
+ ///
+ /// The nullable DateTime to format.
+ /// The fallback string to use if dateTime is null.
+ /// A human-readable relative time string or the fallback value.
+ public static string Format(DateTime? dateTime, string fallback = "Never")
+ {
+ return dateTime.HasValue ? Format(dateTime.Value) : fallback;
+ }
+}