From 5c58cf8f3ef81a93e3633418f3baa12f45b1a705 Mon Sep 17 00:00:00 2001 From: David Moreira Date: Thu, 25 Jan 2024 09:35:03 +0000 Subject: [PATCH] DataGrid: Auto Generate Columns (#5232) * DataGrid | Make it so the DataGrid is able to programatically add columns correctly * DataGrid | AutoGenerateColumns based on model properties * try crlf * AutoGenerateColumns | NullCheck Columns | Generate even if Command Or MultiSelect columns are defined. * DataGridColumn | Fix defaults initialization | It needs to be OnInitialized after parameters are set * ResolveCaption | PascalCaseToFriendlyName * PascalCaseToFriendlyName_Returns_FriendlyFormat | Add null case * Generate Select for enum | Editable If setter available * Add demo page for Auto Generate Columns * Dashboard revert to original * Docs : Add example page --- .../Blazorise.Demo/Components/SideMenu.razor | 4 ++ .../DataGrid/AutoGenerateColumnsPage.razor | 55 ++++++++++++++++++ .../Blazorise.Docs/Layouts/DocsLayout.razor | 1 + .../Models/Snippets.generated.cs | 45 +++++++++++++++ ...ataGridAutoGenerateColumnsExampleCode.html | 49 ++++++++++++++++ .../DataGridAutoGenerateColumnsExample.razor | 45 +++++++++++++++ .../Features/AutoGenerateColumnsPage.razor | 34 +++++++++++ Shared/Blazorise.Shared/Data/PageEntryData.cs | 1 + Shared/Blazorise.Shared/Models/Employee.cs | 21 ++++++- Source/Blazorise/Utilities/Formaters.cs | 31 ++++++++++ .../Blazorise/Utilities/ReflectionHelper.cs | 44 +++++++++++++++ .../BaseDataGridComponent.cs | 8 +-- .../Blazorise.DataGrid/DataGrid.razor.cs | 56 +++++++++++++++++++ .../Blazorise.DataGrid/DataGridColumn.cs | 45 ++++++++++++--- .../Blazorise.DataGrid/GlobalSuppressions.cs | 8 +++ Tests/Blazorise.Tests/Utils/FormatersTests.cs | 22 ++++++-- 16 files changed, 449 insertions(+), 20 deletions(-) create mode 100644 Demos/Blazorise.Demo/Pages/Tests/DataGrid/AutoGenerateColumnsPage.razor create mode 100644 Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Code/DataGridAutoGenerateColumnsExampleCode.html create mode 100644 Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Examples/DataGridAutoGenerateColumnsExample.razor create mode 100644 Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Features/AutoGenerateColumnsPage.razor create mode 100644 Source/Blazorise/Utilities/ReflectionHelper.cs create mode 100644 Source/Extensions/Blazorise.DataGrid/GlobalSuppressions.cs diff --git a/Demos/Blazorise.Demo/Components/SideMenu.razor b/Demos/Blazorise.Demo/Components/SideMenu.razor index d8fd8f6907..5edb9d9558 100644 --- a/Demos/Blazorise.Demo/Components/SideMenu.razor +++ b/Demos/Blazorise.Demo/Components/SideMenu.razor @@ -101,6 +101,10 @@ Aggregates + + Auto Generate Columns + + Columns diff --git a/Demos/Blazorise.Demo/Pages/Tests/DataGrid/AutoGenerateColumnsPage.razor b/Demos/Blazorise.Demo/Pages/Tests/DataGrid/AutoGenerateColumnsPage.razor new file mode 100644 index 0000000000..c7bf03d847 --- /dev/null +++ b/Demos/Blazorise.Demo/Pages/Tests/DataGrid/AutoGenerateColumnsPage.razor @@ -0,0 +1,55 @@ +@page "/tests/datagrid/auto-generate-columns" +@using System.ComponentModel.DataAnnotations + + + + + Datagrid: Auto Generate Columns + + + + + + + + + + +@code { + + public class Example + { + [DisplayAttribute(Name = "Name")] + public string FirstName { get; set; } + + public string LastName { get; set; } + + + public int Age { get; set; } + + public decimal Balance { get; set; } + + public Status Status { get; set; } + } + + public enum Status + { + Active, + Inactive + } + + private IEnumerable data = new List() + { + new(){ FirstName = "John", LastName = "Doe", Age = 30, Balance = 1000, Status = Status.Active }, + new(){ FirstName = "Jane", LastName = "Doe", Age = 28, Balance = 2000, Status = Status.Active }, + new(){ FirstName = "Joe", LastName = "Doe", Age = 26, Balance = 3000, Status = Status.Inactive }, + new(){ FirstName = "Jill", LastName = "Doe", Age = 24, Balance = 4000, Status = Status.Inactive }, + new(){ FirstName = "Jack", LastName = "Doe", Age = 22, Balance = 5000, Status = Status.Active }, + new(){ FirstName = "Jen", LastName = "Doe", Age = 20, Balance = 6000, Status = Status.Active }, + }; + +} \ No newline at end of file diff --git a/Documentation/Blazorise.Docs/Layouts/DocsLayout.razor b/Documentation/Blazorise.Docs/Layouts/DocsLayout.razor index a3bf5df896..9f66b98053 100644 --- a/Documentation/Blazorise.Docs/Layouts/DocsLayout.razor +++ b/Documentation/Blazorise.Docs/Layouts/DocsLayout.razor @@ -176,6 +176,7 @@ Editing Filtering Resizing + Auto Generate Columns Fixed Columns Fixed Header Context Menu diff --git a/Documentation/Blazorise.Docs/Models/Snippets.generated.cs b/Documentation/Blazorise.Docs/Models/Snippets.generated.cs index b85746a33c..c40beac86b 100644 --- a/Documentation/Blazorise.Docs/Models/Snippets.generated.cs +++ b/Documentation/Blazorise.Docs/Models/Snippets.generated.cs @@ -6390,6 +6390,51 @@ private Task OnPredefinedClicked() => dataGrid.ApplySorting( new DataGridSortColumnInfo(nameof(Employee.Childrens), SortDirection.Descending), new DataGridSortColumnInfo(nameof(Employee.Gender), SortDirection.Ascending) ); +}"; + + public const string DataGridAutoGenerateColumnsExample = @"@using System.ComponentModel.DataAnnotations + + + + + +@code { + + public class Example + { + [Display( Name = ""Name"" )] + public string FirstName { get; set; } + + public string LastName { get; set; } + + + public int Age { get; set; } + + public decimal Balance { get; set; } + + public Status Status { get; set; } + } + + public enum Status + { + Active, + Inactive + } + + private IEnumerable data = new List() + { + new(){ FirstName = ""John"", LastName = ""Doe"", Age = 30, Balance = 1000, Status = Status.Active }, + new(){ FirstName = ""Jane"", LastName = ""Doe"", Age = 28, Balance = 2000, Status = Status.Active }, + new(){ FirstName = ""Joe"", LastName = ""Doe"", Age = 26, Balance = 3000, Status = Status.Inactive }, + new(){ FirstName = ""Jill"", LastName = ""Doe"", Age = 24, Balance = 4000, Status = Status.Inactive }, + new(){ FirstName = ""Jack"", LastName = ""Doe"", Age = 22, Balance = 5000, Status = Status.Active }, + new(){ FirstName = ""Jen"", LastName = ""Doe"", Age = 20, Balance = 6000, Status = Status.Active }, + }; + }"; public const string DataGridBatchEditExample = @" diff --git a/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Code/DataGridAutoGenerateColumnsExampleCode.html b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Code/DataGridAutoGenerateColumnsExampleCode.html new file mode 100644 index 0000000000..3a9867b31e --- /dev/null +++ b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Code/DataGridAutoGenerateColumnsExampleCode.html @@ -0,0 +1,49 @@ +
+
+@using System.ComponentModel.DataAnnotations
+
+<DataGrid TItem="Example"
+            Data="data"
+            Responsive
+            ShowPager
+            ShowPageSizes Editable>
+    <DataGridCommandColumn TItem="Example" />
+</DataGrid>
+
+
+@code {
+
+    public class Example
+    {
+        [Display( Name = "Name" )]
+        public string FirstName { get; set; }
+
+        public string LastName { get; set; }
+
+
+        public int Age { get; set; }
+
+        public decimal Balance { get; set; }
+
+        public Status Status { get; set; }
+    }
+
+    public enum Status
+    {
+        Active,
+        Inactive
+    }
+
+    private IEnumerable<Example> data = new List<Example>()
+    {
+        new(){ FirstName = "John", LastName = "Doe", Age = 30, Balance = 1000, Status = Status.Active },
+        new(){ FirstName = "Jane", LastName = "Doe", Age = 28, Balance = 2000, Status = Status.Active },
+        new(){ FirstName = "Joe", LastName = "Doe", Age = 26, Balance = 3000, Status = Status.Inactive },
+        new(){ FirstName = "Jill", LastName = "Doe", Age = 24, Balance = 4000, Status = Status.Inactive },
+        new(){ FirstName = "Jack", LastName = "Doe", Age = 22, Balance = 5000, Status = Status.Active },
+        new(){ FirstName = "Jen", LastName = "Doe", Age = 20, Balance = 6000, Status = Status.Active },
+    };
+
+}
+
+
diff --git a/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Examples/DataGridAutoGenerateColumnsExample.razor b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Examples/DataGridAutoGenerateColumnsExample.razor new file mode 100644 index 0000000000..f78238ff13 --- /dev/null +++ b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Examples/DataGridAutoGenerateColumnsExample.razor @@ -0,0 +1,45 @@ +@namespace Blazorise.Docs.Docs.Examples +@using System.ComponentModel.DataAnnotations + + + + + +@code { + + public class Example + { + [Display( Name = "Name" )] + public string FirstName { get; set; } + + public string LastName { get; set; } + + + public int Age { get; set; } + + public decimal Balance { get; set; } + + public Status Status { get; set; } + } + + public enum Status + { + Active, + Inactive + } + + private IEnumerable data = new List() + { + new(){ FirstName = "John", LastName = "Doe", Age = 30, Balance = 1000, Status = Status.Active }, + new(){ FirstName = "Jane", LastName = "Doe", Age = 28, Balance = 2000, Status = Status.Active }, + new(){ FirstName = "Joe", LastName = "Doe", Age = 26, Balance = 3000, Status = Status.Inactive }, + new(){ FirstName = "Jill", LastName = "Doe", Age = 24, Balance = 4000, Status = Status.Inactive }, + new(){ FirstName = "Jack", LastName = "Doe", Age = 22, Balance = 5000, Status = Status.Active }, + new(){ FirstName = "Jen", LastName = "Doe", Age = 20, Balance = 6000, Status = Status.Active }, + }; + +} \ No newline at end of file diff --git a/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Features/AutoGenerateColumnsPage.razor b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Features/AutoGenerateColumnsPage.razor new file mode 100644 index 0000000000..9d84ff421f --- /dev/null +++ b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Features/AutoGenerateColumnsPage.razor @@ -0,0 +1,34 @@ +@page "/docs/extensions/datagrid/features/auto-generate-columns" + + + + + Blazorise DataGrid: Auto Generate Columns + + + + The DataGrid can automatically generate columns based on the TItem type. + + + + Overview + + + + If no columns are defined, the DataGrid will automatically generate columns based on the TItem type. + + + + Example + + + + + + + + + + + + \ No newline at end of file diff --git a/Shared/Blazorise.Shared/Data/PageEntryData.cs b/Shared/Blazorise.Shared/Data/PageEntryData.cs index c4037f03c8..36a39337dd 100644 --- a/Shared/Blazorise.Shared/Data/PageEntryData.cs +++ b/Shared/Blazorise.Shared/Data/PageEntryData.cs @@ -105,6 +105,7 @@ private Task LoadData( ICacheEntry cacheEntry ) new PageEntry( "docs/extensions/datagrid/features/context-menu", "DataGrid Context Menu", "Right-click on any row to access options such as editing, deleting, and custom actions." ), new PageEntry( "docs/extensions/datagrid/features/editing", "DataGrid Editing", "The DataGrid can perform some basic CRUD operations on the supplied Data collection." ), new PageEntry( "docs/extensions/datagrid/features/filtering", "DataGrid Filtering", "Quickly search and filter by any column, or customize filter options to fit your needs." ), + new PageEntry( "docs/extensions/datagrid/features/auto-generate-columns", "DataGrid Auto Generate Columns", "The DataGrid can automatically generate columns based on the TItem type." ), new PageEntry( "docs/extensions/datagrid/features/fixed-columns", "DataGrid Fixed Columns", "The table columns remains visible as you scroll, making it easy to identify and reference the data in your grid." ), new PageEntry( "docs/extensions/datagrid/features/fixed-header", "DataGrid Fixed Header", "The table header remains visible as you scroll, making it easy to identify and reference the data in your grid." ), new PageEntry( "docs/extensions/datagrid/features/grouping", "DataGrid Grouping", "Grouping feature for Blazorise DataGrid allows you to easily group and organize your data by specific columns." ), diff --git a/Shared/Blazorise.Shared/Models/Employee.cs b/Shared/Blazorise.Shared/Models/Employee.cs index 21e5c8ce64..4c7b01d389 100644 --- a/Shared/Blazorise.Shared/Models/Employee.cs +++ b/Shared/Blazorise.Shared/Models/Employee.cs @@ -28,6 +28,7 @@ public Employee( Employee other ) Zip = other.Zip; } + [Display( Name = "Id" )] public int Id { get; set; } [Required] @@ -38,14 +39,28 @@ public Employee( Employee other ) [Required] [EmailAddress] + [Display( Name = "Email" )] public string Email { get; set; } + [Display( Name = "City" )] public string City { get; set; } + + [Display( Name = "Zip" )] public string Zip { get; set; } + + [Display( Name = "DOB" )] public DateTime? DateOfBirth { get; set; } + + [Display( Name = "Childrens" )] public int? Childrens { get; set; } + + [Display( Name = "Gender" )] public string Gender { get; set; } + + [Display( Name = "Salary" )] public decimal Salary { get; set; } + + [Display( Name = "Tax" )] public decimal Tax { get @@ -56,6 +71,8 @@ public decimal Tax } set { tax = value; } } + + [Display( Name = "Active" )] public bool IsActive { get; set; } public List Salaries { get; set; } = new(); @@ -68,4 +85,6 @@ public decimal ChildrensPerSalary public decimal TaxPercentage = 0.25m; private decimal tax; -} \ No newline at end of file +} + + diff --git a/Source/Blazorise/Utilities/Formaters.cs b/Source/Blazorise/Utilities/Formaters.cs index fceb46bf80..d357c7a082 100644 --- a/Source/Blazorise/Utilities/Formaters.cs +++ b/Source/Blazorise/Utilities/Formaters.cs @@ -1,6 +1,7 @@ #region Using directives using System; using System.Globalization; +using System.Text; #endregion namespace Blazorise.Utilities; @@ -114,4 +115,34 @@ public static string ToFileSize( long source ) return string.Concat( bytes, " Bytes" ); } } + + /// + /// Formats the supplied Pascal Case value to a friendly name with spaces. + /// + /// + /// + public static string PascalCaseToFriendlyName( string input ) + { + if ( string.IsNullOrWhiteSpace( input ) ) + return input; + + StringBuilder result = new StringBuilder(); + var firstUpperChar = true; + foreach ( char c in input ) + { + if ( char.IsUpper( c ) && result.Length > 0 && !firstUpperChar ) + { + result.Append( ' ' ); + } + + if ( char.IsUpper( c ) ) + { + firstUpperChar = false; + } + + result.Append( c ); + } + + return result.ToString(); + } } \ No newline at end of file diff --git a/Source/Blazorise/Utilities/ReflectionHelper.cs b/Source/Blazorise/Utilities/ReflectionHelper.cs new file mode 100644 index 0000000000..d0993eb29c --- /dev/null +++ b/Source/Blazorise/Utilities/ReflectionHelper.cs @@ -0,0 +1,44 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Reflection; + +namespace Blazorise.Utilities; + +/// +/// An helper for reflection based apis. +/// +public class ReflectionHelper +{ + /// + /// Gets the public instance properties of the specified type. + /// + /// + /// + public static PropertyInfo[] GetPublicProperties() + { + var properties = typeof( T ).GetProperties( BindingFlags.Public | BindingFlags.Instance ); + return properties; + } + + /// + /// Based on this particular property, tries to resolve a caption out of the attributes. + /// + /// + /// + public static string ResolveCaption( PropertyInfo propertyInfo ) + { + var displayAttribute = propertyInfo.GetCustomAttribute(); + if ( displayAttribute is not null ) + { + return displayAttribute.GetName(); + } + + var displayNameAttribute = propertyInfo.GetCustomAttribute(); + if ( displayNameAttribute is not null ) + { + return displayNameAttribute.DisplayName; + } + + return Formaters.PascalCaseToFriendlyName( propertyInfo.Name ); + } +} diff --git a/Source/Extensions/Blazorise.DataGrid/BaseDataGridComponent.cs b/Source/Extensions/Blazorise.DataGrid/BaseDataGridComponent.cs index f278734661..11f0f34acb 100644 --- a/Source/Extensions/Blazorise.DataGrid/BaseDataGridComponent.cs +++ b/Source/Extensions/Blazorise.DataGrid/BaseDataGridComponent.cs @@ -17,13 +17,13 @@ public class BaseDataGridComponent : BaseAfterRenderComponent, IAsyncDisposable protected override void OnInitialized() { + base.OnInitialized(); + if ( JSModule is null ) { JSModule = new JSDataGridModule( JSRuntime, VersionProvider ); } - base.OnInitialized(); - ElementId ??= IdGenerator.Generate; } @@ -46,12 +46,12 @@ protected override async ValueTask DisposeAsync( bool disposing ) /// /// Gets or sets the JS runtime. /// - [Inject] private IJSRuntime JSRuntime { get; set; } + [Inject] protected IJSRuntime JSRuntime { get; set; } /// /// Gets or sets the version provider. /// - [Inject] private IVersionProvider VersionProvider { get; set; } + [Inject] protected IVersionProvider VersionProvider { get; set; } /// /// Gets or sets the classname provider. diff --git a/Source/Extensions/Blazorise.DataGrid/DataGrid.razor.cs b/Source/Extensions/Blazorise.DataGrid/DataGrid.razor.cs index 9033add2c4..930902c160 100644 --- a/Source/Extensions/Blazorise.DataGrid/DataGrid.razor.cs +++ b/Source/Extensions/Blazorise.DataGrid/DataGrid.razor.cs @@ -10,6 +10,7 @@ using Blazorise.Extensions; using Blazorise.Licensing; using Blazorise.Modules; +using Blazorise.Utilities; using Force.DeepCloner; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; @@ -333,6 +334,11 @@ public void AddColumn( DataGridColumn column ) => /// If true method will suppress the event. internal void AddColumn( DataGridColumn column, bool suppressSortChangedEvent ) { + if ( column.ParentDataGrid is null ) + { + column.InitializeGeneratedColumn( this, ServiceProvider ); + } + Columns.Add( column ); if ( column.Grouping ) @@ -462,6 +468,11 @@ protected override async Task OnAfterRenderAsync( bool firstRender ) { if ( firstRender ) { + if ( Columns.IsNullOrEmpty() || Columns.Where( x => !( x.IsCommandColumn || x.IsMultiSelectColumn ) ).Count() == 0 ) + { + AutoGenerateColumns(); + } + IsClientMacintoshOS = await IsUserAgentMacintoshOS(); await JSModule.Initialize( tableRef.ElementRef, ElementId ); paginationContext.SubscribeOnPageSizeChanged( OnPageSizeChanged ); @@ -483,6 +494,46 @@ protected override async Task OnAfterRenderAsync( bool firstRender ) await base.OnAfterRenderAsync( firstRender ); } + /// + /// Auto generates columns based on the properties. + /// + private void AutoGenerateColumns() + { + var properties = ReflectionHelper.GetPublicProperties(); + foreach ( var property in properties ) + { + if ( !( property.PropertyType.IsValueType || property.PropertyType == typeof( string ) ) ) + { + continue; + } + + DataGridColumn column; + + if ( property.PropertyType.IsEnum ) + { + var enumValues = Enum.GetValues( property.PropertyType ).Cast(); + + column = new DataGridSelectColumn() + { + Data = enumValues, + TextField = x => x?.ToString(), + ValueField = x => x, + }; + } + else + { + column = new DataGridColumn(); + } + + column.Editable = property.SetMethod is not null; + column.Caption = ReflectionHelper.ResolveCaption( property ); + column.Field = property.Name; + this.AddColumn( column ); + } + + StateHasChanged(); + } + /// protected override ValueTask DisposeAsync( bool disposing ) { @@ -2458,6 +2509,11 @@ private DataGridRowInfo GetRowInfo( TItem item ) /// [Inject] internal BlazoriseLicenseChecker LicenseChecker { get; set; } + /// + /// Gets or sets The service provider. + /// + [Inject] internal IServiceProvider ServiceProvider { get; set; } + /// /// Makes sure the DataGrid has columns defined as groupable. /// diff --git a/Source/Extensions/Blazorise.DataGrid/DataGridColumn.cs b/Source/Extensions/Blazorise.DataGrid/DataGridColumn.cs index 41aca8b8dd..66616da9d0 100644 --- a/Source/Extensions/Blazorise.DataGrid/DataGridColumn.cs +++ b/Source/Extensions/Blazorise.DataGrid/DataGridColumn.cs @@ -6,6 +6,8 @@ using System.Threading.Tasks; using Blazorise.DataGrid.Utils; using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.JSInterop; #endregion namespace Blazorise.DataGrid; @@ -41,24 +43,49 @@ public DataGridColumn() sortFieldGetter = new( () => FunctionCompiler.CreateValueGetter( SortField ) ); } + #endregion #region Methods - protected override void OnInitialized() + /// + /// Initializes the default values for this column. + /// + private void InitializeDefaults() { - base.OnInitialized(); - currentSortDirection[DataGridSortMode.Single] = SortDirection; currentSortDirection[DataGridSortMode.Multiple] = SortDirection; currentFilterMethod = FilterMethod; - if ( ParentDataGrid is not null ) - { - ParentDataGrid.AddColumn( this, true ); + Filter?.Subscribe( OnSearchValueChanged ); + } - Filter?.Subscribe( OnSearchValueChanged ); - } + + /// + /// Provides a way to generate column specific dependencies outside the Blazor engine. + /// + /// + /// + internal void InitializeGeneratedColumn( DataGrid parentDataGrid, IServiceProvider serviceProvider ) + { + this.ParentDataGrid = parentDataGrid; + this.JSRuntime = serviceProvider.GetRequiredService(); + this.VersionProvider = serviceProvider.GetRequiredService(); + this.ClassProvider = serviceProvider.GetRequiredService(); + this.IdGenerator = serviceProvider.GetRequiredService(); + + base.OnInitialized(); + + InitializeDefaults(); + } + + protected override void OnInitialized() + { + base.OnInitialized(); + + InitializeDefaults(); + + ParentDataGrid?.AddColumn( this, true ); } /// @@ -74,7 +101,7 @@ protected override ValueTask DisposeAsync( bool disposing ) private void DisposeSubscriptions() { - ParentDataGrid.RemoveColumn( this ); + ParentDataGrid?.RemoveColumn( this ); if ( Filter is not null ) { diff --git a/Source/Extensions/Blazorise.DataGrid/GlobalSuppressions.cs b/Source/Extensions/Blazorise.DataGrid/GlobalSuppressions.cs new file mode 100644 index 0000000000..9aed776af8 --- /dev/null +++ b/Source/Extensions/Blazorise.DataGrid/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage( "Usage", "BL0005:Component parameter should not be set outside of its component.", Justification = "Internal setting, not critical.", Scope = "member", Target = "~M:Blazorise.DataGrid.DataGrid`1.AutoGenerateColumns" )] diff --git a/Tests/Blazorise.Tests/Utils/FormatersTests.cs b/Tests/Blazorise.Tests/Utils/FormatersTests.cs index bd77e6a3d6..e6e3270ae5 100644 --- a/Tests/Blazorise.Tests/Utils/FormatersTests.cs +++ b/Tests/Blazorise.Tests/Utils/FormatersTests.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Runtime.Serialization; -using Blazorise.Utilities; +using Blazorise.Utilities; using Xunit; namespace Blazorise.Tests.Utils; @@ -28,4 +23,19 @@ public void GetBytesReadable_Returns_HumanReadableFormat( long bytes, string exp Assert.Equal( expected, result ); } + [Theory] + [InlineData( "", "" )] + [InlineData( " ", " " )] + [InlineData( "FirstName", "First Name" )] + [InlineData( "FirstNameVeryLong", "First Name Very Long" )] + [InlineData( " FirstName ", " First Name " )] + [InlineData( "_FirstName ", "_First Name " )] + [InlineData( null, null )] + public void PascalCaseToFriendlyName_Returns_FriendlyFormat( string input, string expected ) + { + var result = Formaters.PascalCaseToFriendlyName( input ); + + Assert.Equal( expected, result ); + } + } \ No newline at end of file