Skip to content

Conversation

@ArgoZhang
Copy link
Member

@ArgoZhang ArgoZhang commented Oct 16, 2025

Link issues

fixes #6916

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Refactor Table component to extract and streamline content row rendering into separate methods and context struct, enhancing readability and maintainability.

Enhancements:

  • Extract cell rendering logic into RenderContentRow and RenderContentCell methods
  • Introduce TableContentCellContext to encapsulate cell state
  • Add helper methods GetCellArgs and GetTreeInfo for cleaner tree and cell argument handling

Copilot AI review requested due to automatic review settings October 16, 2025 01:49
@bb-auto bb-auto bot added the enhancement New feature or request label Oct 16, 2025
@bb-auto bb-auto bot added this to the 9.11.0 milestone Oct 16, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 16, 2025

Reviewer's Guide

Refactored table row rendering by extracting inline cell and row logic into reusable RenderContentRow and RenderContentCell fragments, backed by a TableContentCellContext struct and helper methods, to improve readability and maintainability.

Sequence diagram for refactored table row rendering using RenderContentRow and RenderContentCell

sequenceDiagram
    participant Table
    participant "RenderContentRow()"
    participant "RenderContentCell()"
    participant "TableContentCellContext"
    Table->>"RenderContentRow()": Call for each row
    "RenderContentRow()"->>"GetCellArgs()": Get cell args for each column
    "RenderContentRow()"->>"GetTreeInfo()": Get tree info for first column
    "RenderContentRow()"->>"TableContentCellContext": Create context
    "RenderContentRow()"->>"RenderContentCell()": Render cell with context
    "RenderContentCell()"-->>Table: Rendered cell fragment
Loading

Class diagram for new TableContentCellContext struct and related types

classDiagram
    class TableContentCellContext~TItem~ {
        +TItem Item
        +int Colspan
        +ITableColumn Col
        +string? CellClass
        +bool HasTreeChildren
        +bool IsInCell
        +int Degree
        +bool IsExpand
        +bool IsFirstColOfTree
        +RenderFragment? ValueTemplate
        +string? Value
    }
    class ITableColumn {
    }
    class RenderFragment {
    }
    TableContentCellContext --> ITableColumn : Col
    TableContentCellContext --> RenderFragment : ValueTemplate
Loading

Class diagram for new RenderContentRow and RenderContentCell fragments

classDiagram
    class Table {
        +RenderFragment RenderContentRow(TItem item)
        +RenderFragment<TableContentCellContext<TItem>> RenderContentCell
        +TableContentCellContext<TItem> GetCellArgs(TItem item, ITableColumn col, ref int colIndex)
        +(bool, int, bool, bool) GetTreeInfo(TItem item, int index)
    }
    Table --> TableContentCellContext : uses
    Table --> ITableColumn : uses
    Table --> RenderFragment : uses
Loading

File-Level Changes

Change Details Files
Extract row rendering into RenderContentRow fragment
  • Removed the inline foreach cell-rendering block in Table.razor
  • Replaced it with a call to @RenderContentRow(item)
  • Implemented RenderContentRow in Table.razor.cs to iterate columns and invoke RenderContentCell
src/BootstrapBlazor/Components/Table/Table.razor
src/BootstrapBlazor/Components/Table/Table.razor.cs
Encapsulate cell rendering in RenderContentCell
  • Added RenderContentCell RenderFragment taking TableContentCellContext
  • Moved complex DynamicElement and value/template selection into this fragment
src/BootstrapBlazor/Components/Table/Table.razor
Introduce TableContentCellContext record
  • Created a readonly record struct to carry cell state (item, col, colspan, classes, tree info, value/template)
  • Updated fragment usage to consume this context object
src/BootstrapBlazor/Components/Table/TableContentCellContext.cs
Add helper methods for cell args and tree info
  • Implemented GetCellArgs to populate TableCellArgs and manage colspan
  • Implemented GetTreeInfo to extract tree node state (degree, expand, children)
src/BootstrapBlazor/Components/Table/Table.razor.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#6916 Add RenderContentRow to Table component to encapsulate row rendering logic.
#6916 Refactor Table row rendering code to improve readability by extracting inline cell and row rendering logic into reusable fragments and context structs.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@ArgoZhang ArgoZhang enabled auto-merge (squash) October 16, 2025 01:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the Table component's row rendering logic by extracting inline cell rendering code into a dedicated RenderContentRow method and introducing a new TableContentCellContext record struct. The refactoring improves code readability and maintainability by reducing the complexity of the Razor template and moving rendering logic to the code-behind file.

Key Changes:

  • Introduced TableContentCellContext<TItem> record struct to encapsulate cell rendering state
  • Extracted row rendering logic from Razor template into RenderContentRow method in code-behind
  • Created RenderContentCell render fragment to handle individual cell rendering using the new context

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
TableContentCellContext.cs New record struct defining the context/state for rendering table content cells
Table.razor.cs Added RenderContentRow method containing the extracted row rendering logic
Table.razor Refactored to use the new RenderContentRow method and RenderContentCell fragment, removing inline rendering code

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

sourcery-ai[bot]
sourcery-ai bot previously approved these changes Oct 16, 2025
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • Rename the HesTreeChildren property to HasTreeChildren for clarity and to avoid confusion.
  • Don’t reuse the same sequence number (0) for every call to builder.AddContent; use unique, incrementing sequence values to ensure Blazor diffing works correctly.
  • Creating a new TableContentCellContext and RenderFragment for every cell may impact performance—consider reusing or caching context data where possible to reduce allocations.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Rename the `HesTreeChildren` property to `HasTreeChildren` for clarity and to avoid confusion.
- Don’t reuse the same sequence number (0) for every call to builder.AddContent; use unique, incrementing sequence values to ensure Blazor diffing works correctly.
- Creating a new TableContentCellContext and RenderFragment for every cell may impact performance—consider reusing or caching context data where possible to reduce allocations.

## Individual Comments

### Comment 1
<location> `src/BootstrapBlazor/Components/Table/Table.razor.cs:1373-1382` </location>
<code_context>
+        foreach (var col in GetVisibleColumns())
</code_context>

<issue_to_address>
**suggestion:** The colIndex logic may be unclear and could be refactored for readability.

Consider refactoring the colIndex logic or adding a comment to clarify its role in column rendering and to prevent off-by-one mistakes.
</issue_to_address>

### Comment 2
<location> `src/BootstrapBlazor/Components/Table/Table.razor.cs:1367` </location>
<code_context>
     };
     #endregion

+    private RenderFragment RenderContentRow(TItem item) => builder =>
+    {
+        var index = 0;
</code_context>

<issue_to_address>
**issue (complexity):** Consider refactoring RenderContentRow by extracting cell rendering and tree logic into helper methods for clarity and maintainability.

Here’s one way to collapse the two big chunks (`OnCellRender` / colspan logic and the tree-info logic) into small helpers so that your `RenderContentRow` is just a simple loop + a call into each helper.

```csharp
private TableCellArgs GetCellArgs(TItem item, ITableColumn col, ref int colIndex)
{
    var cell = new TableCellArgs { Row = item, ColumnName = col.GetFieldName() };
    col.OnCellRender?.Invoke(cell);
    colIndex = cell.Colspan;
    return cell;
}

private (bool isFirstColOfTree, int degree, bool isExpand, bool hasChildren)
    GetTreeInfo(TItem item, int index)
{
    var isFirstColOfTree = IsTree && index == 0;
    if (!isFirstColOfTree)
        return (false, 0, false, false);

    var degree = 0;
    var treeItem = TreeNodeCache.Find(TreeRows, item, out degree);
    return ( isFirstColOfTree,
             degree,
             treeItem?.IsExpand  ?? false,
             treeItem?.HasChildren ?? false );
}
```

And then rewrite `RenderContentRow` to just call those:

```csharp
private RenderFragment RenderContentRow(TItem item) => builder =>
{
    var index = 0;
    var colIndex = 0;
    var isInCell = InCellMode && SelectedRows.FirstOrDefault() == item;

    foreach (var col in GetVisibleColumns())
    {
        if (colIndex > 1)
        {
            colIndex--;
            continue;
        }

        // 1) pull out any OnCellRender / colspan logic
        var cellArgs = GetCellArgs(item, col, ref colIndex);

        // 2) pull out tree node logic
        var (isTreeCol, degree, isExpand, hasChildren) = GetTreeInfo(item, index++);
        var hasTreeChildren = isTreeCol && hasChildren;

        // 3) one-liner to create context
        var ctx = new TableContentCellContext<TItem>
        {
            Item             = item,
            Col              = col,
            ColSpan          = cellArgs.Colspan,
            CellClass        = cellArgs.Class,
            Value            = cellArgs.Value,
            ValueTemplate    = cellArgs.ValueTemplate,
            IsInCell         = isInCell,
            IsFirstColOfTree = isTreeCol,
            Degree           = degree,
            IsExpend         = isExpand,
            HesTreeChildren  = hasTreeChildren
        };

        builder.AddContent(0, RenderContentCell(ctx));
    }
};
```

Benefits:

- RenderContentRow is now ~15 lines instead of ~40.
- All colspan/OnCellRender details live in `GetCellArgs`.
- All tree-node lookup lives in `GetTreeInfo`.
- Easy to read, test, or tweak each piece in isolation.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link

codecov bot commented Oct 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (605aca1) to head (295438f).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #6917   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          739       740    +1     
  Lines        31776     31848   +72     
  Branches      4468      4468           
=========================================
+ Hits         31776     31848   +72     
Flag Coverage Δ
BB 100.00% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ArgoZhang
Copy link
Member Author

@sourcery-ai review

sourcery-ai[bot]
sourcery-ai bot previously approved these changes Oct 16, 2025
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `src/BootstrapBlazor/Components/Table/Table.razor.cs:1367` </location>
<code_context>
     };
     #endregion

+    private RenderFragment RenderContentRow(TItem item) => builder =>
+    {
+        var index = 0;
</code_context>

<issue_to_address>
**issue (complexity):** Consider refactoring the loop by extracting cell rendering, tree state, and context-building logic into helper methods for clarity.

Here’s one way to pull most of the “plumbing” out of your loop into three small helpers:  

```csharp
private RenderFragment RenderContentRow(TItem item) => builder =>
{
    var skipCols = 0;
    var treeIndex = 0;
    var isInCell = InCellMode && SelectedRows.FirstOrDefault() == item;

    foreach (var col in GetVisibleColumns())
    {
        if (skipCols > 0)
        {
            skipCols--;
            continue;
        }

        // ← Extracted cell-render hook + colspan logic
        var cellArgs = ProcessOnCellRender(col, item, ref skipCols);

        // ← Extracted “tree” state logic
        var (isFirstTreeCol, degree, isExpand, hasChildren) = EvaluateTreeState(item, treeIndex++);

        // ← Extracted context-build
        var context = BuildCellContext(item, col, cellArgs, isInCell,
                                       isFirstTreeCol, degree, isExpand, hasChildren);

        builder.AddContent(0, RenderContentCell(context));
    }
};
```

And the three helpers:

```csharp
private TableCellArgs ProcessOnCellRender(
    ITableColumn col,
    TItem item,
    ref int skipCols)
{
    var args = new TableCellArgs { Row = item, ColumnName = col.GetFieldName() };
    col.OnCellRender?.Invoke(args);

    if (args.Colspan > 1)
    {
        // skip the next (Colspan-1) columns
        skipCols = args.Colspan - 1;
    }

    return args;
}

private (bool isFirstTreeCol, int degree, bool isExpand, bool hasChildren)
    EvaluateTreeState(TItem item, int currentIndex)
{
    if (!IsTree || currentIndex != 0)
        return (false, 0, false, false);

    var treeItem = TreeNodeCache.Find(TreeRows, item, out var degree);
    return (true,
            degree,
            treeItem?.IsExpand   == true,
            treeItem?.HasChildren == true);
}

private TableContentCellContext<TItem> BuildCellContext(
    TItem item,
    ITableColumn col,
    TableCellArgs cellArgs,
    bool isInCell,
    bool isFirstTreeCol,
    int degree,
    bool isExpand,
    bool hasChildren)
{
    return new TableContentCellContext<TItem>()
    {
        Item             = item,
        Col              = col,
        CellClass        = cellArgs.Class,
        ColSpan          = cellArgs.Colspan,
        Value            = cellArgs.Value,
        ValueTemplate    = cellArgs.ValueTemplate,
        IsInCell         = isInCell,
        IsFirstColOfTree = isFirstTreeCol,
        Degree           = degree,
        IsExpand         = isExpand,
        HasTreeChildren  = isFirstTreeCol && hasChildren
    };
}
```

This keeps your loop body very flat, each helper has one clear job, and overall behavior is unchanged.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@ArgoZhang
Copy link
Member Author

@sourcery-ai review

sourcery-ai[bot]
sourcery-ai bot previously approved these changes Oct 16, 2025
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • Use unique, incrementing sequence values when calling builder.AddContent in RenderContentRow to ensure Blazor diffing works correctly.
  • Consider renaming the loop variables 'index' and 'colIndex' in RenderContentRow to more descriptive names (e.g. 'cellIndex' and 'remainingSpan') to clarify their purposes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Use unique, incrementing sequence values when calling builder.AddContent in RenderContentRow to ensure Blazor diffing works correctly.
- Consider renaming the loop variables 'index' and 'colIndex' in RenderContentRow to more descriptive names (e.g. 'cellIndex' and 'remainingSpan') to clarify their purposes.

## Individual Comments

### Comment 1
<location> `src/BootstrapBlazor/Components/Table/Table.razor.cs:1408` </location>
<code_context>
+        }
+    };
+
+    private static TableCellArgs GetCellArgs(TItem item, ITableColumn col, ref int colIndex)
+    {
+        var cell = new TableCellArgs { Row = item, ColumnName = col.GetFieldName() };
</code_context>

<issue_to_address>
**suggestion:** Reconsider using ref parameter for colIndex in GetCellArgs.

Returning both TableCellArgs and the updated colIndex, or encapsulating the logic, would improve code clarity and reduce the risk of bugs from ref usage.

Suggested implementation:

```csharp
    private static (TableCellArgs cell, int colIndex) GetCellArgs(TItem item, ITableColumn col, int colIndex)
    {
        var cell = new TableCellArgs { Row = item, ColumnName = col.GetFieldName() };
        col.OnCellRender?.Invoke(cell);
        colIndex = cell.Colspan;
        return (cell, colIndex);
    }

```

You will need to update all calls to `GetCellArgs` throughout the file to:
- Remove the `ref` keyword from the `colIndex` argument.
- Use tuple deconstruction to get both the `TableCellArgs` and the updated `colIndex`, e.g.:
  ```csharp
  var (cell, colIndex) = GetCellArgs(item, col, colIndex);
  ```
</issue_to_address>

### Comment 2
<location> `src/BootstrapBlazor/Components/Table/Table.razor.cs:1416` </location>
<code_context>
+        return cell;
+    }
+
+    private (bool isFirstColOfTree, int degree, bool isExpand, bool hasChildren) GetTreeInfo(TItem item, int index)
+    {
+        var isFirstColOfTree = IsTree && index == 0;
</code_context>

<issue_to_address>
**suggestion:** Tuple return type could be replaced with a dedicated struct for tree info.

Using a struct or record for the return type will make the code easier to read and maintain, particularly if more fields are added in the future.

Suggested implementation:

```csharp
    private struct TreeInfo
    {
        public bool IsFirstColOfTree { get; init; }
        public int Degree { get; init; }
        public bool IsExpand { get; init; }
        public bool HasChildren { get; init; }
    }

    private TreeInfo GetTreeInfo(TItem item, int index)
    {
        var isFirstColOfTree = IsTree && index == 0;
        if (!isFirstColOfTree)
        {
            return new TreeInfo
            {
                IsFirstColOfTree = false,
                Degree = 0,
                IsExpand = false,
                HasChildren = false
            };
        }

        var treeItem = TreeNodeCache.Find(TreeRows, item, out var degree);
        return new TreeInfo
        {
            IsFirstColOfTree = isFirstColOfTree,
            Degree = degree,
            IsExpand = treeItem?.IsExpand ?? false,
            HasChildren = treeItem?.HasChildren ?? false
        };

```

If there are usages of `GetTreeInfo` elsewhere in the file or project, you will need to update them to use the new `TreeInfo` struct fields (e.g., `.IsFirstColOfTree`, `.Degree`, etc.) instead of tuple deconstruction.
</issue_to_address>

### Comment 3
<location> `src/BootstrapBlazor/Components/Table/Table.razor:747-756` </location>
<code_context>
+    RenderFragment<TableContentCellContext<TItem>> RenderContentCell => context =>
</code_context>

<issue_to_address>
**suggestion:** Consider extracting inner logic of RenderContentCell to a helper method for readability.

Moving the complex logic from the lambda to a helper method will make the code easier to read and maintain as future changes are made.
</issue_to_address>

### Comment 4
<location> `src/BootstrapBlazor/Components/Table/Table.razor.cs:1367` </location>
<code_context>
     };
     #endregion

+    private RenderFragment RenderContentRow(TItem item) => builder =>
+    {
+        var index = 0;
</code_context>

<issue_to_address>
**issue (complexity):** Consider refactoring the cell rendering loop to use a for-loop with Colspan-based index advancement and helper methods for context and tree info creation.

```suggestion
The manual `colIndex` skipping and tuplebased `GetTreeInfo` can be inlined/simplified by using a `for` loop that advances by `Colspan`, and moving the context building into its own helper. This removes the `if (colIndex > 1) … continue` pattern and flattens the nesting.

```csharp
private RenderFragment RenderContentRow(TItem item) => builder =>
{
    var cols = GetVisibleColumns().ToList();
    var seq = 0;

    for (int i = 0; i < cols.Count; i++)
    {
        var col = cols[i];
        // get cell args and colspan
        var cellArgs = GetCellArgs(item, col);

        // build full context (including tree info if needed)
        var context = BuildCellContext(item, col, cellArgs, seq++);

        builder.AddContent(0, RenderContentCell(context));

        // skip merged columns
        i += cellArgs.Colspan - 1;
    }
};

private TableCellArgs GetCellArgs(TItem item, ITableColumn col)
{
    var args = new TableCellArgs { Row = item, ColumnName = col.GetFieldName() };
    col.OnCellRender?.Invoke(args);
    return args;
}

private TableContentCellContext<TItem> BuildCellContext(
    TItem item,
    ITableColumn col,
    TableCellArgs cellArgs,
    int cellIndex)
{
    var isFirstTreeCol = IsTree && cellIndex == 0;
    var (degree, isExpand, hasChildren) = isFirstTreeCol
        ? GetTreeNodeInfo(item)
        : (0, false, false);

    return new TableContentCellContext<TItem>
    {
        Item            = item,
        Col             = col,
        Colspan         = cellArgs.Colspan,
        CellClass       = cellArgs.Class,
        Value           = cellArgs.Value,
        ValueTemplate   = cellArgs.ValueTemplate,
        HasTreeChildren = isFirstTreeCol && hasChildren,
        IsInCell        = InCellMode && SelectedRows.FirstOrDefault() == item,
        Degree          = degree,
        IsExpand        = isExpand,
        IsFirstColOfTree= isFirstTreeCol
    };
}

private (int degree, bool isExpand, bool hasChildren) GetTreeNodeInfo(TItem item)
{
    var node = TreeNodeCache.Find(TreeRows, item, out var degree);
    return (degree,
            node?.IsExpand    ?? false,
            node?.HasChildren ?? false);
}
```

Steps:
1. Switch to a `for`‐loop over a `List<ITableColumn>` so you can `i += Colspan - 1`.
2. Inline skipping logic via the loop increment.
3. Extract treeinfo and contextbuilding into `BuildCellContext` and `GetTreeNodeInfo` for clearer separation.
4. Keep `GetCellArgs` focused on `col.OnCellRender` and `Colspan` determination.

This preserves all functionality but makes the flow linear and each helper singlepurpose.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@ArgoZhang ArgoZhang disabled auto-merge October 16, 2025 02:44
@ArgoZhang ArgoZhang merged commit 8768786 into main Oct 16, 2025
7 checks passed
@ArgoZhang ArgoZhang deleted the perf-table branch October 16, 2025 02:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(Table): add RenderContentRow improve readability

2 participants