From 7300da2463dbd5c2601c0b135858b8b3490f7b66 Mon Sep 17 00:00:00 2001 From: Felix-CodingClimber Date: Wed, 31 Jan 2024 20:43:03 +0100 Subject: [PATCH] Lot's of improvements for MudBlazor components. --- .../AuditedModelDetailsRow.razor | 72 +++++++++++++++++++ src/DotNetElements.Web.MudBlazor/CrudTable.cs | 14 ++-- .../CrudTableActionsCell.razor | 40 +++++++++++ .../CrudTableLoadingCell.razor | 5 ++ .../CrudTableNewEntryButton.razor | 21 ++++++ .../CrudTableOptions.cs | 5 +- .../CrudTableSearchField.razor | 18 +++++ .../DeleteDialog.razor | 4 +- .../DialogeServiceExtensions.cs | 2 +- .../HttpClientExtensions.cs | 8 ++- .../PageHeader.razor | 14 ++++ .../ThemeToggleButton.razor | 25 +++++++ 12 files changed, 213 insertions(+), 15 deletions(-) create mode 100644 src/DotNetElements.Web.MudBlazor/AuditedModelDetailsRow.razor create mode 100644 src/DotNetElements.Web.MudBlazor/CrudTableActionsCell.razor create mode 100644 src/DotNetElements.Web.MudBlazor/CrudTableLoadingCell.razor create mode 100644 src/DotNetElements.Web.MudBlazor/CrudTableNewEntryButton.razor create mode 100644 src/DotNetElements.Web.MudBlazor/CrudTableSearchField.razor create mode 100644 src/DotNetElements.Web.MudBlazor/PageHeader.razor create mode 100644 src/DotNetElements.Web.MudBlazor/ThemeToggleButton.razor diff --git a/src/DotNetElements.Web.MudBlazor/AuditedModelDetailsRow.razor b/src/DotNetElements.Web.MudBlazor/AuditedModelDetailsRow.razor new file mode 100644 index 0000000..832120d --- /dev/null +++ b/src/DotNetElements.Web.MudBlazor/AuditedModelDetailsRow.razor @@ -0,0 +1,72 @@ +@inherits MudComponentBase + +@typeparam TKey where TKey : notnull, IEquatable +@typeparam TModel where TModel : IModel +@typeparam TDetails where TDetails : AuditedModelDetails + +@if (Context.DetailsShown && Context.Details is not null) +{ + @if (SimpleTable) + { + + + + + + ID + @Context.Value.Id + + + + + Creation Time + @Context.Details.CreationTime + + + + + Last Modification Time + @Context.Details.LastModificationTime + + + + + + } + else + { + + + + + + ID + @Context.Value.Id + + + + + Creation Time + @Context.Details.CreationTime + + + + + Last Modification Time + @Context.Details.LastModificationTime + + + + + + } +} + +@code +{ + [Parameter, EditorRequired] + public ModelWithDetails Context { get; set; } = default!; + + [Parameter] + public bool SimpleTable { get; set; } +} \ No newline at end of file diff --git a/src/DotNetElements.Web.MudBlazor/CrudTable.cs b/src/DotNetElements.Web.MudBlazor/CrudTable.cs index b35fb3c..59a15e2 100644 --- a/src/DotNetElements.Web.MudBlazor/CrudTable.cs +++ b/src/DotNetElements.Web.MudBlazor/CrudTable.cs @@ -25,14 +25,14 @@ public abstract class CrudTable protected bool IsLoaded; - private readonly CrudTableOptions options; + private readonly CrudTableOptions options; public CrudTable() { options = OnConfiguring(); } - protected abstract CrudTableOptions OnConfiguring(); + protected abstract CrudTableOptions OnConfiguring(); protected override async Task OnInitializedAsync() { @@ -103,15 +103,11 @@ protected async Task OnEditEntry(ModelWithDetails context) } } - protected async Task OnDeleteEntry(ModelWithDetails context, string modelName) + protected async Task OnDeleteEntry(ModelWithDetails context) { - bool? canDelete = await DialogService.ShowMessageBox( - "Attention", - $"Are you sure you want to delete this {modelName}?", - yesText: "Confirm", - cancelText: "Cancel"); + Result canDelete = await DialogService.ShowDeleteDialogAsync($"Delete {options.DeleteEntryLabel}?", options.DeleteEntryValue.Invoke(context.Value), options.DeleteEntryLabel); - if (canDelete is false) + if (canDelete.IsFail) return; Result result = await HttpClient.DeleteWithResultAsync(options.BaseEndpointUri, context.Value); diff --git a/src/DotNetElements.Web.MudBlazor/CrudTableActionsCell.razor b/src/DotNetElements.Web.MudBlazor/CrudTableActionsCell.razor new file mode 100644 index 0000000..0767de2 --- /dev/null +++ b/src/DotNetElements.Web.MudBlazor/CrudTableActionsCell.razor @@ -0,0 +1,40 @@ +@inherits MudComponentBase + +@typeparam TKey where TKey : notnull, IEquatable +@typeparam TModel where TModel : IModel +@typeparam TDetails where TDetails : ModelDetails + +@if (SimpleTable) +{ + + + + + +} +else +{ + + + + + +} + +@code +{ + [Parameter, EditorRequired] + public ModelWithDetails Context { get; set; } = default!; + + [Parameter, EditorRequired] + public EventCallback> OnEditEntry { get; set; } + + [Parameter, EditorRequired] + public EventCallback> OnDeleteEntry { get; set; } + + [Parameter, EditorRequired] + public EventCallback> OnShowEntryDetails { get; set; } + + [Parameter] + public bool SimpleTable { get; set; } +} \ No newline at end of file diff --git a/src/DotNetElements.Web.MudBlazor/CrudTableLoadingCell.razor b/src/DotNetElements.Web.MudBlazor/CrudTableLoadingCell.razor new file mode 100644 index 0000000..cf5ef30 --- /dev/null +++ b/src/DotNetElements.Web.MudBlazor/CrudTableLoadingCell.razor @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/DotNetElements.Web.MudBlazor/CrudTableNewEntryButton.razor b/src/DotNetElements.Web.MudBlazor/CrudTableNewEntryButton.razor new file mode 100644 index 0000000..81c179b --- /dev/null +++ b/src/DotNetElements.Web.MudBlazor/CrudTableNewEntryButton.razor @@ -0,0 +1,21 @@ +@inherits MudButton + +@{ + ChildContent = @Create New; +} + +@{ + base.BuildRenderTree(__builder); +} + +@code +{ + public CrudTableNewEntryButton() + { + StartIcon = Icons.Material.Outlined.Add; + Color = Color.Success; + Variant = Variant.Outlined; + Size = Size.Small; + Class = "ml-4"; + } +} \ No newline at end of file diff --git a/src/DotNetElements.Web.MudBlazor/CrudTableOptions.cs b/src/DotNetElements.Web.MudBlazor/CrudTableOptions.cs index 7b988ee..f8ac49a 100644 --- a/src/DotNetElements.Web.MudBlazor/CrudTableOptions.cs +++ b/src/DotNetElements.Web.MudBlazor/CrudTableOptions.cs @@ -1,6 +1,6 @@ namespace DotNetElements.Web.MudBlazor; -public class CrudTableOptions +public class CrudTableOptions { public string BaseEndpointUri { get; private init; } @@ -17,6 +17,9 @@ public string GetAllEndpoint } } + public required string DeleteEntryLabel { get; set; } + public required Func DeleteEntryValue { get; set; } + public string GetDetailsEndpoint(string id) => $"{BaseEndpointUri.TrimEnd('/')}/{id}/details"; public DialogOptions EditDialogOptions { get; init; } diff --git a/src/DotNetElements.Web.MudBlazor/CrudTableSearchField.razor b/src/DotNetElements.Web.MudBlazor/CrudTableSearchField.razor new file mode 100644 index 0000000..be6e139 --- /dev/null +++ b/src/DotNetElements.Web.MudBlazor/CrudTableSearchField.razor @@ -0,0 +1,18 @@ +@inherits MudInput + +@{ + base.BuildRenderTree(__builder); +} + +@code +{ + public CrudTableSearchField() + { + Placeholder = "Search"; + Clearable = true; + Adornment = Adornment.Start; + AdornmentIcon = Icons.Material.Filled.Search; + IconSize = Size.Medium; + Style = "width: 40%"; + } +} \ No newline at end of file diff --git a/src/DotNetElements.Web.MudBlazor/DeleteDialog.razor b/src/DotNetElements.Web.MudBlazor/DeleteDialog.razor index 63012dc..d342d67 100644 --- a/src/DotNetElements.Web.MudBlazor/DeleteDialog.razor +++ b/src/DotNetElements.Web.MudBlazor/DeleteDialog.razor @@ -1,12 +1,12 @@  - + @DialogInstance.Title - + Cancel diff --git a/src/DotNetElements.Web.MudBlazor/DialogeServiceExtensions.cs b/src/DotNetElements.Web.MudBlazor/DialogeServiceExtensions.cs index 332d2d2..080699a 100644 --- a/src/DotNetElements.Web.MudBlazor/DialogeServiceExtensions.cs +++ b/src/DotNetElements.Web.MudBlazor/DialogeServiceExtensions.cs @@ -2,7 +2,7 @@ public static class DialogeServiceExtensions { - public static async Task ShowDeleteDialog(this IDialogService dialogService, string title, string itemValue, string itemLabel) + public static async Task ShowDeleteDialogAsync(this IDialogService dialogService, string title, string itemValue, string itemLabel) { var dialogParameters = new DialogParameters { diff --git a/src/DotNetElements.Web.MudBlazor/HttpClientExtensions.cs b/src/DotNetElements.Web.MudBlazor/HttpClientExtensions.cs index 5a4d66f..fc36f9e 100644 --- a/src/DotNetElements.Web.MudBlazor/HttpClientExtensions.cs +++ b/src/DotNetElements.Web.MudBlazor/HttpClientExtensions.cs @@ -6,6 +6,7 @@ namespace DotNetElements.Web.MudBlazor; public static class HttpClientExtensions { + // todo [Performance] Check if we can use custom Json converter for improved performance. public static async Task>>> GetModelWithDetailsListFromJsonAsync(this HttpClient httpClient, string? requestUri, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) where TDetails : ModelDetails { @@ -14,9 +15,12 @@ public static async Task>>> GetMo if (!response.IsSuccessStatusCode) return Result.Fail($"Get request failed with status: {response.StatusCode} and reason: {response.ReasonPhrase}"); - List>? returnValue = await response.Content.ReadFromJsonAsync>>(cancellationToken); + List? returnValue = await response.Content.ReadFromJsonAsync>(cancellationToken); - return Result.OkIfNotNull(returnValue, $"Failed to convert response content to type ModelWithDetails<{typeof(TModel)}, {typeof(TDetails)}>"); + if (returnValue is null) + return Result.Fail($"Failed to convert response content to type {typeof(TModel)}"); + + return returnValue.Select(model => new ModelWithDetails(model)).ToList(); } public static async Task> GetFromJsonWithResultAsync(this HttpClient httpClient, string? requestUri, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) diff --git a/src/DotNetElements.Web.MudBlazor/PageHeader.razor b/src/DotNetElements.Web.MudBlazor/PageHeader.razor new file mode 100644 index 0000000..82748d0 --- /dev/null +++ b/src/DotNetElements.Web.MudBlazor/PageHeader.razor @@ -0,0 +1,14 @@ +@using Microsoft.AspNetCore.Components.Sections + + + @Title + + +@code +{ + [Parameter, EditorRequired] + public string Title { get; set; } = default!; + + [Parameter] + public string SectionName { get; set; } = "page-header"; +} \ No newline at end of file diff --git a/src/DotNetElements.Web.MudBlazor/ThemeToggleButton.razor b/src/DotNetElements.Web.MudBlazor/ThemeToggleButton.razor new file mode 100644 index 0000000..c9bfe4b --- /dev/null +++ b/src/DotNetElements.Web.MudBlazor/ThemeToggleButton.razor @@ -0,0 +1,25 @@ +@if (DarkModeActive) +{ + +} +else +{ + +} + +@code +{ + [Parameter, EditorRequired] + public bool DarkModeActive { get; set; } + + [Parameter] + public EventCallback DarkModeActiveChanged { get; set; } + + private async Task OnToggleDarkMode() + { + DarkModeActive = !DarkModeActive; + + if (DarkModeActiveChanged.HasDelegate) + await DarkModeActiveChanged.InvokeAsync(DarkModeActive); + } +} \ No newline at end of file