From 9a97a904fb0e8e773dc7e0cf2a5454f9c4e36a7e Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Sun, 14 Sep 2025 16:35:20 +0200 Subject: [PATCH] Add credentials alphabetical sort option to web app (#1207) --- .../Credentials/CredentialsTable.razor | 81 +++++++++++++++++-- .../Main/Models/CredentialSortOrder.cs | 29 +++++++ .../Main/Pages/Credentials/Home.razor | 41 ++++++---- .../Pages/Main/Credentials/Home.en.resx | 4 + .../Services/SettingsService.cs | 14 +++- 5 files changed, 142 insertions(+), 27 deletions(-) create mode 100644 apps/server/AliasVault.Client/Main/Models/CredentialSortOrder.cs diff --git a/apps/server/AliasVault.Client/Main/Components/Credentials/CredentialsTable.razor b/apps/server/AliasVault.Client/Main/Components/Credentials/CredentialsTable.razor index 3004214e8..6c80705fe 100644 --- a/apps/server/AliasVault.Client/Main/Components/Credentials/CredentialsTable.razor +++ b/apps/server/AliasVault.Client/Main/Components/Credentials/CredentialsTable.razor @@ -1,8 +1,9 @@ @using AliasVault.RazorComponents.Tables +@using AliasVault.Client.Main.Models @inject NavigationManager NavigationManager - - @foreach (var credential in SortedCredentials) + + @foreach (var credential in DisplayedCredentials) { @@ -26,16 +27,26 @@ public List Credentials { get; set; } = []; /// - /// Gets or sets the default sort direction that is applied to the provided credentials list. + /// Gets or sets the sort order for the credentials (used to determine initial table state). /// [Parameter] - public SortDirection SortDirection { get; set; } = SortDirection.Ascending; + public CredentialSortOrder SortOrder { get; set; } = CredentialSortOrder.OldestFirst; /// /// Gets or sets the column to sort by. /// private string SortColumn { get; set; } = "CreatedAt"; + /// + /// Gets or sets the current sort direction for table column sorting. + /// + private SortDirection CurrentSortDirection { get; set; } = SortDirection.Ascending; + + /// + /// Gets or sets whether the user has explicitly clicked a column to sort. + /// + private bool UserHasClickedColumn { get; set; } = false; + /// /// Gets or sets the columns to show in the table. /// @@ -47,9 +58,64 @@ ]; /// - /// Gets or sets the sorted credentials. + /// Gets the credentials to display, with optional column-based sorting applied. /// - private IEnumerable SortedCredentials => SortList(Credentials, SortColumn, SortDirection); + private IEnumerable DisplayedCredentials + { + get + { + // If user has explicitly clicked a column header to sort, apply that sorting + if (UserHasClickedColumn) + { + return SortList(Credentials, SortColumn, CurrentSortDirection); + } + + // Otherwise use the pre-sorted credentials passed from parent + return Credentials; + } + } + + /// + /// Gets the default sort column based on the sort order. + /// + private string GetDefaultSortColumn() + { + return SortOrder switch + { + CredentialSortOrder.Alphabetical => "Service", + _ => "CreatedAt", // OldestFirst and NewestFirst + }; + } + + /// + /// Gets the default sort direction based on the sort order. + /// + private SortDirection GetDefaultSortDirection() + { + return SortOrder switch + { + CredentialSortOrder.NewestFirst => SortDirection.Descending, + CredentialSortOrder.Alphabetical => SortDirection.Ascending, + _ => SortDirection.Ascending, // OldestFirst (default) + }; + } + + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + + // Only reset if the SortOrder parameter has changed + var newDefaultColumn = GetDefaultSortColumn(); + var newDefaultDirection = GetDefaultSortDirection(); + + if (SortColumn != newDefaultColumn || (!UserHasClickedColumn && CurrentSortDirection != newDefaultDirection)) + { + SortColumn = newDefaultColumn; + CurrentSortDirection = newDefaultDirection; + UserHasClickedColumn = false; // Reset user interaction state when parameters change + } + } /// /// Handles the sort changed event. @@ -58,7 +124,8 @@ private void HandleSortChanged((string column, SortDirection direction) sort) { SortColumn = sort.column; - SortDirection = sort.direction; + CurrentSortDirection = sort.direction; + UserHasClickedColumn = true; StateHasChanged(); } diff --git a/apps/server/AliasVault.Client/Main/Models/CredentialSortOrder.cs b/apps/server/AliasVault.Client/Main/Models/CredentialSortOrder.cs new file mode 100644 index 000000000..c950c3316 --- /dev/null +++ b/apps/server/AliasVault.Client/Main/Models/CredentialSortOrder.cs @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------- +// +// 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.Client.Main.Models; + +/// +/// Defines the sort order options for credentials. +/// +public enum CredentialSortOrder +{ + /// + /// Sort by creation date, oldest first. + /// + OldestFirst, + + /// + /// Sort by creation date, newest first. + /// + NewestFirst, + + /// + /// Sort alphabetically by service name. + /// + Alphabetical, +} diff --git a/apps/server/AliasVault.Client/Main/Pages/Credentials/Home.razor b/apps/server/AliasVault.Client/Main/Pages/Credentials/Home.razor index 626224cb9..c08424019 100644 --- a/apps/server/AliasVault.Client/Main/Pages/Credentials/Home.razor +++ b/apps/server/AliasVault.Client/Main/Pages/Credentials/Home.razor @@ -2,6 +2,7 @@ @inherits MainBase @inject CredentialService CredentialService @using AliasVault.RazorComponents.Tables +@using AliasVault.Client.Main.Models @using Microsoft.Extensions.Localization Home @@ -33,8 +34,9 @@
@@ -55,7 +57,7 @@ else @if (DbService.Settings.CredentialsViewMode == "table") {
- +
} else @@ -88,7 +90,7 @@ else } - @foreach (var credential in Credentials) + @foreach (var credential in SortedCredentials) { } @@ -126,12 +128,28 @@ else /// /// Gets or sets the sort order for the credentials. /// - private string SortOrder + private CredentialSortOrder SortOrder { get => DbService.Settings.CredentialsSortOrder; set => DbService.Settings.SetCredentialsSortOrder(value); } + /// + /// Gets the credentials sorted according to the current sort order. + /// + private IEnumerable SortedCredentials + { + get + { + return SortOrder switch + { + CredentialSortOrder.NewestFirst => Credentials.OrderByDescending(x => x.CreatedAt), + CredentialSortOrder.Alphabetical => Credentials.OrderBy(x => x.Service ?? string.Empty), + _ => Credentials.OrderBy(x => x.CreatedAt), // OldestFirst (default) + }; + } + } + /// /// Toggles the settings dropdown. /// @@ -187,18 +205,7 @@ else return; } - // Apply sort based on config. - switch (DbService.Settings.CredentialsSortOrder) - { - case "desc": - credentialListEntries = credentialListEntries.OrderByDescending(x => x.CreatedAt).ToList(); - break; - - default: - credentialListEntries = credentialListEntries.OrderBy(x => x.CreatedAt).ToList(); - break; - } - + // Pass unsorted list to the view - sorting will be handled by the table/grid components Credentials = credentialListEntries; IsLoading = false; StateHasChanged(); diff --git a/apps/server/AliasVault.Client/Resources/Pages/Main/Credentials/Home.en.resx b/apps/server/AliasVault.Client/Resources/Pages/Main/Credentials/Home.en.resx index 4b9f3d498..3294f4dfd 100644 --- a/apps/server/AliasVault.Client/Resources/Pages/Main/Credentials/Home.en.resx +++ b/apps/server/AliasVault.Client/Resources/Pages/Main/Credentials/Home.en.resx @@ -94,6 +94,10 @@ Newest First Newest first sort option + + Alphabetical + Alphabetical sort option + diff --git a/apps/server/AliasVault.Client/Services/SettingsService.cs b/apps/server/AliasVault.Client/Services/SettingsService.cs index 3700e7324..87afe42c9 100644 --- a/apps/server/AliasVault.Client/Services/SettingsService.cs +++ b/apps/server/AliasVault.Client/Services/SettingsService.cs @@ -13,6 +13,7 @@ using System.Globalization; using System.Text.Json; using System.Threading.Tasks; using AliasClientDb; +using AliasVault.Client.Main.Models; using Microsoft.EntityFrameworkCore; /// @@ -66,8 +67,15 @@ public sealed class SettingsService /// /// Gets the CredentialsSortOrder setting. /// - /// Credentials sort order as string. - public string CredentialsSortOrder => GetSetting("CredentialsSortOrder", "asc")!; + /// Credentials sort order as enum. + public CredentialSortOrder CredentialsSortOrder + { + get + { + var value = GetSetting("CredentialsSortOrder", "OldestFirst")!; + return Enum.TryParse(value, out var result) ? result : CredentialSortOrder.OldestFirst; + } + } /// /// Gets the AppLanguage setting. @@ -154,7 +162,7 @@ public sealed class SettingsService /// /// The new value. /// Task. - public Task SetCredentialsSortOrder(string value) => SetSettingAsync("CredentialsSortOrder", value); + public Task SetCredentialsSortOrder(CredentialSortOrder value) => SetSettingAsync("CredentialsSortOrder", value.ToString()); /// /// Sets the AppLanguage setting.