Skip to content

Conversation

msynk
Copy link
Member

@msynk msynk commented Aug 31, 2025

closes #11311

Summary by CodeRabbit

  • New Features

    • Added a dedicated Columns slot for defining grid columns (fallback to previous content if not set).
    • Introduced customizable LoadingTemplate for showing a loading state in non-virtualized mode.
    • Enabled data binding via direct collections or an async data provider.
    • Improved loading indicator behavior to respect custom templates.
  • Documentation

    • Expanded DataGrid demos with a LoadingTemplate example, provider-based data loading, pagination, and virtualization.
    • Added multiple new sample snippets illustrating column templates, search/filtering, and external data sources.

Copy link

coderabbitai bot commented Aug 31, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds a Columns render slot, a customizable LoadingTemplate, and Items/ItemsProvider APIs to BitDataGrid. Updates non-virtualized rendering to show a loading row when IsLoading and LoadingTemplate are set. Demo extended with a new loading template example and multiple provider-based samples.

Changes

Cohort / File(s) Summary
Core component: Razor surface
src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor
Adds Columns slot rendering (fallback to ChildContent). In non-virtualized mode, conditionally renders a single-row LoadingTemplate. Virtualization path formatting adjusted only.
Core component: Logic & API
src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor.cs
Introduces IsLoading state; new parameters: Columns, LoadingTemplate, Items, ItemsProvider. Updates GridClass loading logic. Supports data via IQueryable or provider callback.
Demo page markup
.../Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor
Adds “LoadingTemplate” demo with custom loader UI, columns, pagination, and grid refs.
Demo page logic
.../Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.cs
Expands demo: items providers (FDA, OData), filters with RefreshDataAsync, pagination/virtualization states, new parameters metadata reflecting updated API.
Demo embedded samples
.../Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.samples.cs
Adds partial class with multiple sample code strings covering columns, templates, filtering, pagination, virtualization, and provider-backed data.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant DG as BitDataGrid
  participant DP as ItemsProvider (optional)
  participant DS as IQueryable Items (optional)

  rect rgba(230,240,255,0.4)
  Note over DG: Column definitions
  U->>DG: Provide Columns (or ChildContent)
  DG->>DG: Render Columns if provided else ChildContent
  end

  alt ItemsProvider provided
    U->>DG: Navigate/Filter/Paginate
    DG->>DP: Request items (range, sort, filter)
    activate DP
    DP-->>DG: Items + total count
    deactivate DP
  else IQueryable Items provided
    DG->>DS: Query items (optionally paged/sorted)
    DS-->>DG: Items
  end

  rect rgba(240,230,255,0.4)
  Note over DG: Loading state
  U->>DG: Triggers data load
  DG->>DG: Set IsLoading = true
  alt LoadingTemplate provided AND non-virtualized
    DG-->>U: Render single row with LoadingTemplate
  else
    DG-->>U: Apply "loading" CSS class (no template)
  end
  DG->>DG: Set IsLoading = false on completion
  end

  DG-->>U: Render rows (virtualized or not)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective Addressed Explanation
Custom loading UI for BitDataGrid (#11311)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Introduce Columns render slot replacing/preceding ChildContent (src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor, .razor.cs; exact lines not provided) Not part of the loading UI requirement; alters column-definition API surface.
Add Items and ItemsProvider dual data-source APIs (src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor.cs; exact lines not provided) Expands data loading architecture beyond the scope of adding a custom loading template.
Demo: New provider-backed examples (FDA/OData) and virtualization/pagination wiring (…/BitDataGridDemo.razor.cs; exact lines not provided) Demo enhancements unrelated to the specific loading UI feature; broaden demo scope.
Demo: Addition of extensive embedded samples file (…/BitDataGridDemo.razor.samples.cs; exact lines not provided) Documentation/sample expansion, not directly tied to implementing loading UI in the core component.

Poem

I tap my paws on loading time, tick-tock in dotted rings,
A template blooms—now look at me!—I cheer what backend brings.
Columns hop to ordered lines, providers fetch the greens,
While grids spin tales of pages turned and virtual fields of beans.
Hip-hop, hop hooray—my UI’s crisp and keen! 🐇✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor.cs (2)

320-348: LoadingTemplate may never be seen; render immediately on load start and fix CTS disposal.

Currently the component doesn’t re-render when loading starts, so the LoadingTemplate won’t show until after data arrives. Also, CTS instances are never disposed.

Apply:

-        // Move into a "loading" state, cancelling any earlier-but-still-pending load
-        _pendingDataLoadCancellationTokenSource?.Cancel();
-        var thisLoadCts = _pendingDataLoadCancellationTokenSource = new CancellationTokenSource();
-
-        if (_virtualizeComponent is not null)
-        {
-            // If we're using Virtualize, we have to go through its RefreshDataAsync API otherwise:
-            // (1) It won't know to update its own internal state if the provider output has changed
-            // (2) We won't know what slice of data to query for
-            await _virtualizeComponent.RefreshDataAsync();
-            _pendingDataLoadCancellationTokenSource = null;
-        }
-        else
-        {
-            // If we're not using Virtualize, we build and execute a request against the items provider directly
-            _lastRefreshedPaginationStateHash = Pagination?.GetHashCode();
-            var startIndex = Pagination is null ? 0 : (Pagination.CurrentPageIndex * Pagination.ItemsPerPage);
-            var request = new BitDataGridItemsProviderRequest<TGridItem>(
-                startIndex, Pagination?.ItemsPerPage, _sortByColumn, _sortByAscending, thisLoadCts.Token);
-            var result = await ResolveItemsRequestAsync(request);
-            if (!thisLoadCts.IsCancellationRequested)
-            {
-                _currentNonVirtualizedViewItems = result.Items;
-                _ariaBodyRowCount = _currentNonVirtualizedViewItems.Count;
-                Pagination?.SetTotalItemCountAsync(result.TotalItemCount);
-                _pendingDataLoadCancellationTokenSource = null;
-            }
-        }
+        // Move into a "loading" state; cancel and dispose any previous load
+        _pendingDataLoadCancellationTokenSource?.Cancel();
+        _pendingDataLoadCancellationTokenSource?.Dispose();
+        var thisLoadCts = new CancellationTokenSource();
+        _pendingDataLoadCancellationTokenSource = thisLoadCts;
+
+        // Re-render immediately so LoadingTemplate/CSS "loading" state is visible
+        await InvokeAsync(StateHasChanged);
+
+        try
+        {
+            if (_virtualizeComponent is not null)
+            {
+                // If we're using Virtualize, we have to go through its RefreshDataAsync API otherwise:
+                // (1) It won't know to update its own internal state if the provider output has changed
+                // (2) We won't know what slice of data to query for
+                await _virtualizeComponent.RefreshDataAsync();
+            }
+            else
+            {
+                // Build and execute a request against the items provider directly
+                _lastRefreshedPaginationStateHash = Pagination?.GetHashCode();
+                var startIndex = Pagination is null ? 0 : (Pagination.CurrentPageIndex * Pagination.ItemsPerPage);
+                var request = new BitDataGridItemsProviderRequest<TGridItem>(
+                    startIndex, Pagination?.ItemsPerPage, _sortByColumn, _sortByAscending, thisLoadCts.Token);
+                var result = await ResolveItemsRequestAsync(request);
+                if (!thisLoadCts.IsCancellationRequested)
+                {
+                    _currentNonVirtualizedViewItems = result.Items;
+                    _ariaBodyRowCount = _currentNonVirtualizedViewItems.Count;
+                    Pagination?.SetTotalItemCountAsync(result.TotalItemCount);
+                }
+            }
+        }
+        finally
+        {
+            if (_pendingDataLoadCancellationTokenSource == thisLoadCts)
+            {
+                _pendingDataLoadCancellationTokenSource = null;
+            }
+            thisLoadCts.Dispose();
+        }

356-359: Respect cancellation in debounce.

Pass the request token to Task.Delay to avoid unnecessary delay after cancellation.

Apply:

-        await Task.Delay(100);
+        await Task.Delay(100, request.CancellationToken);
🧹 Nitpick comments (4)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor (1)

126-131: Optional: Announce loading to screen readers.

Consider adding aria-live/role to the loading container for better a11y when the row appears.

Example:

-                        <BitStack Alignment="BitAlignment.Center" Style="height:185px">
+                        <BitStack Alignment="BitAlignment.Center" Style="height:185px" AriaLive="BitAriaLive.Polite" Role="status">
src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor (1)

33-44: Loading row never spans exactly; compute colspan.

Using a hardcoded colspan="100" is brittle. Span actual column count and guard for zero.

Apply:

-                        <tr>
-                            <td colspan="100">
+                        <tr>
+                            <td colspan="@Math.Max(1, _columns.Count)">
                                 @LoadingTemplate
                             </td>
                         </tr>
src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor.cs (1)

129-135: Typo in API doc.

"rid" → "grid".

Apply:

-    /// A callback that supplies data for the rid.
+    /// A callback that supplies data for the grid.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.cs (1)

68-70: Typo in parameter description.

"rid" → "grid". This appears in the public docs table.

Apply:

-            Description = @"A callback that supplies data for the rid.
+            Description = @"A callback that supplies data for the grid.
                             You should supply either Items or ItemsProvider, but not both.",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 2724b88 and 25bdf15.

📒 Files selected for processing (5)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor (2 hunks)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor.cs (5 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor (1 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.cs (5 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.samples.cs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build and test
🔇 Additional comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor (1)

8-8: Back-compat alias looks good.

Preferring Columns over ChildContent keeps existing usage working.

src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.razor.cs (1)

434-435: Conditional 'loading' class logic looks correct.

Only applies CSS loader when no LoadingTemplate is supplied.

@msynk msynk merged commit 888fbe7 into bitfoundation:develop Sep 1, 2025
3 checks passed
@msynk msynk deleted the 11311-blazorui-datagrid-loadingtemplate branch September 1, 2025 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The BitDataGrid component needs a feature to render custom UI for the loading state
2 participants