Skip to content

Conversation

@msynk
Copy link
Member

@msynk msynk commented Jun 25, 2025

closes #10996

Summary by CodeRabbit

  • New Features

    • Introduced "Load More" functionality to the basic list component, allowing incremental loading of items with customizable templates and text.
    • Added support for asynchronous parameter set callbacks in components, enabling async side effects during parameter assignment.
    • Added new attribute for marking async parameter set methods.
  • Enhancements

    • Improved virtualization and item provider support in the basic list, including new parameters for virtualization, placeholders, and item provisioning.
    • Enhanced demo examples to showcase new features and reorganized for clarity.
    • Updated styles for new list features and templates.
  • Bug Fixes

    • Corrected attribute and parameter naming for virtualization in the basic list component and related tests.
  • Documentation

    • Added comprehensive code samples and usage documentation for new and existing list features.
  • Refactor

    • Cleaned up and reorganized demo markup and code for better readability and demonstration.
  • Style

    • Updated and added CSS classes to support new list layouts and interactions.

@msynk msynk requested a review from Cyrus-Sushiant June 25, 2025 14:43
@coderabbitai
Copy link

coderabbitai bot commented Jun 25, 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

The changes introduce a "LoadMore" feature to the BitBasicList component, enabling incremental loading of list items either from a static collection or an asynchronous provider. Supporting updates include new parameters, rendering logic, demo examples, and source generator enhancements for async parameter callbacks. Additional minor refactoring and documentation improvements are included.

Changes

Files / Group Change Summary
src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.razor, .razor.cs, .scss, _BitBasicListVirtualize.cs Added LoadMore functionality with new parameters, state management, and rendering logic; updated virtualization and item provider support; new CSS classes for LoadMore UI; minor refactoring and bug fixes.
src/BlazorUI/Bit.BlazorUI.SourceGenerators/Component/BlazorParameter.cs, ComponentSourceGenerator.cs, ComponentSyntaxContextReceiver.cs Added support for async parameter set callbacks via new property and attribute; updated code generation for async handling.
src/BlazorUI/Bit.BlazorUI/Utils/CallOnSetAsyncAttribute.cs Introduced new internal attribute class for async parameter set callback support.
src/BlazorUI/Bit.BlazorUI.Tests/Components/Lists/BasicList/BitBasicListTest.razor Updated attribute name from EnableVirtualization to Virtualize for consistency.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor, .razor.cs, .razor.samples.cs, .razor.scss Refactored and expanded demo to showcase new LoadMore feature, virtualize, providers, and templates; improved code organization and styling.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant BitBasicList
    participant ItemsProvider
    participant UI

    User->>BitBasicList: Triggers LoadMore (e.g., clicks button)
    alt ItemsProvider is set
        BitBasicList->>ItemsProvider: Request next batch (skip, size)
        ItemsProvider-->>BitBasicList: Returns items
    else
        BitBasicList->>BitBasicList: Slice Items collection (skip, size)
    end
    BitBasicList->>UI: Update _viewItems and loading state
    UI-->>User: Render new items and updated LoadMore button
Loading

Assessment against linked issues

Objective Addressed Explanation
Add LoadMore feature to BitBasicList component (#10996)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Support for async parameter set callbacks and new CallOnSetAsyncAttribute (SourceGenerators, Utils, etc.) These changes support async parameter handling, which is not mentioned in the LoadMore objective.
Refactoring and expansion of demo/sample code unrelated to LoadMore (Demo .razor.samples.cs, .razor.scss, etc.) Demo code reorganization and unrelated examples go beyond the scope of the LoadMore feature.

Poem

A bunny hopped through fields of code,
And found a list that could now load,
More items with a single click—
No need to fetch the whole big brick!
With LoadMore magic, lists delight,
Happy users, code feels light.
🥕✨

✨ Finishing Touches
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in 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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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: 1

🧹 Nitpick comments (3)
src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.scss (1)

12-19: Add visual feedback & disabled style for load-more trigger
.bit-bsl-lmt is clickable (cursor: pointer) but has no :hover, :active, or disabled states. A minimal hover style improves affordance; a [disabled] style prevents misleading cursor when loading.

 .bit-bsl-lmt {
     width: 100%;
     display: flex;
     cursor: pointer;
     padding: spacing(2);
     align-items: center;
     justify-content: center;
+    &:hover:not([disabled]) {
+        background-color: rgba(0,0,0,.04);
+    }
+    &[disabled] {
+        cursor: default;
+        opacity: .5;
+    }
 }
src/BlazorUI/Bit.BlazorUI.SourceGenerators/Component/BlazorParameter.cs (1)

15-16: Make async callback name immutable & constructor-supplied
All other fields are initialised through the primary constructor; leaving CallOnSetAsyncMethodName mutable invites accidental nulls. Consider extending the constructor and making the set accessor init.

-public string? CallOnSetAsyncMethodName { get; set; }
+public string? CallOnSetAsyncMethodName { get; init; }

and add a sixth constructor parameter.

src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.razor.cs (1)

8-11: Consider thread-safe access to _globalCts

While Blazor components typically execute on a single thread, the _globalCts field is accessed from multiple methods (RefreshDataAsync, PerformLoadMore, DisposeAsync). Consider using Interlocked.CompareExchange for atomic operations if there's any possibility of concurrent access.

For more robust thread safety:

 private async Task PerformLoadMore(bool reset)
 {
     // ... existing reset logic ...
 
     if (LoadMore is false || _globalCts is not null) return;
 
     var localCts = new CancellationTokenSource();
-    _globalCts = localCts;
+    var existingCts = Interlocked.CompareExchange(ref _globalCts, localCts, null);
+    if (existingCts is not null)
+    {
+        localCts.Dispose();
+        return; // Another operation is already in progress
+    }

Also applies to: 189-192, 253-261

📜 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 6100458 and 412bb38.

📒 Files selected for processing (13)
  • src/BlazorUI/Bit.BlazorUI.SourceGenerators/Component/BlazorParameter.cs (1 hunks)
  • src/BlazorUI/Bit.BlazorUI.SourceGenerators/Component/ComponentSourceGenerator.cs (5 hunks)
  • src/BlazorUI/Bit.BlazorUI.SourceGenerators/Component/ComponentSyntaxContextReceiver.cs (1 hunks)
  • src/BlazorUI/Bit.BlazorUI.Tests/Components/Lists/BasicList/BitBasicListTest.razor (1 hunks)
  • src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.razor (1 hunks)
  • src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.razor.cs (4 hunks)
  • src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.scss (1 hunks)
  • src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/_BitBasicListVirtualize.cs (1 hunks)
  • src/BlazorUI/Bit.BlazorUI/Utils/CallOnSetAsyncAttribute.cs (1 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor (1 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor.cs (4 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor.samples.cs (1 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor.scss (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build and test
🔇 Additional comments (13)
src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.scss (1)

8-11: Consider display: contents accessibility limitations
display: contents removes the element from the accessibility tree in several browsers (notably Safari ≤ 17 and some AT combinations). If .bit-bsl-lmb ever carries ARIA roles/attributes, they will be lost.

-.bit-bsl-lmb {
-    display: contents;
-}
+.bit-bsl-lmb {
+    /* Fallback keeps element in the tree for non-supporting UAs */
+    display: block;
+    @supports (display: contents) {
+        display: contents;
+    }
+}

Please verify that losing the element from the AX tree does not break list semantics and test in Safari.

src/BlazorUI/Bit.BlazorUI.Tests/Components/Lists/BasicList/BitBasicListTest.razor (1)

1-1: Ensure all tests & samples use the new Virtualize parameter
The rename looks correct here, but several demos/tests referenced EnableVirtualization previously. A repo-wide search avoids silent regressions.

rg -n "EnableVirtualization"
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor.scss (1)

1-11: LGTM – SCSS nesting only
The change is purely syntactic; compiled CSS is unchanged.

src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/_BitBasicListVirtualize.cs (1)

38-47: Good consistency improvement!

Using the open generic type Virtualize<> in nameof expressions is cleaner and more maintainable than specifying the full generic type Virtualize<TItem>. This change improves code consistency without affecting functionality.

src/BlazorUI/Bit.BlazorUI.SourceGenerators/Component/ComponentSyntaxContextReceiver.cs (1)

47-52: Well-implemented async callback support!

The implementation correctly follows the existing pattern for handling attributes. The null-safe extraction of the async callback method name is properly handled.

src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.razor (2)

11-49: Well-structured rendering logic for LoadMore and virtualization!

The implementation properly handles all rendering scenarios:

  • Virtualization enabled/disabled
  • LoadMore mode with internal items management
  • ItemsProvider delegation
  • Empty content display suppression during loading

The conditional logic is clear and covers all cases appropriately.


51-72: Comprehensive LoadMore button implementation!

The LoadMore button rendering correctly:

  • Respects the _loadMoreFinished flag to hide when all items are loaded
  • Supports custom templates via LoadMoreTemplate
  • Provides default loading indicator with "..."
  • Handles click events to trigger PerformLoadMore
src/BlazorUI/Bit.BlazorUI.SourceGenerators/Component/ComponentSourceGenerator.cs (1)

60-60: Excellent async support implementation!

The async patterns are correctly implemented:

  • SetParametersAsync properly returns Task and uses async
  • Async callbacks are conditionally awaited only when values change
  • Base method calls are consistently awaited
  • Two-way binding Assign methods support async callbacks

The implementation follows async/await best practices throughout.

Also applies to: 107-110, 128-139, 169-172

src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor.samples.cs (1)

1-456: Comprehensive demo samples covering all features!

The demo code effectively showcases:

  • Basic and virtualized rendering
  • Async ItemsProvider with HTTP data fetching
  • LoadMore functionality with various configurations
  • Custom templates and styling
  • RTL support

The examples provide clear patterns for developers to follow.

src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor (1)

14-253: Demo examples effectively showcase the new LoadMore functionality!

The reorganization and new examples provide comprehensive coverage of the BitBasicList features, including basic usage, virtualization, ItemsProvider, and the new LoadMore functionality with various configurations.

src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Lists/BasicList/BitBasicListDemo.razor.cs (1)

70-235: Well-structured demo implementation with proper async patterns!

The new LoadMore parameters are properly documented, and the async data providers effectively simulate real-world scenarios with appropriate delays and pagination handling.

src/BlazorUI/Bit.BlazorUI/Components/Lists/BasicList/BitBasicList.razor.cs (2)

150-178: Well-implemented parameter change detection!

The OnParametersSetAsync method properly detects changes to both Items and ItemsProvider parameters and initiates the LoadMore process when appropriate. The priority given to ItemsProvider over Items is a good design decision.


181-231: Add comprehensive exception handling in PerformLoadMore

The method only catches OperationCanceledException. If any other exception occurs (e.g., network errors from ItemsProvider), it won't be caught, potentially leaving _globalCts in an inconsistent state.

Consider wrapping the entire try block logic in an additional try-catch:

 try
 {
     StateHasChanged();
 
     try
     {
         if (ItemsProvider is null)
         {
             var items = Items ?? [];
 
             _viewItems = [.. _viewItems, .. items.Skip(_loadMoreSkip).Take(LoadMoreSize)];
 
             _loadMoreFinished = _viewItems.Count >= items.Count;
         }
         else
         {
             var result = await ProvideVirtualizedItems(new(_loadMoreSkip, LoadMoreSize, localCts.Token));
 
             if (localCts.IsCancellationRequested is false)
             {
                 _viewItems = [.. _viewItems, .. result.Items];
 
                 _loadMoreFinished = _viewItems.Count >= result.TotalItemCount;
             }
         }
 
         _loadMoreSkip += LoadMoreSize;
     }
     catch (OperationCanceledException oce) when (oce.CancellationToken == localCts.Token) { }
+    catch (Exception ex)
+    {
+        // Log the exception or handle it appropriately
+        // You might want to set an error state or notify the user
+        throw; // Re-throw after cleanup in finally block
+    }
 }
 finally
 {
     _globalCts = null;
     localCts.Dispose();
 }

Likely an incorrect or invalid review comment.

@msynk msynk force-pushed the 10996-blazorui-basiclist-loadmore branch from 412bb38 to 8bbf60e Compare June 25, 2025 15:42
@msynk msynk merged commit 3392e25 into bitfoundation:develop Jun 26, 2025
3 checks passed
@msynk msynk deleted the 10996-blazorui-basiclist-loadmore branch June 26, 2025 12:26
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 BitBasicList component needs LoadMore feature

2 participants