diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000..7c1f20b3 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,52 @@ +# ASP.NET +# Build and test ASP.NET projects. +# Add steps that publish symbols, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4 + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + Parameters.requestedMajorVersion: '1' + Parameters.requestedMinorVersion: '17' + Parameters.requestedPatchVersion: '3' +steps: + +- task: NuGetToolInstaller@1 + +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + feedsToUse: 'select' + +- task: VSBuild@1 + inputs: + solution: '$(solution)' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + inputs: + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'pack' + packagesToPack: '**/BlazorTable.csproj' + includesymbols: true + versioningScheme: 'byPrereleaseNumber' + majorVersion: '1' + minorVersion: '17' + patchVersion: '3' + displayName: 'Nuget Push' + +- task: NuGetCommand@2 + inputs: + command: 'push' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: '62fc85ae-4447-4b56-a2ea-c6ab74293507/dbfc01ad-afcb-448b-bda5-e0ef32ca9d70' \ No newline at end of file diff --git a/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor b/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor index 929403e9..c4e4a4a1 100644 --- a/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor +++ b/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor @@ -6,15 +6,27 @@

Server side data

- - - +Selected: @(selectedItems.Any() ? selectedItems.Select(x => x.full_name).Aggregate((c, n) => $"{c},{n}") : "None") + +
+ + + + + + + + + + + + - + @@ -25,7 +37,7 @@ @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty) - +
@code @@ -33,6 +45,8 @@ [Inject] private HttpClient httpClient { get; set; } + private ITable Table; + public class PersonData { public int? id { get; set; } @@ -47,10 +61,33 @@ private IEnumerable data; + private List selectedItems = new List(); + protected override async Task OnInitializedAsync() { _loader = new PersonDataLoader(httpClient); data = (await _loader.LoadDataAsync(null)).Records; + + await Table.SetInitialFiltersAsync(new List() + { + //new FilterString() + //{ + // Condition = StringCondition.IsEqualTo.ToString(), + // Field = nameof(PersonData.full_name), + // FilterValue = "Marja Mustill" + //}, + new FilterString() + { + Condition = BooleanCondition.True.ToString(), + Field = nameof(PersonData.paid) + } + }); + + } + + public void RowClick(PersonData data) + { + StateHasChanged(); } public class PersonDataLoader : IDataLoader @@ -60,7 +97,7 @@ { _client = client; } - public async Task> LoadDataAsync(FilterData parameters) + public async Task> LoadDataAsync(FilterData parameters) { var data = await _client.GetFromJsonAsync("sample-data/MOCK_DATA.json"); @@ -82,6 +119,13 @@ : query.OrderBy(x => prop.GetValue(x, null)); } } + if(parameters?.Filters != null) + { + foreach (var filter in parameters?.Filters) + { + query = query.Where(filter); + } + } var results = parameters?.Top.HasValue ?? false ? query.Skip(parameters.Skip.GetValueOrDefault()) .Take(parameters.Top.Value).ToArray() : @@ -97,4 +141,6 @@ } } + + } diff --git a/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css b/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css index aa02184c..bde68409 100644 --- a/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css +++ b/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css @@ -255,4 +255,8 @@ app { justify-content: center; flex-direction: column; --sk-color: white; +} + +.page-link { + border: none; } \ No newline at end of file diff --git a/src/BlazorTable.Sample.Wasm/wwwroot/index.html b/src/BlazorTable.Sample.Wasm/wwwroot/index.html index b8670c70..82cf2712 100644 --- a/src/BlazorTable.Sample.Wasm/wwwroot/index.html +++ b/src/BlazorTable.Sample.Wasm/wwwroot/index.html @@ -7,6 +7,7 @@ + diff --git a/src/BlazorTable/BlazorTable.csproj b/src/BlazorTable/BlazorTable.csproj index 4d04d6e9..37cf4d75 100644 --- a/src/BlazorTable/BlazorTable.csproj +++ b/src/BlazorTable/BlazorTable.csproj @@ -15,6 +15,8 @@ git MIT true + + 1.17.11-preview @@ -35,6 +37,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/BlazorTable/Components/Column.razor.cs b/src/BlazorTable/Components/Column.razor.cs index dec41914..52137011 100644 --- a/src/BlazorTable/Components/Column.razor.cs +++ b/src/BlazorTable/Components/Column.razor.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Components; +using BlazorTable.Components.ServerSide; +using Microsoft.AspNetCore.Components; using System; using System.Globalization; using System.Linq; @@ -122,6 +123,16 @@ public string Title /// public Expression> Filter { get; set; } + /// + /// Filter as string + /// + public FilterString FilterString { get; set; } + + /// + /// Initial filters + /// + public FilterString InitialFilterString { get; set; } + /// /// True if this is the default Sort Column /// @@ -147,7 +158,7 @@ public string Title /// /// Filter Panel is open /// - public bool FilterOpen { get; private set; } + public bool FilterOpen { get; set; } private bool _visible = true; @@ -220,6 +231,10 @@ protected override void OnParametersSet() public void ToggleFilter() { FilterOpen = !FilterOpen; + foreach (var column in Table.Columns.Where(x => x != this)) + { + column.FilterOpen = false; + } Table.Refresh(); } diff --git a/src/BlazorTable/Components/FilterManager.razor.cs b/src/BlazorTable/Components/FilterManager.razor.cs index bb1f8285..7fc24407 100644 --- a/src/BlazorTable/Components/FilterManager.razor.cs +++ b/src/BlazorTable/Components/FilterManager.razor.cs @@ -20,13 +20,13 @@ public partial class FilterManager IStringLocalizer Localization { get; set; } private async Task ApplyFilterAsync() - { Column.ToggleFilter(); if (Column.FilterControl != null) { Column.Filter = Column.FilterControl.GetFilter(); + Column.FilterString = Column.FilterControl.GetFilterString(); await Column.Table.UpdateAsync().ConfigureAwait(false); await Column.Table.FirstPageAsync().ConfigureAwait(false); } diff --git a/src/BlazorTable/Components/Pager.razor b/src/BlazorTable/Components/Pager.razor index 8cd3332e..9e83ab82 100644 --- a/src/BlazorTable/Components/Pager.razor +++ b/src/BlazorTable/Components/Pager.razor @@ -2,50 +2,78 @@ @if (AlwaysShow || (Table.TotalPages > 1)) { -
- +
+ + } diff --git a/src/BlazorTable/Components/Pager.razor.cs b/src/BlazorTable/Components/Pager.razor.cs index d51bee2b..b6c40229 100644 --- a/src/BlazorTable/Components/Pager.razor.cs +++ b/src/BlazorTable/Components/Pager.razor.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.Localization; using System.Collections.Generic; using System.Threading.Tasks; @@ -43,6 +44,18 @@ public partial class Pager [Parameter] public bool ShowPageSizes { get; set; } + /// + /// Show Pages Numbers + /// + [Parameter] + public bool ShowPageNumberSelector { get; set; } + + /// + /// Show Pages Number selector input + /// + [Parameter] + public bool ShowPageNumberInput { get; set; } + [Inject] IStringLocalizer Localization { get; set; } @@ -53,5 +66,30 @@ private async Task SetPageSizeAsync(ChangeEventArgs args) await Table.SetPageSizeAsync(result).ConfigureAwait(false); } } + + private int inputPage { get; set; } = 1; + + private async Task SetPageInput(KeyboardEventArgs e) + { + if (e.Code == "Enter" || e.Code == "NumpadEnter") + { + await GoToPage().ConfigureAwait(false); + } + } + + private async Task GoToPage() + { + if (inputPage > Table.TotalPages) + { + inputPage = Table.TotalPages; + } + + if (inputPage < 1) + { + inputPage = 1; + } + + await Table.GoToPageAsync(inputPage - 1).ConfigureAwait(false); + } } } diff --git a/src/BlazorTable/Components/Pager.razor.css b/src/BlazorTable/Components/Pager.razor.css new file mode 100644 index 00000000..ef97bc6d --- /dev/null +++ b/src/BlazorTable/Components/Pager.razor.css @@ -0,0 +1,3 @@ +.page-link { + border: none; +} \ No newline at end of file diff --git a/src/BlazorTable/Components/ServerSide/FilterData.cs b/src/BlazorTable/Components/ServerSide/FilterData.cs index b2dbf743..356b97c3 100644 --- a/src/BlazorTable/Components/ServerSide/FilterData.cs +++ b/src/BlazorTable/Components/ServerSide/FilterData.cs @@ -1,6 +1,10 @@ -namespace BlazorTable.Components.ServerSide +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace BlazorTable.Components.ServerSide { - public class FilterData + public class FilterData { public string OrderBy { get; set; } @@ -9,6 +13,10 @@ public class FilterData public int? Top { get; set; } public int? Skip { get; set; } + + public List>> Filters { get; set; } + + public List FilterStrings { get; set; } } } diff --git a/src/BlazorTable/Components/ServerSide/FilterString.cs b/src/BlazorTable/Components/ServerSide/FilterString.cs new file mode 100644 index 00000000..06c878b4 --- /dev/null +++ b/src/BlazorTable/Components/ServerSide/FilterString.cs @@ -0,0 +1,21 @@ +namespace BlazorTable.Components.ServerSide +{ + + public class FilterString + { + /// + /// Field name + /// + public string Field { get; set; } + + /// + /// it should be a enum converted to string according with field type. Available enums are StringCondition, NumberCondition, EnumCondition, CustomSelectCondition and BooleanCondition + /// + public string Condition { get; set; } + + /// + /// Value to filter + /// + public string FilterValue { get; set; } + } +} diff --git a/src/BlazorTable/Components/Table.razor b/src/BlazorTable/Components/Table.razor index f9411af2..dd4e6dbc 100644 --- a/src/BlazorTable/Components/Table.razor +++ b/src/BlazorTable/Components/Table.razor @@ -21,7 +21,7 @@ @if (ShowSearchBar) { - + } @if (Columns.Exists(column => !column.Visible)) { @@ -139,6 +139,24 @@ } + @if(AddExtraTh) + { + + + @if (_detailTemplate != null) + { + + } + @foreach (IColumn column in Columns) + { + @if (column.Visible) + { + + } + } + + + } @if (FilteredItems != null) { @@ -163,7 +181,7 @@ if (!rowDisplayed) { - + @{ int locali = i; diff --git a/src/BlazorTable/Components/Table.razor.cs b/src/BlazorTable/Components/Table.razor.cs index 57c959c3..55e8fdcb 100644 --- a/src/BlazorTable/Components/Table.razor.cs +++ b/src/BlazorTable/Components/Table.razor.cs @@ -56,6 +56,8 @@ public partial class Table : ITable [Parameter] public int PageSize { get; set; } = DEFAULT_PAGE_SIZE; + public int? ServerPageSize { get; set; } + /// /// Allow Columns to be reordered /// @@ -113,7 +115,7 @@ public partial class Table : ITable /// /// List of All Available Columns /// - public List> Columns { get; } = new List>(); + public List> Columns { get; set; } = new List>(); /// /// Current Page Number @@ -142,7 +144,7 @@ public partial class Table : ITable protected override async Task OnParametersSetAsync() { - await UpdateAsync().ConfigureAwait(false); + await UpdateAsync(true).ConfigureAwait(false); } private IEnumerable GetData() @@ -156,6 +158,11 @@ private IEnumerable GetData() ItemsQueryable = Items.AsQueryable(); } + if (DataLoader != null) + { + return ItemsQueryable.ToList(); + } + foreach (var item in Columns) { if (item.Filter != null) @@ -163,11 +170,7 @@ private IEnumerable GetData() ItemsQueryable = ItemsQueryable.Where(item.Filter); } } - - if (DataLoader != null) - { - return ItemsQueryable.ToList(); - } + // Global Search if (!string.IsNullOrEmpty(GlobalSearch)) { @@ -227,9 +230,10 @@ public void ToggleAllDetailsView(bool open) /// /// Gets Data and redraws the Table /// - public async Task UpdateAsync() + public async Task UpdateAsync(bool updateServerData = true) { - await LoadServerSideDataAsync().ConfigureAwait(false); + if(updateServerData) + await LoadServerSideDataAsync().ConfigureAwait(false); FilteredItems = GetData(); Refresh(); } @@ -248,12 +252,28 @@ private async Task LoadServerSideDataAsync() .Append(sortColumn.SortDescending ? "desc" : "asc"); } - var result = await DataLoader.LoadDataAsync(new FilterData + var filters = new List>>(); + var filterStrings = new List(); + if (Columns != null) { - Top = PageSize, + foreach (var item in Columns) + { + if (item.Filter != null) + { + filters.Add(item.Filter); + filterStrings.Add(item.FilterString); + } + } + } + + var result = await DataLoader.LoadDataAsync(new FilterData + { + Top = ServerPageSize.GetValueOrDefault(PageSize), Skip = PageNumber * PageSize, Query = GlobalSearch, - OrderBy = sortExpression.ToString() + OrderBy = sortExpression.ToString(), + Filters = filters, + FilterStrings = filterStrings }).ConfigureAwait(false); Items = result.Records; TotalCount = result.Total.GetValueOrDefault(1); @@ -336,6 +356,18 @@ public async Task LastPageAsync() await UpdateAsync().ConfigureAwait(false); } + /// + /// Go to specific page + /// + /// Page number to go + /// + public async Task GoToPageAsync(int pageNumber) + { + PageNumber = pageNumber; + detailsViewOpen.Clear(); + await UpdateAsync().ConfigureAwait(false); + } + /// /// Redraws the Table using EditTemplate instead of Template /// @@ -348,9 +380,9 @@ public void ToggleEditMode() /// /// Redraws Table without Getting Data /// - public void Refresh() + public async void Refresh() { - InvokeAsync(StateHasChanged); + await InvokeAsync(StateHasChanged); } /// @@ -468,7 +500,7 @@ public SelectionType SelectionType /// Handles the onclick action for table rows. /// This allows the RowClickAction to be optional. /// - private void OnRowClickHandler(TableItem tableItem) + private async void OnRowClickHandler(TableItem tableItem) { try { @@ -488,8 +520,8 @@ private void OnRowClickHandler(TableItem tableItem) SelectedItems.Add(tableItem); break; case SelectionType.Multiple: - if (SelectedItems.Contains(tableItem)) - SelectedItems.Remove(tableItem); + if (SelectedItems.Any(x=> x.CompareEx(tableItem))) + SelectedItems.RemoveAll(x=> x.CompareEx(tableItem)); else SelectedItems.Add(tableItem); break; @@ -560,14 +592,77 @@ private Expression> GlobalSearchQuery(string value) public async Task SetPageSizeAsync(int pageSize) { PageSize = pageSize; + ServerPageSize = pageSize; + PageNumber = 0; + detailsViewOpen.Clear(); await UpdateAsync().ConfigureAwait(false); } + /// + /// Set initial filters to grid + /// + /// + /// + public async Task SetInitialFiltersAsync(IEnumerable filters) + { + foreach (var item in filters) + { + var column = Columns.FirstOrDefault(x => x.Field.GetPropertyMemberInfo().Name == item.Field); + if (column != null && column.Filterable) + { + column.InitialFilterString = item; + if (column.FilterControl == null) + { + if (column.CustomIFilters != null) + column.FilterControl = new CustomSelect() { Column = column }; + else if (column.Type == typeof(string)) + column.FilterControl = new StringFilter() { Column = column }; + else if (column.Type.IsNumeric() && !column.Type.GetNonNullableType().IsEnum) + column.FilterControl = new NumberFilter() { Column = column }; + else if (column.Type.GetNonNullableType().IsEnum) + column.FilterControl = new EnumFilter() { Column = column }; + else if (column.Type.GetNonNullableType() == typeof(DateTime)) + column.FilterControl = new DateFilter() { Column = column }; + else if (new List() { typeof(bool) }.Contains(column.Type.GetNonNullableType())) + column.FilterControl = new BooleanFilter() { Column = column }; + } + column.Filter = column.FilterControl.GetFilter(); + column.FilterString = column.FilterControl.GetFilterString(); + } + } + await FirstPageAsync().ConfigureAwait(false); + await UpdateAsync().ConfigureAwait(false); + } + + /// + /// Clear filter + /// + /// Column name + /// + public async Task ClearFilterAsync(string columnName) + { + var column = Columns.FirstOrDefault(x => x.Field.GetPropertyMemberInfo().Name == columnName); + if (column != null && column.Filterable) + { + column.Filter = null; + column.FilterString = null; + await FirstPageAsync().ConfigureAwait(false); + await UpdateAsync().ConfigureAwait(false); + } + } + + /// /// Show table child content at the top of the table. /// [Parameter] public bool ShowChildContentAtTop { get; set; } + /// + /// Add a new th row + /// + [Parameter] + public bool AddExtraTh { get; set; } + } } diff --git a/src/BlazorTable/Filters/BooleanFilter.razor.cs b/src/BlazorTable/Filters/BooleanFilter.razor.cs index 1b17aeca..3d8aa530 100644 --- a/src/BlazorTable/Filters/BooleanFilter.razor.cs +++ b/src/BlazorTable/Filters/BooleanFilter.razor.cs @@ -1,4 +1,5 @@ -using BlazorTable.Localization; +using BlazorTable.Components.ServerSide; +using BlazorTable.Localization; using Microsoft.AspNetCore.Components; using System; using System.Collections.Generic; @@ -24,6 +25,15 @@ protected override void OnInitialized() { Column.FilterControl = this; + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + + Column.InitialFilterString = null; + + Column.Filter = GetFilter(); + } + if (Column.Filter != null) { var nodeType = Column.Filter.Body.NodeType; @@ -55,6 +65,13 @@ protected override void OnInitialized() public Expression> GetFilter() { + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + + Column.InitialFilterString = null; + } + return Condition switch { BooleanCondition.True => @@ -88,8 +105,18 @@ public Expression> GetFilter() _ => null, }; } + public FilterString GetFilterString() + { + return new FilterString() + { + Field = Column.Field.GetPropertyMemberInfo().Name, + Condition = Condition.ToString() + }; + } } + + public enum BooleanCondition { [LocalizedDescription("BooleanConditionTrue", typeof(Localization.Localization))] diff --git a/src/BlazorTable/Filters/CustomSelect.razor.cs b/src/BlazorTable/Filters/CustomSelect.razor.cs index 9a0c5ca3..72a44666 100644 --- a/src/BlazorTable/Filters/CustomSelect.razor.cs +++ b/src/BlazorTable/Filters/CustomSelect.razor.cs @@ -1,4 +1,5 @@ -using BlazorTable.Localization; +using BlazorTable.Components.ServerSide; +using BlazorTable.Localization; using Microsoft.AspNetCore.Components; using System; using System.Collections.Generic; @@ -26,6 +27,15 @@ protected override void OnInitialized() { Column.FilterControl = this; + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterValue = Column.InitialFilterString.FilterValue; + Column.InitialFilterString = null; + + Column.Filter = GetFilter(); + } + if (Column.Filter?.Body is BinaryExpression binaryExpression && binaryExpression.Right is BinaryExpression logicalBinary && logicalBinary.Right is ConstantExpression constant) @@ -46,6 +56,14 @@ protected override void OnInitialized() public Expression> GetFilter() { + + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterValue = Column.InitialFilterString.FilterValue; + Column.InitialFilterString = null; + } + return Condition switch { CustomSelectCondition.IsEqualTo => @@ -83,6 +101,16 @@ public Expression> GetFilter() }; } + public FilterString GetFilterString() + { + return new FilterString() + { + Field = Column.Field.GetPropertyMemberInfo().Name, + Condition = Condition.ToString(), + FilterValue = FilterValue.ToString() + }; + } + public void AddSelect(string key, object value) { Items.Add(new KeyValuePair(key, value)); diff --git a/src/BlazorTable/Filters/DateFilter.razor.cs b/src/BlazorTable/Filters/DateFilter.razor.cs index 52170959..17bb6154 100644 --- a/src/BlazorTable/Filters/DateFilter.razor.cs +++ b/src/BlazorTable/Filters/DateFilter.razor.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Components; +using BlazorTable.Components.ServerSide; +using Microsoft.AspNetCore.Components; using System; using System.Linq.Expressions; @@ -19,6 +20,17 @@ protected override void OnInitialized() { Column.FilterControl = this; + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + if (DateTime.TryParse(Column.InitialFilterString.FilterValue, out DateTime filterValue)) + FilterValue = filterValue; + + Column.InitialFilterString = null; + + Column.Filter = GetFilter(); + } + if (Column.Filter?.Body is BinaryExpression binaryExpression && binaryExpression.Right is BinaryExpression logicalBinary && logicalBinary.Right is ConstantExpression constant) @@ -55,6 +67,15 @@ protected override void OnInitialized() public Expression> GetFilter() { + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + if (DateTime.TryParse(Column.InitialFilterString.FilterValue, out DateTime filterValue)) + FilterValue = filterValue; + + Column.InitialFilterString = null; + } + return Condition switch { NumberCondition.IsEqualTo => @@ -128,5 +149,15 @@ public Expression> GetFilter() _ => throw new ArgumentException(Condition + " is not defined!"), }; } + + public FilterString GetFilterString() + { + return new FilterString() + { + Field = Column.Field.GetPropertyMemberInfo().Name, + Condition = Condition.ToString(), + FilterValue = FilterValue.ToString("MM-dd-yyyy") + }; + } } } \ No newline at end of file diff --git a/src/BlazorTable/Filters/EnumFilter.razor.cs b/src/BlazorTable/Filters/EnumFilter.razor.cs index 29807eca..89c41069 100644 --- a/src/BlazorTable/Filters/EnumFilter.razor.cs +++ b/src/BlazorTable/Filters/EnumFilter.razor.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq.Expressions; using Microsoft.Extensions.Localization; +using BlazorTable.Components.ServerSide; namespace BlazorTable { @@ -25,6 +26,15 @@ protected override void OnInitialized() { Column.FilterControl = this; + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterValue = Column.InitialFilterString.FilterValue; + Column.InitialFilterString = null; + + Column.Filter = GetFilter(); + } + if (Column.Filter?.Body is BinaryExpression binaryExpression && binaryExpression.Right is BinaryExpression logicalBinary && logicalBinary.Right is ConstantExpression constant) @@ -51,6 +61,13 @@ protected override void OnInitialized() public Expression> GetFilter() { + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterValue = Column.InitialFilterString.FilterValue; + Column.InitialFilterString = null; + } + return Condition switch { EnumCondition.IsEqualTo => @@ -89,6 +106,16 @@ public Expression> GetFilter() }; } + public FilterString GetFilterString() + { + return new FilterString() + { + Field = Column.Field.GetPropertyMemberInfo().Name, + Condition = Condition.ToString(), + FilterValue = FilterValue.ToString() + }; + } + public enum EnumCondition { [LocalizedDescription("EnumConditionIsEqualTo", typeof(Localization.Localization))] diff --git a/src/BlazorTable/Filters/NumberFilter.razor.cs b/src/BlazorTable/Filters/NumberFilter.razor.cs index d4131981..00ed499d 100644 --- a/src/BlazorTable/Filters/NumberFilter.razor.cs +++ b/src/BlazorTable/Filters/NumberFilter.razor.cs @@ -1,4 +1,5 @@ -using BlazorTable.Localization; +using BlazorTable.Components.ServerSide; +using BlazorTable.Localization; using Microsoft.AspNetCore.Components; using System; using System.Globalization; @@ -24,6 +25,16 @@ protected override void OnInitialized() { Column.FilterControl = this; + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterValue = Column.InitialFilterString.FilterValue; + Column.InitialFilterString = null; + + Column.Filter = GetFilter(); + } + + if (Column.Filter?.Body is BinaryExpression binaryExpression && binaryExpression.Right is BinaryExpression logicalBinary && logicalBinary.Right is ConstantExpression constant) @@ -60,6 +71,13 @@ protected override void OnInitialized() public Expression> GetFilter() { + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterValue = Column.InitialFilterString.FilterValue; + Column.InitialFilterString = null; + } + if (Condition != NumberCondition.IsNull && Condition != NumberCondition.IsNotNull && string.IsNullOrEmpty(FilterValue)) { return null; @@ -138,6 +156,17 @@ public Expression> GetFilter() _ => throw new ArgumentException(Condition + " is not defined!"), }; } + + public FilterString GetFilterString() + { + + return new FilterString() + { + Field = Column.Field.GetPropertyMemberInfo().Name, + Condition = Condition.ToString(), + FilterValue = FilterValue + }; + } } public enum NumberCondition diff --git a/src/BlazorTable/Filters/StringFilter.razor.cs b/src/BlazorTable/Filters/StringFilter.razor.cs index d86440c6..1f8a7cdb 100644 --- a/src/BlazorTable/Filters/StringFilter.razor.cs +++ b/src/BlazorTable/Filters/StringFilter.razor.cs @@ -1,4 +1,5 @@ -using BlazorTable.Localization; +using BlazorTable.Components.ServerSide; +using BlazorTable.Localization; using Microsoft.AspNetCore.Components; using System; using System.Linq.Expressions; @@ -25,6 +26,15 @@ protected override void OnInitialized() { Column.FilterControl = this; + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterText = Column.InitialFilterString.FilterValue; + Column.InitialFilterString = null; + + Column.Filter = GetFilter(); + } + if (Column.Filter != null) { bool NotCondition = false; @@ -87,6 +97,15 @@ private StringCondition GetConditionFromMethod(string method, bool not) public Expression> GetFilter() { + + if (Column.InitialFilterString != null) + { + Condition = Utilities.ParseEnum(Column.InitialFilterString.Condition); + FilterText = Column.InitialFilterString.FilterValue; + + Column.InitialFilterString = null; + } + FilterText = FilterText?.Trim(); if (Condition != StringCondition.IsNullOrEmpty && Condition != StringCondition.IsNotNulOrEmpty && string.IsNullOrEmpty(FilterText)) @@ -183,6 +202,18 @@ public Expression> GetFilter() _ => throw new ArgumentException(Condition + " is not defined!"), }; } + + public FilterString GetFilterString() + { + FilterText = FilterText?.Trim(); + + return new FilterString() + { + Field = Column.Field.GetPropertyMemberInfo().Name, + Condition = Condition.ToString(), + FilterValue = FilterText + }; + } } public enum StringCondition diff --git a/src/BlazorTable/Interfaces/IColumn.cs b/src/BlazorTable/Interfaces/IColumn.cs index d5d13ae3..c6783d9c 100644 --- a/src/BlazorTable/Interfaces/IColumn.cs +++ b/src/BlazorTable/Interfaces/IColumn.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Components; +using BlazorTable.Components.ServerSide; +using Microsoft.AspNetCore.Components; using System; using System.Linq.Expressions; using System.Threading.Tasks; @@ -49,7 +50,7 @@ public interface IColumn /// /// Filter Panel is open /// - bool FilterOpen { get; } + bool FilterOpen { get; set; } /// /// Column visibility @@ -84,6 +85,16 @@ public interface IColumn /// Expression> Filter { get; set; } + /// + /// Filter as string + /// + FilterString FilterString { get; set; } + + /// + /// Filter as string + /// + FilterString InitialFilterString { get; set; } + /// /// Edit Mode Item Template /// diff --git a/src/BlazorTable/Interfaces/IDataLoader.cs b/src/BlazorTable/Interfaces/IDataLoader.cs index c9d38047..6a1911d2 100644 --- a/src/BlazorTable/Interfaces/IDataLoader.cs +++ b/src/BlazorTable/Interfaces/IDataLoader.cs @@ -1,10 +1,12 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using BlazorTable.Components.ServerSide; namespace BlazorTable.Interfaces { public interface IDataLoader { - public Task> LoadDataAsync(FilterData parameters); + public Task> LoadDataAsync(FilterData parameters); + } } diff --git a/src/BlazorTable/Interfaces/IFilter.cs b/src/BlazorTable/Interfaces/IFilter.cs index 77800215..917dd99c 100644 --- a/src/BlazorTable/Interfaces/IFilter.cs +++ b/src/BlazorTable/Interfaces/IFilter.cs @@ -1,4 +1,5 @@ -using System; +using BlazorTable.Components.ServerSide; +using System; using System.Linq.Expressions; namespace BlazorTable @@ -14,5 +15,11 @@ public interface IFilter /// /// Expression> GetFilter(); + + /// + /// Get filter as string object + /// + /// + FilterString GetFilterString(); } } diff --git a/src/BlazorTable/Interfaces/ITable.cs b/src/BlazorTable/Interfaces/ITable.cs index 7af8de02..c5c203ca 100644 --- a/src/BlazorTable/Interfaces/ITable.cs +++ b/src/BlazorTable/Interfaces/ITable.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using BlazorTable.Components.ServerSide; +using System.Collections.Generic; +using System.Threading.Tasks; namespace BlazorTable { @@ -12,6 +14,8 @@ public interface ITable /// int PageSize { get; } + int? ServerPageSize { get; } + /// /// Allow Columns to be reordered /// @@ -58,6 +62,11 @@ public interface ITable /// Task LastPageAsync(); + /// + /// Go to Specific Page Async + /// + Task GoToPageAsync(int pageNumber); + /// /// Redraws the Table using EditTemplate instead of Template /// @@ -86,7 +95,9 @@ public interface ITable /// /// Gets Data and redraws the Table /// - Task UpdateAsync(); + /// false if it is not needed to update server data + /// + Task UpdateAsync(bool updateServerData = true); /// /// Open/Close detail view in specified row. /// @@ -138,5 +149,12 @@ public interface ITable /// /// Task SetPageSizeAsync(int pageSize); + + /// + /// Set initial filters + /// + /// + /// + Task SetInitialFiltersAsync(IEnumerable filters); } } diff --git a/src/BlazorTable/Interfaces/ITableGen.cs b/src/BlazorTable/Interfaces/ITableGen.cs index 72eaa7ae..14a49b40 100644 --- a/src/BlazorTable/Interfaces/ITableGen.cs +++ b/src/BlazorTable/Interfaces/ITableGen.cs @@ -14,7 +14,7 @@ public interface ITable : ITable /// /// List of All Available Columns /// - List> Columns { get; } + List> Columns { get; set; } /// /// Adds a Column to the Table diff --git a/src/BlazorTable/Localization/Localization.Designer.cs b/src/BlazorTable/Localization/Localization.Designer.cs index f5e12743..51c77472 100644 --- a/src/BlazorTable/Localization/Localization.Designer.cs +++ b/src/BlazorTable/Localization/Localization.Designer.cs @@ -19,7 +19,7 @@ namespace BlazorTable.Localization { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Localization { @@ -195,6 +195,15 @@ internal static string FilterManagerClose { } } + /// + /// Looks up a localized string similar to Go to page:. + /// + internal static string GoToPage { + get { + return ResourceManager.GetString("GoToPage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Is equal to. /// @@ -303,6 +312,15 @@ internal static string PagerPrevious { } } + /// + /// Looks up a localized string similar to Set Page Size. + /// + internal static string SetPageSize { + get { + return ResourceManager.GetString("SetPageSize", resourceCulture); + } + } + /// /// Looks up a localized string similar to Contains. /// diff --git a/src/BlazorTable/Localization/Localization.da.resx b/src/BlazorTable/Localization/Localization.da.resx index dd9bd6d1..886a99a5 100644 --- a/src/BlazorTable/Localization/Localization.da.resx +++ b/src/BlazorTable/Localization/Localization.da.resx @@ -162,6 +162,9 @@ Luk + + Gå til side: + Er lig med diff --git a/src/BlazorTable/Localization/Localization.de.resx b/src/BlazorTable/Localization/Localization.de.resx index 05448a3d..0fc4cab1 100644 --- a/src/BlazorTable/Localization/Localization.de.resx +++ b/src/BlazorTable/Localization/Localization.de.resx @@ -162,6 +162,9 @@ Schließen + + Gehe zur seite: + Ist gleich diff --git a/src/BlazorTable/Localization/Localization.es.resx b/src/BlazorTable/Localization/Localization.es.resx index 7053e2f8..be0a2928 100644 --- a/src/BlazorTable/Localization/Localization.es.resx +++ b/src/BlazorTable/Localization/Localization.es.resx @@ -1,17 +1,17 @@  - @@ -231,4 +231,7 @@ Cargando... - + + Ir a página: + + \ No newline at end of file diff --git a/src/BlazorTable/Localization/Localization.fr.resx b/src/BlazorTable/Localization/Localization.fr.resx index adaa484b..4b5c2d2a 100644 --- a/src/BlazorTable/Localization/Localization.fr.resx +++ b/src/BlazorTable/Localization/Localization.fr.resx @@ -53,6 +53,7 @@ value : The object must be serialized with : System.Runtime.Serialization.Formatters.Soap.SoapFormatter : and then encoded with base64 encoding. + mimetype: application/x-microsoft.net.object.bytearray.base64 value : The object must be serialized into a byte array : using a System.ComponentModel.TypeConverter @@ -161,6 +162,9 @@ Fermer + + Aller à la page: + Est égal à diff --git a/src/BlazorTable/Localization/Localization.pt-BR.resx b/src/BlazorTable/Localization/Localization.pt-BR.resx index 7c54a348..6dfa8f70 100644 --- a/src/BlazorTable/Localization/Localization.pt-BR.resx +++ b/src/BlazorTable/Localization/Localization.pt-BR.resx @@ -162,6 +162,9 @@ Fechar + + Vá para página: + É igual a diff --git a/src/BlazorTable/Localization/Localization.resx b/src/BlazorTable/Localization/Localization.resx index 8c94477f..1ebe5fb5 100644 --- a/src/BlazorTable/Localization/Localization.resx +++ b/src/BlazorTable/Localization/Localization.resx @@ -162,6 +162,9 @@ Close + + Go to page: + Is equal to @@ -198,6 +201,9 @@ Previous + + Set Page Size + Contains diff --git a/src/BlazorTable/Localization/Localization.zh-CN.resx b/src/BlazorTable/Localization/Localization.zh-CN.resx index 27f84536..847f9216 100644 --- a/src/BlazorTable/Localization/Localization.zh-CN.resx +++ b/src/BlazorTable/Localization/Localization.zh-CN.resx @@ -162,6 +162,9 @@ 关闭 + + 转到页面: + 等于 @@ -231,4 +234,4 @@ 加载中... - + \ No newline at end of file diff --git a/src/BlazorTable/Properties/PublishProfiles/FolderProfile.pubxml b/src/BlazorTable/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 00000000..6f5e1117 --- /dev/null +++ b/src/BlazorTable/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,12 @@ + + + + + Release + Any CPU + bin\Release\netstandard2.1\publish\ + FileSystem + + \ No newline at end of file diff --git a/src/BlazorTable/Utillities.cs b/src/BlazorTable/Utillities.cs index f7359284..09399f6f 100644 --- a/src/BlazorTable/Utillities.cs +++ b/src/BlazorTable/Utillities.cs @@ -1,4 +1,5 @@ using LinqKit; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; @@ -181,6 +182,11 @@ public static string ToDescriptionString(this Enum val) return attributes.Length > 0 ? attributes[0].Description : string.Empty; } + public static T ParseEnum(string value) + { + return (T)Enum.Parse(typeof(T), value, true); + } + /// /// Recursively walks up the tree and adds null checks /// @@ -229,5 +235,17 @@ public static BinaryExpression CreateNullChecks(this Expression expression, bool return newExpression; } + + public static bool CompareEx(this object obj, object another) + { + if (ReferenceEquals(obj, another)) return true; + if ((obj == null) || (another == null)) return false; + if (obj.GetType() != another.GetType()) return false; + + var objJson = JsonConvert.SerializeObject(obj); + var anotherJson = JsonConvert.SerializeObject(another); + + return objJson == anotherJson; + } } }