Files
aliasvault/apps/server/AliasVault.Client/Main/Pages/Credentials/Home.razor
2025-04-30 19:03:18 +02:00

203 lines
8.7 KiB
Plaintext

@page "/credentials"
@inherits MainBase
@inject CredentialService CredentialService
@using AliasVault.RazorComponents.Tables
<LayoutPageTitle>Home</LayoutPageTitle>
<PageHeader
BreadcrumbItems="@BreadcrumbItems"
Title="Credentials"
Description="Find all of your credentials below.">
<CustomActions>
<div class="relative">
<button @onclick="ToggleSettingsDropdown" id="settingsButton" class="p-2 text-gray-500 rounded-lg hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd"></path>
</svg>
</button>
@if (ShowSettingsDropdown)
{
<ClickOutsideHandler OnClose="CloseSettingsPopup" ContentId="settingsDropdown,settingsButton">
<div id="settingsDropdown" class="absolute right-0 z-10 mt-2 min-w-[220px] origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-700">
<div class="p-4">
<div class="mb-4">
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">View Mode</label>
<select @bind="ViewMode" @bind:after="CloseSettingsPopup" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<option value="grid">Grid View</option>
<option value="table">Table View</option>
</select>
</div>
<div class="mb-4">
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Sort Order</label>
<select @bind="SortOrder" @bind:after="CloseSettingsPopup" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<option value="asc">Oldest First</option>
<option value="desc">Newest First</option>
</select>
</div>
</div>
</div>
</ClickOutsideHandler>
}
</div>
<RefreshButton OnClick="LoadCredentialsAsync" ButtonText="Refresh" />
</CustomActions>
</PageHeader>
@if (IsLoading)
{
<LoadingIndicator />
}
else
{
@if (DbService.Settings.CredentialsViewMode == "table")
{
<div class="px-4 min-h-[250px]">
<CredentialsTable Credentials="Credentials" SortDirection="@(SortOrder == "desc" ? SortDirection.Descending : SortDirection.Ascending)" />
</div>
}
else
{
<div class="grid gap-4 px-4 mb-4 md:grid-cols-4 xl:grid-cols-6">
@if (Credentials.Count == 0)
{
<div class="credential-card col-span-full p-4 space-y-2 bg-amber-50 border border-primary-500 rounded-lg shadow-sm dark:border-primary-700 dark:bg-gray-800">
<div class="px-4 py-6 text-gray-700 dark:text-gray-200 rounded text-center flex flex-col items-center">
<p class="mb-2 text-lg font-semibold text-primary-700 dark:text-primary-400">No credentials yet</p>
<div class="max-w-md mx-auto">
<div class="mb-6">
<p class="text-sm mb-2">Create your first credential using the <span class="hidden md:inline">"+ New Alias"</span><span class="md:hidden">"+"</span> button in the top right corner.</p>
</div>
<div class="flex items-center my-6">
<div class="flex-1 h-px bg-gray-300 dark:bg-gray-600"></div>
<span class="px-4 text-sm text-gray-500 dark:text-gray-400">or</span>
<div class="flex-1 h-px bg-gray-300 dark:bg-gray-600"></div>
</div>
<div>
<p class="text-sm mb-2">If you previously used a different password manager, you can import your credentials from it.</p>
<a href="/settings/import-export" class="inline-block text-sm px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors dark:bg-primary-700 dark:hover:bg-primary-600">
Import from KeePass, Bitwarden, Chrome, Firefox...
</a>
</div>
</div>
</div>
</div>
}
@foreach (var credential in Credentials)
{
<CredentialCard Obj="@credential"/>
}
</div>
}
}
@code {
/// <summary>
/// Gets or sets whether the credentials are being loaded.
/// </summary>
private bool IsLoading { get; set; } = true;
/// <summary>
/// Gets or sets the credentials.
/// </summary>
private List<CredentialListEntry> Credentials { get; set; } = new();
/// <summary>
/// Gets or sets whether the settings dropdown is shown.
/// </summary>
private bool ShowSettingsDropdown { get; set; }
/// <summary>
/// Gets or sets the view mode for the credentials.
/// </summary>
private string ViewMode
{
get => DbService.Settings.CredentialsViewMode;
set => DbService.Settings.SetCredentialsViewMode(value);
}
/// <summary>
/// Gets or sets the sort order for the credentials.
/// </summary>
private string SortOrder
{
get => DbService.Settings.CredentialsSortOrder;
set => DbService.Settings.SetCredentialsSortOrder(value);
}
/// <summary>
/// Toggles the settings dropdown.
/// </summary>
private void ToggleSettingsDropdown()
{
ShowSettingsDropdown = !ShowSettingsDropdown;
StateHasChanged();
}
/// <summary>
/// Closes the settings dropdown.
/// </summary>
private async Task CloseSettingsPopup()
{
ShowSettingsDropdown = false;
// Reload the credentials in case the settings were changed.
await LoadCredentialsAsync();
}
/// <inheritdoc />
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
await LoadCredentialsAsync();
}
}
/// <summary>
/// Loads and/or refreshes the credentials.
/// </summary>
private async Task LoadCredentialsAsync()
{
IsLoading = true;
StateHasChanged();
// Load the aliases from the webapi via AliasService.
var credentialListEntries = await CredentialService.GetListAsync();
if (credentialListEntries is null)
{
// Error loading aliases.
GlobalNotificationService.AddErrorMessage("Failed to load credentials.", true);
return;
}
if (credentialListEntries.Count == 0 && !DbService.Settings.TutorialDone)
{
// Redirect to the welcome page.
NavigationManager.NavigateTo("/welcome");
}
// 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;
}
Credentials = credentialListEntries;
IsLoading = false;
StateHasChanged();
}
}