Skip to content

Conversation

@ArgoZhang
Copy link
Member

@ArgoZhang ArgoZhang commented Mar 27, 2025

Link issues

fixes #5732

Summary By Copilot

This pull request introduces a new tab context menu feature to the Layout component, along with some refactoring and localization updates. The most important changes include adding new parameters and methods to support the context menu, updating icon definitions, and modifying unit tests to cover the new functionality.

New Features:

  • Added support for a tab context menu with options to refresh, close, close other tabs, and close all tabs. This includes new parameters such as ShowTabContextMenu, BeforeTabContextMenuTemplate, TabContextMenuTemplate, TabContextMenuRefreshIcon, TabContextMenuCloseIcon, TabContextMenuCloseOtherIcon, and TabContextMenuCloseAllIcon in Layout.razor.cs. [1] [2] [3]

Code Refactoring:

  • Refactored the Layout.razor file to integrate the tab context menu rendering logic. [1] [2]

Icon Updates:

  • Added new icon definitions for the tab context menu actions in ComponentIcons, BootstrapIcons, FontAwesomeIcons, and MaterialDesignIcons. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]

Localization:

  • Updated localization files en.json and zh.json to include new context menu text entries. [1] [2]

Unit Tests:

  • Modified LayoutTest.cs to include tests for the new tab context menu functionality, ensuring the context menu renders correctly and the event handlers work as expected. [1] [2]

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 tab context menu functionality to the Layout component, enabling users to refresh, close, and manage tabs through a right-click context menu

New Features:

  • Introduce a new ShowTabContextMenu parameter to enable tab context menu functionality
  • Add context menu options to refresh, close, close other tabs, and close all tabs
  • Provide customizable context menu templates and icons

Enhancements:

  • Refactor Layout component to support context menu rendering
  • Add new icon definitions for context menu actions across different icon libraries

Tests:

  • Modify LayoutTest.cs to include tests for new tab context menu functionality
  • Add test coverage for context menu event handlers and rendering

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Mar 27, 2025

Reviewer's Guide by Sourcery

This pull request introduces a new tab context menu feature to the Layout component. It adds a ShowTabContextMenu parameter, refactors the Layout.razor file to integrate the context menu rendering logic, updates icon definitions, and modifies unit tests to cover the new functionality. Localization files are also updated to include new context menu text entries.

No diagrams generated as the changes look simple and do not need a visual representation.

File-Level Changes

Change Details Files
Introduced a new ShowTabContextMenu parameter to the Layout component, enabling a tab context menu with options to refresh, close, close other tabs, and close all tabs.
  • Added ShowTabContextMenu parameter to Layout.razor.cs.
  • Added BeforeTabContextMenuTemplate parameter to Layout.razor.cs.
  • Added TabContextMenuTemplate parameter to Layout.razor.cs.
  • Added TabContextMenuRefreshIcon parameter to Layout.razor.cs.
  • Added TabContextMenuCloseIcon parameter to Layout.razor.cs.
  • Added TabContextMenuCloseOtherIcon parameter to Layout.razor.cs.
  • Added TabContextMenuCloseAllIcon parameter to Layout.razor.cs.
src/BootstrapBlazor/Components/Layout/Layout.razor.cs
Refactored Layout.razor to integrate the tab context menu rendering logic, utilizing a ContextMenuZone to encapsulate the tab and its context menu.
  • Wrapped the Tab component within a ContextMenuZone when ShowTabContextMenu is enabled.
  • Added a ContextMenu component containing ContextMenuItem components for refresh, close, close other, and close all actions.
  • Implemented conditional rendering of BeforeTabContextMenuTemplate and TabContextMenuTemplate.
  • Created a RenderFragment RenderTab to avoid code duplication.
src/BootstrapBlazor/Components/Layout/Layout.razor
Added new icon definitions for the tab context menu actions across different icon sets.
  • Added TabContextMenuRefreshIcon to ComponentIcons enum.
  • Added TabContextMenuCloseIcon to ComponentIcons enum.
  • Added TabContextMenuCloseOtherIcon to ComponentIcons enum.
  • Added TabContextMenuCloseAllIcon to ComponentIcons enum.
  • Added corresponding icon definitions for Bootstrap, FontAwesome, and MaterialDesign icon sets.
src/BootstrapBlazor/Enums/ComponentIcons.cs
src/BootstrapBlazor/Icons/BootstrapIcons.cs
src/BootstrapBlazor/Icons/MaterialDesignIcons.cs
src/BootstrapBlazor/Icons/FontAwesomeIcons.cs
Updated localization files to include new context menu text entries.
  • Added ContextRefresh entry to en.json.
  • Added ContextClose entry to en.json.
  • Added ContextCloseOther entry to en.json.
  • Added ContextCloseAll entry to en.json.
  • Added ContextRefresh entry to zh.json.
  • Added ContextClose entry to zh.json.
  • Added ContextCloseOther entry to zh.json.
  • Added ContextCloseAll entry to zh.json.
src/BootstrapBlazor/Locales/en.json
src/BootstrapBlazor/Locales/zh.json
Modified unit tests to include tests for the new tab context menu functionality.
  • Added tests to verify the rendering of the context menu.
  • Added tests to simulate clicks on context menu items.
test/UnitTest/Components/LayoutTest.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#5732 Implement a tab context menu in the Layout component.

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!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

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

@bb-auto bb-auto bot added the enhancement New feature or request label Mar 27, 2025
@bb-auto bb-auto bot added this to the v9.4.0 milestone Mar 27, 2025
@ArgoZhang ArgoZhang merged commit 32eb2b1 into main Mar 27, 2025
4 checks passed
@ArgoZhang ArgoZhang deleted the refactor-layout branch March 27, 2025 11:25
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 @ArgoZhang - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a ShowTabContextMenu property to the Tab component itself, rather than just the Layout component.
  • The OnCloseOther method could be simplified by calling _tab.ActiveTab(tabItem) before _tab.CloseOtherTabs().
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟡 Testing: 2 issues found
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

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.


private string? GetTargetString() => IsFixedTabHeader ? ".tabs-body" : null;

private async Task OnRefrsh(ContextMenuItem item, object? context)
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick (typo): Typo in method name 'OnRefrsh' – consider renaming to 'OnRefresh'.

Renaming this method will improve consistency and readability for developers working with tab context menu callbacks.

Suggested change
private async Task OnRefrsh(ContextMenuItem item, object? context)
private async Task OnRefresh(ContextMenuItem item, object? context)

namespace UnitTest.Components;

public class LayoutTest : BootstrapBlazorTestBase
{
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Missing assertions for context menu actions.

Add assertions to verify that the expected actions (refresh, close, close other, close all) occur when the corresponding context menu items are clicked. For example, check if the correct tab is closed or if a refresh action is triggered.

Suggested implementation:

        // test context menu onclick event handler
        var tab = cut.Find(".tabs-item");

        // Test "Refresh" action:
        await cut.InvokeAsync(() => tab.ContextMenu());
        var buttons = cut.FindAll(".bb-cm-zone > .dropdown-menu .dropdown-item");
        var refreshButton = buttons.SingleOrDefault(b => b.TextContent.Contains("Refresh"));
        if (refreshButton != null)
        {
            await cut.InvokeAsync(() => refreshButton.Click());
            // Assert that the refresh action occurred.
            // Example: the tab remains present and gets a "refreshed" state/class.
            Assert.True(cut.Find(".tabs-item").ClassList.Contains("refreshed"), "Expected the tab to be refreshed");

            // Re-open the context menu for subsequent actions if needed.
            await cut.InvokeAsync(() => tab.ContextMenu());
            buttons = cut.FindAll(".bb-cm-zone > .dropdown-menu .dropdown-item");
        }

        // Test "Close" action:
        var closeButton = buttons.SingleOrDefault(b => b.TextContent.Contains("Close") && !b.TextContent.Contains("Other"));
        if (closeButton != null)
        {
            await cut.InvokeAsync(() => closeButton.Click());
            // Assert that the tab is closed.
            Assert.Throws<ElementNotFoundException>(() => cut.Find(".tabs-item"));

            // Re-render or reset the state for further tests as needed.
            // (Re-add the tab element if your test requires to run further context menu actions.)
            // For example:
            // cut.SetParametersAndRender(pb => pb.Add(a => a.TabContextMenuTemplate, tab => b => b.AddContent(0, "test-tab-context-menu")));
            // tab = cut.Find(".tabs-item");
        }

        // Test "Close Other" action:
        // (Ensure that at least two tabs are present before testing this behavior.)
        await cut.InvokeAsync(() => tab.ContextMenu());
        buttons = cut.FindAll(".bb-cm-zone > .dropdown-menu .dropdown-item");
        var closeOtherButton = buttons.SingleOrDefault(b => b.TextContent.Contains("Close Other"));
        if (closeOtherButton != null)
        {
            await cut.InvokeAsync(() => closeOtherButton.Click());
            // Assert that the "Close Other" action occurred.
            // Example: only one tab remains.
            Assert.Equal(1, cut.FindAll(".tabs-item").Count);

            // Re-render or reset the state for further tests if needed.
        }

        // Test "Close All" action:
        await cut.InvokeAsync(() => tab.ContextMenu());
        buttons = cut.FindAll(".bb-cm-zone > .dropdown-menu .dropdown-item");
        var closeAllButton = buttons.SingleOrDefault(b => b.TextContent.Contains("Close All"));
        if (closeAllButton != null)
        {
            await cut.InvokeAsync(() => closeAllButton.Click());
            // Assert that the "Close All" action occurred.
            Assert.Empty(cut.FindAll(".tabs-item"));
        }

Depending on your codebase, you might need to re-render or reinitialize the tab component between tests for each context menu action.
Also ensure that the assertions (for example, checking class "refreshed" or element absence) match the actual behavior that occurs when these actions are triggered.
If the context menu actions are asynchronous or trigger additional events, you may want to add proper waits or event subscriptions before asserting.

Comment on lines +54 to +55
cut.SetParametersAndRender(pb => pb.Add(a => a.BeforeTabContextMenuTemplate, tab => b => b.AddContent(0, "test-before-tab-context-menu")));
cut.Contains("test-before-tab-context-menu");
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Edge case: null BeforeTabContextMenuTemplate.

Add a test case to verify the behavior when BeforeTabContextMenuTemplate is set to null. This ensures the layout renders correctly even without a before template.

Suggested implementation:

using Xunit;
[Fact]
public async Task Layout_RendersCorrectly_WhenBeforeTabContextMenuTemplateIsNull()
{
    // Arrange: Render the Layout component with BeforeTabContextMenuTemplate set to null.
    var cut = Context.RenderComponent<Layout>(pb =>
    {
        pb.Add(a => a.ToolbarTemplate, builder => builder.AddContent(0, "test-toolbar-template"));
        pb.Add(a => a.ShowTabContextMenu, true);
        pb.Add(a => a.BeforeTabContextMenuTemplate, (RenderFragment)null);
        pb.Add(a => a.TabContextMenuTemplate, tab => b => b.AddContent(0, "test-tab-context-menu"));
    });

    // Assert: Verify that the toolbar and tab context menu render correctly.
    Assert.Contains("test-toolbar-template", cut.Markup);
    cut.Contains("bb-cm-zone");
    cut.Contains("test-tab-context-menu");
    // Ensure that the before tab context menu content is not rendered.
    Assert.DoesNotContain("test-before-tab-context-menu", cut.Markup);

    // Act: Test the context menu onclick event handler.
    var tab = cut.Find(".tabs-item");
    await cut.InvokeAsync(() => tab.ContextMenu());

    var buttons = cut.FindAll(".bb-cm-zone > .dropdown-menu .dropdown-item");
    foreach (var button in buttons)
    {
        await cut.InvokeAsync(() => button.Click());
    }
}

If necessary, adjust namespace imports to include Xunit and any other required dependencies. Also, ensure that the test utility Context and the Layout component are correctly imported in this file.

@codecov
Copy link

codecov bot commented Mar 27, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (7ea1b4c) to head (3d030fa).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #5733   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          657       657           
  Lines        29833     29877   +44     
  Branches      4230      4237    +7     
=========================================
+ Hits         29833     29877   +44     

☔ 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.

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(Layout): support tab context menu

2 participants