Skip to content

Productize QuickGrid #46573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +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 Microsoft.AspNetCore.Components.QuickGrid;
using Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter;
using Microsoft.AspNetCore.Components.QuickGrid.Infrastructure;

namespace Microsoft.Extensions.DependencyInjection;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Linq;
using Microsoft.AspNetCore.Components.QuickGrid.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Description>Provides an Entity Framework Core adapter for the <a href="https://www.nuget.org/packages/Microsoft.AspNetCore.Components.QuickGrid">Microsoft.AspNetCore.Components.QuickGrid</a> package.</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,27 @@ namespace Microsoft.AspNetCore.Components.QuickGrid;
public enum Align
{
/// <summary>
/// Justifies the content against the start of the container.
/// Justifies the content against the start of the container
/// </summary>
Left,
Start,

/// <summary>
/// Justifies the content at the center of the container.
/// </summary>
Center,

/// <summary>
/// Justifies the content at the end of the container.
/// Justifies the content at the end of the container
/// </summary>
End,

/// <summary>
/// Justifies the content against the left of the container.
/// </summary>
Left,

/// <summary>
/// Justifies the content at the right of the container.
/// </summary>
Right,
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@namespace Microsoft.AspNetCore.Components.QuickGrid
@typeparam TGridItem
@{
InternalGridContext.Grid.AddColumn(this, IsDefaultSort);
InternalGridContext.Grid.AddColumn(this, InitialSortDirection, IsDefaultSortColumn);
}

@code
Expand All @@ -17,9 +17,9 @@
}
else
{
@if (ColumnOptions is not null && Align != Align.Right)
@if (ColumnOptions is not null && (Align != Align.Right || Align != Align.End))
{
<button class="col-options-button" @onclick="@(() => Grid.ShowColumnOptions(this))"></button>
<button class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))"></button>
}

if (Sortable.HasValue ? Sortable.Value : IsSortableByDefault())
Expand All @@ -36,9 +36,9 @@
</div>
}

@if (ColumnOptions is not null && Align == Align.Right)
@if (ColumnOptions is not null && (Align == Align.Right || Align == Align.End))
{
<button class="col-options-button" @onclick="@(() => Grid.ShowColumnOptions(this))"></button>
<button class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))"></button>
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public abstract partial class ColumnBase<TGridItem>
/// UI will be included in the header cell by default.
///
/// If <see cref="HeaderTemplate" /> is used, it is left up to that template to render any relevant
/// "show options" UI and invoke the grid's <see cref="QuickGrid{TGridItem}.ShowColumnOptions(ColumnBase{TGridItem})" />).
/// "show options" UI and invoke the grid's <see cref="QuickGrid{TGridItem}.ShowColumnOptionsAsync(ColumnBase{TGridItem})" />).
/// </summary>
[Parameter] public RenderFragment? ColumnOptions { get; set; }

Expand All @@ -55,10 +55,20 @@ public abstract partial class ColumnBase<TGridItem>
[Parameter] public bool? Sortable { get; set; }

/// <summary>
/// If specified and not null, indicates that this column represents the initial sort order
/// for the grid. The supplied value controls the default sort direction.
/// Specifies sorting rules for a column.
/// </summary>
[Parameter] public SortDirection? IsDefaultSort { get; set; }
public abstract GridSort<TGridItem>? SortBy { get; set; }

/// <summary>
/// Indicates which direction to sort in
/// if <see cref="IsDefaultSortColumn"/> is true.
/// </summary>
[Parameter] public SortDirection InitialSortDirection { get; set; } = default;

/// <summary>
/// Indicates whether this column should be sorted by default.
/// </summary>
[Parameter] public bool IsDefaultSortColumn { get; set; } = false;

/// <summary>
/// If specified, virtualized grids will use this template to render cells whose data has not yet been loaded.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public sealed class GridSort<TGridItem>
private (LambdaExpression, bool) _firstExpression;
private List<(LambdaExpression, bool)>? _thenExpressions;

private IReadOnlyCollection<(string PropertyName, SortDirection Direction)>? _cachedPropertyListAscending;
private IReadOnlyCollection<(string PropertyName, SortDirection Direction)>? _cachedPropertyListDescending;
private IReadOnlyCollection<SortedProperty>? _cachedPropertyListAscending;
private IReadOnlyCollection<SortedProperty>? _cachedPropertyListDescending;

internal GridSort(Func<IQueryable<TGridItem>, bool, IOrderedQueryable<TGridItem>> first, (LambdaExpression, bool) firstExpression)
{
Expand Down Expand Up @@ -100,7 +100,7 @@ internal IOrderedQueryable<TGridItem> Apply(IQueryable<TGridItem> queryable, boo
return orderedQueryable;
}

internal IReadOnlyCollection<(string PropertyName, SortDirection Direction)> ToPropertyList(bool ascending)
internal IReadOnlyCollection<SortedProperty> ToPropertyList(bool ascending)
{
if (ascending)
{
Expand All @@ -114,18 +114,18 @@ internal IOrderedQueryable<TGridItem> Apply(IQueryable<TGridItem> queryable, boo
}
}

private List<(string PropertyName, SortDirection Direction)> BuildPropertyList(bool ascending)
private List<SortedProperty> BuildPropertyList(bool ascending)
{
var result = new List<(string, SortDirection)>
var result = new List<SortedProperty>
{
(ToPropertyName(_firstExpression.Item1), (_firstExpression.Item2 ^ ascending) ? SortDirection.Descending : SortDirection.Ascending)
new SortedProperty { PropertyName = ToPropertyName(_firstExpression.Item1), Direction = (_firstExpression.Item2 ^ ascending) ? SortDirection.Descending : SortDirection.Ascending }
};

if (_thenExpressions is not null)
{
foreach (var (thenLambda, thenAscending) in _thenExpressions)
{
result.Add((ToPropertyName(thenLambda), (thenAscending ^ ascending) ? SortDirection.Descending : SortDirection.Ascending));
result.Add(new SortedProperty { PropertyName = ToPropertyName(thenLambda), Direction = (thenAscending ^ ascending) ? SortDirection.Descending : SortDirection.Ascending });
}
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Components.QuickGrid;
/// </summary>
/// <typeparam name="TGridItem">The type of data represented by each row in the grid.</typeparam>
/// <typeparam name="TProp">The type of the value being displayed in the column's cells.</typeparam>
public class PropertyColumn<TGridItem, TProp> : ColumnBase<TGridItem>, ISortBuilderColumn<TGridItem>
public class PropertyColumn<TGridItem, TProp> : ColumnBase<TGridItem>
{
private Expression<Func<TGridItem, TProp>>? _lastAssignedProperty;
private Func<TGridItem, string?>? _cellTextFunc;
Expand All @@ -29,7 +29,12 @@ public class PropertyColumn<TGridItem, TProp> : ColumnBase<TGridItem>, ISortBuil
/// </summary>
[Parameter] public string? Format { get; set; }

GridSort<TGridItem>? ISortBuilderColumn<TGridItem>.SortBuilder => _sortBuilder;
/// <inheritdoc/>
public override GridSort<TGridItem>? SortBy
{
get => _sortBuilder;
set => throw new NotSupportedException($"PropertyColumn generates this member internally. For custom sorting rules, see '{typeof(TemplateColumn<TGridItem>)}'.");
}

/// <inheritdoc />
protected override void OnParametersSet()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.Components.QuickGrid;

/// <summary>
/// A ValueTuple that holds the name of a property and the direction to sort by.
/// </summary>
public readonly struct SortedProperty
{
/// <summary>
/// The property name for the sorting rule.
/// </summary>
public required string PropertyName { get; init; }

/// <summary>
/// The direction to sort by.
/// </summary>
public SortDirection Direction { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Components.QuickGrid;
/// Represents a <see cref="QuickGrid{TGridItem}"/> column whose cells render a supplied template.
/// </summary>
/// <typeparam name="TGridItem">The type of data represented by each row in the grid.</typeparam>
public class TemplateColumn<TGridItem> : ColumnBase<TGridItem>, ISortBuilderColumn<TGridItem>
public class TemplateColumn<TGridItem> : ColumnBase<TGridItem>
{
private static readonly RenderFragment<TGridItem> EmptyChildContent = _ => builder => { };

Expand All @@ -18,12 +18,8 @@ public class TemplateColumn<TGridItem> : ColumnBase<TGridItem>, ISortBuilderColu
/// </summary>
[Parameter] public RenderFragment<TGridItem> ChildContent { get; set; } = EmptyChildContent;

/// <summary>
/// Optionally specifies sorting rules for this column.
/// </summary>
[Parameter] public GridSort<TGridItem>? SortBy { get; set; }

GridSort<TGridItem>? ISortBuilderColumn<TGridItem>.SortBuilder => SortBy;
/// <inheritdoc/>
[Parameter] public override GridSort<TGridItem>? SortBy { get; set; }

/// <inheritdoc />
protected internal override void CellContent(RenderTreeBuilder builder, TGridItem item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ namespace Microsoft.AspNetCore.Components.QuickGrid;
/// </summary>
/// <typeparam name="TGridItem">The type of data represented by each row in the grid.</typeparam>
/// <param name="request">Parameters describing the data being requested.</param>
/// <returns>A <see cref="ValueTask{GridItemsProviderResult{TResult}}" /> that gives the data to be displayed.</returns>
/// <returns>A <see cref="ValueTask{GridItemsProviderResult}" /> that gives the data to be displayed.</returns>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While technically not correct, the compiler would not eat the original line. This may be due to the existence of a struct with a generic parameter and a static class (that just grabs instances of the struct) with the same name. Regardless, the actual output of this is reduced to ValueTask<TResult> anyways, so this clarification isn't any more useful.

public delegate ValueTask<GridItemsProviderResult<TGridItem>> GridItemsProvider<TGridItem>(
GridItemsProviderRequest<TGridItem> request);
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,33 @@ public readonly struct GridItemsProviderRequest<TGridItem>
/// <summary>
/// The zero-based index of the first item to be supplied.
/// </summary>
public int StartIndex { get; }
public int StartIndex { get; init; }

/// <summary>
/// If set, the maximum number of items to be supplied. If not set, the maximum number is unlimited.
/// </summary>
public int? Count { get; }
public int? Count { get; init; }

/// <summary>
/// Specifies which column represents the sort order.
///
/// Rather than inferring the sort rules manually, you should normally call either <see cref="ApplySorting(IQueryable{TGridItem})"/>
/// or <see cref="GetSortByProperties"/>, since they also account for <see cref="SortByColumn" /> and <see cref="SortByAscending" /> automatically.
/// </summary>
public ColumnBase<TGridItem>? SortByColumn { get; }
public ColumnBase<TGridItem>? SortByColumn { get; init; }

/// <summary>
/// Specifies the current sort direction.
///
/// Rather than inferring the sort rules manually, you should normally call either <see cref="ApplySorting(IQueryable{TGridItem})"/>
/// or <see cref="GetSortByProperties"/>, since they also account for <see cref="SortByColumn" /> and <see cref="SortByAscending" /> automatically.
/// </summary>
public bool SortByAscending { get; }
public bool SortByAscending { get; init; }

/// <summary>
/// A token that indicates if the request should be cancelled.
/// </summary>
public CancellationToken CancellationToken { get; }
public CancellationToken CancellationToken { get; init; }

internal GridItemsProviderRequest(
int startIndex, int? count, ColumnBase<TGridItem>? sortByColumn, bool sortByAscending,
Expand All @@ -55,33 +55,22 @@ internal GridItemsProviderRequest(

/// <summary>
/// Applies the request's sorting rules to the supplied <see cref="IQueryable{TGridItem}"/>.
///
/// Note that this only works if the current <see cref="SortByColumn"/> implements <see cref="ISortBuilderColumn{TGridItem}"/>,
/// otherwise it will throw.
/// </summary>
/// <param name="source">An <see cref="IQueryable{TGridItem}"/>.</param>
/// <returns>A new <see cref="IQueryable{TGridItem}"/> representing the <paramref name="source"/> with sorting rules applied.</returns>
public IQueryable<TGridItem> ApplySorting(IQueryable<TGridItem> source) => SortByColumn switch
{
ISortBuilderColumn<TGridItem> sbc => sbc.SortBuilder?.Apply(source, SortByAscending) ?? source,
ColumnBase<TGridItem> sbc => sbc.SortBy?.Apply(source, SortByAscending) ?? source,
null => source,
_ => throw new NotSupportedException(ColumnNotSortableMessage(SortByColumn)),
};

/// <summary>
/// Produces a collection of (property name, direction) pairs representing the sorting rules.
///
/// Note that this only works if the current <see cref="SortByColumn"/> implements <see cref="ISortBuilderColumn{TGridItem}"/>,
/// otherwise it will throw.
/// </summary>
/// <returns>A collection of (property name, direction) pairs representing the sorting rules</returns>
public IReadOnlyCollection<(string PropertyName, SortDirection Direction)> GetSortByProperties() => SortByColumn switch
public IReadOnlyCollection<SortedProperty> GetSortByProperties() => SortByColumn switch
{
ISortBuilderColumn<TGridItem> sbc => sbc.SortBuilder?.ToPropertyList(SortByAscending) ?? Array.Empty<(string, SortDirection)>(),
null => Array.Empty<(string, SortDirection)>(),
_ => throw new NotSupportedException(ColumnNotSortableMessage(SortByColumn)),
ColumnBase<TGridItem> sbc => sbc.SortBy?.ToPropertyList(SortByAscending) ?? Array.Empty<SortedProperty>(),
null => Array.Empty<SortedProperty>(),
};

private static string ColumnNotSortableMessage<T>(ColumnBase<T> col)
=> $"The current sort column is of type '{col.GetType().FullName}', which does not implement {nameof(ISortBuilderColumn<TGridItem>)}, so its sorting rules cannot be applied automatically.";
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,20 @@ namespace Microsoft.AspNetCore.Components.QuickGrid;
/// Holds data being supplied to a <see cref="QuickGrid{TGridItem}"/>'s <see cref="QuickGrid{TGridItem}.ItemsProvider"/>.
/// </summary>
/// <typeparam name="TGridItem">The type of data represented by each row in the grid.</typeparam>
public struct GridItemsProviderResult<TGridItem>
public readonly struct GridItemsProviderResult<TGridItem>
{
/// <summary>
/// The items being supplied.
/// </summary>
public ICollection<TGridItem> Items { get; set; }
public required ICollection<TGridItem> Items { get; init; }

/// <summary>
/// The total number of items that may be displayed in the grid. This normally means the total number of items in the
/// underlying data source after applying any filtering that is in effect.
///
/// If the grid is paginated, this should include all pages. If the grid is virtualized, this should include the entire scroll range.
/// </summary>
public int TotalItemCount { get; set; }

/// <summary>
/// Constructs an instance of <see cref="GridItemsProviderResult{TGridItem}"/>.
/// </summary>
/// <param name="items">The items being supplied.</param>
/// <param name="totalItemCount">The total numer of items that exist. See <see cref="TotalItemCount"/> for details.</param>
public GridItemsProviderResult(ICollection<TGridItem> items, int totalItemCount)
{
Items = items;
TotalItemCount = totalItemCount;
}
public int TotalItemCount { get; init; }
}

/// <summary>
Expand All @@ -46,8 +35,8 @@ public static class GridItemsProviderResult
/// </summary>
/// <typeparam name="TGridItem">The type of data represented by each row in the grid.</typeparam>
/// <param name="items">The items being supplied.</param>
/// <param name="totalItemCount">The total numer of items that exist. See <see cref="TotalItemCount"/> for details.</param>
/// <param name="totalItemCount">The total numer of items that exist. See <see cref="GridItemsProviderResult{TGridItem}.TotalItemCount"/> for details.</param>
/// <returns>An instance of <see cref="GridItemsProviderResult{TGridItem}"/>.</returns>
public static GridItemsProviderResult<TGridItem> From<TGridItem>(ICollection<TGridItem> items, int totalItemCount)
=> new(items, totalItemCount);
=> new() { Items = items, TotalItemCount = totalItemCount };
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using System.Linq;

namespace Microsoft.AspNetCore.Components.QuickGrid.Infrastructure;
namespace Microsoft.AspNetCore.Components.QuickGrid;

/// <summary>
/// Provides methods for asynchronous evaluation of queries against an <see cref="IQueryable{T}" />.
Expand Down
Loading