diff --git a/src/Application/Features/KeyValues/Commands/AddEdit/AddEditKeyValueCommandValidator.cs b/src/Application/Features/KeyValues/Commands/AddEdit/AddEditKeyValueCommandValidator.cs index 6690792db..d9f1bc201 100644 --- a/src/Application/Features/KeyValues/Commands/AddEdit/AddEditKeyValueCommandValidator.cs +++ b/src/Application/Features/KeyValues/Commands/AddEdit/AddEditKeyValueCommandValidator.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using CleanArchitecture.Blazor.Application.Features.Tenants.Commands.AddEdit; + namespace CleanArchitecture.Blazor.Application.Features.KeyValues.Commands.AddEdit; public class AddEditKeyValueCommandValidator : AbstractValidator @@ -8,12 +10,15 @@ public class AddEditKeyValueCommandValidator : AbstractValidator v.Name).NotNull(); - RuleFor(v => v.Text) - .MaximumLength(256) - .NotEmpty(); - RuleFor(v => v.Value) - .MaximumLength(256) - .NotEmpty(); + RuleFor(v => v.Text).MaximumLength(256).NotEmpty(); + RuleFor(v => v.Value).MaximumLength(256).NotEmpty(); } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((AddEditKeyValueCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; } diff --git a/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs b/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs index aff5d53d9..d3ab26ca8 100644 --- a/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs +++ b/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs @@ -3,11 +3,17 @@ using CleanArchitecture.Blazor.Application.Features.KeyValues.DTOs; using CleanArchitecture.Blazor.Application.Features.KeyValues.Caching; +using CleanArchitecture.Blazor.Application.Features.AuditTrails.DTOs; namespace CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.PaginationQuery; -public class KeyValuesWithPaginationQuery : PaginationFilter, ICacheableRequest> +public class KeyValuesWithPaginationQuery : PaginationFilterBase, ICacheableRequest> { + [CompareTo("Value", "Text", "Description")] // <-- This filter will be applied to Name or Brand or Description. + [StringFilterOptions(StringFilterOption.Contains)] + public string? Keyword { get; set; } + [OperatorComparison(OperatorType.Equal)] + public Picklist? Picklist { get; set; } public string CacheKey => $"{nameof(KeyValuesWithPaginationQuery)},{this}"; public MemoryCacheEntryOptions? Options => KeyValueCacheKey.MemoryCacheEntryOptions; @@ -32,11 +38,10 @@ IMapper mapper #pragma warning disable CS8604 public async Task> Handle(KeyValuesWithPaginationQuery request, CancellationToken cancellationToken) { - - var data = await _context.KeyValues.Where(x=>x.Value.Contains(request.Keyword)|| x.Text.Contains(request.Keyword) || x.Description.Contains(request.Keyword)) - .OrderBy($"{request.OrderBy} {request.SortDirection}") - .ProjectTo(_mapper.ConfigurationProvider) - .PaginatedDataAsync(request.PageNumber, request.PageSize); + + var data = await _context.KeyValues.ApplyFilterWithoutPagination(request) + .ProjectTo(_mapper.ConfigurationProvider) + .PaginatedDataAsync(request.Page, request.PerPage); return data; } diff --git a/src/Blazor.Server.UI/Pages/SystemManagement/Dictionaries.razor b/src/Blazor.Server.UI/Pages/SystemManagement/Dictionaries.razor index a50a3e52e..31adb60a8 100644 --- a/src/Blazor.Server.UI/Pages/SystemManagement/Dictionaries.razor +++ b/src/Blazor.Server.UI/Pages/SystemManagement/Dictionaries.razor @@ -9,6 +9,7 @@ @using CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.ByName @using CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.Export @using CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.GetAll +@using CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.PaginationQuery; @attribute [Authorize(Policy = Permissions.Dictionaries.View)] @inject IStringLocalizer L @@ -23,11 +24,9 @@ + ServerData="@(new Func>>(ServerReload))">
@L["Picklist"] @@ -145,10 +144,11 @@ @if (_canSearch) { - - + + + + } @@ -195,7 +195,7 @@ @code { - private MudTable? _table=default!; + private MudTable _table=default!; public string Title { get; set; } = "Picklist"; private IList _keyValueList = new List(); private HashSet _selectedItems = new HashSet(); @@ -203,6 +203,7 @@ private KeyValueDto _elementBeforeEdit { get; set; } = new(); private bool _canCancelEdit=true; private string _searchString = string.Empty; + private Picklist? _searchPicklist = null; private int _defaultPageSize = 15; private bool _editing; [CascadingParameter] @@ -213,6 +214,7 @@ private IBlazorDownloadFileService _blazorDownloadFileService { get; set; } = null!; [Inject] private IMediator _mediator { get; set; } = default!; + private KeyValuesWithPaginationQuery request = new(); private bool _canCreate; private bool _canSearch; private bool _canEdit; @@ -232,43 +234,46 @@ _canDelete = (await AuthService.AuthorizeAsync(state.User, Permissions.Dictionaries.Delete)).Succeeded; _canImport = (await AuthService.AuthorizeAsync(state.User, Permissions.Dictionaries.Import)).Succeeded; _canExport = (await AuthService.AuthorizeAsync(state.User, Permissions.Dictionaries.Export)).Succeeded; - await LoadData(); - } - private bool _quickFilter(KeyValueDto dto) => FilterFunc(dto, _searchString); - private bool FilterFunc(KeyValueDto dto, string searchString) - { - if (string.IsNullOrWhiteSpace(searchString)) - return true; - if ($"{dto.Name.GetDescription()} {dto.Value} {dto.Text} {dto.Description}".Contains(searchString)) - return true; - return false; } - - private async Task LoadData() + private async Task> ServerReload(TableState state) { - if(_loading) return; - try{ + try + { _loading = true; - _editing = false; - var cmd = new GetAllKeyValuesQuery(); - _keyValueList = (await _mediator.Send(cmd).ConfigureAwait(false)).ToList(); - _selectedItems=new HashSet(); - _selectedItem = new(); + var request = new KeyValuesWithPaginationQuery() + { + Keyword = _searchString, + Picklist = _searchPicklist, + Sort = string.IsNullOrEmpty(state.SortLabel) ? "Id" : state.SortLabel, + SortBy = (state.SortDirection == SortDirection.Ascending ? AutoFilterer.Enums.Sorting.Ascending : AutoFilterer.Enums.Sorting.Descending), + Page = state.Page + 1, + PerPage = state.PageSize + }; + var result = await _mediator.Send(request).ConfigureAwait(false); + return new TableData() { TotalItems = result.TotalItems, Items = result.Items }; } finally { _loading = false; } - - + } + private async Task OnSearch(string text) + { + _searchString = text; + await _table.ReloadServerData(); + } + private async Task OnSearch(Picklist? val) + { + _searchPicklist = val; + await _table.ReloadServerData(); } private async Task OnRefresh() { KeyValueCacheKey.Refresh(); _searchString = string.Empty; - await LoadData(); + await _table.ReloadServerData(); } private async Task OnDeleteChecked() { @@ -284,24 +289,30 @@ { var command = new DeleteKeyValueCommand(_selectedItems.Select(x => x.Id).ToArray()); var result = await _mediator.Send(command); - await LoadData(); + await _table.ReloadServerData(); Snackbar.Add($"{ConstantString.DELETESUCCESS}", MudBlazor.Severity.Info); } } private async Task OnCreate() { - _editing = true; - _table!.SetEditingItem(null); - var newitem = new KeyValueDto() + var command = new AddEditKeyValueCommand() { Name = _selectedItem.Name, Description = _selectedItem?.Description, - TrackingState = TrackingState.Added }; - _keyValueList.Insert(0, newitem); - await Task.Delay(50); - _table!.SetSelectedItem(newitem); - _table!.SetEditingItem(newitem); + var parameters = new DialogParameters + { + { nameof(_CreatePicklistDialog.model),command }, + }; + var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.Small, FullWidth = true }; + var dialog = DialogService.Show<_CreatePicklistDialog> + (L["Create a new picklist"], parameters, options); + var state = await dialog.Result; + if (!state.Canceled) + { + await _table.ReloadServerData(); + } + } private void BackupItem(object element) { diff --git a/src/Blazor.Server.UI/Pages/SystemManagement/_CreatePicklistDialog.razor b/src/Blazor.Server.UI/Pages/SystemManagement/_CreatePicklistDialog.razor new file mode 100644 index 000000000..d01b4922e --- /dev/null +++ b/src/Blazor.Server.UI/Pages/SystemManagement/_CreatePicklistDialog.razor @@ -0,0 +1,82 @@ +@using CleanArchitecture.Blazor.Application.Features.KeyValues.Commands.AddEdit; +@using SixLabors.ImageSharp +@using SixLabors.ImageSharp.Formats +@using SixLabors.ImageSharp.Processing +@inherits MudComponentBase +@inject IStringLocalizer L + + + + + + + + + + + + + + + + + + + + + + + + + + @ConstantString.CANCEL + @ConstantString.SAVE + + + +@code { + MudForm? _form = default!; + bool _saving = false; + [CascadingParameter] + MudDialogInstance MudDialog { get; set; } = default!; + AddEditKeyValueCommandValidator modelValidator = new AddEditKeyValueCommandValidator(); + [EditorRequired][Parameter] public AddEditKeyValueCommand model { get; set; } = default!; + [Inject] + private IMediator _mediator { get; set; } = default!; + async Task Submit() + { + try + { + _saving = true; + await _form!.Validate().ConfigureAwait(false); + if (!_form!.IsValid) + return; + var result = await _mediator.Send(model); + + if (result.Succeeded) + { + MudDialog.Close(DialogResult.Ok(true)); + Snackbar.Add(ConstantString.SAVESUCCESS, MudBlazor.Severity.Info); + } + else + { + Snackbar.Add(result.ErrorMessage, MudBlazor.Severity.Error); + } + } + finally + { + _saving = false; + } + } + void Cancel() => MudDialog.Cancel(); +}