From 6f9cb01ef4c238ca5e99cc2de7282538f687020d Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 8 May 2026 11:17:36 +0800 Subject: [PATCH 01/14] Prevent double-submit in mud Create/Update Entity actions Saas tenant create modal (and other mud CRUD pages) duplicated rows when the user double-clicked Save: the second click hit AppService.CreateAsync before the first response had returned. Add IsCreating / IsUpdating gates to AbpMudCrudPageBase so concurrent calls return immediately. Wrap the body in try/finally and trigger StateHasChanged so any UI bindings to these flags reflect the busy state. --- .../AbpMudCrudPageBase.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs index 7943003eeb..265cb5b4bb 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs @@ -203,6 +203,9 @@ public abstract class AbpMudCrudPageBase< protected MudDialog? _createDialog; protected MudDialog? _editDialog; + protected bool IsCreating { get; set; } + protected bool IsUpdating { get; set; } + protected virtual DialogOptions CreateDialogOptions => new DialogOptions { MaxWidth = MaxWidth.Medium, @@ -452,8 +455,16 @@ public abstract class AbpMudCrudPageBase< protected virtual async Task CreateEntityAsync() { + if (IsCreating) + { + return; + } + try { + IsCreating = true; + await InvokeAsync(StateHasChanged); + var isValid = true; if (CreateFormRef != null) { @@ -476,6 +487,11 @@ public abstract class AbpMudCrudPageBase< { await HandleErrorAsync(ex); } + finally + { + IsCreating = false; + await InvokeAsync(StateHasChanged); + } } protected virtual Task OnCreatingEntityAsync() @@ -497,8 +513,16 @@ public abstract class AbpMudCrudPageBase< protected virtual async Task UpdateEntityAsync() { + if (IsUpdating) + { + return; + } + try { + IsUpdating = true; + await InvokeAsync(StateHasChanged); + var isValid = true; if (EditFormRef != null) { @@ -521,6 +545,11 @@ public abstract class AbpMudCrudPageBase< { await HandleErrorAsync(ex); } + finally + { + IsUpdating = false; + await InvokeAsync(StateHasChanged); + } } protected virtual Task OnUpdatingEntityAsync() From 93144f8faa1c9ada80f5cf44c0a9bd2f31f3c880 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 8 May 2026 13:34:51 +0800 Subject: [PATCH 02/14] Show indeterminate state on mud "Select All in This Tab" checkbox Top-level "Select All in All Tabs" already used `Indeterminate` to show a partial-grant state. The per-tab "Select All in This Tab" checkbox was a plain two-state binding to `Permissions.All(x => x.IsGranted)`, so a tab with some (but not all) permissions granted rendered as unchecked - reading as "no permissions granted" to QA. Bind `Indeterminate` to "any granted but not all granted" to match the top-level behavior. --- .../Components/PermissionManagementModal.razor | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor index 4c7eba0bfc..5413f4bbb6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor @@ -41,10 +41,11 @@ { x.IsGranted)})")">
- From d50e41a6e649e12578459c8f574ac60e7fcf33e7 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 8 May 2026 15:46:35 +0800 Subject: [PATCH 03/14] Wrap mud OnDeletedEntityAsync with InvokeAsync and null-check _dataGrid --- framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs index 265cb5b4bb..f502d671c9 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs @@ -598,7 +598,10 @@ public abstract class AbpMudCrudPageBase< protected virtual async Task OnDeletedEntityAsync() { - await _dataGrid.ReloadServerDataAsync(); + if (_dataGrid != null) + { + await InvokeAsync(() => _dataGrid.ReloadServerDataAsync()); + } Snackbar.Add(GetDeleteMessage(), Severity.Success); } From 51c7580308b5734a8268e7af2294ccbf7db24831 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 8 May 2026 20:23:25 +0800 Subject: [PATCH 04/14] Show loading spinner on mud Setting Management while contributors load to avoid empty card flicker --- .../Pages/SettingManagement/SettingManagement.razor | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor index 785374eb55..9bb7e1362c 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor @@ -13,9 +13,15 @@ @* ************************* PAGE HEADER ************************* *@ - + - @if (!string.IsNullOrEmpty(SelectedGroup)) + @if (string.IsNullOrEmpty(SelectedGroup)) + { +
+ +
+ } + else {
+ From 35b4d6b7743199ef68072c7525885f7581bc22cd Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 11 May 2026 18:47:13 +0800 Subject: [PATCH 05/14] Upgrade MudBlazor to 9.4.0 - Directory.Packages.props bumps MudBlazor 8.0.0 to 9.4.0 - AbpMudCrudPageBase: ShowMessageBox to ShowMessageBoxAsync, OnDataGridReadAsync adds CancellationToken - AbpMudExtensibleDataGrid: ServerData adds CancellationToken, SortFunc becomes Func - basic-theme LoginDisplay (Server + WASM): name MudMenu ActivatorContent context to avoid AuthorizeView clash - permission-management and feature-management modals: ShowMessageBox to ShowMessageBoxAsync --- Directory.Packages.props | 2 +- .../Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs | 5 +++-- .../Components/AbpMudExtensibleDataGrid.razor.cs | 15 ++++++++------- .../Themes/Basic/LoginDisplay.razor | 2 +- .../Themes/Basic/LoginDisplay.razor | 2 +- .../Components/FeatureManagementModal.razor.cs | 2 +- .../Components/PermissionManagementModal.razor.cs | 2 +- .../ResourcePermissionManagementModal.razor.cs | 2 +- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 15f9016131..1157509643 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -23,7 +23,7 @@ - + diff --git a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs index f502d671c9..3d27ab8dd8 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Authorization; @@ -332,7 +333,7 @@ public abstract class AbpMudCrudPageBase< } } - protected virtual async Task> OnDataGridReadAsync(GridState state) + protected virtual async Task> OnDataGridReadAsync(GridState state, CancellationToken cancellationToken = default) { CurrentSorting = state.SortDefinitions .Select(s => _dataGrid.ResolveSortPropertyName(s) + (s.Descending ? " DESC" : "")) @@ -617,7 +618,7 @@ public abstract class AbpMudCrudPageBase< protected virtual async Task ConfirmDeleteAsync(TListViewModel entity) { - var result = await DialogService.ShowMessageBox( + var result = await DialogService.ShowMessageBoxAsync( UiLocalizer["AreYouSure"], GetDeleteConfirmationMessage(entity), yesText: UiLocalizer["Yes"], diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs index 0efd289d64..1c57c40a80 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Components; @@ -28,9 +29,9 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase /// Maps SortBy func references to their corresponding property names. /// Used to resolve property names from MudBlazor SortDefinition.SortFunc. /// - private readonly Dictionary, string> _sortFuncToPropertyMap = new(); + private readonly Dictionary, string> _sortFuncToPropertyMap = new(); - [Parameter] public Func, Task>>? ServerData { get; set; } + [Parameter] public Func, CancellationToken, Task>>? ServerData { get; set; } [Parameter] public bool Loading { get; set; } @@ -192,7 +193,7 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase return string.Empty; } - protected virtual Func? GetSortByFunc(TableColumn column) + protected virtual Func? GetSortByFunc(TableColumn column) { if (!column.Sortable) { @@ -221,7 +222,7 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase var parameter = System.Linq.Expressions.Expression.Parameter(typeof(TItem), "x"); System.Linq.Expressions.Expression expression = parameter; - Func? sortFunc = null; + Func? sortFunc = null; foreach (var prop in properties) { var propertyInfo = expression.Type.GetProperty(prop, BindingFlags.Public | BindingFlags.Instance); @@ -237,7 +238,7 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase if (sortFunc == null) { var convertExpression = System.Linq.Expressions.Expression.Convert(expression, typeof(object)); - var lambda = System.Linq.Expressions.Expression.Lambda>(convertExpression, parameter); + var lambda = System.Linq.Expressions.Expression.Lambda>(convertExpression, parameter); sortFunc = lambda.Compile(); } @@ -247,7 +248,7 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase return sortFunc; } - protected virtual Func? GetExtensionPropertySortFunc(TableColumn column) + protected virtual Func? GetExtensionPropertySortFunc(TableColumn column) { if (!column.Sortable || string.IsNullOrWhiteSpace(column.Data)) { @@ -261,7 +262,7 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase } var propertyName = match.Groups[1].Value; - Func sortFunc = item => + Func sortFunc = item => { var entity = item as IHasExtraProperties; return entity?.GetProperty(propertyName) ?? string.Empty; diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor index 295080fa04..8a55cd7751 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor @@ -14,7 +14,7 @@ - + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor index 1cb4c41718..2c6fbf6c6c 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor @@ -17,7 +17,7 @@ - + diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs index cfbee7f16f..c913b05f3c 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs @@ -140,7 +140,7 @@ public partial class FeatureManagementModal { try { - var confirmed = await DialogService.ShowMessageBox( + var confirmed = await DialogService.ShowMessageBoxAsync( L["AreYouSure"], L["AreYouSureToResetToDefault"], yesText: L["Yes"], diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor.cs index 0d2b3d4192..9ed212236c 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor.cs @@ -144,7 +144,7 @@ public partial class PermissionManagementModal if (!updateDto.Permissions.Any(x => x.IsGranted)) { - var confirmed = await DialogService.ShowMessageBox( + var confirmed = await DialogService.ShowMessageBoxAsync( L["Warning"], L["SaveWithoutAnyPermissionsWarningMessage"], yesText: L["Yes"], diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs index 1df024471e..485451c5bf 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs @@ -291,7 +291,7 @@ public partial class ResourcePermissionManagementModal protected virtual async Task DeleteResourcePermissionAsync(ResourcePermissionGrantInfoDto permission) { - var confirmed = await DialogService.ShowMessageBox( + var confirmed = await DialogService.ShowMessageBoxAsync( L["AreYouSure"], L["ResourcePermissionDeletionConfirmationMessage"], yesText: L["Yes"], From 3d391fb8aa875138b37e300a9a0112a1fae20bb9 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 12 May 2026 13:25:24 +0800 Subject: [PATCH 06/14] Apply MudBlazor 9 runtime fixes and QA polish - MudMenu: switch ActivatorContent to MenuContext.ToggleAsync pattern (v9 breaking) - MudForm: rename Validate to ValidateAsync (v9.1 obsoletion) - MudInput: replace AutoGrow with Sizing for textarea - DataGrid: add white-space:nowrap on header to prevent CJK characters stacking vertically - BlockUI: shrink loading spinner inside mud-dialog - Search field: switch Label to Placeholder so the text shows next to the magnifier icon --- .../AbpMudCrudPageBase.cs | 4 +-- .../MudTextAreaExtensionProperty.razor | 2 +- .../wwwroot/volo.abp.mudblazorui.css | 27 ++++++++++++++++++- .../Pages/Account/AccountManage.razor.cs | 4 +-- .../Themes/Basic/LanguageSwitch.razor | 4 +-- .../Themes/Basic/LoginDisplay.razor | 4 +-- .../Themes/Basic/LanguageSwitch.razor | 4 +-- .../Themes/Basic/LoginDisplay.razor | 4 +-- .../Pages/Identity/UserManagement.razor | 2 +- .../PermissionManagementModal.razor | 2 +- ...ResourcePermissionManagementModal.razor.cs | 4 +-- .../EmailSettingGroupViewComponent.razor.cs | 4 +-- .../TenantManagement.razor.cs | 4 +-- 13 files changed, 47 insertions(+), 22 deletions(-) diff --git a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs index 3d27ab8dd8..9bc201bdca 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs @@ -469,7 +469,7 @@ public abstract class AbpMudCrudPageBase< var isValid = true; if (CreateFormRef != null) { - await CreateFormRef.Validate(); + await CreateFormRef.ValidateAsync(); isValid = CreateFormRef.IsValid; } @@ -527,7 +527,7 @@ public abstract class AbpMudCrudPageBase< var isValid = true; if (EditFormRef != null) { - await EditFormRef.Validate(); + await EditFormRef.ValidateAsync(); isValid = EditFormRef.IsValid; } diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/ObjectExtending/MudTextAreaExtensionProperty.razor b/framework/src/Volo.Abp.MudBlazorUI/Components/ObjectExtending/MudTextAreaExtensionProperty.razor index 2aa3e55f75..4d26db8deb 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/ObjectExtending/MudTextAreaExtensionProperty.razor +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/ObjectExtending/MudTextAreaExtensionProperty.razor @@ -9,7 +9,7 @@ Label="@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)" @bind-Value="@Value" Lines="3" - AutoGrow="true" + Sizing="InputSizing.Auto" Disabled="IsReadonlyField" Validation="@((Func)Validate)" Immediate="true" /> diff --git a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css index bd6174466b..2562386a54 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css +++ b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css @@ -57,4 +57,29 @@ .abp-crud-page-header-actions { display: flex; gap: 8px; -} \ No newline at end of file +} +/* BlockUI spinner inside mud-dialog: shrink to fit short modal bodies (e.g. file upload modal). + abp.css defines a 150px x 150px spinner via .abp-block-area-busy:before, which gets clipped + by mud-dialog's overflow when the modal content is short. */ +.mud-dialog .abp-block-area.abp-block-area-busy:before { + width: 48px; + height: 48px; + top: calc(50% - 24px); + left: calc(50% - 24px); +} + +.mud-dialog .abp-block-area.abp-block-area-busy:after { + font-size: 12px; +} + + +/* DataGrid header: prevent CJK characters from breaking one-per-line when column is narrow. + v9 column-header is a flex container with flex item width:100%; without nowrap, CJK + (no word boundary) collapses to min-content = single character width, stacking each + header character vertically. */ +.mud-data-grid .mud-table-cell .column-header .sortable-column-header, +.mud-data-grid .mud-table-cell .column-header > span:not(.column-options), +.mud-data-grid .mud-table-head .mud-table-cell { + white-space: nowrap; +} + diff --git a/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/Pages/Account/AccountManage.razor.cs b/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/Pages/Account/AccountManage.razor.cs index a4fc96941c..fa0bc1c31b 100644 --- a/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/Pages/Account/AccountManage.razor.cs +++ b/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/Pages/Account/AccountManage.razor.cs @@ -59,7 +59,7 @@ public partial class AccountManage return; } - await _changePasswordForm.Validate(); + await _changePasswordForm.ValidateAsync(); if (!_changePasswordForm.IsValid) { return; @@ -100,7 +100,7 @@ public partial class AccountManage return; } - await _personalInfoForm.Validate(); + await _personalInfoForm.ValidateAsync(); if (!_personalInfoForm.IsValid) { diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor index 6f68415b1f..601479a35f 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor @@ -9,8 +9,8 @@ @if (_otherLanguages != null && _otherLanguages.Any()) { - - + + @_currentLanguage.DisplayName diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor index 8a55cd7751..a48e7971dd 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor @@ -14,8 +14,8 @@ - - + + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor index 7d059a91ff..3add335cd7 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LanguageSwitch.razor @@ -11,8 +11,8 @@ @if (_otherLanguages != null && _otherLanguages.Any()) { - - + + @_currentLanguage.DisplayName diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor index 2c6fbf6c6c..44972ae16a 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme/Themes/Basic/LoginDisplay.razor @@ -17,8 +17,8 @@ - - + + diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor index 23ac8872c5..77f335eed4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor +++ b/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor @@ -23,7 +23,7 @@ diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs index 485451c5bf..e45473bb04 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor.cs @@ -231,7 +231,7 @@ public partial class ResourcePermissionManagementModal return; } - await _createFormRef.Validate(); + await _createFormRef.ValidateAsync(); if (!_createFormRef.IsValid) { return; @@ -266,7 +266,7 @@ public partial class ResourcePermissionManagementModal return; } - await _editFormRef.Validate(); + await _editFormRef.ValidateAsync(); if (!_editFormRef.IsValid) { return; diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor.cs index 9e15fad338..28c74ad285 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor.cs @@ -68,7 +68,7 @@ public partial class EmailSettingGroupViewComponent return; } - await _emailFormRef.Validate(); + await _emailFormRef.ValidateAsync(); if (!_emailFormRef.IsValid) { return; @@ -132,7 +132,7 @@ public partial class EmailSettingGroupViewComponent return; } - await _testEmailFormRef.Validate(); + await _testEmailFormRef.ValidateAsync(); if (!_testEmailFormRef.IsValid) { return; diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor.cs index 4587475f01..dcfb0c3152 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor.cs @@ -163,7 +163,7 @@ public partial class TenantManagement return; } - await _createFormRef.Validate(); + await _createFormRef.ValidateAsync(); if (!_createFormRef.IsValid) { return; @@ -179,7 +179,7 @@ public partial class TenantManagement return; } - await _editFormRef.Validate(); + await _editFormRef.ValidateAsync(); if (!_editFormRef.IsValid) { return; From dd4b2d3fac18bf8dfb9e73a86f21cdb5052df672 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 12 May 2026 14:04:59 +0800 Subject: [PATCH 07/14] Truncate long picker labels so they no longer overlap the toggle icon Long label text (e.g. Turkish translations) on MudDatePicker / MudTimePicker overflowed the input and visually overlapped the calendar toggle icon on the right. Reserve 40px on the right for the end-adornment icon so the label clips with ellipsis. --- .../Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css index 2562386a54..c265fd5830 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css +++ b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css @@ -83,3 +83,11 @@ white-space: nowrap; } + +/* Picker label (date / time / color picker): when label is long it overflows into the + toggle icon on the right and visually overlaps the calendar/clock icon. + Reserve ~40px on the right for the end-adornment toggle icon so the label truncates with ellipsis. */ +.mud-picker .mud-input-label.mud-input-label-inputcontrol { + max-width: calc(100% - 40px); +} + From 7a7004ca9a7809e80fef8e4fda4fd6dfb1ab7ac3 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 12 May 2026 14:10:38 +0800 Subject: [PATCH 08/14] Remove inner scroll from PermissionManagementModal MudTabs The custom Style="max-height: 600px; overflow-y: auto;" on MudTabs produced an inner scrollbar in addition to mud-dialog's own scrollbar, resulting in a double scrolling experience inside the permissions modal. Let mud-dialog handle overflow natively. --- .../Components/PermissionManagementModal.razor | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor index 02aafba36e..4668e7d973 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor @@ -35,8 +35,7 @@ + PanelClass="pa-4"> @foreach (var group in _groups) { x.IsGranted)})")"> From 575ed79b405b8c56da0640a6c5a801d7bc862ac9 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 12 May 2026 14:34:04 +0800 Subject: [PATCH 09/14] Increase input label line-height to fit descenders (g/p/q/y) MudBlazor 9 defaults .mud-input-label-inputcontrol to line-height: 1.15rem, which is smaller than a typical 16px character with descenders. Letters like g, p, q, y in the floated label visually clipped under the input baseline. Bump to 1.4rem so descenders have room without enlarging the overall control. --- .../Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css index c265fd5830..ff68f89c0f 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css +++ b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css @@ -91,3 +91,10 @@ max-width: calc(100% - 40px); } + +/* Input label: increase line-height slightly so descenders (g, p, q, y) in the floated + label text are not clipped by the input baseline immediately below. */ +.mud-input-control .mud-input-label-inputcontrol { + line-height: 1.4rem; +} + From c68c97da0a2a339a499889d17bbd0d4a9542130d Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 12 May 2026 16:11:31 +0800 Subject: [PATCH 10/14] Add horizontal gap to vertical MudTabs between tabbar and panels MudBlazor 9 renders mud-tabs-vertical with the tabbar flush against the panels container, making the active tab indicator visually touch the panel content. Add 16px padding-inline-start on the panels area (and -end for the reverse layout) so the tabbar and panels have breathing room. --- .../wwwroot/volo.abp.mudblazorui.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css index ff68f89c0f..5fa2c86435 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css +++ b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/volo.abp.mudblazorui.css @@ -98,3 +98,15 @@ line-height: 1.4rem; } + +/* Vertical MudTabs (Position="Left"/"Right"): add horizontal gap between the tabbar + and the panels container so the active tab indicator does not visually touch the + panel content. v9 default puts them flush against each other. */ +.mud-tabs.mud-tabs-vertical > .mud-tabs-panels { + padding-inline-start: 16px; +} + +.mud-tabs.mud-tabs-vertical-reverse > .mud-tabs-panels { + padding-inline-end: 16px; +} + From 2a5fe38be3ade640703ab27a957bceab4c005444 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 21 May 2026 15:52:33 +0800 Subject: [PATCH 11/14] Enhance MudBlazor UI components with improved dialog focus and layout options --- .../MudBlazorUiPageProgressService.cs | 35 ++++++++++++++----- .../_Imports.razor | 1 + .../Components/FeatureManagementModal.razor | 4 +-- .../_Imports.razor | 1 + .../Pages/Identity/RoleManagement.razor | 4 +-- .../Pages/Identity/UserManagement.razor | 10 +++--- .../_Imports.razor | 1 + .../PermissionManagementModal.razor | 22 ++++++------ .../ResourcePermissionManagementModal.razor | 6 ++-- .../_Imports.razor | 1 + .../EmailSettingGroupViewComponent.razor | 2 +- .../_Imports.razor | 1 + .../TenantManagement/TenantManagement.razor | 4 +-- .../_Imports.razor | 1 + 14 files changed, 61 insertions(+), 32 deletions(-) diff --git a/framework/src/Volo.Abp.MudBlazorUI/MudBlazorUiPageProgressService.cs b/framework/src/Volo.Abp.MudBlazorUI/MudBlazorUiPageProgressService.cs index 0104eebebf..aeb9d51841 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/MudBlazorUiPageProgressService.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/MudBlazorUiPageProgressService.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.AspNetCore.Components.Progression; using Volo.Abp.DependencyInjection; @@ -6,25 +7,43 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.MudBlazorUI; [Dependency(ReplaceServices = true)] -public class MudBlazorUiPageProgressService : IUiPageProgressService, IScopedDependency +public class MudBlazorUiPageProgressService : IUiPageProgressService, IScopedDependency, IDisposable { /// /// An event raised after the progress is changed. /// public event EventHandler? ProgressChanged; + protected virtual int HideDelayMs => 250; + + private int _activeCount; + private UiPageProgressOptions _lastOptions = new(); + private readonly Timer _hideTimer; + + public MudBlazorUiPageProgressService() + { + _hideTimer = new Timer(_ => ProgressChanged?.Invoke(this, new UiPageProgressEventArgs(-1, _lastOptions))); + } + public Task Go(int? percentage, Action? options = null) { - var uiPageProgressOptions = CreateDefaultOptions(); - options?.Invoke(uiPageProgressOptions); + var opt = new UiPageProgressOptions(); + options?.Invoke(opt); + _lastOptions = opt; - ProgressChanged?.Invoke(this, new UiPageProgressEventArgs(percentage, uiPageProgressOptions)); + if (percentage == -1 && Interlocked.Decrement(ref _activeCount) <= 0) + { + Interlocked.Exchange(ref _activeCount, 0); + _hideTimer.Change(HideDelayMs, Timeout.Infinite); + } + else if (percentage == null && Interlocked.Increment(ref _activeCount) == 1) + { + _hideTimer.Change(Timeout.Infinite, Timeout.Infinite); + ProgressChanged?.Invoke(this, new UiPageProgressEventArgs(null, opt)); + } return Task.CompletedTask; } - protected virtual UiPageProgressOptions CreateDefaultOptions() - { - return new UiPageProgressOptions(); - } + public void Dispose() => _hideTimer.Dispose(); } diff --git a/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/_Imports.razor b/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/_Imports.razor index 95b2bfdc7f..a5bda013b8 100644 --- a/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/_Imports.razor +++ b/modules/account/src/Volo.Abp.Account.Blazor.MudBlazor/_Imports.razor @@ -3,3 +3,4 @@ @using Volo.Abp.MudBlazorUI @using Volo.Abp.MudBlazorUI.Components @using MudBlazor +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor index 57831e2598..fd4711c104 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor @@ -5,7 +5,7 @@ @using Volo.Abp.FeatureManagement.Localization @inherits AbpFeatureManagementComponentBase - + @L["Features"]@ProviderKeyDisplayName @@ -16,7 +16,7 @@ } else { - @foreach (var group in Groups) { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/_Imports.razor b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/_Imports.razor index 4e91324cd8..b1be76fe73 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/_Imports.razor +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/_Imports.razor @@ -1,4 +1,5 @@ @using Microsoft.AspNetCore.Components.Web @using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout @using MudBlazor @using Volo.Abp.MudBlazorUI diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/RoleManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/RoleManagement.razor index 995b1859de..d9f8700ee2 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/RoleManagement.razor +++ b/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/RoleManagement.razor @@ -33,7 +33,7 @@ @* ************************* CREATE DIALOG ************************* *@ @if (HasCreatePermission) { - + @L["NewRole"] @@ -58,7 +58,7 @@ @* ************************* EDIT DIALOG ************************* *@ @if (HasUpdatePermission) { - + @L["Edit"] diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor index 77f335eed4..f6b0849311 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor +++ b/modules/identity/src/Volo.Abp.Identity.Blazor.MudBlazor/Pages/Identity/UserManagement.razor @@ -44,16 +44,17 @@ @* ************************* CREATE DIALOG ************************* *@ @if (HasCreatePermission) { - + @L["NewUser"] - + + @L["Edit"] - + + @L["Permissions"] - @_entityDisplayName @@ -18,11 +18,11 @@ Immediate="true" /> - @@ -32,7 +32,7 @@ @if (_groups != null && _groups.Any()) { - @@ -41,11 +41,13 @@ x.IsGranted)})")">
diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor index 011c5dd926..14aa92d735 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor @@ -1,7 +1,7 @@ @using global::MudBlazor @inherits Volo.Abp.AspNetCore.Components.AbpComponentBase - + @L["ResourcePermissions"] - @ResourceDisplayName @@ -82,7 +82,7 @@ @* Create Resource Permission Dialog *@ @if (_createDialogVisible) { - + @L["AddResourcePermission"] @@ -127,7 +127,7 @@ @* Edit Resource Permission Dialog *@ @if (_editDialogVisible) { - + @L["UpdateResourcePermission"] diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor index bfec4381b3..614bc218c7 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor @@ -1,3 +1,4 @@ @using Microsoft.AspNetCore.Components.Web @using Volo.Abp.AspNetCore.Components.Web +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout @using MudBlazor diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor index e306bebe83..bec6df4d84 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor @@ -73,7 +73,7 @@ @if (HasSendTestEmailPermission) { - + @L["SendTestEmail"] diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/_Imports.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/_Imports.razor index 4e91324cd8..b1be76fe73 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/_Imports.razor +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/_Imports.razor @@ -1,4 +1,5 @@ @using Microsoft.AspNetCore.Components.Web @using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout @using MudBlazor @using Volo.Abp.MudBlazorUI diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor index 3cbbc614dc..e2211914f4 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor @@ -32,7 +32,7 @@ @* ************************* CREATE MODAL ************************* *@ @if (HasCreatePermission) { - + @L["NewTenant"] @@ -69,7 +69,7 @@ @* ************************* EDIT MODAL ************************* *@ @if (HasUpdatePermission) { - + @L["Edit"] diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/_Imports.razor b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/_Imports.razor index 4e91324cd8..b1be76fe73 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/_Imports.razor +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/_Imports.razor @@ -1,4 +1,5 @@ @using Microsoft.AspNetCore.Components.Web @using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout @using MudBlazor @using Volo.Abp.MudBlazorUI From 609fc56f0187f646a022335436e38d59653a0863 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 21 May 2026 16:36:34 +0800 Subject: [PATCH 12/14] docs(blazor): enhance forms-validation and page-header documentation with modal focus behavior and namespace usage --- .../framework/ui/blazor/forms-validation.md | 29 +++++++++++++++++++ docs/en/framework/ui/blazor/page-header.md | 18 +++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/docs/en/framework/ui/blazor/forms-validation.md b/docs/en/framework/ui/blazor/forms-validation.md index c7f799c484..769fc71dbb 100644 --- a/docs/en/framework/ui/blazor/forms-validation.md +++ b/docs/en/framework/ui/blazor/forms-validation.md @@ -138,4 +138,33 @@ protected override Task OnCreatingEntityAsync() > Check the [MudBlazor documentation](https://mudblazor.com/components/form) for the full list of validation modes and the [MudBlazor inputs reference](https://mudblazor.com/components/textfield). +### Modal Focus Behavior + +By default a `MudFocusTrap` inside `` focuses the first tabbable child element after the dialog opens. When the dialog contains a `` as the first child, that "first tabbable element" is the tab button — not the first input on the active tab — so the user has to click into the field manually. + +For dialogs that contain a ``, use this three-part setup to focus the intended input automatically: + +```razor + + + + + + + ... + + ... +``` + +- `DefaultFocus="DefaultFocus.None"` on the `` disables the focus trap's automatic focus so it doesn't grab the tab button. +- `KeepPanelsAlive="true"` on the `` mounts every tab panel up front, so the first input's `firstRender` happens at dialog-open time (otherwise inactive panels are mounted later, and `AutoFocus` runs after the dialog is already visible). +- `AutoFocus="true"` on the first input asks MudBlazor to focus that field on its first render. + +`DialogOptions.DefaultFocus` is ignored for inline dialogs (` + ShowAsync()`), so always set `DefaultFocus` directly on the `` element. + +For a dialog without `` (first child is the input), `DefaultFocus="DefaultFocus.FirstChild"` (the MudBlazor default) is enough and you don't need `AutoFocus`. + {{end}} \ No newline at end of file diff --git a/docs/en/framework/ui/blazor/page-header.md b/docs/en/framework/ui/blazor/page-header.md index 5c03af6aa4..eb4ea8ed30 100644 --- a/docs/en/framework/ui/blazor/page-header.md +++ b/docs/en/framework/ui/blazor/page-header.md @@ -14,7 +14,23 @@ # Blazor UI: Page Header -You can use the`PageHeader` component to set the page title, the breadcrumb items and the toolbar items for a page. Before using the `PageHeader` component, you need to add a using statement for the `Volo.Abp.AspNetCore.Components.Web.Theming.Layout` namespace. +You can use the `PageHeader` component to set the page title, the breadcrumb items and the toolbar items for a page. Before using the `PageHeader` component, you need to add a using statement for the namespace: + +{{if BlazorUI == "Blazorise"}} + +```razor +@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout +``` + +{{end}} + +{{if BlazorUI == "MudBlazor"}} + +```razor +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout +``` + +{{end}} Once you add the `PageHeader` component to your page, you can control the related values using the parameters. From a5aa6bc47592e82d22a5835eefe6abe411ea3f83 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 25 May 2026 21:13:48 +0800 Subject: [PATCH 13/14] feat: add abp-mud-popover-patch.js and include it in script contributors --- .../MauiBlazorMudBlazorScriptContributor.cs | 1 + .../BlazorServerMudBlazorScriptContributor.cs | 1 + ...lazorWebAssemblyMudBlazorScriptContributor.cs | 1 + .../wwwroot/abp-mud-popover-patch.js | 16 ++++++++++++++++ 4 files changed, 19 insertions(+) create mode 100644 framework/src/Volo.Abp.MudBlazorUI/wwwroot/abp-mud-popover-patch.js diff --git a/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.MudBlazor.Bundling/MauiBlazorMudBlazorScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.MudBlazor.Bundling/MauiBlazorMudBlazorScriptContributor.cs index 73bb95c5bd..767b0cc22e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.MudBlazor.Bundling/MauiBlazorMudBlazorScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.MudBlazor.Bundling/MauiBlazorMudBlazorScriptContributor.cs @@ -8,6 +8,7 @@ public class MauiBlazorMudBlazorScriptContributor : BundleContributor public override void ConfigureBundle(BundleConfigurationContext context) { context.Files.AddIfNotContains("_content/MudBlazor/MudBlazor.min.js"); + context.Files.AddIfNotContains("_content/Volo.Abp.MudBlazorUI/abp-mud-popover-patch.js"); context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js"); context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/lang-utils.js"); } diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming.MudBlazor/Bundling/BlazorServerMudBlazorScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming.MudBlazor/Bundling/BlazorServerMudBlazorScriptContributor.cs index 72a49486ee..ca0d9f5690 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming.MudBlazor/Bundling/BlazorServerMudBlazorScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming.MudBlazor/Bundling/BlazorServerMudBlazorScriptContributor.cs @@ -16,6 +16,7 @@ public class BlazorServerMudBlazorScriptContributor : BundleContributor context.Files.AddIfNotContains("/_framework/blazor.server.js"); } context.Files.AddIfNotContains("/_content/MudBlazor/MudBlazor.min.js"); + context.Files.AddIfNotContains("/_content/Volo.Abp.MudBlazorUI/abp-mud-popover-patch.js"); context.Files.AddIfNotContains("/_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js"); context.Files.AddIfNotContains("/_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/authentication-state-listener.js"); } diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.MudBlazor.Bundling/BlazorWebAssemblyMudBlazorScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.MudBlazor.Bundling/BlazorWebAssemblyMudBlazorScriptContributor.cs index 246f32f15b..82e6184c06 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.MudBlazor.Bundling/BlazorWebAssemblyMudBlazorScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.MudBlazor.Bundling/BlazorWebAssemblyMudBlazorScriptContributor.cs @@ -9,6 +9,7 @@ public class BlazorWebAssemblyMudBlazorScriptContributor : BundleContributor { context.Files.AddIfNotContains("_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"); context.Files.AddIfNotContains("_content/MudBlazor/MudBlazor.min.js"); + context.Files.AddIfNotContains("_content/Volo.Abp.MudBlazorUI/abp-mud-popover-patch.js"); context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js"); context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/lang-utils.js"); context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/authentication-state-listener.js"); diff --git a/framework/src/Volo.Abp.MudBlazorUI/wwwroot/abp-mud-popover-patch.js b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/abp-mud-popover-patch.js new file mode 100644 index 0000000000..c083e1277a --- /dev/null +++ b/framework/src/Volo.Abp.MudBlazorUI/wwwroot/abp-mud-popover-patch.js @@ -0,0 +1,16 @@ +(function () { + 'use strict'; + + var popover = window.mudPopover; + if (!popover || typeof popover.createObservers !== 'function') { + return; + } + + var original = popover.createObservers; + popover.createObservers = function (id) { + if (!this.map[id]) { + return; + } + return original.call(this, id); + }; +})(); From af349086c0ed4badd8c791dff0375637f58d1276 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 26 May 2026 09:46:58 +0000 Subject: [PATCH 14/14] docs: update package version changes [skip ci] --- docs/en/package-version-changes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/package-version-changes.md b/docs/en/package-version-changes.md index 84a10fafe9..0312719731 100644 --- a/docs/en/package-version-changes.md +++ b/docs/en/package-version-changes.md @@ -7,6 +7,12 @@ # Package Version Changes +## 10.4.1 + +| Package | Old Version | New Version | PR | +|---------|-------------|-------------|-----| +| MudBlazor | 8.0.0 | 9.4.0 | #25393 | + ## 10.4.0-rc.2 | Package | Old Version | New Version | PR |