Browse Source

Merge pull request #6647 from abpframework/ui-extensions-blazor

Blazor UI extensions
pull/8180/head
Halil İbrahim Kalkan 5 years ago
committed by GitHub
parent
commit
10decfc8b9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
  2. 4
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
  3. 92
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
  4. 12
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor
  5. 78
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs
  6. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs
  7. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs
  8. 12
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs
  9. 21
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs
  10. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs
  11. 8
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs
  12. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs
  13. 71
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs
  14. 27
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs
  15. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs
  16. 40
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs
  17. 53
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs
  18. 20
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs
  19. 12
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityActionDictionary.cs
  20. 10
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/ILookupApiRequestService.cs
  21. 25
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs
  22. 12
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumnDictionary.cs
  23. 69
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs
  24. 85
      framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
  25. 261
      framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs
  26. 121
      framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor
  27. 50
      framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor.cs
  28. 6
      framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor
  29. 6
      framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs
  30. 2
      framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor
  31. 2
      framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor.cs
  32. 11
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor
  33. 32
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs
  34. 17
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor
  35. 37
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs
  36. 33
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs
  37. 29
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor
  38. 20
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor.cs
  39. 18
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor
  40. 109
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs
  41. 13
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor
  42. 61
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs
  43. 14
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor
  44. 33
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs
  45. 13
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor
  46. 37
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs
  47. 29
      framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs
  48. 7
      framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor
  49. 25
      framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor.cs
  50. 40
      framework/src/Volo.Abp.BlazoriseUI/ObjectExtensionPropertyInfoBlazorExtensions.cs
  51. 11
      framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj
  52. 1
      framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj
  53. 16
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyLookupConfiguration.cs
  54. 27
      modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityBlazorModule.cs
  55. 93
      modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor
  56. 90
      modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor.cs
  57. 16
      modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor
  58. 9
      modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor.cs
  59. 115
      modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor
  60. 92
      modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor.cs
  61. 19
      modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/AbpTenantManagementBlazorModule.cs
  62. 85
      modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor
  63. 85
      modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs
  64. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBundleContributor.cs
  65. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyProjectNameModuleExtensionConfigurator.cs

2
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj

@ -11,6 +11,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.Web\Volo.Abp.AspNetCore.Components.Web.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.SignalR\Volo.Abp.AspNetCore.SignalR.csproj" />
</ItemGroup>

4
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs

@ -4,13 +4,17 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.SignalR;
using Volo.Abp.AspNetCore.Uow;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Components.Server
{
[DependsOn(
typeof(AbpHttpClientModule),
typeof(AbpAspNetCoreComponentsWebModule),
typeof(AbpAspNetCoreSignalRModule)
)]
public class AbpAspNetCoreComponentsServerModule : AbpModule

92
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs

@ -0,0 +1,92 @@
using System;
using System.Globalization;
using System.Linq.Dynamic.Core;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.AspNetCore.Components.Web.Extensibility;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.Components.Server.Extensibility
{
public class BlazorServerLookupApiRequestService : ILookupApiRequestService, ITransientDependency
{
public IHttpClientFactory HttpClientFactory { get; }
public IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
public AbpRemoteServiceOptions RemoteServiceOptions { get; }
public ICurrentTenant CurrentTenant { get; }
public IHttpContextAccessor HttpContextAccessor { get; }
public NavigationManager NavigationManager { get; }
public BlazorServerLookupApiRequestService(IHttpClientFactory httpClientFactory,
IRemoteServiceHttpClientAuthenticator httpClientAuthenticator,
ICurrentTenant currentTenant,
IOptions<AbpRemoteServiceOptions> remoteServiceOptions,
IHttpContextAccessor httpContextAccessor,
NavigationManager navigationManager)
{
HttpClientFactory = httpClientFactory;
HttpClientAuthenticator = httpClientAuthenticator;
RemoteServiceOptions = remoteServiceOptions.Value;
CurrentTenant = currentTenant;
HttpContextAccessor = httpContextAccessor;
NavigationManager = navigationManager;
}
public async Task<string> SendAsync(string url)
{
var client = HttpClientFactory.CreateClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
var baseUrl = string.Empty;
try
{
//Blazor tiered -- mode
var remoteServiceConfig = RemoteServiceOptions.RemoteServices.GetConfigurationOrDefault("Default");
baseUrl = remoteServiceConfig.BaseUrl;
client.BaseAddress = new Uri(baseUrl);
AddHeaders(requestMessage);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client,
requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
}
catch (AbpException) // Blazor-Server mode.
{
baseUrl = NavigationManager.BaseUri;
client.BaseAddress = new Uri(baseUrl);
foreach (var header in HttpContextAccessor.HttpContext.Request.Headers)
{
requestMessage.Headers.Add(header.Key, header.Value.ToArray());
}
}
}
var response = await client.SendAsync(requestMessage);
return await response.Content.ReadAsStringAsync();
}
protected virtual void AddHeaders(HttpRequestMessage requestMessage)
{
if (CurrentTenant.Id.HasValue)
{
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
}
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
if (!currentCulture.IsNullOrEmpty())
{
requestMessage.Headers.AcceptLanguage.Add(new(currentCulture));
}
}
}
}

12
framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor → framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor

@ -1,4 +1,5 @@
<Row Class="entry-row">
@using Blazorise
<Row Class="entry-row">
<Column ColumnSize="ColumnSize.IsAuto">
<h1 class="content-header-title">@Title</h1>
</Column>
@ -31,7 +32,12 @@
}
<Column>
<Row Class="justify-content-end mx-n1">
@ChildContent
@foreach (var toolbarItemRender in ToolbarItemRenders)
{
<Column ColumnSize="ColumnSize.IsAuto" Class="px-1 pt-2">
@toolbarItemRender
</Column>
}
</Row>
</Column>
</Row>
</Row>

78
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs

@ -0,0 +1,78 @@
using System;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
using Volo.Abp.BlazoriseUI;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout
{
public partial class PageHeader : ComponentBase
{
protected List<RenderFragment> ToolbarItemRenders { get; set; }
public IPageToolbarManager PageToolbarManager { get; set; }
[Parameter]
public string Title { get; set; }
[Parameter]
public bool BreadcrumbShowHome { get; set; } = true;
[Parameter]
public bool BreadcrumbShowCurrent { get; set; } = true;
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public List<BreadcrumbItem> BreadcrumbItems { get; set; }
[Parameter]
public PageToolbar Toolbar { get; set; }
[Parameter]
public string PageName { get; set; }
public PageHeader()
{
BreadcrumbItems = new List<BreadcrumbItem>();
ToolbarItemRenders = new List<RenderFragment>();
}
protected override async Task OnParametersSetAsync()
{
await base.OnParametersSetAsync();
if (Toolbar!=null)
{
Console.WriteLine("Toolbar is not null");
var toolbarItems = await PageToolbarManager.GetItemsAsync(Toolbar);
Console.WriteLine($"Toolbar item count:{toolbarItems.Length}");
ToolbarItemRenders.Clear();
foreach (var item in toolbarItems)
{
var sequence = 0;
ToolbarItemRenders.Add(builder =>
{
builder.OpenComponent(sequence, item.ComponentType);
if (item.Arguments != null)
{
foreach (var argument in item.Arguments)
{
sequence++;
builder.AddAttribute(sequence, argument.Key, argument.Value);
}
}
builder.CloseComponent();
});
}
}
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
}
}
}

9
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public interface IPageToolbarContributor
{
Task ContributeAsync(PageToolbarContributionContext context);
}
}

9
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public interface IPageToolbarManager
{
Task<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar);
}
}

12
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs

@ -0,0 +1,12 @@
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class PageToolbar
{
public PageToolbarContributorList Contributors { get; set; }
public PageToolbar()
{
Contributors = new PageToolbarContributorList();
}
}
}

21
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs

@ -0,0 +1,21 @@
using JetBrains.Annotations;
using System;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class PageToolbarContributionContext
{
[NotNull]
public IServiceProvider ServiceProvider { get; }
[NotNull]
public PageToolbarItemList Items { get; }
public PageToolbarContributionContext(
[NotNull] IServiceProvider serviceProvider)
{
ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider));
Items = new PageToolbarItemList();
}
}
}

9
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public abstract class PageToolbarContributor : IPageToolbarContributor
{
public abstract Task ContributeAsync(PageToolbarContributionContext context);
}
}

8
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs

@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class PageToolbarContributorList : List<IPageToolbarContributor>
{
}
}

9
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class PageToolbarDictionary : Dictionary<string, PageToolbar>
{
}
}

71
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs

@ -0,0 +1,71 @@
using Blazorise;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.BlazoriseUI.Components;
using Volo.Abp.Localization;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public static class PageToolbarExtensions
{
public static PageToolbar AddComponent<TComponent>(
this PageToolbar toolbar,
Dictionary<string, object> arguments = null,
int order = 0,
string requiredPolicyName = null)
{
return toolbar.AddComponent(
typeof(TComponent),
arguments,
order,
requiredPolicyName
);
}
public static PageToolbar AddComponent(
this PageToolbar toolbar,
Type componentType,
Dictionary<string, object> arguments = null,
int order = 0,
string requiredPolicyName = null)
{
toolbar.Contributors.Add(
new SimplePageToolbarContributor(
componentType,
arguments,
order,
requiredPolicyName
)
);
return toolbar;
}
public static PageToolbar AddButton(
this PageToolbar toolbar,
string text,
Func<Task> clicked,
object icon = null,
Color color = Color.Primary,
bool disabled = false,
int order = 0,
string requiredPolicyName = null)
{
toolbar.AddComponent<ToolbarButton>(
new Dictionary<string, object>
{
{ nameof(ToolbarButton.Color), color},
{ nameof(ToolbarButton.Text), text},
{ nameof(ToolbarButton.Disabled), disabled},
{ nameof(ToolbarButton.Icon), icon},
{ nameof(ToolbarButton.Clicked),clicked},
},
order,
requiredPolicyName
);
return toolbar;
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs

@ -0,0 +1,27 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class PageToolbarItem
{
[NotNull]
public Type ComponentType { get; }
[CanBeNull]
public Dictionary<string, object> Arguments { get; set; }
public int Order { get; set; }
public PageToolbarItem(
[NotNull] Type componentType,
[CanBeNull] Dictionary<string, object> arguments = null,
int order = 0)
{
ComponentType = Check.NotNull(componentType, nameof(componentType));
Arguments = arguments;
Order = order;
}
}
}

9
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class PageToolbarItemList : List<PageToolbarItem>
{
}
}

40
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs

@ -0,0 +1,40 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class PageToolbarManager : IPageToolbarManager, ITransientDependency
{
protected IHybridServiceScopeFactory ServiceScopeFactory { get; }
public PageToolbarManager(
IHybridServiceScopeFactory serviceScopeFactory)
{
ServiceScopeFactory = serviceScopeFactory;
}
public virtual async Task<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar)
{
if (toolbar == null || !toolbar.Contributors.Any())
{
return Array.Empty<PageToolbarItem>();
}
using (var scope = ServiceScopeFactory.CreateScope())
{
var context = new PageToolbarContributionContext(scope.ServiceProvider);
foreach (var contributor in toolbar.Contributors)
{
await contributor.ContributeAsync(context);
}
return context.Items.OrderBy(i => i.Order).ToArray();
}
}
}
}

53
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs

@ -0,0 +1,53 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
{
public class SimplePageToolbarContributor : IPageToolbarContributor
{
public Type ComponentType { get; }
public Dictionary<string, object> Arguments { get; set; }
public int Order { get; }
public string RequiredPolicyName { get; }
public SimplePageToolbarContributor(
Type componentType,
Dictionary<string, object> arguments = null,
int order = 0,
string requiredPolicyName = null)
{
ComponentType = componentType;
Arguments = arguments;
Order = order;
RequiredPolicyName = requiredPolicyName;
}
public async Task ContributeAsync(PageToolbarContributionContext context)
{
if (await ShouldAddComponentAsync(context))
{
context.Items.Add(new PageToolbarItem(ComponentType, Arguments, Order));
}
}
protected virtual async Task<bool> ShouldAddComponentAsync(PageToolbarContributionContext context)
{
if (RequiredPolicyName != null)
{
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
if (!await authorizationService.IsGrantedAsync(RequiredPolicyName))
{
return false;
}
}
return true;
}
}
}

20
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs

@ -0,0 +1,20 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions
{
public class EntityAction : IEquatable<EntityAction>
{
public string Text { get; set; }
public Func<object, Task> Clicked { get; set; }
public Func<object, string> ConfirmationMessage { get; set; }
public bool Primary { get; set; }
public object Color { get; set; }
public string Icon { get; set; }
public Func<object, bool> Visible { get; set; }
public bool Equals(EntityAction other)
{
return string.Equals(Text, other?.Text, StringComparison.OrdinalIgnoreCase);
}
}
}

12
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityActionDictionary.cs

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions
{
public class EntityActionDictionary : Dictionary<string, List<EntityAction>>
{
public List<EntityAction> Get<T>()
{
return this.GetOrAdd(typeof(T).FullName, () => new List<EntityAction>());
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/ILookupApiRequestService.cs

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.AspNetCore.Components.Web.Extensibility
{
public interface ILookupApiRequestService
{
Task<string> SendAsync([NotNull]string url);
}
}

25
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs

@ -0,0 +1,25 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
namespace Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns
{
public class TableColumn
{
public string Title { get; set; }
public string Data { get; set; }
[CanBeNull]
public string DisplayFormat { get; set; }
[CanBeNull]
public Type Component { get; set; }
public List<EntityAction> Actions { get; set; }
[CanBeNull]
public Func<object,string> ValueConverter { get; set; }
public TableColumn()
{
Actions = new List<EntityAction>();
}
}
}

12
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumnDictionary.cs

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns
{
public class TableColumnDictionary : Dictionary<string, List<TableColumn>>
{
public List<TableColumn> Get<T>()
{
return this.GetOrAdd(typeof(T).FullName, () => new List<TableColumn>());
}
}
}

69
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs

@ -0,0 +1,69 @@
using System;
using System.Globalization;
using System.Net.Http;
using System.Threading.Tasks;
using Castle.Components.DictionaryAdapter;
using Fody;
using Volo.Abp.AspNetCore.Components.Web.Extensibility;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.Http.Client;
using Microsoft.Extensions.Options;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Extensibility
{
public class WebAssemblyLookupApiRequestService : ILookupApiRequestService, ITransientDependency
{
public IHttpClientFactory HttpClientFactory { get; }
public IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
public AbpRemoteServiceOptions RemoteServiceOptions { get; }
public ICurrentTenant CurrentTenant { get; }
public WebAssemblyLookupApiRequestService(IHttpClientFactory httpClientFactory,
IRemoteServiceHttpClientAuthenticator httpClientAuthenticator,
ICurrentTenant currentTenant,
IOptions<AbpRemoteServiceOptions> remoteServiceOptions)
{
HttpClientFactory = httpClientFactory;
HttpClientAuthenticator = httpClientAuthenticator;
RemoteServiceOptions = remoteServiceOptions.Value;
CurrentTenant = currentTenant;
}
public async Task<string> SendAsync(string url)
{
var client = HttpClientFactory.CreateClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
AddHeaders(requestMessage);
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
var remoteServiceConfig = RemoteServiceOptions.RemoteServices.GetConfigurationOrDefault("Default");
client.BaseAddress = new Uri(remoteServiceConfig.BaseUrl);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration(remoteServiceConfig.BaseUrl), string.Empty));
}
var response = await client.SendAsync(requestMessage);
return await response.Content.ReadAsStringAsync();
}
protected virtual void AddHeaders(HttpRequestMessage requestMessage)
{
if (CurrentTenant.Id.HasValue)
{
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
}
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
if (!currentCulture.IsNullOrEmpty())
{
requestMessage.Headers.AcceptLanguage.Add(new (currentCulture));
}
}
}
}

85
framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs

@ -9,11 +9,18 @@ using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.AspNetCore.Components;
using Volo.Abp.Localization;
using Volo.Abp.Authorization;
using Volo.Abp.BlazoriseUI.Components;
using Volo.Abp.BlazoriseUI.Components.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns;
namespace Volo.Abp.BlazoriseUI
{
@ -186,6 +193,8 @@ namespace Volo.Abp.BlazoriseUI
protected Validations EditValidationsRef;
protected List<BreadcrumbItem> BreadcrumbItems = new List<BreadcrumbItem>(2);
protected DataGridEntityActionsColumn<TListViewModel> EntityActionsColumn;
protected EntityActionDictionary EntityActions { get; set; }
protected TableColumnDictionary TableColumns { get; set; }
protected string CreatePolicyName { get; set; }
protected string UpdatePolicyName { get; set; }
@ -199,14 +208,30 @@ namespace Volo.Abp.BlazoriseUI
{
NewEntity = new TCreateViewModel();
EditingEntity = new TUpdateViewModel();
TableColumns = new TableColumnDictionary();
EntityActions = new EntityActionDictionary();
}
protected override async Task OnInitializedAsync()
{
await SetBreadcrumbItemsAsync();
await SetPermissionsAsync();
await SetEntityActionsAsync();
await SetTableColumnsAsync();
await InvokeAsync(StateHasChanged);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await base.OnAfterRenderAsync(firstRender);
await SetToolbarItemsAsync();
await SetBreadcrumbItemsAsync();
}
}
protected virtual async Task SetPermissionsAsync()
{
if (CreatePolicyName != null)
@ -463,6 +488,7 @@ namespace Volo.Abp.BlazoriseUI
await AppService.DeleteAsync(entity.Id);
await GetEntitiesAsync();
await InvokeAsync(StateHasChanged);
}
catch (Exception ex)
{
@ -511,5 +537,62 @@ namespace Volo.Abp.BlazoriseUI
{
return ValueTask.CompletedTask;
}
protected virtual ValueTask SetEntityActionsAsync()
{
return ValueTask.CompletedTask;
}
protected virtual ValueTask SetTableColumnsAsync()
{
return ValueTask.CompletedTask;
}
protected virtual ValueTask SetToolbarItemsAsync()
{
return ValueTask.CompletedTask;
}
protected virtual IEnumerable<TableColumn> GetExtensionTableColumns(string moduleName, string entityType)
{
var properties = ModuleExtensionConfigurationHelper.GetPropertyConfigurations(moduleName, entityType);
foreach (var propertyInfo in properties)
{
if (propertyInfo.IsAvailableToClients && propertyInfo.UI.OnTable.IsVisible)
{
if (propertyInfo.Name.EndsWith("_Text"))
{
var lookupPropertyName = propertyInfo.Name.RemovePostFix("_Text");
var lookupPropertyDefinition = properties.SingleOrDefault(t => t.Name == lookupPropertyName);
yield return new TableColumn
{
Title = lookupPropertyDefinition.GetLocalizedDisplayName(StringLocalizerFactory),
Data = $"ExtraProperties[{propertyInfo.Name}]"
};
}
else
{
var column = new TableColumn
{
Title = propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory),
Data = $"ExtraProperties[{propertyInfo.Name}]"
};
if (propertyInfo.IsDate() || propertyInfo.IsDateTime())
{
column.DisplayFormat = propertyInfo.GetDateEditInputFormatOrNull();
}
if (propertyInfo.Type.IsEnum)
{
column.ValueConverter = (val) =>
EnumHelper.GetLocalizedMemberName(propertyInfo.Type, val, StringLocalizerFactory);
}
yield return column;
}
}
}
}
}
}

261
framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs

@ -0,0 +1,261 @@
using Blazorise;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Volo.Abp.BlazoriseUI.Components.ObjectExtending;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Reflection;
namespace Volo.Abp.BlazoriseUI
{
public static class BlazoriseUiObjectExtensionPropertyInfoExtensions
{
private static readonly HashSet<Type> NumberTypes = new HashSet<Type> {
typeof(int),
typeof(long),
typeof(byte),
typeof(sbyte),
typeof(short),
typeof(ushort),
typeof(uint),
typeof(long),
typeof(ulong),
typeof(float),
typeof(double),
typeof(decimal),
typeof(int?),
typeof(long?),
typeof(byte?),
typeof(sbyte?),
typeof(short?),
typeof(ushort?),
typeof(uint?),
typeof(long?),
typeof(ulong?),
typeof(float?),
typeof(double?),
typeof(decimal?)
};
private static readonly HashSet<Type> TextEditSupportedAttributeTypes = new HashSet<Type> {
typeof(EmailAddressAttribute),
typeof(UrlAttribute),
typeof(PhoneAttribute)
};
public static string GetDateEditInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property)
{
if (property.IsDate())
{
return "{0:yyyy-MM-dd}";
}
if (property.IsDateTime())
{
return "{0:yyyy-MM-ddTHH:mm}";
}
return null;
}
public static string GetTextInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object value)
{
if (value == null)
{
return null;
}
if (TypeHelper.IsFloatingType(property.Type))
{
return value.ToString()?.Replace(',', '.');
}
return value.ToString();
}
public static T GetInputValueOrDefault<T>(this IBasicObjectExtensionPropertyInfo property, object value)
{
if (value == null)
{
return default;
}
return (T)value;
}
public static TextInputMode GetTextInputMode(this ObjectExtensionPropertyInfo propertyInfo)
{
foreach (var attribute in propertyInfo.Attributes)
{
var textRoleByAttribute = GetTextInputModeFromAttributeOrNull(attribute);
if (textRoleByAttribute != null)
{
return textRoleByAttribute.Value;
}
}
return GetTextInputModeFromTypeOrNull(propertyInfo.Type)
?? TextInputMode.None; //default
}
private static TextInputMode? GetTextInputModeFromTypeOrNull(Type type)
{
if (TypeHelper.IsFloatingType(type))
{
return TextInputMode.Decimal;
}
if (NumberTypes.Contains(type))
{
return TextInputMode.Numeric;
}
return null;
}
private static TextInputMode? GetTextInputModeFromAttributeOrNull(Attribute attribute)
{
if (attribute is EmailAddressAttribute)
{
return TextInputMode.Email;
}
if (attribute is UrlAttribute)
{
return TextInputMode.Url;
}
if (attribute is PhoneAttribute)
{
return TextInputMode.Tel;
}
if (attribute is DataTypeAttribute dataTypeAttribute)
{
switch (dataTypeAttribute.DataType)
{
case DataType.EmailAddress:
return TextInputMode.Email;
case DataType.Url:
return TextInputMode.Url;
case DataType.PhoneNumber:
return TextInputMode.Tel;
}
}
return null;
}
public static TextRole GetTextRole(this ObjectExtensionPropertyInfo propertyInfo)
{
foreach (var attribute in propertyInfo.Attributes)
{
var textRoleByAttribute = GetTextRoleFromAttributeOrNull(attribute);
if (textRoleByAttribute != null)
{
return textRoleByAttribute.Value;
}
}
return TextRole.Text; //default
}
private static TextRole? GetTextRoleFromAttributeOrNull(Attribute attribute)
{
if (attribute is EmailAddressAttribute)
{
return TextRole.Email;
}
if (attribute is UrlAttribute)
{
return TextRole.Url;
}
if (attribute is DataTypeAttribute dataTypeAttribute)
{
switch (dataTypeAttribute.DataType)
{
case DataType.Password:
return TextRole.Password;
case DataType.EmailAddress:
return TextRole.Email;
case DataType.Url:
return TextRole.Url;
}
}
return null;
}
public static Type GetInputType(this ObjectExtensionPropertyInfo propertyInfo)
{
foreach (var attribute in propertyInfo.Attributes)
{
var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute);
if (inputTypeByAttribute != null)
{
return inputTypeByAttribute;
}
}
return GetInputTypeFromTypeOrNull(propertyInfo.Type)
?? typeof(TextExtensionProperty<,>); //default
}
private static Type GetInputTypeFromAttributeOrNull(Attribute attribute)
{
var hasTextEditSupport = TextEditSupportedAttributeTypes.Any(t => t == attribute.GetType());
if (hasTextEditSupport)
{
return typeof(TextExtensionProperty<,>);
}
if (attribute is DataTypeAttribute dataTypeAttribute)
{
switch (dataTypeAttribute.DataType)
{
case DataType.Password:
return typeof(TextExtensionProperty<,>);
case DataType.Date:
return typeof(DateTimeExtensionProperty<,>);
case DataType.Time:
return typeof(TimeExtensionProperty<,>);
case DataType.EmailAddress:
return typeof(TextExtensionProperty<,>);
case DataType.Url:
return typeof(TextExtensionProperty<,>);
case DataType.PhoneNumber:
return typeof(TextExtensionProperty<,>);
case DataType.DateTime:
return typeof(DateTimeExtensionProperty<,>);
}
}
return null;
}
private static Type GetInputTypeFromTypeOrNull(Type type)
{
if (type == typeof(bool))
{
return typeof(CheckExtensionProperty<,>);
}
if (type == typeof(DateTime))
{
return typeof(DateTimeExtensionProperty<,>);
}
if (NumberTypes.Contains(type))
{
return typeof(TextExtensionProperty<,>);
}
return null;
}
}
}

121
framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor

@ -0,0 +1,121 @@
@typeparam TItem
@using Blazorise.DataGrid;
@using Volo.Abp.Data
@using Volo.Abp.BlazoriseUI.Components.ObjectExtending
<DataGrid TItem="TItem"
Data="@Data"
ReadData="@ReadData"
TotalItems="@TotalItems"
ShowPager="@ShowPager"
CurrentPage="@CurrentPage"
PageSize="@PageSize">
<DataGridColumns>
@if (Columns != null)
{
@foreach (var column in Columns)
{
if (column.Actions.Any())
{
<DataGridEntityActionsColumn TItem="TItem" @ref="ActionColumns[column.Title]" Caption="@column.Title">
<DisplayTemplate>
<EntityActions TItem="TItem" EntityActionsColumn="ActionColumns[column.Title]">
@foreach (var action in column.Actions)
{
if (action.ConfirmationMessage != null)
{
<EntityAction TItem="TItem"
Color="@(action.Color!=null ? (Blazorise.Color)action.Color : Blazorise.Color.Primary)"
Icon="@action.Icon"
Clicked="async () => await action.Clicked(context)"
ConfirmationMessage="() => action.ConfirmationMessage.Invoke(context)"
Visible="@(action.Visible!=null ? action.Visible(context) : true)"
Text="@action.Text">
</EntityAction>
}
else
{
<EntityAction TItem="TItem"
Clicked="async () => await action.Clicked(context)"
Color="@(action.Color!=null ? (Blazorise.Color)action.Color : Blazorise.Color.None)"
Icon="@action.Icon"
Visible="@(action.Visible!=null ? action.Visible(context) : true)"
Text="@action.Text">
</EntityAction>
}
}
</EntityActions>
</DisplayTemplate>
</DataGridEntityActionsColumn>
}
else
{
@if (column.Component != null)
{
<DataGridColumn TItem="TItem" Field="@typeof(TItem).GetProperties().First().Name" Caption="@column.Title">
<DisplayTemplate>
@RenderCustomTableColumnComponent(column.Component, context)
</DisplayTemplate>
</DataGridColumn>
}
else
{
if (!ExtensionPropertiesRegex.IsMatch(column.Data))
{
<DataGridColumn TItem="TItem" Field="@column.Data" Caption="@column.Title"/>
}
else
{
<DataGridColumn TItem="TItem" Field="@nameof(IHasExtraProperties.ExtraProperties)" Caption="@column.Title">
<DisplayTemplate>
@{
var entity = context as IHasExtraProperties;
var propertyName = ExtensionPropertiesRegex.Match(column.Data).Groups[1].Value;
var propertyValue = entity.GetProperty(propertyName);
if (propertyValue != null && propertyValue.GetType() == typeof(bool))
{
if ((bool) propertyValue)
{
<Icon class="text-success" Name="IconName.Check"/>
}
else
{
<Icon class="text-danger" Name="IconName.Times"/>
}
}
else
{
if (column.ValueConverter != null)
{
if (column.DisplayFormat == null)
{
@(column.ValueConverter(propertyValue))
}
else
{
@(string.Format(column.DisplayFormat, column.ValueConverter(propertyValue)))
}
}
else
{
if (column.DisplayFormat == null)
{
@(propertyValue)
}
else
{
@(string.Format(column.DisplayFormat, propertyValue))
}
}
}
}
</DisplayTemplate>
</DataGridColumn>
}
}
}
}
}
</DataGridColumns>
</DataGrid>

50
framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor.cs

@ -0,0 +1,50 @@
using System;
using Blazorise.Extensions;
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Localization;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns;
namespace Volo.Abp.BlazoriseUI.Components
{
public partial class AbpExtensibleDataGrid<TItem> : ComponentBase
{
protected const string DataFieldAttributeName = "Data";
protected Dictionary<string, DataGridEntityActionsColumn<TItem>> ActionColumns =
new Dictionary<string, DataGridEntityActionsColumn<TItem>>();
protected Regex ExtensionPropertiesRegex = new Regex(@"ExtraProperties\[(.*?)\]");
[Parameter] public IEnumerable<TItem> Data { get; set; }
[Parameter] public EventCallback<DataGridReadDataEventArgs<TItem>> ReadData { get; set; }
[Parameter] public int? TotalItems { get; set; }
[Parameter] public bool ShowPager { get; set; }
[Parameter] public int PageSize { get; set; }
[Parameter] public IEnumerable<TableColumn> Columns { get; set; }
[Parameter] public int CurrentPage { get; set; } = 1;
[Inject]
public IStringLocalizerFactory StringLocalizerFactory { get; set; }
protected virtual RenderFragment RenderCustomTableColumnComponent(Type type, object data)
{
return (builder) =>
{
builder.OpenComponent(type);
builder.AddAttribute(0, DataFieldAttributeName, data);
builder.CloseComponent();
};
}
}
}

6
framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor

@ -1,6 +1,6 @@
@typeparam TItem
@if (IsVisible && HasPermission)
@if (Visible && HasPermission)
{
if (ParentActions.Type == ActionType.Dropdown)
{
@ -14,6 +14,10 @@
<Button Block="true"
Color="@Color"
Clicked="@ActionClickedAsync">
@if(!string.IsNullOrEmpty(Icon))
{
<Icon Name="@Icon"/>
}
@Text
</Button>
}

6
framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs

@ -10,7 +10,7 @@ namespace Volo.Abp.BlazoriseUI.Components
public partial class EntityAction<TItem> : ComponentBase
{
[Parameter]
public bool IsVisible { get; set; } = true;
public bool Visible { get; set; }
internal bool HasPermission { get; set; } = true;
@ -33,6 +33,9 @@ namespace Volo.Abp.BlazoriseUI.Components
[Parameter]
public Func<string> ConfirmationMessage { get; set; }
[Parameter]
public string Icon { get; set; }
[CascadingParameter]
public EntityActions<TItem> ParentActions { get; set; }
@ -46,6 +49,7 @@ namespace Volo.Abp.BlazoriseUI.Components
{
await base.OnInitializedAsync();
await SetDefaultValuesAsync();
if (!RequiredPolicy.IsNullOrEmpty())
{
HasPermission = await AuthorizationService.IsGrantedAsync(RequiredPolicy);

2
framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor

@ -14,7 +14,7 @@
}
else
{
<DropdownToggle Color="@ToggleColor">
<DropdownToggle Class="btn-block" Color="@ToggleColor">
@ToggleText
</DropdownToggle>
}

2
framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor.cs

@ -52,7 +52,7 @@ namespace Volo.Abp.BlazoriseUI.Components
{
if (ParentEntityActionsColumn != null)
{
ParentEntityActionsColumn.Displayable = Actions.Any(t => t.IsVisible && t.HasPermission);
ParentEntityActionsColumn.Displayable = Actions.Any(t => t.Visible && t.HasPermission);
}
await InvokeAsync(StateHasChanged);

11
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor

@ -0,0 +1,11 @@
@typeparam TEntity
@typeparam TResourceType
@using Volo.Abp.BlazoriseUI
@using Volo.Abp.Localization
@if (PropertyInfo != null && Entity != null)
{
<Field>
<Check TValue="bool" @bind-Checked="@Value">@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)</Check>
</Field>
}

32
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs

@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public partial class CheckExtensionProperty<TEntity, TResourceType> : ComponentBase
where TEntity : IHasExtraProperties
{
[Inject]
public IStringLocalizerFactory StringLocalizerFactory { get; set; }
[Parameter]
public TEntity Entity { get; set; }
[Parameter]
public ObjectExtensionPropertyInfo PropertyInfo { get; set; }
protected bool Value
{
get
{
return PropertyInfo.GetInputValueOrDefault<bool>(Entity.GetProperty(PropertyInfo.Name));
}
set
{
Entity.SetProperty(PropertyInfo.Name, value, false);
}
}
}
}

17
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor

@ -0,0 +1,17 @@
@typeparam TEntity
@typeparam TResourceType
@using Volo.Abp.BlazoriseUI
@using Volo.Abp.Localization
@using Volo.Abp.ObjectExtending
@if (PropertyInfo != null && Entity != null)
{
<Field>
<FieldLabel>@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)</FieldLabel>
<DateEdit TValue="DateTime?"
InputMode="@(PropertyInfo.IsDate() ? DateInputMode.Date : DateInputMode.DateTime)"
Pattern="@PropertyInfo.GetDateEditInputFormatOrNull()"
@bind-Date="@Value">
</DateEdit>
</Field>
}

37
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs

@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public partial class DateTimeExtensionProperty<TEntity, TResourceType> : ComponentBase
where TEntity : IHasExtraProperties
{
[Inject]
public IStringLocalizerFactory StringLocalizerFactory { get; set; }
[Parameter]
public TEntity Entity { get; set; }
[Parameter]
public ObjectExtensionPropertyInfo PropertyInfo { get; set; }
protected DateTime? Value
{
get
{
return PropertyInfo.GetInputValueOrDefault<DateTime?>(Entity.GetProperty(PropertyInfo.Name));
}
set
{
Entity.SetProperty(PropertyInfo.Name, value, false);
}
}
}
}

33
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs

@ -0,0 +1,33 @@
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Localization;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public static class EnumHelper
{
public static string GetLocalizedMemberName(Type enumType, object value, IStringLocalizerFactory stringLocalizerFactory)
{
var memberName = enumType.GetEnumName(value);
var localizedMemberName = AbpInternalLocalizationHelper.LocalizeWithFallback(
new[]
{
stringLocalizerFactory.CreateDefaultOrNull()
},
new[]
{
$"Enum:{enumType.Name}.{memberName}",
$"{enumType.Name}.{memberName}",
memberName
},
memberName
);
return localizedMemberName;
}
}
}

29
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor

@ -0,0 +1,29 @@
@typeparam TEntityType
@typeparam TResourceType
@using Volo.Abp.ObjectExtending
@using Volo.Abp.Localization
@using Volo.Abp.Data
@foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<TEntityType>())
{
if (!propertyInfo.Name.EndsWith("_Text"))
{
if (propertyInfo.Type.IsEnum)
{
<SelectExtensionProperty PropertyInfo="@propertyInfo" Entity="@Entity" TEntity="TEntityType" TResourceType="TResourceType" />
}
else if (!propertyInfo.Lookup.Url.IsNullOrEmpty())
{
<LookupExtensionProperty PropertyInfo="@propertyInfo" Entity="@Entity" TEntity="TEntityType" TResourceType="TResourceType" />
}
else
{
var inputType = propertyInfo.GetInputType();
__builder.OpenComponent(0, inputType.MakeGenericType(new[] { typeof(TEntityType), typeof(TResourceType) }));
__builder.AddAttribute(1, "PropertyInfo", propertyInfo);
__builder.AddAttribute(2, "Entity", Entity);
__builder.CloseComponent();
}
}
}

20
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor.cs

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.Data;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public partial class ExtensionProperties<TEntityType, TResourceType> : ComponentBase
where TEntityType : IHasExtraProperties
{
[Inject]
public IStringLocalizerFactory StringLocalizerFactory { get; set; }
[Parameter]
public AbpBlazorMessageLocalizerHelper<TResourceType> LH { get; set; }
[Parameter]
public TEntityType Entity { get; set; }
}
}

18
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor

@ -0,0 +1,18 @@
@typeparam TEntity
@typeparam TResourceType
@using Abp.Localization
@using Blazorise.Components
<Field>
<FieldLabel>@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)</FieldLabel>
<Autocomplete Data="@lookupItems"
TItem="SelectItem<object>"
TValue="object"
TextField="item=>item.Text"
ValueField="item=>item.Value"
SelectedValue="@SelectedValue"
SelectedValueChanged="@SelectedValueChanged"
SearchChanged="@SearchFilterChangedAsync">
</Autocomplete>
</Field>

109
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs

@ -0,0 +1,109 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Components.Web.Extensibility;
using Volo.Abp.Data;
using Volo.Abp.Http;
using Volo.Abp.Http.Client;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public partial class LookupExtensionProperty<TEntity, TResourceType> : ComponentBase
where TEntity : IHasExtraProperties
{
protected List<SelectItem<object>> lookupItems;
[Inject] public IStringLocalizerFactory StringLocalizerFactory { get; set; }
[Parameter] public TEntity Entity { get; set; }
[Parameter] public ObjectExtensionPropertyInfo PropertyInfo { get; set; }
[Inject] public ILookupApiRequestService LookupApiService { get; set; }
public string TextPropertyName => PropertyInfo.Name + "_Text";
public object SelectedValue
{
get { return Entity.GetProperty(PropertyInfo.Name); }
set
{
Entity.SetProperty(PropertyInfo.Name, value, false);
UpdateLookupTextProperty(value);
}
}
public LookupExtensionProperty()
{
lookupItems = new List<SelectItem<object>>();
}
protected override void OnParametersSet()
{
var value = Entity.GetProperty(PropertyInfo.Name);
var text = Entity.GetProperty(TextPropertyName);
if (value != null && text != null)
{
lookupItems.Add(new SelectItem<object>
{
Text = Entity.GetProperty(TextPropertyName).ToString(),
Value = value
});
}
}
protected virtual void UpdateLookupTextProperty(object value)
{
var selectedItemText = lookupItems.SingleOrDefault(t => t.Value.Equals(value)).Text;
Entity.SetProperty(TextPropertyName, selectedItemText);
}
protected virtual async Task<List<SelectItem<object>>> GetLookupItemsAsync(string filter)
{
var selectItems = new List<SelectItem<object>>();
var url = PropertyInfo.Lookup.Url;
if (!filter.IsNullOrEmpty())
{
url += $"?{PropertyInfo.Lookup.FilterParamName}={filter.Trim()}";
}
var response = await LookupApiService.SendAsync(url);
var document = JsonDocument.Parse(response);
var itemsArrayProp = document.RootElement.GetProperty(PropertyInfo.Lookup.ResultListPropertyName);
foreach (var item in itemsArrayProp.EnumerateArray())
{
selectItems.Add(new SelectItem<object>
{
Text = item.GetProperty(PropertyInfo.Lookup.DisplayPropertyName).GetString(),
Value = JsonSerializer.Deserialize(
item.GetProperty(PropertyInfo.Lookup.ValuePropertyName).GetRawText(), PropertyInfo.Type)
});
}
return selectItems;
}
protected virtual void SelectedValueChanged(object selectedItem)
{
SelectedValue = selectedItem;
}
protected async Task SearchFilterChangedAsync(string filter)
{
lookupItems = await GetLookupItemsAsync(filter);
}
}
}

13
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor

@ -0,0 +1,13 @@
@typeparam TEntity
@typeparam TResourceType
@using Abp.Localization
<Field>
<FieldLabel>@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)</FieldLabel>
<Select @bind-SelectedValue="@SelectedValue" >
@foreach (var item in SelectItems)
{
<SelectItem Value="@item.Value">@item.Text</SelectItem>
}
</Select>
</Field>

61
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs

@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using Volo.Abp.Data;
using Volo.Abp.Localization;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public partial class SelectExtensionProperty<TEntity, TResourceType> : ComponentBase
where TEntity : IHasExtraProperties
{
protected List<SelectItem<int>> SelectItems = new ();
[Inject] public IStringLocalizerFactory StringLocalizerFactory { get; set; }
[Parameter] public TEntity Entity { get; set; }
[Parameter] public ObjectExtensionPropertyInfo PropertyInfo { get; set; }
public int SelectedValue
{
get { return Entity.GetProperty<int>(PropertyInfo.Name); }
set { Entity.SetProperty(PropertyInfo.Name, value, false); }
}
protected virtual List<SelectItem<int>> GetSelectItemsFromEnum()
{
var selectItems = new List<SelectItem<int>>();
foreach (var enumValue in PropertyInfo.Type.GetEnumValues())
{
selectItems.Add( new SelectItem<int>
{
Value = (int) enumValue,
Text = EnumHelper.GetLocalizedMemberName(PropertyInfo.Type, enumValue, StringLocalizerFactory)
});
}
return selectItems;
}
protected override void OnParametersSet()
{
SelectItems = GetSelectItemsFromEnum();
StateHasChanged();
if (!Entity.HasProperty(PropertyInfo.Name))
{
SelectedValue = (int)PropertyInfo.Type.GetEnumValues().GetValue(0);
}
}
}
public class SelectItem<TValue>
{
public string Text { get; set; }
public TValue Value { get; set; }
}
}

14
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor

@ -0,0 +1,14 @@
@typeparam TEntity
@typeparam TResourceType
@using Volo.Abp.BlazoriseUI
@using Volo.Abp.Localization
@if (PropertyInfo != null && Entity != null)
{
<Field>
<FieldLabel>@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)</FieldLabel>
<TextEdit @bind-Text="@Value" Role="@PropertyInfo.GetTextRole()" InputMode="@PropertyInfo.GetTextInputMode()">
</TextEdit>
</Field>
}

33
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public partial class TextExtensionProperty<TEntity, TResourceType> : ComponentBase
where TEntity : IHasExtraProperties
{
[Inject]
public IStringLocalizerFactory StringLocalizerFactory { get; set; }
[Parameter]
public TEntity Entity { get; set; }
[Parameter]
public ObjectExtensionPropertyInfo PropertyInfo { get; set; }
protected string Value
{
get
{
return PropertyInfo.GetTextInputValueOrNull(Entity.GetProperty(PropertyInfo.Name));
}
set
{
Entity.SetProperty(PropertyInfo.Name, value, validate: false);
}
}
}
}

13
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor

@ -0,0 +1,13 @@
@typeparam TEntity
@typeparam TResourceType
@using Volo.Abp.BlazoriseUI
@using Volo.Abp.Localization
@if (PropertyInfo != null && Entity != null)
{
<Field>
<FieldLabel>@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)</FieldLabel>-->
<TimeEdit TValue="TimeSpan?" @bind-Time="@Value">
</TimeEdit>
</Field>
}

37
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs

@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending
{
public partial class TimeExtensionProperty<TEntity, TResourceType> : ComponentBase
where TEntity : IHasExtraProperties
{
[Inject]
public IStringLocalizerFactory StringLocalizerFactory { get; set; }
[Parameter]
public TEntity Entity { get; set; }
[Parameter]
public ObjectExtensionPropertyInfo PropertyInfo { get; set; }
protected TimeSpan? Value
{
get
{
return PropertyInfo.GetInputValueOrDefault<TimeSpan?>(Entity.GetProperty(PropertyInfo.Name));
}
set
{
Entity.SetProperty(PropertyInfo.Name, value, false);
}
}
}
}

29
framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs

@ -1,29 +0,0 @@
using System.Collections.Generic;
using Blazorise;
using Microsoft.AspNetCore.Components;
namespace Volo.Abp.BlazoriseUI.Components
{
public partial class PageHeader : ComponentBase
{
[Parameter]
public string Title { get; set; }
[Parameter]
public bool BreadcrumbShowHome { get; set; } = true;
[Parameter]
public bool BreadcrumbShowCurrent { get; set; } = true;
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public List<BreadcrumbItem> BreadcrumbItems { get; set; }
public PageHeader()
{
BreadcrumbItems = new List<BreadcrumbItem>();
}
}
}

7
framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor

@ -0,0 +1,7 @@
<Button Color="@Color" Clicked="@Clicked" Disabled="@Disabled">
@if (Icon != null)
{
<Icon Name="IconName.Add" Class="mr-1"></Icon>
}
@Text
</Button>

25
framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor.cs

@ -0,0 +1,25 @@
using Blazorise;
using Microsoft.AspNetCore.Components;
using System;
using System.Threading.Tasks;
namespace Volo.Abp.BlazoriseUI.Components
{
public partial class ToolbarButton : ComponentBase
{
[Parameter]
public Color Color { get; set; }
[Parameter]
public object Icon { get; set; }
[Parameter]
public string Text { get; set; }
[Parameter]
public Func<Task> Clicked { get; set; }
[Parameter]
public bool Disabled { get; set; }
}
}

40
framework/src/Volo.Abp.BlazoriseUI/ObjectExtensionPropertyInfoBlazorExtensions.cs

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Volo.Abp.ObjectExtending
{
public static class ObjectExtensionPropertyInfoBlazorExtensions
{
private static readonly Type[] DateTimeTypes =
{
typeof(DateTime),
typeof(DateTime?),
typeof(DateTimeOffset),
typeof(DateTimeOffset?)
};
public static bool IsDate(this IBasicObjectExtensionPropertyInfo property)
{
return DateTimeTypes.Contains(property.Type) &&
property.GetDataTypeOrNull() == DataType.Date;
}
public static bool IsDateTime(this IBasicObjectExtensionPropertyInfo property)
{
return DateTimeTypes.Contains(property.Type) &&
!property.IsDate();
}
public static DataType? GetDataTypeOrNull(this IBasicObjectExtensionPropertyInfo property)
{
return property
.Attributes
.OfType<DataTypeAttribute>()
.FirstOrDefault()?.DataType;
}
}
}

11
framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.Web\Volo.Abp.AspNetCore.Components.Web.csproj" />
@ -17,6 +17,7 @@
<PackageReference Include="Blazorise" Version="0.9.3" />
<PackageReference Include="Blazorise.DataGrid" Version="0.9.3" />
<PackageReference Include="Blazorise.Snackbar" Version="0.9.3" />
<PackageReference Include="Blazorise.Components" Version="0.9.3" />
</ItemGroup>
</Project>

1
framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj

@ -30,5 +30,4 @@
<ProjectReference Include="..\Volo.Abp.IdentityModel\Volo.Abp.IdentityModel.csproj" />
<ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" />
</ItemGroup>
</Project>

16
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyLookupConfiguration.cs

@ -5,9 +5,25 @@ namespace Volo.Abp.ObjectExtending.Modularity
public class ExtensionPropertyLookupConfiguration
{
public string Url { get; set; }
/// <summary>
/// Default value: "items".
/// </summary>
public string ResultListPropertyName { get; set; } = "items";
/// <summary>
/// Default value: "text".
/// </summary>
public string DisplayPropertyName { get; set; } = "text";
/// <summary>
/// Default value: "id".
/// </summary>
public string ValuePropertyName { get; set; } = "id";
/// <summary>
/// Default value: "filter".
/// </summary>
public string FilterParamName { get; set; } = "filter";
}
}

27
modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityBlazorModule.cs

@ -3,7 +3,10 @@ using Volo.Abp.AspNetCore.Components.Web.Theming.Routing;
using Volo.Abp.AutoMapper;
using Volo.Abp.BlazoriseUI;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.PermissionManagement.Blazor;
using Volo.Abp.Threading;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.Identity.Blazor
@ -16,6 +19,8 @@ namespace Volo.Abp.Identity.Blazor
)]
public class AbpIdentityBlazorModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpIdentityBlazorModule>();
@ -35,5 +40,27 @@ namespace Volo.Abp.Identity.Blazor
options.AdditionalAssemblies.Add(typeof(AbpIdentityBlazorModule).Assembly);
});
}
public override void PostConfigureServices(ServiceConfigurationContext context)
{
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.Role,
createFormTypes: new[] { typeof(IdentityRoleCreateDto) },
editFormTypes: new[] { typeof(IdentityRoleUpdateDto) }
);
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.User,
createFormTypes: new[] { typeof(IdentityUserCreateDto) },
editFormTypes: new[] { typeof(IdentityUserUpdateDto) }
);
});
}
}
}

93
modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor

@ -1,74 +1,35 @@
@page "/identity/roles"
@attribute [Authorize( IdentityPermissions.Roles.Default )]
@attribute [Authorize(IdentityPermissions.Roles.Default)]
@using Volo.Abp.Identity
@using Microsoft.AspNetCore.Authorization
@using Volo.Abp.PermissionManagement.Blazor.Components
@using Volo.Abp.Identity.Localization
@using Volo.Abp.AspNetCore.Components.Web
@using Volo.Abp.AspNetCore.Components.Web.Theming
@using Volo.Abp.BlazoriseUI.Components.ObjectExtending
@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout
@inject AbpBlazorMessageLocalizerHelper<IdentityResource> LH
@inherits AbpCrudPageBase<IIdentityRoleAppService, IdentityRoleDto, Guid, GetIdentityRolesInput, IdentityRoleCreateDto, IdentityRoleUpdateDto>
<Card>
<CardHeader>
@* ************************* PAGE HEADER ************************* *@
<Row Class="justify-content-between">
<Column ColumnSize="ColumnSize.IsAuto">
<Heading Size="HeadingSize.Is1">@L["Roles"]</Heading>
</Column>
<Column ColumnSize="ColumnSize.IsAuto">
@if ( HasCreatePermission )
{
<Button Color="Color.Primary" Clicked="OpenCreateModalAsync">
<Icon Margin="Margin.Is1.FromRight" Name="IconName.Add"></Icon>@L["NewRole"]
</Button>
}
</Column>
</Row>
<PageHeader Title="@L["Roles"]"
BreadcrumbItems="@BreadcrumbItems"
Toolbar="@Toolbar">
</PageHeader>
</CardHeader>
<CardBody>
@* ************************* DATA GRID ************************* *@
<DataGrid TItem="IdentityRoleDto"
Data="Entities"
ReadData="OnDataGridReadAsync"
TotalItems="TotalCount"
ShowPager="true"
PageSize="PageSize">
<DataGridColumns>
<DataGridEntityActionsColumn TItem="IdentityRoleDto" @ref="@EntityActionsColumn">
<DisplayTemplate>
<EntityActions TItem="IdentityRoleDto" EntityActionsColumn="@EntityActionsColumn">
<EntityAction TItem="IdentityRoleDto"
RequiredPolicy="@UpdatePolicyName"
Clicked="() => OpenEditModalAsync(context)"
Text="@L["Edit"]"></EntityAction>
<EntityAction TItem="IdentityRoleDto"
RequiredPolicy="@ManagePermissionsPolicyName"
Clicked="() => PermissionManagementModal.OpenAsync(PermissionProviderName, context.Name, context.Name)"
Text="@L["Permissions"]"></EntityAction>
<EntityAction TItem="IdentityRoleDto"
RequiredPolicy="@DeletePolicyName"
Clicked="() => DeleteEntityAsync(context)"
ConfirmationMessage="()=> GetDeleteConfirmationMessage(context)"
Text="@L["Delete"]"></EntityAction>
</EntityActions>
</DisplayTemplate>
</DataGridEntityActionsColumn>
<DataGridColumn TItem="IdentityRoleDto" Field="@nameof(IdentityRoleDto.Name)" Caption="@L["RoleName"].Value">
<DisplayTemplate>
@(context.Name)
@if (context.IsDefault)
{
<Badge Color="Color.Primary" Margin="Margin.Is1.FromLeft">@L["DisplayName:IsDefault"]</Badge>
}
@if (context.IsPublic)
{
<Badge Color="Color.Light" Margin="Margin.Is1.FromLeft">@L["DisplayName:IsPublic"]</Badge>
}
</DisplayTemplate>
</DataGridColumn>
</DataGridColumns>
</DataGrid>
<AbpExtensibleDataGrid TItem="IdentityRoleDto"
Data="@Entities"
ReadData="@OnDataGridReadAsync"
TotalItems="@TotalCount"
ShowPager="true"
PageSize="@PageSize"
CurrentPage="@CurrentPage"
Columns="@RoleManagementTableColumns">
</AbpExtensibleDataGrid>
</CardBody>
</Card>
@ -80,7 +41,7 @@
<Form>
<ModalHeader>
<ModalTitle>@L["NewRole"]</ModalTitle>
<CloseButton Clicked="CloseCreateModalAsync" />
<CloseButton Clicked="CloseCreateModalAsync"/>
</ModalHeader>
<ModalBody>
<Validations @ref="@CreateValidationsRef" Model="@NewEntity" ValidateOnLoad="false">
@ -89,10 +50,11 @@
<FieldLabel>@L["DisplayName:RoleName"]</FieldLabel>
<TextEdit @bind-Text="@NewEntity.Name">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
<ExtensionProperties TEntityType="IdentityRoleCreateDto" TResourceType="IdentityResource" Entity="@NewEntity" LH="@LH"/>
</Validation>
<Field>
<Check TValue="bool" @bind-Checked="@NewEntity.IsDefault">@L["DisplayName:IsDefault"]</Check>
@ -102,7 +64,7 @@
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="CloseCreateModalAsync">@L["Cancel"]</Button>
<SubmitButton Clicked="@CreateEntityAsync" />
<SubmitButton Clicked="@CreateEntityAsync"/>
</ModalFooter>
</Form>
</ModalContent>
@ -116,20 +78,21 @@
<Form>
<ModalHeader>
<ModalTitle>@L["Edit"]</ModalTitle>
<CloseButton Clicked="CloseEditModalAsync" />
<CloseButton Clicked="CloseEditModalAsync"/>
</ModalHeader>
<ModalBody>
<Validations @ref="@EditValidationsRef" Model="@EditingEntity" ValidateOnLoad="false">
<input type="hidden" name="ConcurrencyStamp" @bind-value="EditingEntity.ConcurrencyStamp" />
<input type="hidden" name="ConcurrencyStamp" @bind-value="EditingEntity.ConcurrencyStamp"/>
<Validation MessageLocalizer="@LH.Localize">
<Field>
<FieldLabel>@L["DisplayName:RoleName"]</FieldLabel>
<TextEdit @bind-Text="EditingEntity.Name">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
<ExtensionProperties TEntityType="IdentityRoleUpdateDto" TResourceType="IdentityResource" Entity="@EditingEntity" LH="@LH"/>
</Validation>
<Field>
<Check TValue="bool" @bind-Checked="@EditingEntity.IsDefault">@L["DisplayName:IsDefault"]</Check>
@ -139,7 +102,7 @@
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="CloseEditModalAsync">@L["Cancel"]</Button>
<SubmitButton Clicked="@UpdateEntityAsync" />
<SubmitButton Clicked="@UpdateEntityAsync"/>
</ModalFooter>
</Form>
</ModalContent>
@ -148,5 +111,5 @@
@if (HasManagePermissionsPermission)
{
<PermissionManagementModal @ref="PermissionManagementModal" />
}
<PermissionManagementModal @ref="PermissionManagementModal"/>
}

90
modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor.cs

@ -1,7 +1,16 @@
using System.Threading.Tasks;
using Blazorise;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns;
using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
using Volo.Abp.Identity.Localization;
using Volo.Abp.PermissionManagement.Blazor.Components;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Data;
namespace Volo.Abp.Identity.Blazor.Pages.Identity
{
@ -10,11 +19,15 @@ namespace Volo.Abp.Identity.Blazor.Pages.Identity
protected const string PermissionProviderName = "R";
protected PermissionManagementModal PermissionManagementModal;
protected string ManagePermissionsPolicyName;
protected bool HasManagePermissionsPermission { get; set; }
protected PageToolbar Toolbar { get; } = new();
protected List<TableColumn> RoleManagementTableColumns => TableColumns.Get<RoleManagement>();
public RoleManagement()
{
ObjectMapperContext = typeof(AbpIdentityBlazorModule);
@ -26,16 +39,85 @@ namespace Volo.Abp.Identity.Blazor.Pages.Identity
ManagePermissionsPolicyName = IdentityPermissions.Roles.ManagePermissions;
}
protected override ValueTask SetEntityActionsAsync()
{
EntityActions
.Get<RoleManagement>()
.AddRange(new EntityAction[]
{
new EntityAction
{
Text = L["Edit"],
Visible = (data) => HasUpdatePermission,
Clicked = async (data) => { await OpenEditModalAsync(data.As<IdentityRoleDto>()); }
},
new EntityAction
{
Text = L["Permissions"],
Visible = (data) => HasManagePermissionsPermission,
Clicked = async (data) =>
{
await PermissionManagementModal.OpenAsync(PermissionProviderName,
data.As<IdentityRoleDto>().Name);
}
},
new EntityAction
{
Text = L["Delete"],
Visible = (data) => HasDeletePermission,
Clicked = async (data) => await DeleteEntityAsync(data.As<IdentityRoleDto>()),
ConfirmationMessage = (data) => GetDeleteConfirmationMessage(data.As<IdentityRoleDto>())
}
});
return base.SetEntityActionsAsync();
}
protected override ValueTask SetTableColumnsAsync()
{
RoleManagementTableColumns
.AddRange(new TableColumn[]
{
new TableColumn
{
Title = L["Actions"],
Actions = EntityActions.Get<RoleManagement>()
},
new TableColumn
{
Title = L["RoleName"],
Data = nameof(IdentityRoleDto.Name),
Component = typeof(RoleNameComponent)
},
});
RoleManagementTableColumns.AddRange(GetExtensionTableColumns(IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.Role));
return base.SetTableColumnsAsync();
}
protected override async Task SetPermissionsAsync()
{
await base.SetPermissionsAsync();
HasManagePermissionsPermission = await AuthorizationService.IsGrantedAsync(IdentityPermissions.Roles.ManagePermissions);
HasManagePermissionsPermission =
await AuthorizationService.IsGrantedAsync(IdentityPermissions.Roles.ManagePermissions);
}
protected override string GetDeleteConfirmationMessage(IdentityRoleDto entity)
{
return string.Format(L["RoleDeletionConfirmationMessage"], entity.Name);
}
protected override ValueTask SetToolbarItemsAsync()
{
Toolbar.AddButton(L["NewRole"],
OpenCreateModalAsync,
IconName.Add,
requiredPolicyName: CreatePolicyName);
return base.SetToolbarItemsAsync();
}
}
}
}

16
modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor

@ -0,0 +1,16 @@
@using System;
@using Volo.Abp.Identity
@using Microsoft.Extensions.Localization
@using Volo.Abp.Identity.Localization
@inject IStringLocalizer<IdentityResource> L
@(Data.As<IdentityRoleDto>().Name)
@if (Data.As<IdentityRoleDto>().IsDefault)
{
<Badge Color="Color.Primary" Margin="Margin.Is1.FromLeft">@L["DisplayName:IsDefault"]</Badge>
}
@if (Data.As<IdentityRoleDto>().IsPublic)
{
<Badge Color="Color.Light" Margin="Margin.Is1.FromLeft">@L["DisplayName:IsPublic"]</Badge>
}

9
modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor.cs

@ -0,0 +1,9 @@
using Microsoft.AspNetCore.Components;
namespace Volo.Abp.Identity.Blazor.Pages.Identity
{
public partial class RoleNameComponent : ComponentBase
{
[Parameter] public object Data { get; set; }
}
}

115
modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor

@ -1,8 +1,10 @@
@page "/identity/users"
@attribute [Authorize( IdentityPermissions.Users.Default )]
@attribute [Authorize(IdentityPermissions.Users.Default)]
@using Microsoft.AspNetCore.Authorization
@using Volo.Abp.PermissionManagement.Blazor.Components
@using Volo.Abp.BlazoriseUI.Components.ObjectExtending
@using Volo.Abp.Identity.Localization
@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout
@inject AbpBlazorMessageLocalizerHelper<IdentityResource> LH
@inherits AbpCrudPageBase<IIdentityUserAppService, IdentityUserDto, Guid, GetIdentityUsersInput, IdentityUserCreateDto, IdentityUserUpdateDto>
@ -10,65 +12,22 @@
<Card>
<CardHeader>
@* ************************* PAGE HEADER ************************* *@
<Row Class="justify-content-between">
<Column ColumnSize="ColumnSize.IsAuto">
<h1>@L["Users"]</h1>
</Column>
<Column ColumnSize="ColumnSize.IsAuto">
@if ( HasCreatePermission )
{
<Button Color="Color.Primary" Clicked="OpenCreateModalAsync">
<Icon Margin="Margin.Is1.FromRight" Name="IconName.Add"></Icon>@L["NewUser"]
</Button>
}
</Column>
</Row>
<PageHeader Title="@L["Users"]"
BreadcrumbItems="@BreadcrumbItems"
Toolbar="@Toolbar">
</PageHeader>
</CardHeader>
<CardBody>
@* ************************* DATA GRID ************************* *@
<DataGrid TItem="IdentityUserDto"
Data="Entities"
ReadData="OnDataGridReadAsync"
TotalItems="TotalCount"
ShowPager="true"
PageSize="PageSize">
<DataGridColumns>
<DataGridEntityActionsColumn TItem="IdentityUserDto" @ref="@EntityActionsColumn">
<DisplayTemplate>
<EntityActions TItem="IdentityUserDto" EntityActionsColumn="@EntityActionsColumn">
<EntityAction TItem="IdentityUserDto"
RequiredPolicy="@UpdatePolicyName"
Clicked="() => OpenEditModalAsync(context)"
Text="@L["Edit"]" />
<EntityAction TItem="IdentityUserDto"
RequiredPolicy="@ManagePermissionsPolicyName"
Clicked="() => PermissionManagementModal.OpenAsync(PermissionProviderName, context.Id.ToString(), context.Name)"
Text="@L["Permissions"]" />
<EntityAction TItem="IdentityUserDto"
RequiredPolicy="@DeletePolicyName"
Clicked="() => DeleteEntityAsync(context)"
ConfirmationMessage="()=>GetDeleteConfirmationMessage(context)"
Text="@L["Delete"]" />
</EntityActions>
</DisplayTemplate>
</DataGridEntityActionsColumn>
<DataGridColumn TItem="IdentityUserDto" Field="@nameof(IdentityUserDto.UserName)" Caption="@L["UserName"].Value">
<DisplayTemplate>
@(context.As<IdentityUserDto>().UserName)
</DisplayTemplate>
</DataGridColumn>
<DataGridColumn TItem="IdentityUserDto" Field="@nameof(IdentityUserDto.Email)" Caption="@L["Email"].Value">
<DisplayTemplate>
@(context.As<IdentityUserDto>().Email)
</DisplayTemplate>
</DataGridColumn>
<DataGridColumn TItem="IdentityUserDto" Field="@nameof(IdentityUserDto.PhoneNumber)" Caption="@L["PhoneNumber"].Value">
<DisplayTemplate>
@(context.As<IdentityUserDto>().PhoneNumber)
</DisplayTemplate>
</DataGridColumn>
</DataGridColumns>
</DataGrid>
<AbpExtensibleDataGrid TItem="IdentityUserDto"
Data="Entities"
ReadData="OnDataGridReadAsync"
TotalItems="TotalCount"
ShowPager="true"
PageSize="PageSize"
CurrentPage="@CurrentPage"
Columns="@UserManagementTableColumns">
</AbpExtensibleDataGrid>
</CardBody>
</Card>
@ -80,7 +39,7 @@
<Form>
<ModalHeader>
<ModalTitle>@L["NewUser"]</ModalTitle>
<CloseButton Clicked="CloseCreateModalAsync" />
<CloseButton Clicked="CloseCreateModalAsync"/>
</ModalHeader>
<ModalBody>
<Validations @ref="@CreateValidationsRef" Model="@NewEntity" ValidateOnLoad="false">
@ -96,7 +55,7 @@
<FieldLabel>@L["DisplayName:UserName"]</FieldLabel>
<TextEdit @bind-Text="NewEntity.UserName">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -106,7 +65,7 @@
<FieldLabel>@L["DisplayName:Name"]</FieldLabel>
<TextEdit @bind-Text="NewEntity.Name">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -116,7 +75,7 @@
<FieldLabel>@L["DisplayName:Surname"]</FieldLabel>
<TextEdit @bind-Text="NewEntity.Surname">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -126,7 +85,7 @@
<FieldLabel>@L["DisplayName:Password"]</FieldLabel>
<TextEdit Role="TextRole.Password" @bind-Text="NewEntity.Password">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -136,7 +95,7 @@
<FieldLabel>@L["DisplayName:Email"]</FieldLabel>
<TextEdit @bind-Text="NewEntity.Email">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -146,7 +105,7 @@
<FieldLabel>@L["DisplayName:PhoneNumber"]</FieldLabel>
<TextEdit @bind-Text="NewEntity.PhoneNumber">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -154,6 +113,7 @@
<Field>
<Check TValue="bool" @bind-Checked="@NewEntity.LockoutEnabled">@L["DisplayName:LockoutEnabled"]</Check>
</Field>
<ExtensionProperties TEntityType="IdentityUserCreateDto" TResourceType="IdentityResource" Entity="@NewEntity" LH="@LH"/>
</TabPanel>
<TabPanel Name="Roles">
@if ( NewUserRoles != null )
@ -161,7 +121,7 @@
@foreach ( var role in NewUserRoles )
{
<Field>
<input type="hidden" @bind-value="@role.Name" />
<input type="hidden" @bind-value="@role.Name"/>
<Check TValue="bool" @bind-Checked="@role.IsAssigned">@role.Name</Check>
</Field>
}
@ -173,7 +133,7 @@
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="CloseCreateModalAsync">@L["Cancel"]</Button>
<SubmitButton Clicked="@CreateEntityAsync" />
<SubmitButton Clicked="@CreateEntityAsync"/>
</ModalFooter>
</Form>
</ModalContent>
@ -188,11 +148,11 @@
<Form>
<ModalHeader>
<ModalTitle>@L["Edit"]</ModalTitle>
<CloseButton Clicked="CloseEditModalAsync" />
<CloseButton Clicked="CloseEditModalAsync"/>
</ModalHeader>
<ModalBody>
<Validations @ref="@EditValidationsRef" Model="@EditingEntity" ValidateOnLoad="false">
<input type="hidden" name="ConcurrencyStamp" @bind-value="EditingEntity.ConcurrencyStamp" />
<input type="hidden" name="ConcurrencyStamp" @bind-value="EditingEntity.ConcurrencyStamp"/>
<Tabs @bind-SelectedTab="@EditModalSelectedTab">
<Items>
@ -206,7 +166,7 @@
<FieldLabel>@L["DisplayName:UserName"]</FieldLabel>
<TextEdit @bind-Text="EditingEntity.UserName">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -216,7 +176,7 @@
<FieldLabel>@L["DisplayName:Name"]</FieldLabel>
<TextEdit @bind-Text="EditingEntity.Name">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -226,7 +186,7 @@
<FieldLabel>@L["DisplayName:Surname"]</FieldLabel>
<TextEdit @bind-Text="EditingEntity.Surname">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -236,7 +196,7 @@
<FieldLabel>@L["DisplayName:Password"]</FieldLabel>
<TextEdit Role="TextRole.Password" @bind-Text="EditingEntity.Password">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -246,7 +206,7 @@
<FieldLabel>@L["DisplayName:Email"]</FieldLabel>
<TextEdit @bind-Text="EditingEntity.Email">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -256,7 +216,7 @@
<FieldLabel>@L["DisplayName:PhoneNumber"]</FieldLabel>
<TextEdit @bind-Text="EditingEntity.PhoneNumber">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -264,6 +224,7 @@
<Field>
<Check TValue="bool" @bind-Checked="EditingEntity.LockoutEnabled">@L["DisplayName:LockoutEnabled"]</Check>
</Field>
<ExtensionProperties TEntityType="IdentityUserUpdateDto" TResourceType="IdentityResource" Entity="@EditingEntity" LH="@LH"/>
</TabPanel>
<TabPanel Name="Roles">
@if ( EditUserRoles != null )
@ -271,7 +232,7 @@
@foreach ( var role in EditUserRoles )
{
<Field>
<input type="hidden" @bind-value="@role.Name" />
<input type="hidden" @bind-value="@role.Name"/>
<Check TValue="bool" @bind-Checked="@role.IsAssigned">@role.Name</Check>
</Field>
}
@ -283,7 +244,7 @@
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="CloseEditModalAsync">@L["Cancel"]</Button>
<SubmitButton Clicked="@UpdateEntityAsync" />
<SubmitButton Clicked="@UpdateEntityAsync"/>
</ModalFooter>
</Form>
</ModalContent>
@ -292,5 +253,5 @@
@if ( HasManagePermissionsPermission )
{
<PermissionManagementModal @ref="PermissionManagementModal" />
<PermissionManagementModal @ref="PermissionManagementModal"/>
}

92
modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor.cs

@ -4,7 +4,11 @@ using System.Linq;
using System.Threading.Tasks;
using Blazorise;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns;
using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
using Volo.Abp.Identity.Localization;
using Volo.Abp.ObjectExtending;
using Volo.Abp.PermissionManagement.Blazor.Components;
namespace Volo.Abp.Identity.Blazor.Pages.Identity
@ -24,13 +28,17 @@ namespace Volo.Abp.Identity.Blazor.Pages.Identity
protected AssignedRoleViewModel[] EditUserRoles;
protected string ManagePermissionsPolicyName;
protected bool HasManagePermissionsPermission { get; set; }
protected string CreateModalSelectedTab = DefaultSelectedTab;
protected string EditModalSelectedTab = DefaultSelectedTab;
protected PageToolbar Toolbar { get; } = new();
private List<TableColumn> UserManagementTableColumns => TableColumns.Get<UserManagement>();
public UserManagement()
{
ObjectMapperContext = typeof(AbpIdentityBlazorModule);
@ -55,12 +63,13 @@ namespace Volo.Abp.Identity.Blazor.Pages.Identity
await HandleErrorAsync(ex);
}
}
protected override async Task SetPermissionsAsync()
{
await base.SetPermissionsAsync();
HasManagePermissionsPermission = await AuthorizationService.IsGrantedAsync(IdentityPermissions.Users.ManagePermissions);
HasManagePermissionsPermission =
await AuthorizationService.IsGrantedAsync(IdentityPermissions.Users.ManagePermissions);
}
protected override Task OpenCreateModalAsync()
@ -118,6 +127,81 @@ namespace Volo.Abp.Identity.Blazor.Pages.Identity
{
return string.Format(L["UserDeletionConfirmationMessage"], entity.UserName);
}
protected override ValueTask SetEntityActionsAsync()
{
EntityActions
.Get<UserManagement>()
.AddRange(new EntityAction[]
{
new EntityAction
{
Text = L["Edit"],
Visible = (data) => HasUpdatePermission,
Clicked = async (data) => await OpenEditModalAsync(data.As<IdentityUserDto>())
},
new EntityAction
{
Text = L["Permissions"],
Visible = (data) => HasManagePermissionsPermission,
Clicked = async (data) =>
{
await PermissionManagementModal.OpenAsync(PermissionProviderName,
data.As<IdentityUserDto>().Id.ToString());
}
},
new EntityAction
{
Text = L["Delete"],
Visible = (data) => HasDeletePermission,
Clicked = async (data) => await DeleteEntityAsync(data.As<IdentityUserDto>()),
ConfirmationMessage = (data) => GetDeleteConfirmationMessage(data.As<IdentityUserDto>())
}
});
return base.SetEntityActionsAsync();
}
protected override ValueTask SetTableColumnsAsync()
{
UserManagementTableColumns
.AddRange(new TableColumn[]
{
new TableColumn
{
Title = L["Actions"],
Actions = EntityActions.Get<UserManagement>()
},
new TableColumn
{
Title = L["UserName"],
Data = nameof(IdentityUserDto.UserName),
},
new TableColumn
{
Title = L["Email"],
Data = nameof(IdentityUserDto.Email),
},
new TableColumn
{
Title = L["PhoneNumber"],
Data = nameof(IdentityUserDto.PhoneNumber),
}
});
UserManagementTableColumns.AddRange(GetExtensionTableColumns(IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.User));
return base.SetEntityActionsAsync();
}
protected override ValueTask SetToolbarItemsAsync()
{
Toolbar.AddButton(L["NewUser"], OpenCreateModalAsync,
IconName.Add,
requiredPolicyName: CreatePolicyName);
return base.SetToolbarItemsAsync();
}
}
public class AssignedRoleViewModel
@ -126,4 +210,4 @@ namespace Volo.Abp.Identity.Blazor.Pages.Identity
public bool IsAssigned { get; set; }
}
}
}

19
modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/AbpTenantManagementBlazorModule.cs

@ -3,7 +3,10 @@ using Volo.Abp.AspNetCore.Components.Web.Theming.Routing;
using Volo.Abp.AutoMapper;
using Volo.Abp.FeatureManagement.Blazor;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.TenantManagement.Blazor.Navigation;
using Volo.Abp.Threading;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.TenantManagement.Blazor
@ -15,6 +18,8 @@ namespace Volo.Abp.TenantManagement.Blazor
)]
public class AbpTenantManagementBlazorModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new();
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpTenantManagementBlazorModule>();
@ -34,5 +39,19 @@ namespace Volo.Abp.TenantManagement.Blazor
options.AdditionalAssemblies.Add(typeof(AbpTenantManagementBlazorModule).Assembly);
});
}
public override void PostConfigureServices(ServiceConfigurationContext context)
{
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant,
createFormTypes: new[] { typeof(TenantCreateDto) },
editFormTypes: new[] { typeof(TenantUpdateDto) }
);
});
}
}
}

85
modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor

@ -1,9 +1,11 @@
@page "/tenant-management/tenants"
@attribute [Authorize( TenantManagementPermissions.Tenants.Default )]
@attribute [Authorize(TenantManagementPermissions.Tenants.Default)]
@using Microsoft.AspNetCore.Authorization
@using Volo.Abp.FeatureManagement.Blazor.Components
@using Microsoft.AspNetCore.Components.Forms
@using Volo.Abp.TenantManagement.Localization
@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout
@using Volo.Abp.BlazoriseUI.Components.ObjectExtending
@using Volo.Abp.AspNetCore.Components.Web
@inject AbpBlazorMessageLocalizerHelper<AbpTenantManagementResource> LH
@inherits AbpCrudPageBase<ITenantAppService, TenantDto, Guid, GetTenantsInput, TenantCreateDto, TenantUpdateDto>
@ -11,55 +13,22 @@
<Card>
<CardHeader>
@* ************************* PAGE HEADER ************************* *@
<Row Class="justify-content-between">
<Column ColumnSize="ColumnSize.IsAuto">
<Heading Size="HeadingSize.Is1">@L["Tenants"]</Heading>
</Column>
<Column ColumnSize="ColumnSize.IsAuto">
@if ( HasCreatePermission )
{
<Button Color="Color.Primary" Clicked="OpenCreateModalAsync">
<Icon Margin="Margin.Is1.FromRight" Name="IconName.Add"></Icon>@L["NewTenant"]
</Button>
}
</Column>
</Row>
<PageHeader Title="@L["Tenants"]"
BreadcrumbItems="@BreadcrumbItems"
Toolbar="@Toolbar">
</PageHeader>
</CardHeader>
<CardBody>
@* ************************* DATA GRID ************************* *@
<DataGrid TItem="TenantDto"
Data="Entities"
ReadData="OnDataGridReadAsync"
TotalItems="TotalCount"
ShowPager="true"
PageSize="PageSize">
<DataGridColumns>
<DataGridEntityActionsColumn TItem="TenantDto" @ref="@EntityActionsColumn">
<DisplayTemplate>
<EntityActions TItem="TenantDto" EntityActionsColumn="@EntityActionsColumn">
<EntityAction TItem="TenantDto"
RequiredPolicy="@UpdatePolicyName"
Clicked="() => OpenEditModalAsync(context)"
Text="@L["Edit"]"></EntityAction>
<EntityAction TItem="TenantDto"
RequiredPolicy="@ManageFeaturesPolicyName"
Clicked="() => FeatureManagementModal.OpenAsync(FeatureProviderName, context.Id.ToString())"
Text="@L["Features"]"></EntityAction>
<EntityAction TItem="TenantDto"
RequiredPolicy="@DeletePolicyName"
Clicked="() => DeleteEntityAsync(context)"
ConfirmationMessage="()=>GetDeleteConfirmationMessage(context)"
Text="@L["Delete"]"></EntityAction>
</EntityActions>
</DisplayTemplate>
</DataGridEntityActionsColumn>
<DataGridColumn TItem="TenantDto" Field="@nameof(TenantDto.Name)" Caption="@L["TenantName"].Value">
<DisplayTemplate>
@(context.Name)
</DisplayTemplate>
</DataGridColumn>
</DataGridColumns>
</DataGrid>
<AbpExtensibleDataGrid TItem="TenantDto"
Data="@Entities"
ReadData="@OnDataGridReadAsync"
TotalItems="@TotalCount"
ShowPager="true"
PageSize="@PageSize"
CurrentPage="@CurrentPage"
Columns="@TenantManagementTableColumns">
</AbpExtensibleDataGrid>
</CardBody>
</Card>
@ -71,7 +40,7 @@
<Form>
<ModalHeader>
<ModalTitle>@L["NewTenant"]</ModalTitle>
<CloseButton Clicked="CloseCreateModalAsync" />
<CloseButton Clicked="CloseCreateModalAsync"/>
</ModalHeader>
<ModalBody>
<Validations @ref="@CreateValidationsRef" Model="@NewEntity" ValidateOnLoad="false">
@ -80,7 +49,7 @@
<FieldLabel>@L["TenantName"]</FieldLabel>
<TextEdit @bind-Text="@NewEntity.Name">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -90,7 +59,7 @@
<FieldLabel>@L["DisplayName:AdminEmailAddress"]</FieldLabel>
<TextEdit Role="@TextRole.Email" @bind-Text="@NewEntity.AdminEmailAddress">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
@ -100,16 +69,17 @@
<FieldLabel>@L["DisplayName:AdminPassword"]</FieldLabel>
<TextEdit Role="@TextRole.Password" @bind-Text="@NewEntity.AdminPassword">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
</Validation>
<ExtensionProperties TEntityType="TenantCreateDto" TResourceType="AbpTenantManagementResource" Entity="@NewEntity" LH="@LH"/>
</Validations>
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="CloseCreateModalAsync">@L["Cancel"]</Button>
<SubmitButton Clicked="@CreateEntityAsync" />
<SubmitButton Clicked="@CreateEntityAsync"/>
</ModalFooter>
</Form>
</ModalContent>
@ -124,7 +94,7 @@
<Form>
<ModalHeader>
<ModalTitle>@L["Edit"]</ModalTitle>
<CloseButton Clicked="CloseEditModalAsync" />
<CloseButton Clicked="CloseEditModalAsync"/>
</ModalHeader>
<ModalBody>
<Validations @ref="@EditValidationsRef" Model="@EditingEntity" ValidateOnLoad="false">
@ -133,16 +103,17 @@
<FieldLabel>@L["TenantName"]</FieldLabel>
<TextEdit @bind-Text="@EditingEntity.Name">
<Feedback>
<ValidationError />
<ValidationError/>
</Feedback>
</TextEdit>
</Field>
</Validation>
</Validations>
<ExtensionProperties TEntityType="TenantUpdateDto" TResourceType="AbpTenantManagementResource" Entity="@EditingEntity" LH="@LH"/>
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="CloseEditModalAsync">@L["Cancel"]</Button>
<SubmitButton Clicked="@UpdateEntityAsync" />
<SubmitButton Clicked="@UpdateEntityAsync"/>
</ModalFooter>
</Form>
</ModalContent>
@ -151,5 +122,5 @@
@if (HasManageFeaturesPermission)
{
<FeatureManagementModal @ref="FeatureManagementModal" />
}
<FeatureManagementModal @ref="FeatureManagementModal"/>
}

85
modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs

@ -1,6 +1,15 @@
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Blazorise;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns;
using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
using Volo.Abp.BlazoriseUI;
using Volo.Abp.FeatureManagement.Blazor.Components;
using Volo.Abp.ObjectExtending;
using Volo.Abp.TenantManagement.Localization;
namespace Volo.Abp.TenantManagement.Blazor.Pages.TenantManagement
@ -14,6 +23,10 @@ namespace Volo.Abp.TenantManagement.Blazor.Pages.TenantManagement
protected FeatureManagementModal FeatureManagementModal;
protected PageToolbar Toolbar { get; } = new();
protected List<TableColumn> TenantManagementTableColumns => TableColumns.Get<TenantManagement>();
public TenantManagement()
{
LocalizationResource = typeof(AbpTenantManagementResource);
@ -37,5 +50,73 @@ namespace Volo.Abp.TenantManagement.Blazor.Pages.TenantManagement
{
return string.Format(L["TenantDeletionConfirmationMessage"], entity.Name);
}
protected override ValueTask SetToolbarItemsAsync()
{
Toolbar.AddButton(L["NewTenant"],
OpenCreateModalAsync,
IconName.Add,
requiredPolicyName: CreatePolicyName);
return base.SetToolbarItemsAsync();
}
protected override ValueTask SetEntityActionsAsync()
{
EntityActions
.Get<TenantManagement>()
.AddRange(new EntityAction[]
{
new EntityAction
{
Text = L["Edit"],
Visible = (data) => HasUpdatePermission,
Clicked = async (data) => { await OpenEditModalAsync(data.As<TenantDto>()); }
},
new EntityAction
{
Text = L["Features"],
Visible = (data) => HasManageFeaturesPermission,
Clicked = async (data) =>
{
var tenant = data.As<TenantDto>();
await FeatureManagementModal.OpenAsync(FeatureProviderName, tenant.Id.ToString());
}
},
new EntityAction
{
Text = L["Delete"],
Visible = (data) => HasDeletePermission,
Clicked = async (data) => await DeleteEntityAsync(data.As<TenantDto>()),
ConfirmationMessage = (data) => GetDeleteConfirmationMessage(data.As<TenantDto>())
}
});
return base.SetEntityActionsAsync();
}
protected override ValueTask SetTableColumnsAsync()
{
TenantManagementTableColumns
.AddRange(new TableColumn[]
{
new TableColumn
{
Title = L["Actions"],
Actions = EntityActions.Get<TenantManagement>()
},
new TableColumn
{
Title = L["TenantName"],
Data = nameof(TenantDto.Name),
},
});
TenantManagementTableColumns.AddRange(GetExtensionTableColumns(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant));
return base.SetTableColumnsAsync();
}
}
}
}

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBundleContributor.cs

@ -6,6 +6,7 @@ namespace MyCompanyName.MyProjectName.Blazor
{
public void AddScripts(BundleContext context)
{
}
public void AddStyles(BundleContext context)

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyProjectNameModuleExtensionConfigurator.cs

@ -65,7 +65,7 @@ namespace MyCompanyName.MyProjectName
});
* See the documentation for more:
* https://docs.abp.io/en/latest/Module-Entity-Extensions
* https://docs.abp.io/en/abp/latest/Module-Entity-Extensions
*/
}
}

Loading…
Cancel
Save