Open Closed

customize edit user page #4017


User avatar
0
hussein created
  • ABP Framework version: v6.0.1
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no
  • Exception message and stack trace:
  • Steps to reproduce the issue:"

1- I want to customize the user UI, to add a new tab page when editing the user

2- how to prevent a user who has the privilege to manage the users from deleting the Admin user or Sys Role?


5 Answer(s)
  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    You can override the existing cshtml file of the modal via following this documentation: https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface#overriding-a-razor-page-cshtml

    To achieve that, create a file in this path:

    • /Pages/Identity/Users/CreateModal.cshtml

    • And content of this newly created file should be:

    @page
    @using Microsoft.AspNetCore.Mvc.Localization
    @using Microsoft.Extensions.Localization
    @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
    @using Volo.Abp.Data
    @using Volo.Abp.Identity
    @using Volo.Abp.Identity.Localization
    @using Volo.Abp.Identity.Settings
    @using Volo.Abp.Identity.Web.Pages.Identity.Users
    @using Volo.Abp.Localization
    @using Volo.Abp.ObjectExtending
    @using Volo.Abp.Settings
    @model Volo.Abp.Identity.Web.Pages.Identity.Users.CreateModalModel
    @inject ISettingProvider SettingProvider
    @inject IHtmlLocalizer<IdentityResource> L
    @inject IStringLocalizerFactory StringLocalizerFactory
    @{
        Layout = null;
    }
    <form method="post" asp-page="/Identity/Users/CreateModal">
        <abp-modal>
            <abp-modal-header title="@L["NewUser"].Value"></abp-modal-header>
            <abp-modal-body>
                <abp-tabs name="create-user-modal-tabs">
                    <abp-tab title="@L["UserInformations"].Value">
                        <abp-input asp-for="UserInfo.UserName" />
                        <abp-input asp-for="UserInfo.Name" />
                        <abp-input asp-for="UserInfo.Surname" />
                        <div class="mb-3">
                            <label asp-for="UserInfo.Password" class="form-label">@L["Password"] *</label>
                            <div class="input-group">
                                <input type="password" class="form-control" maxlength="@IdentityUserConsts.MaxPasswordLength" asp-for="UserInfo.Password" />
                                <button class="btn btn-secondary" type="button" id="PasswordVisibilityButton"><i class="fa fa-eye-slash" aria-hidden="true"></i></button>
                            </div>
                            <span asp-validation-for="UserInfo.Password"></span>
                        </div>
                        <abp-input asp-for="UserInfo.Email" label="@(L["EmailAddress"].Value + " * ")" />
                        @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<CreateModalModel.UserInfoViewModel>())
                        {
                            if (!propertyInfo.Name.EndsWith("_Text"))
                            {
                                if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty())
                                {
                                    if (propertyInfo.Type.IsEnum)
                                    {
                                        Model.UserInfo.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type);
                                    }
                                    <abp-select asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                                label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                                autocomplete-api-url="@propertyInfo.Lookup.Url"
                                                autocomplete-selected-item-name="@Model.UserInfo.GetProperty(propertyInfo.Name+"_Text")"
                                                autocomplete-selected-item-value="@Model.UserInfo.GetProperty(propertyInfo.Name)"
                                                autocomplete-filter-param-name="@propertyInfo.Lookup.FilterParamName"
                                                autocomplete-items-property-name="@propertyInfo.Lookup.ResultListPropertyName"
                                                autocomplete-display-property-name="@propertyInfo.Lookup.DisplayPropertyName"
                                                autocomplete-value-property-name="@propertyInfo.Lookup.ValuePropertyName"></abp-select>
                                }
                                else
                                {
                                    <abp-input type="@propertyInfo.GetInputType()"
                                               asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                               label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                               asp-format="@propertyInfo.GetInputFormatOrNull()"
                                               value="@propertyInfo.GetInputValueOrNull(Model.UserInfo.GetProperty(propertyInfo.Name))" />
                                }
                            }
                        }
                        <abp-input asp-for="UserInfo.PhoneNumber" />
                        <abp-input asp-for="UserInfo.IsActive" />
                        <abp-input asp-for="UserInfo.LockoutEnabled" />
                        @if (await SettingProvider.IsTrueAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail))
                        {
                            <abp-input asp-for="UserInfo.SendConfirmationEmail" />
                        }
                    </abp-tab>
                    <abp-tab name="Roles" title="@L.GetString("Roles{0}", Model.Roles.Count(r => r.IsAssigned))">
                        @for (var i = 0; i < Model.Roles.Length; i++)
                        {
                            var role = Model.Roles[i];
                            if (role.IsDefault)
                            {
    
                                <abp-input asp-for="@role.IsAssigned" abp-id-name="@Model.Roles[i].IsAssigned" label="@HtmlEncoder.Encode(role.Name)" checked="checked" />
                            }
                            else
                            {
                                <abp-input asp-for="@role.IsAssigned" abp-id-name="@Model.Roles[i].IsAssigned" label="@HtmlEncoder.Encode(role.Name)" />
                            }
    
                            <input asp-for="@role.Name" abp-id-name="@Model.Roles[i].Name" />
                        }
                    </abp-tab>
                    @if (Model.OrganizationUnits.Any())
                    {
                        <abp-tab name="OrganizationUnits" title="@L.GetString("OrganizationUnits{0}", Model.OrganizationUnits.Count(r => r.IsAssigned))">
                            <div id="JsTreeCheckable" class="tree jstree jstree-2 jstree-default jstree-checkbox-no-clicked jstree-checkbox-selection" role="tree" aria-multiselectable="true" tabindex="0" aria-activedescendant="j2_1" aria-busy="false" aria-selected="false">
                                <ul class="jstree-container-ul jstree-children" role="group">
                                    @for (int i = 0; i < Model.OrganizationUnitTreeRootNode.Children.Count; i++)
                                    {
                                        @await Html.PartialAsync("OrganizationUnitTreeNode", new OrganizationUnitTreeNodeModel
                                        {
                                            Depth = 0,
                                            Node = Model.OrganizationUnitTreeRootNode.Children[i],
                                            OrganizationUnits = Model.OrganizationUnits
                                        })
                                    }
                                </ul>
                            </div>
                            @for (var i = 0; i < Model.OrganizationUnits.Length; i++)
                            {
                                var organizationUnits = Model.OrganizationUnits[i];
                                <input asp-for="@organizationUnits.IsAssigned" abp-id-name="@Model.OrganizationUnits[i].IsAssigned" />
                                <input asp-for="@organizationUnits.DisplayName" abp-id-name="@Model.OrganizationUnits[i].DisplayName" />
                                <input asp-for="@organizationUnits.Id" abp-id-name="@Model.OrganizationUnits[i].Id" />
                            }
                        </abp-tab>
                    }
                    
                    <abp-tab name="your-custom-tab" title="Your Custom Tab">
                        YOUR TAB CONTENT HERE 👈
                    </abp-tab>
                </abp-tabs>
            </abp-modal-body>
            <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer>
        </abp-modal>
    </form>
    <input hidden id="RolesCount" value="@Model.Roles.Count(r => r.IsAssigned)" />
    
  • User Avatar
    0
    hussein created

    thanks enisn appreciated , could you share with me the EditModal and the code behind the file for the razor page what about my second question plz?

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Yeah sure,

    You can use following files to override:

    • /Pages/Identity/Users/EditModal.cshtml
    @page
    @using Microsoft.AspNetCore.Mvc.Localization
    @using Microsoft.Extensions.Localization
    @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
    @using Volo.Abp.Data
    @using Volo.Abp.Identity.Localization
    @using Volo.Abp.Identity.Web.Pages.Identity.Users
    @using Volo.Abp.Localization
    @using Volo.Abp.ObjectExtending
    @model EditModalModel
    @inject IHtmlLocalizer<IdentityResource> L
    @inject IStringLocalizerFactory StringLocalizerFactory
    @{
        Layout = null;
    }
    <form method="post" asp-page="/Identity/Users/EditModal">
        <abp-modal>
            <abp-modal-header title="@L["Edit"].Value"></abp-modal-header>
            <abp-modal-body>
                <abp-tabs name="create-user-modal-tabs">
                    <abp-tab title="@L["UserInformation"].Value">
                        <input asp-for="UserInfo.Id" />
                        <input asp-for="UserInfo.ConcurrencyStamp" />
                        <abp-input asp-for="UserInfo.UserName" />
                        <abp-input asp-for="UserInfo.Name" />
                        <abp-input asp-for="UserInfo.Surname" />
                        <abp-input asp-for="UserInfo.Email" label="@(L["EmailAddress"].Value + " * ")" />
                        @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<EditModalModel.UserInfoViewModel>())
                        {
                            if (!propertyInfo.Name.EndsWith("_Text"))
                            {
                                if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty())
                                {
                                    if (propertyInfo.Type.IsEnum)
                                    {
                                        Model.UserInfo.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type);
                                    }
                                    <abp-select asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                                label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                                autocomplete-api-url="@propertyInfo.Lookup.Url"
                                                autocomplete-selected-item-name="@Model.UserInfo.GetProperty(propertyInfo.Name+"_Text")"
                                                autocomplete-selected-item-value="@Model.UserInfo.GetProperty(propertyInfo.Name)"
                                                autocomplete-filter-param-name="@propertyInfo.Lookup.FilterParamName"
                                                autocomplete-items-property-name="@propertyInfo.Lookup.ResultListPropertyName"
                                                autocomplete-display-property-name="@propertyInfo.Lookup.DisplayPropertyName"
                                                autocomplete-value-property-name="@propertyInfo.Lookup.ValuePropertyName"></abp-select>
                                }
                                else
                                {
                                    <abp-input type="@propertyInfo.GetInputType()"
                                               asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                               label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                               asp-format="@propertyInfo.GetInputFormatOrNull()"
                                               value="@propertyInfo.GetInputValueOrNull(Model.UserInfo.GetProperty(propertyInfo.Name))" />
                                }
                            }
                        }
                        <abp-input asp-for="UserInfo.PhoneNumber" />
                        <abp-input asp-for="UserInfo.IsActive" />
                        <abp-input asp-for="UserInfo.LockoutEnabled" />
                    </abp-tab>
                    @if (Model.Roles.Any())
                    {
                        <abp-tab name="Roles" title="@L.GetString("Roles{0}", Model.Roles.Count(r => r.IsAssigned))">
                            @for (var i = 0; i < Model.Roles.Length; i++)
                            {
                                var role = Model.Roles[i];
                                <abp-input asp-for="@role.IsAssigned"
                                           abp-id-name="@Model.Roles[i].IsAssigned"
                                           label="@role.GetShownName(HtmlEncoder, L.GetString("OU"))"
                                           disabled="@role.IsInheritedFromOu" />
                                <input asp-for="@role.Name" abp-id-name="@Model.Roles[i].Name" />
                            }
                        </abp-tab>
                    }
    
                    @if (Model.OrganizationUnits.Any())
                    {
                        <abp-tab name="OrganizationUnits" title="@L.GetString("OrganizationUnits{0}", Model.OrganizationUnits.Count(r => r.IsAssigned))">
    
                            <div id="JsTreeCheckable" class="tree jstree jstree-2 jstree-default jstree-checkbox-no-clicked jstree-checkbox-selection" role="tree" aria-multiselectable="true" tabindex="0" aria-activedescendant="j2_1" aria-busy="false" aria-selected="false">
                                <ul class="jstree-container-ul jstree-children" role="group">
                                    @for (int i = 0; i < Model.OrganizationUnitTreeRootNode.Children.Count; i++)
                                    {
                                        @await Html.PartialAsync("OrganizationUnitTreeNode", new OrganizationUnitTreeNodeModel
                                        {
                                            Depth = 0,
                                            Node = Model.OrganizationUnitTreeRootNode.Children[i],
                                            OrganizationUnits = Model.OrganizationUnits
                                        })
                                    }
                                </ul>
                            </div>
                            @for (var i = 0; i < Model.OrganizationUnits.Length; i++)
                            {
                                var organizationUnits = Model.OrganizationUnits[i];
                                <input asp-for="@organizationUnits.IsAssigned" abp-id-name="@Model.OrganizationUnits[i].IsAssigned" />
                                <input asp-for="@organizationUnits.DisplayName" abp-id-name="@Model.OrganizationUnits[i].DisplayName" />
                                <input asp-for="@organizationUnits.Id" abp-id-name="@Model.OrganizationUnits[i].Id" />
                            }
                        </abp-tab>
                    }
                </abp-tabs>
            </abp-modal-body>
            <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer>
        </abp-modal>
    </form>
    <input hidden id="RolesCount" value="@Model.Roles.Count(r => r.IsAssigned)" />
    
    

    For the models, you can just inherit from IdentityUserModalPageModel, IdentityUserModalPageModel and add your custom logic instead of writing all the model again.

    
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Identity;
    using Volo.Abp.Identity.Web.Pages.Identity.Users;
    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(CreateModalModel))]
    public class MyCreateModalModel : CreateModalModel
    {
        public MyCreateModalModel(IIdentityUserAppService identityUserAppService) : base(identityUserAppService)
        {
        }
    
        public override async Task OnGetAsync()
        {
            await base.OnGetAsync(); // Keep base operations.
    
            // your own logic here
        }
    
        public override async Task<NoContentResult> OnPostAsync()
        {
            var result = await base.OnPostAsync();
    
            // your own logic here
    		
            return result;
        }
    }
    
  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    how to prevent a user who has the privilege to manage the users from deleting the Admin user or Sys Role?

    You can replace and customize AppService

    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IdentityUserAppService))]
    public class MyIdenityUserAppService : IdentityUserAppService
    {
        // base ctor here
    
        public override  async Task DeleteAsync(Guid id)
        {
            var user = await UserManager.FindByIdAsync(id.ToString());
            if(user.UserName == "admin")
            {
                throw new Exception("can not delete admin");
            }
            (await UserManager.DeleteAsync(user)).CheckErrors();
        }
    }
    
  • User Avatar
    0
    hussein created

    thanks enisn

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on June 20, 2025, 11:20