Skip to content

Commit 4e8f363

Browse files
vnbaaijdvoituron
andauthored
[dev-v5] Add DataGrid - part 4, docs and examples (#3971)
* - Add enums - Add doc start - Add Paginator / PaginationState * - Add DataGrid component * Add DataGridGeneratedHeaderType * Fix analyzer errors * - Add Typical demo and flags - Remove ::deep - Change county codes to align with v4 * Work on review comments * Process review comments * Add language resources * Add Unit Tests for Paginator * More review comments * Update tests. Now 100% lc * Replace tokens (WIP) * Remove flags. These will be added to sample data project in separate PR * Remove DI abstractions package. Not needed * Add IsFixed parameter * MAke example grid mor functional and look better * Add initial tests. They are not passing yet * Add surpression atribute, fix other analyzer warnings * Use localized strings * Fix tests * Add Tests * Add tests for PaginatinState and TotalItemCountChangedEventArgs * Add Row tests * process review comments * More tests * More tests * - Add typical demo - Fix error with flags - Fix css colors - Add tests * More tests * - More tests - Fix ToDo items - Misc code changes * Update file headers * Convert DataGrid JS to TS * Implement fix for #3963 * Bring in changes made in v4 with #3949 * - Update file headers - Add more tests * Process review comments: - Add and use DataGridCellAlignment enum - Use overriden DisposeAsync - Use correct comment format * Forgot to change the docs * - Use auto-generated constant - Use local variables in testing cell/row * DataGrid docs and examples * Process review comments * More review comments * - Undo make internal GridItemsProvider* - Implement SelectColumn localization - Fix CSS issue with select column * Update test verified files * - Fix when to show header menu - Make all examples work - Create example pages * - Rename getting started - Remove double section - Use primary color on paginator buttos (and apply better style when button is diabled) * WIP * Update samples and structure * Make all DataGrid samples work * Update DataGrid verified tests files --------- Co-authored-by: Denis Voituron <dvoituron@outlook.com>
1 parent 3fc5668 commit 4e8f363

File tree

72 files changed

+1729
-103
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1729
-103
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
:star: We appreciate your star, it helps!
1212

13-
**This package is for use in .NET 8 Blazor projects. If you are using .NET 6 or 7, please use the v3 version of the package which is named `Microsoft.Fast.Components.FluentUI`**
13+
**This package is for use in .NET 8 (and up) Blazor projects. If you are using .NET 6 or 7, please use the v3 version of the package which is named `Microsoft.Fast.Components.FluentUI`**
1414

1515
## 🔹Introduction
1616

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
@using System.ComponentModel.DataAnnotations
2+
3+
<FluentGrid Spacing="4">
4+
<FluentGridItem xs="12">
5+
<h4>With auto-fit</h4>
6+
<FluentDataGrid Items="@people" Style="width: 100%;" AutoFit="true">
7+
<PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
8+
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
9+
<PropertyColumn Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
10+
<PropertyColumn Property="@(p => p.Bio)" />
11+
</FluentDataGrid>
12+
</FluentGridItem>
13+
<FluentGridItem xs="12">
14+
<h4>Without auto-fit</h4>
15+
<FluentDataGrid Items="@people">
16+
<PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
17+
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
18+
<PropertyColumn Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
19+
<PropertyColumn Property="@(p => p.Bio)" />
20+
</FluentDataGrid>
21+
</FluentGridItem>
22+
</FluentGrid>
23+
24+
@code {
25+
public class Person
26+
{
27+
public Person(int personId, string name, DateOnly birthDate, string bio)
28+
{
29+
PersonId = personId;
30+
Name = name;
31+
BirthDate = birthDate;
32+
Bio = bio;
33+
}
34+
35+
[Display(Name = "Identity")]
36+
public int PersonId { get; set; }
37+
38+
[Display(Name = "Name")]
39+
public string Name { get; set; }
40+
41+
[Display(Name = "Birth date")]
42+
public DateOnly BirthDate { get; set; }
43+
44+
[Display(Name = "Biography")]
45+
public string Bio { get; set; }
46+
}
47+
48+
IQueryable<Person> people = new[]
49+
{
50+
new Person(10895, "Jean Martin", new DateOnly(1825, 11, 29), "Born on November 29, 1825, in Paris, France, is renowned as the founder of modern neurology."),
51+
new Person(10944, "António Langa", new DateOnly(1972, 5, 15), "Born on May 15, 1972, in Columbia, South Carolina, is a distinguished former professional basketball player."),
52+
new Person(11203, "Julie Smith", new DateOnly(1944, 11, 25), "Born on November 25, 1944, in Annapolis, Maryland, is an acclaimed American mystery writer celebrated for her rich storytelling."),
53+
new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27), "Nur Sari is a fictional character known for her extraordinary contributions to the field of renewable energy."),
54+
new Person(11898, "Jose Hernandez", new DateOnly(1962, 8, 7), "Born on August 7, 1962, in French Camp, California, is a Mexican-American engineer."),
55+
new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9), ""),
56+
}.AsQueryable();
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@using static FluentUI.Demo.SampleData.Olympics2024
2+
3+
@inject IJSRuntime JSRuntime
4+
5+
<div id="datagrid-container">
6+
<FluentDataGrid Items="items!.AsQueryable()"
7+
Pagination="@pagination"
8+
RowSize="@rowSize"
9+
AutoItemsPerPage="true"
10+
Style="overflow-y:hidden;">
11+
<PropertyColumn Property="@(c => c.Code)" Sortable="true" />
12+
<PropertyColumn Property="@(c => c.Medals.Gold)" Sortable="true" />
13+
<PropertyColumn Property="@(c => c.Medals.Silver)" Sortable="true" />
14+
<PropertyColumn Property="@(c => c.Medals.Bronze)" Sortable="true" />
15+
<PropertyColumn Property="@(c => c.Medals.Total)" Sortable="true" />
16+
</FluentDataGrid>
17+
</div>
18+
19+
<FluentPaginator State="@pagination" />
20+
21+
@code {
22+
23+
DataGridRowSize rowSize = DataGridRowSize.Small;
24+
IQueryable<Country>? items;
25+
PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
26+
27+
protected override void OnInitialized() =>
28+
items = SampleData.Olympics2024.Countries.AsQueryable();
29+
30+
}
31+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#datagrid-container {
2+
height: calc(45vh - 3rem);
3+
min-height: 8rem;
4+
overflow-x: auto;
5+
overflow-y: hidden;
6+
}
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@using System.ComponentModel.DataAnnotations
2+
<FluentDataGrid Items="@people">
3+
<PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
4+
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
5+
<PropertyColumn Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
6+
</FluentDataGrid>
7+
8+
@code {
9+
public class Person
10+
{
11+
public Person(int personId, string name, DateOnly birthDate)
12+
{
13+
PersonId = personId;
14+
Name = name;
15+
BirthDate = birthDate;
16+
}
17+
18+
[Display(Name="Identity")]
19+
public int PersonId { get; set; }
20+
21+
[Display(Name = "Full _name")]
22+
public string Name { get; set; }
23+
24+
[Display(Name = "Birth date")]
25+
public DateOnly BirthDate { get; set; }
26+
}
27+
28+
IQueryable<Person> people = new[]
29+
{
30+
new Person(10895, "Jean Martin", new DateOnly(1985, 3, 16)),
31+
new Person(10944, "António Langa", new DateOnly(1991, 12, 1)),
32+
new Person(11203, "Julie Smith", new DateOnly(1958, 10, 10)),
33+
new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27)),
34+
new Person(11898, "Jose Hernandez", new DateOnly(2011, 5, 3)),
35+
new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9)),
36+
}.AsQueryable();
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<FluentDataGrid Items="@_gridData" ResizableColumns=true GridTemplateColumns="0.5fr 0.5fr">
2+
<TemplateColumn Sortable="true" Title="First Name" SortBy="_firstNameSort">
3+
@context.Properties["firstname"]
4+
</TemplateColumn>
5+
6+
<TemplateColumn Sortable="true" Title="Last Name" SortBy="_lastNameSort">
7+
@context.Properties["lastname"]
8+
</TemplateColumn>
9+
</FluentDataGrid>
10+
11+
@code {
12+
private ColumnKeyGridSort<GridRow> _firstNameSort = new ColumnKeyGridSort<GridRow>(
13+
"firstname",
14+
(queryable, sortAscending) =>
15+
{
16+
if (sortAscending)
17+
{
18+
return queryable.OrderBy(x => x.Properties["firstname"]);
19+
}
20+
else
21+
{
22+
return queryable.OrderByDescending(x => x.Properties["firstname"]);
23+
}
24+
}
25+
);
26+
27+
private ColumnKeyGridSort<GridRow> _lastNameSort = new ColumnKeyGridSort<GridRow>(
28+
"lastname",
29+
(queryable, sortAscending) =>
30+
{
31+
if (sortAscending)
32+
{
33+
return queryable.OrderBy(x => x.Properties["lastname"]);
34+
}
35+
else
36+
{
37+
return queryable.OrderByDescending(x => x.Properties["lastname"]);
38+
}
39+
}
40+
);
41+
42+
private static readonly IQueryable<GridRow> _gridData = new GridRow[] {
43+
new(new Dictionary<string, string>{ { "firstname", "Tom" }, { "lastname", "Cruise" } }),
44+
new(new Dictionary<string, string>{ { "firstname", "Dolly" }, { "lastname", "Parton" } }),
45+
new(new Dictionary<string, string>{ { "firstname", "Nicole" }, { "lastname", "Kidmon" } }),
46+
new(new Dictionary<string, string>{ { "firstname", "James" }, { "lastname", "Bond" } }),
47+
}.AsQueryable();
48+
49+
public record GridRow(Dictionary<string, string> Properties);
50+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
@using static FluentUI.Demo.SampleData.Olympics2024
2+
3+
@if (altcolor)
4+
{
5+
<style>
6+
:root {
7+
--datagrid-hover-color: lightyellow;
8+
9+
}
10+
11+
.fluent-data-grid {
12+
--fluent-data-grid-resize-handle-color: var(--neutral-stroke-rest) !important;
13+
}
14+
</style>
15+
}
16+
17+
<FluentStack HorizontalGap="15">
18+
<FluentRadioGroup Name="rt" @bind-Value="@_resizeType" Label="Resize type" TValue="DataGridResizeType?">
19+
<FluentRadio Value="@((DataGridResizeType?)DataGridResizeType.Discrete)" Label="Discrete" />
20+
<FluentRadio Value="@((DataGridResizeType?)DataGridResizeType.Exact)" Label="Exact" />
21+
</FluentRadioGroup>
22+
<FluentSpacer Width="25" />
23+
<FluentCheckbox @bind-Value="@_showActionsMenu" Label="Use menu for column actions" />
24+
<FluentCheckbox @bind-Value="@_useMenuService" Label="Use service for rendering menu" Disabled="!_showActionsMenu" />
25+
<FluentCheckbox @bind-Value="@_resizeColumnOnAllRows" Label="Resize column on all rows" />
26+
</FluentStack>
27+
28+
<div style="height: 400px; overflow-x:auto; display:flex;">
29+
<FluentDataGrid Items="@FilteredItems"
30+
ResizableColumns=true
31+
ResizeType="@_resizeType"
32+
ResizeColumnOnAllRows="@_resizeColumnOnAllRows"
33+
HeaderCellAsButtonWithMenu="_showActionsMenu"
34+
UseMenuService="_useMenuService"
35+
Pagination="@pagination"
36+
TGridItem="Country"
37+
OnRowFocus="HandleRowFocus"
38+
GridTemplateColumns="0.2fr 1fr 0.2fr 0.2fr 0.2fr 0.2fr"
39+
ShowHover="true">
40+
<TemplateColumn Title="Rank" Sortable="true" SortBy="@rankSort" Align="DataGridCellAlignment.Center">
41+
<img class="flag" src="@(context.Flag())" alt="Flag of @(context.Code)" />
42+
</TemplateColumn>
43+
<PropertyColumn Property="@(c => c.Name)" InitialSortDirection=DataGridSortDirection.Descending Sortable="true" IsDefaultSortColumn=true Comparer="@StringLengthComparer.Instance" Filtered="!string.IsNullOrWhiteSpace(nameFilter)">
44+
<ColumnOptions>
45+
<div class="search-box" style="width: 100%;">
46+
<FluentTextInput Autofocus=true @bind-Value=nameFilter @oninput="HandleCountryFilter" @bind-Value:after="HandleClear" Placeholder="Country name..." Style="width: 100%;" Width="100%"/>
47+
</div>
48+
</ColumnOptions>
49+
</PropertyColumn>
50+
@* <TemplateColumn Title="Name" InitialSortDirection=SortDirection.Descending SortBy="@nameSort" IsDefaultSortColumn=true Filtered="!string.IsNullOrWhiteSpace(nameFilter)">
51+
<ColumnOptions>
52+
<div class="search-box">
53+
<FluentSearch type="search" Autofocus=true @bind-Value=nameFilter @oninput="HandleCountryFilter" @bind-Value:after="HandleClear" Placeholder="Country name..." />
54+
</div>
55+
</ColumnOptions>
56+
<ChildContent>
57+
@(context.Name)
58+
</ChildContent>
59+
</TemplateColumn> *@
60+
<PropertyColumn Property="@(c => c.Medals.Gold)" Sortable="true" Align="DataGridCellAlignment.Start" />
61+
<PropertyColumn Property="@(c => c.Medals.Silver)" Sortable="true" Align="DataGridCellAlignment.Center" />
62+
<PropertyColumn Property="@(c => c.Medals.Bronze)" Sortable="true" Align="DataGridCellAlignment.End" />
63+
<PropertyColumn Property="@(c => c.Medals.Total)" Sortable="true" Align="DataGridCellAlignment.End" />
64+
</FluentDataGrid>
65+
</div>
66+
67+
<FluentPaginator State="@pagination">
68+
<SummaryTemplate>
69+
There are <strong>@(pagination.TotalItemCount ?? 0)</strong> rows
70+
</SummaryTemplate>
71+
<PaginationTextTemplate>
72+
This is page <strong>@(pagination.CurrentPageIndex + 1)</strong> out of a total of <strong>@(pagination.LastPageIndex + 1)</strong> pages
73+
</PaginationTextTemplate>
74+
</FluentPaginator>
75+
76+
<FluentSwitch @bind-Value="altcolor" Label="Alternative hover color"></FluentSwitch>
77+
78+
79+
@code {
80+
bool altcolor = false;
81+
IQueryable<Country>? items;
82+
PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
83+
string nameFilter = string.Empty;
84+
DataGridResizeType? _resizeType = null;
85+
bool _showActionsMenu;
86+
bool _useMenuService = true;
87+
bool _resizeColumnOnAllRows = true;
88+
89+
GridSort<Country> rankSort = GridSort<Country>
90+
.ByDescending(x => x.Medals.Gold)
91+
.ThenDescending(x => x.Medals.Silver)
92+
.ThenDescending(x => x.Medals.Bronze);
93+
94+
// Uncomment line below when using the TemplateColumn example for the country _name
95+
//GridSort<Country> nameSort = GridSort<Country>.ByAscending(x => x.Name, StringLengthComparer.Instance);
96+
97+
98+
IQueryable<Country>? FilteredItems => items?.Where(x => x.Name.Contains(nameFilter, StringComparison.CurrentCultureIgnoreCase));
99+
100+
protected override void OnInitialized()
101+
{
102+
items = SampleData.Olympics2024.Countries.AsQueryable();
103+
}
104+
105+
private void HandleCountryFilter(ChangeEventArgs args)
106+
{
107+
if (args.Value is string value)
108+
{
109+
nameFilter = value;
110+
}
111+
}
112+
113+
private void HandleClear()
114+
{
115+
if (string.IsNullOrWhiteSpace(nameFilter))
116+
{
117+
nameFilter = string.Empty;
118+
}
119+
}
120+
121+
private void HandleRowFocus(FluentDataGridRow<Country> row)
122+
{
123+
Console.WriteLine($"[Custom comparer] Row focused: {row.Item?.Name}");
124+
}
125+
126+
public class StringLengthComparer : IComparer<string>
127+
{
128+
public static readonly StringLengthComparer Instance = new StringLengthComparer();
129+
130+
public int Compare(string? x, string? y)
131+
{
132+
if (x is null)
133+
{
134+
return y is null ? 0 : -1;
135+
}
136+
137+
if (y is null)
138+
{
139+
return 1;
140+
}
141+
142+
return x.Length.CompareTo(y.Length);
143+
}
144+
}
145+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* Ensure all the flags are the same size, and centered */
2+
.flag {
3+
height: 1rem;
4+
margin: auto;
5+
border: 1px solid var(--neutral-layer-3);
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<FluentDataGrid Items="@_gridData" ResizableColumns=true GridTemplateColumns="0.5fr 0.5fr">
2+
<PropertyColumn Sortable="true" Property="x => x.Number" Title="Rank" />
3+
4+
<TemplateColumn Sortable="true" SortBy="groupRank" Title="Group">
5+
@context.Group
6+
</TemplateColumn>
7+
8+
</FluentDataGrid>
9+
10+
<p>Keep numbers always sorted ascending inside the group when sorting by group</p>
11+
<FluentDataGrid Items="@_gridData" ResizableColumns=true GridTemplateColumns="0.5fr 0.5fr">
12+
13+
<PropertyColumn Sortable="true" Property="x => x.Number" Title="Rank" />
14+
<PropertyColumn Property="x => x.Group" SortBy="groupRankNumberAlwaysAscending" Title="Group" />
15+
16+
</FluentDataGrid>
17+
18+
19+
20+
@code {
21+
GridSort<GridRow> groupRank = GridSort<GridRow>
22+
.ByAscending(x => x.Group)
23+
.ThenAscending(x => x.Number);
24+
25+
GridSort<GridRow> groupRankNumberAlwaysAscending = GridSort<GridRow>
26+
.ByAscending(x => x.Group)
27+
.ThenAlwaysAscending(x => x.Number);
28+
29+
private static readonly IQueryable<GridRow> _gridData = new GridRow[] {
30+
new(2, "B"),
31+
new(1, "A"),
32+
new(4, "B"),
33+
new(3, "A")
34+
}.AsQueryable();
35+
36+
public class GridRow(int number, string group)
37+
{
38+
public int Number { get; } = number;
39+
public string Group { get; } = group;
40+
}
41+
}

0 commit comments

Comments
 (0)