Skip to content

Conversation

@momijijin
Copy link
Collaborator

@momijijin momijijin commented Dec 16, 2025

Link issues

fixes #7345

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

Add optional extended column selection capabilities to the table column list dropdown, including bulk visibility controls, search, and localization support.

New Features:

  • Introduce an optional column list extension in the table header that provides search, bulk select/deselect, and inverse selection for visible columns.
  • Add localized toast messages that warn when attempting to hide all columns from the table column selector.

Enhancements:

  • Adjust table column selector styles to accommodate the extended selection controls and ensure proper layout.
  • Extend table localization initialization to include strings for the new column selection warning toasts.

@bb-auto
Copy link

bb-auto bot commented Dec 16, 2025

Thanks for your PR, @momijijin. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@bb-auto bb-auto bot requested a review from ArgoZhang December 16, 2025 11:21
@bb-auto bb-auto bot added the enhancement New feature or request label Dec 16, 2025
@bb-auto bb-auto bot added this to the v10.1.0 milestone Dec 16, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 16, 2025

Reviewer's Guide

Adds an optional 'column list select extension' feature to the Table column chooser, including search, bulk select/clear/invert behavior, and localized warning toasts when all columns would be hidden, plus minimal styling updates and a new enabling parameter.

Sequence diagram for column list bulk visibility toggle with warning toast

sequenceDiagram
    actor User
    participant UI_Dropdown as UI_ColumnDropdown
    participant Table as Table_TItem

    User->>UI_Dropdown: Click column list button
    UI_Dropdown->>User: Show column list with select extension

    User->>UI_Dropdown: Uncheck master checkbox
    UI_Dropdown->>Table: OnToggleAllColumnsVisibleState(UnChecked, empty)

    alt state is UnChecked
        loop for each column except first
            Table->>Table: Set column.Visible = false
            Table->>Table: OnToggleColumnVisible(column.Name, false)
        end
        Table->>Table: ShowToastAsync(ColumnGroupSelectButtonWarnToastTitle,
        Table->>Table: ColumnGroupSelectButtonWarnToastContent, Warning)
    end

    Table-->>UI_Dropdown: InvokeAsync(StateHasChanged)
    UI_Dropdown->>User: Update column list and show warning toast
Loading

Class diagram for updated Table_TItem column list select extension

classDiagram
    class Table_TItem {
        +bool ShowColumnList
        +bool ShowColumnListSelectExtension
        +string ColumnGroupSelectButtonWarnToastTitle
        +string ColumnGroupSelectButtonWarnToastContent
        -string _visibleColumnsSearchKey
        -List_ColumnVisibleItem _visibleColumns
        -List_ColumnVisibleItem _visibleColumnsSearchResult
        +CheckboxState get_VisibleColumnsCurrentSelectedResult()
        +List_ColumnVisibleItem get_VisibleColumnsSearchResult()
        +Task SearchVisibleColumns(string searchKey)
        +Task InverseSelected()
        +Task OnToggleAllColumnsVisibleState(CheckboxState state, string columnName)
        +Task OnToggleColumnVisible(string columnName, bool visible)
        +Task ShowToastAsync(string title, string content, ToastCategory category)
        -void OnInitLocalization()
    }

    class ColumnVisibleItem {
        +string Name
        +string DisplayName
        +bool Visible
    }

    class CheckboxState {
        <<enumeration>>
        Checked
        UnChecked
        Indeterminate
    }

    class ToastCategory {
        <<enumeration>>
        Info
        Success
        Warning
        Error
    }

    class Checkbox {
        +CheckboxState State
        +Task OnStateChanged(CheckboxState state, string value)
    }

    class BootstrapInputGroup
    class BootstrapInput {
        +string Value
        +bool IsClearable
        +bool UseInputEvent
        +Task OnValueChanged(string value)
    }

    class Button {
        +string Icon
        +string TooltipText
        +string TooltipTrigger
        +Color Color
        +Task OnClick()
    }

    class Color {
        <<enumeration>>
        Primary
        Secondary
        Success
        Danger
        Warning
        Info
        Light
        Dark
    }

    Table_TItem "1" o-- "*" ColumnVisibleItem : manages
    Table_TItem --> CheckboxState : uses
    Table_TItem --> ToastCategory : uses
    Table_TItem --> Checkbox : binds_state
    Table_TItem --> BootstrapInput : binds_search
    Table_TItem --> Button : binds_inverse

    Checkbox --> CheckboxState : exposes_state
Loading

File-Level Changes

Change Details Files
Add search, tri‑state select-all, and invert-selection logic for the column visibility list, including guardrails to prevent hiding all columns and showing warning toasts.
  • Compute a tri-state checkbox value based on whether all/none/some visible columns are selected.
  • Maintain a search key and a filtered _visibleColumnsSearchResult list, updating it on input change and triggering StateHasChanged.
  • Implement InverseSelected to toggle visibility of each column, emit OnToggleColumnVisible for each, and ensure at least one column remains visible with a warning toast if necessary.
  • Implement OnToggleAllColumnsVisibleState to set all columns visible or hide all but the first with a warning toast, then refresh UI.
src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs
Extend the column chooser dropdown UI to include the new extension controls (select-all checkbox, search box, invert button) behind a feature flag and wire them to the new behaviors.
  • Add ShowColumnListSelectExtension check to optionally render an input group with tri-state checkbox, clearable search input, and an invert-selection button at the top of the dropdown.
  • Wire the tri-state checkbox to VisibleColumnsCurrentSelectedResult and OnToggleAllColumnsVisibleState, the search box to SearchVisibleColumns, and the button to InverseSelected.
  • Change the foreach data source to use the filtered VisibleColumnsSearchResult when the extension is enabled, otherwise use the original _visibleColumns list.
src/BootstrapBlazor/Components/Table/Table.razor
Introduce new localized parameters and resource usage for warning toast text used when all columns would be hidden.
  • Add ColumnGroupSelectButtonWarnToastTitle and ColumnGroupSelectButtonWarnToastContent as [Parameter] properties on Table.
  • Initialize the new parameters from IStringLocalizer in OnInitLocalization when not explicitly set.
  • Update locale JSON files to include the new localization keys for both English and Chinese.
src/BootstrapBlazor/Components/Table/Table.razor.Localization.cs
src/BootstrapBlazor/Locales/en.json
src/BootstrapBlazor/Locales/zh.json
Add a new parameter to control whether the column list select extension is shown and provide basic styling for the new controls in the dropdown.
  • Add a ShowColumnListSelectExtension boolean [Parameter] in the toolbar-related partial class to feature-flag the new UI.
  • Add SCSS rules for .column-list-select-extension to set a minimum width and adjust the checkbox layout inside the input group.
src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs
src/BootstrapBlazor/Components/Table/Table.razor.scss

Assessment against linked issues

Issue Objective Addressed Explanation
#7345 Add a ColumnListSelectExtension feature to the Table column list dropdown that provides enhanced column selection controls (tri‑state select-all checkbox, search/filter for columns, and invert selection), integrated into the existing column visibility UI.
#7345 Expose configuration and localization support for the new ColumnListSelectExtension feature, including a parameter to enable/disable it and localized toast messages when attempting to hide all columns.

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

sourcery-ai[bot]
sourcery-ai bot previously approved these changes Dec 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:

  • When preventing all columns from being hidden in InverseSelected, you set _visibleColumns[0].Visible = true but don't call OnToggleColumnVisible for that column, which may leave the table's internal state or consumers out of sync with the UI.
  • The search cache _visibleColumnsSearchResult is only updated inside SearchVisibleColumns; if _visibleColumns changes (e.g., columns added/removed or renamed) while a search is active, the filtered list can become stale—consider recomputing the search result when the underlying columns collection changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- When preventing all columns from being hidden in `InverseSelected`, you set `_visibleColumns[0].Visible = true` but don't call `OnToggleColumnVisible` for that column, which may leave the table's internal state or consumers out of sync with the UI.
- The search cache `_visibleColumnsSearchResult` is only updated inside `SearchVisibleColumns`; if `_visibleColumns` changes (e.g., columns added/removed or renamed) while a search is active, the filtered list can become stale—consider recomputing the search result when the underlying columns collection changes.

## Individual Comments

### Comment 1
<location> `src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs:225` </location>
<code_context>
+            await ShowToastAsync(
+                ColumnGroupSelectButtonWarnToastTitle,
+                ColumnGroupSelectButtonWarnToastContent, ToastCategory.Warning);
+            _visibleColumns[0].Visible = true;
+        }
+        await InvokeAsync(StateHasChanged);
</code_context>

<issue_to_address>
**issue (bug_risk):** Restoring visibility for the first column doesn’t notify `OnToggleColumnVisible`.

In `InverseSelected`, when all columns are unchecked you set `_visibleColumns[0].Visible = true` but don’t call `OnToggleColumnVisible`. This can leave any external state that relies on that callback out of sync for the first column. Consider invoking `await OnToggleColumnVisible(_visibleColumns[0].Name, true);` after updating `Visible`.
</issue_to_address>

### Comment 2
<location> `src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs:177` </location>
<code_context>
         }
     }
+
+    /// <summary>
+    /// 当前所有列的是否全都显示/全都不显示/部分显示状态计算
+    /// </summary>
</code_context>

<issue_to_address>
**issue (complexity):** Consider simplifying the new column-visibility logic by removing redundant state, clarifying conditionals, extracting shared helpers, and centralizing the "at least one visible" rule.

You can simplify the new logic and remove some state/branching without changing behavior.

### 1. Remove redundant `_visibleColumnsSearchResult` state

You don’t need both `_visibleColumnsSearchKey` and `_visibleColumnsSearchResult`. You can compute the filtered list from `_visibleColumns` + key directly:

```csharp
private string _visibleColumnsSearchKey = "";

private IEnumerable<ColumnVisibleItem> VisibleColumnsSearchResult
    => string.IsNullOrWhiteSpace(_visibleColumnsSearchKey)
        ? _visibleColumns
        : _visibleColumns.Where(r =>
            (r.DisplayName ?? r.Name).Contains(_visibleColumnsSearchKey));

private Task SearchVisibleColumns(string searchKey)
{
    _visibleColumnsSearchKey = searchKey;
    return InvokeAsync(StateHasChanged);
}
```

This removes one source of truth and avoids keeping a second list in sync.

### 2. Replace nested ternary with clearer logic

`VisibleColumnsCurrentSelectedResult` is currently a nested ternary, which is harder to read. A small helper or an explicit property body is simpler:

```csharp
private CheckboxState VisibleColumnsCurrentSelectedResult
{
    get
    {
        if (_visibleColumns.All(r => r.Visible))
            return CheckboxState.Checked;
        if (_visibleColumns.All(r => !r.Visible))
            return CheckboxState.UnChecked;
        return CheckboxState.Indeterminate;
    }
}
```

Same behavior, easier to extend and debug.

### 3. Extract shared “toggle all” behavior

`InverseSelected` and `OnToggleAllColumnsVisibleState` both iterate `_visibleColumns`, toggle visibility, and call `OnToggleColumnVisible`. You can centralize this pattern:

```csharp
private async Task SetColumnsVisible(IEnumerable<ColumnVisibleItem> columns, bool visible)
{
    foreach (var column in columns)
    {
        column.Visible = visible;
        await OnToggleColumnVisible(column.Name, visible);
    }
}
```

Then use it:

```csharp
private async Task InverseSelected()
{
    foreach (var column in _visibleColumns)
    {
        column.Visible = !column.Visible;
        await OnToggleColumnVisible(column.Name, column.Visible);
    }

    EnsureAtLeastOneColumnVisible();
    await InvokeAsync(StateHasChanged);
}

private async Task OnToggleAllColumnsVisibleState(CheckboxState state, string _)
{
    if (state == CheckboxState.Checked)
    {
        await SetColumnsVisible(_visibleColumns, true);
    }
    else if (state == CheckboxState.UnChecked)
    {
        await ShowToastAsync(
            ColumnGroupSelectButtonWarnToastTitle,
            ColumnGroupSelectButtonWarnToastContent,
            ToastCategory.Warning);

        await SetColumnsVisible(_visibleColumns.Skip(1), false);
    }

    EnsureAtLeastOneColumnVisible();
    await InvokeAsync(StateHasChanged);
}
```

### 4. Encapsulate “at least one visible” rule

Instead of inlining the “must keep one visible” logic in different places, encapsulate it:

```csharp
private void EnsureAtLeastOneColumnVisible()
{
    if (_visibleColumns.All(c => !c.Visible) && _visibleColumns.Any())
    {
        _visibleColumns[0].Visible = true;
    }
}
```

You can call `EnsureAtLeastOneColumnVisible()` after bulk operations or inversions, and keep the toast behavior where it is today. This keeps the constraint in one place and simplifies future changes to the rule.
</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 Dec 16, 2025

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #7346   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          748       748           
  Lines        32764     32793   +29     
  Branches      4546      4551    +5     
=========================================
+ Hits         32764     32793   +29     
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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ArgoZhang ArgoZhang changed the title Momiji/table show column list select extension feat(Table): add ShowSearchInColumnList parameter Dec 21, 2025
@ArgoZhang ArgoZhang merged commit 227ead3 into main Dec 21, 2025
6 checks passed
@ArgoZhang ArgoZhang deleted the momiji/table-show-column-list-select-extension branch December 21, 2025 06:34
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 ShowSearchInColumnList parameter

3 participants