diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj index e84d7fa8ea..050c438d11 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj @@ -11,6 +11,8 @@ + + diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs index 2fa745d9c5..dfd3cafce2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs +++ b/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 diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs new file mode 100644 index 0000000000..b7e2de8364 --- /dev/null +++ b/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 remoteServiceOptions, + IHttpContextAccessor httpContextAccessor, + NavigationManager navigationManager) + { + HttpClientFactory = httpClientFactory; + HttpClientAuthenticator = httpClientAuthenticator; + RemoteServiceOptions = remoteServiceOptions.Value; + CurrentTenant = currentTenant; + HttpContextAccessor = httpContextAccessor; + NavigationManager = navigationManager; + } + + public async Task 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)); + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor similarity index 81% rename from framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor rename to framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor index 4a569cfe95..aec0eada09 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor @@ -1,4 +1,5 @@ - +@using Blazorise +

@Title

@@ -31,7 +32,12 @@ } - @ChildContent + @foreach (var toolbarItemRender in ToolbarItemRenders) + { + + @toolbarItemRender + + } -
\ No newline at end of file +
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs new file mode 100644 index 0000000000..365df5f713 --- /dev/null +++ b/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 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 BreadcrumbItems { get; set; } + + [Parameter] + public PageToolbar Toolbar { get; set; } + + [Parameter] + public string PageName { get; set; } + + public PageHeader() + { + BreadcrumbItems = new List(); + ToolbarItemRenders = new List(); + } + + 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(); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs new file mode 100644 index 0000000000..dd04c0a1ff --- /dev/null +++ b/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); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs new file mode 100644 index 0000000000..507fa8070b --- /dev/null +++ b/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 GetItemsAsync(PageToolbar toolbar); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs new file mode 100644 index 0000000000..84a9bae7c4 --- /dev/null +++ b/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(); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs new file mode 100644 index 0000000000..5544510b71 --- /dev/null +++ b/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(); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs new file mode 100644 index 0000000000..3c5196c449 --- /dev/null +++ b/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); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs new file mode 100644 index 0000000000..984f4618dc --- /dev/null +++ b/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 + { + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs new file mode 100644 index 0000000000..2368ab9caf --- /dev/null +++ b/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 + { + + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs new file mode 100644 index 0000000000..3879e27e3c --- /dev/null +++ b/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( + this PageToolbar toolbar, + Dictionary 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 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 clicked, + object icon = null, + Color color = Color.Primary, + bool disabled = false, + int order = 0, + string requiredPolicyName = null) + { + toolbar.AddComponent( + new Dictionary + { + { nameof(ToolbarButton.Color), color}, + { nameof(ToolbarButton.Text), text}, + { nameof(ToolbarButton.Disabled), disabled}, + { nameof(ToolbarButton.Icon), icon}, + { nameof(ToolbarButton.Clicked),clicked}, + }, + order, + requiredPolicyName + ); + + return toolbar; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs new file mode 100644 index 0000000000..0e1650a803 --- /dev/null +++ b/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 Arguments { get; set; } + + public int Order { get; set; } + + public PageToolbarItem( + [NotNull] Type componentType, + [CanBeNull] Dictionary arguments = null, + int order = 0) + { + ComponentType = Check.NotNull(componentType, nameof(componentType)); + Arguments = arguments; + Order = order; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs new file mode 100644 index 0000000000..7042b2ed05 --- /dev/null +++ b/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 + { + + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs new file mode 100644 index 0000000000..adcd72f25e --- /dev/null +++ b/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 GetItemsAsync(PageToolbar toolbar) + { + if (toolbar == null || !toolbar.Contributors.Any()) + { + return Array.Empty(); + } + + 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(); + } + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs new file mode 100644 index 0000000000..82afe19f7f --- /dev/null +++ b/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 Arguments { get; set; } + + public int Order { get; } + + public string RequiredPolicyName { get; } + + public SimplePageToolbarContributor( + Type componentType, + Dictionary 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 ShouldAddComponentAsync(PageToolbarContributionContext context) + { + if (RequiredPolicyName != null) + { + var authorizationService = context.ServiceProvider.GetRequiredService(); + if (!await authorizationService.IsGrantedAsync(RequiredPolicyName)) + { + return false; + } + } + + return true; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs new file mode 100644 index 0000000000..61bea5c27a --- /dev/null +++ b/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 + { + public string Text { get; set; } + public Func Clicked { get; set; } + public Func ConfirmationMessage { get; set; } + public bool Primary { get; set; } + public object Color { get; set; } + public string Icon { get; set; } + public Func Visible { get; set; } + public bool Equals(EntityAction other) + { + return string.Equals(Text, other?.Text, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityActionDictionary.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityActionDictionary.cs new file mode 100644 index 0000000000..36117abb37 --- /dev/null +++ b/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> + { + public List Get() + { + return this.GetOrAdd(typeof(T).FullName, () => new List()); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/ILookupApiRequestService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/ILookupApiRequestService.cs new file mode 100644 index 0000000000..2351606306 --- /dev/null +++ b/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 SendAsync([NotNull]string url); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs new file mode 100644 index 0000000000..0676c14399 --- /dev/null +++ b/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 Actions { get; set; } + [CanBeNull] + public Func ValueConverter { get; set; } + + public TableColumn() + { + Actions = new List(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumnDictionary.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumnDictionary.cs new file mode 100644 index 0000000000..a68ad437d4 --- /dev/null +++ b/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> + { + public List Get() + { + return this.GetOrAdd(typeof(T).FullName, () => new List()); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs new file mode 100644 index 0000000000..be4a6f8bfb --- /dev/null +++ b/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 remoteServiceOptions) + { + HttpClientFactory = httpClientFactory; + HttpClientAuthenticator = httpClientAuthenticator; + RemoteServiceOptions = remoteServiceOptions.Value; + CurrentTenant = currentTenant; + } + + public async Task 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)); + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index dfd02817b4..6ce4a10a53 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/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 BreadcrumbItems = new List(2); protected DataGridEntityActionsColumn 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 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; + } + } + } + } } } diff --git a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs new file mode 100644 index 0000000000..c6e22d07a4 --- /dev/null +++ b/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 NumberTypes = new HashSet { + 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 TextEditSupportedAttributeTypes = new HashSet { + 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(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; + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor new file mode 100644 index 0000000000..f060450ffd --- /dev/null +++ b/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 + + + + @if (Columns != null) + { + @foreach (var column in Columns) + { + if (column.Actions.Any()) + { + + + + @foreach (var action in column.Actions) + { + if (action.ConfirmationMessage != null) + { + + + } + else + { + + + } + } + + + + } + else + { + @if (column.Component != null) + { + + + @RenderCustomTableColumnComponent(column.Component, context) + + + } + else + { + if (!ExtensionPropertiesRegex.IsMatch(column.Data)) + { + + } + else + { + + + @{ + 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) + { + + } + else + { + + } + } + 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)) + } + } + + } + } + + + } + } + } + } + } + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor.cs new file mode 100644 index 0000000000..72a58f94a5 --- /dev/null +++ b/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 : ComponentBase + { + protected const string DataFieldAttributeName = "Data"; + + protected Dictionary> ActionColumns = + new Dictionary>(); + + protected Regex ExtensionPropertiesRegex = new Regex(@"ExtraProperties\[(.*?)\]"); + + [Parameter] public IEnumerable Data { get; set; } + + [Parameter] public EventCallback> ReadData { get; set; } + + [Parameter] public int? TotalItems { get; set; } + + [Parameter] public bool ShowPager { get; set; } + + [Parameter] public int PageSize { get; set; } + + [Parameter] public IEnumerable 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(); + }; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor index dba1a47c16..8e4544e09c 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor +++ b/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 @@ } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs index 0d6f1c7107..822cca49d3 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.BlazoriseUI.Components public partial class EntityAction : 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 ConfirmationMessage { get; set; } + [Parameter] + public string Icon { get; set; } + [CascadingParameter] public EntityActions 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); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor index bdce83b13a..7a2fd20145 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor @@ -14,7 +14,7 @@ } else { - + @ToggleText } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor.cs index 319c2d9c89..7d8460b79f 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/EntityActions.razor.cs +++ b/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); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor new file mode 100644 index 0000000000..ed9f1664fe --- /dev/null +++ b/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) +{ + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs new file mode 100644 index 0000000000..3425d5c060 --- /dev/null +++ b/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 : 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(Entity.GetProperty(PropertyInfo.Name)); + } + set + { + Entity.SetProperty(PropertyInfo.Name, value, false); + } + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor new file mode 100644 index 0000000000..a9847d8e33 --- /dev/null +++ b/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) +{ + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs new file mode 100644 index 0000000000..63fec8d262 --- /dev/null +++ b/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 : 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(Entity.GetProperty(PropertyInfo.Name)); + } + set + { + Entity.SetProperty(PropertyInfo.Name, value, false); + } + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs new file mode 100644 index 0000000000..4b4e2fafd5 --- /dev/null +++ b/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; + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor new file mode 100644 index 0000000000..b8d4a9b715 --- /dev/null +++ b/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()) +{ + if (!propertyInfo.Name.EndsWith("_Text")) + { + if (propertyInfo.Type.IsEnum) + { + + } + else if (!propertyInfo.Lookup.Url.IsNullOrEmpty()) + { + + } + 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(); + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor.cs new file mode 100644 index 0000000000..f5d9704155 --- /dev/null +++ b/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 : ComponentBase + where TEntityType : IHasExtraProperties + { + [Inject] + public IStringLocalizerFactory StringLocalizerFactory { get; set; } + + [Parameter] + public AbpBlazorMessageLocalizerHelper LH { get; set; } + + [Parameter] + public TEntityType Entity { get; set; } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor new file mode 100644 index 0000000000..a8257b9570 --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor @@ -0,0 +1,18 @@ +@typeparam TEntity +@typeparam TResourceType +@using Abp.Localization +@using Blazorise.Components + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs new file mode 100644 index 0000000000..b4e74b16d9 --- /dev/null +++ b/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 : ComponentBase + where TEntity : IHasExtraProperties + { + protected List> 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>(); + } + + protected override void OnParametersSet() + { + var value = Entity.GetProperty(PropertyInfo.Name); + var text = Entity.GetProperty(TextPropertyName); + if (value != null && text != null) + { + lookupItems.Add(new SelectItem + { + 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>> GetLookupItemsAsync(string filter) + { + var selectItems = new List>(); + + 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 + { + 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); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor new file mode 100644 index 0000000000..c70dc11237 --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor @@ -0,0 +1,13 @@ +@typeparam TEntity +@typeparam TResourceType +@using Abp.Localization + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs new file mode 100644 index 0000000000..4759a37c8d --- /dev/null +++ b/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 : ComponentBase + where TEntity : IHasExtraProperties + { + protected List> 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(PropertyInfo.Name); } + set { Entity.SetProperty(PropertyInfo.Name, value, false); } + } + + protected virtual List> GetSelectItemsFromEnum() + { + var selectItems = new List>(); + + foreach (var enumValue in PropertyInfo.Type.GetEnumValues()) + { + selectItems.Add( new SelectItem + { + 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 + { + public string Text { get; set; } + public TValue Value { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor new file mode 100644 index 0000000000..ade78ee6d2 --- /dev/null +++ b/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) +{ + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + + +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs new file mode 100644 index 0000000000..4436a95918 --- /dev/null +++ b/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 : 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); + } + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor new file mode 100644 index 0000000000..ce2215e621 --- /dev/null +++ b/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) +{ + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)--> + + + +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs new file mode 100644 index 0000000000..b894c3e340 --- /dev/null +++ b/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 : 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(Entity.GetProperty(PropertyInfo.Name)); + } + set + { + Entity.SetProperty(PropertyInfo.Name, value, false); + } + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs deleted file mode 100644 index 90e4b0f0c7..0000000000 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs +++ /dev/null @@ -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 BreadcrumbItems { get; set; } - - public PageHeader() - { - BreadcrumbItems = new List(); - } - } -} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor new file mode 100644 index 0000000000..0cd13de50d --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor @@ -0,0 +1,7 @@ + diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ToolbarButton.razor.cs new file mode 100644 index 0000000000..bdfc068833 --- /dev/null +++ b/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 Clicked { get; set; } + + [Parameter] + public bool Disabled { get; set; } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/ObjectExtensionPropertyInfoBlazorExtensions.cs b/framework/src/Volo.Abp.BlazoriseUI/ObjectExtensionPropertyInfoBlazorExtensions.cs new file mode 100644 index 0000000000..b9c4613161 --- /dev/null +++ b/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() + .FirstOrDefault()?.DataType; + } + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj b/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj index face4de219..1900a890c1 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj +++ b/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj @@ -1,11 +1,11 @@  - - + + - - net5.0 - + + net5.0 + @@ -17,6 +17,7 @@ + diff --git a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj index c9ea67209f..feb1c075d5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj +++ b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj @@ -30,5 +30,4 @@ - diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyLookupConfiguration.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyLookupConfiguration.cs index 42eaa46da1..3c2907d633 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyLookupConfiguration.cs +++ b/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; } + + /// + /// Default value: "items". + /// public string ResultListPropertyName { get; set; } = "items"; + + /// + /// Default value: "text". + /// public string DisplayPropertyName { get; set; } = "text"; + + /// + /// Default value: "id". + /// public string ValuePropertyName { get; set; } = "id"; + + /// + /// Default value: "filter". + /// public string FilterParamName { get; set; } = "filter"; } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityBlazorModule.cs b/modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityBlazorModule.cs index 0a24c813f1..14b5494531 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityBlazorModule.cs +++ b/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(); @@ -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) } + ); + }); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor index 423e1f5ebf..0bddf36c98 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor +++ b/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 LH @inherits AbpCrudPageBase - @* ************************* PAGE HEADER ************************* *@ - - - @L["Roles"] - - - @if ( HasCreatePermission ) - { - - } - - + + @* ************************* DATA GRID ************************* *@ - - - - - - - - - - - - - - @(context.Name) - @if (context.IsDefault) - { - @L["DisplayName:IsDefault"] - } - @if (context.IsPublic) - { - @L["DisplayName:IsPublic"] - } - - - - + + @@ -80,7 +41,7 @@
@L["NewRole"] - + @@ -89,10 +50,11 @@ @L["DisplayName:RoleName"] - + + @L["DisplayName:IsDefault"] @@ -102,7 +64,7 @@ - +
@@ -116,20 +78,21 @@
@L["Edit"] - + - + @L["DisplayName:RoleName"] - + + @L["DisplayName:IsDefault"] @@ -139,7 +102,7 @@ - +
@@ -148,5 +111,5 @@ @if (HasManagePermissionsPermission) { - -} + +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor.cs b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor.cs index 9a8304502c..f0a222f765 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor.cs +++ b/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 RoleManagementTableColumns => TableColumns.Get(); + 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() + .AddRange(new EntityAction[] + { + new EntityAction + { + Text = L["Edit"], + Visible = (data) => HasUpdatePermission, + Clicked = async (data) => { await OpenEditModalAsync(data.As()); } + }, + new EntityAction + { + Text = L["Permissions"], + Visible = (data) => HasManagePermissionsPermission, + Clicked = async (data) => + { + await PermissionManagementModal.OpenAsync(PermissionProviderName, + data.As().Name); + } + }, + new EntityAction + { + Text = L["Delete"], + Visible = (data) => HasDeletePermission, + Clicked = async (data) => await DeleteEntityAsync(data.As()), + ConfirmationMessage = (data) => GetDeleteConfirmationMessage(data.As()) + } + }); + + return base.SetEntityActionsAsync(); + } + + protected override ValueTask SetTableColumnsAsync() + { + RoleManagementTableColumns + .AddRange(new TableColumn[] + { + new TableColumn + { + Title = L["Actions"], + Actions = EntityActions.Get() + }, + 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(); + } } -} +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor new file mode 100644 index 0000000000..86d698e2b8 --- /dev/null +++ b/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 L + +@(Data.As().Name) +@if (Data.As().IsDefault) +{ + @L["DisplayName:IsDefault"] +} +@if (Data.As().IsPublic) +{ + @L["DisplayName:IsPublic"] +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor.cs b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleNameComponent.razor.cs new file mode 100644 index 0000000000..5c16512afc --- /dev/null +++ b/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; } + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor index 891cf321d6..172d41c019 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor +++ b/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 LH @inherits AbpCrudPageBase @@ -10,65 +12,22 @@ @* ************************* PAGE HEADER ************************* *@ - - -

@L["Users"]

-
- - @if ( HasCreatePermission ) - { - - } - -
+ +
@* ************************* DATA GRID ************************* *@ - - - - - - - - - - - - - - @(context.As().UserName) - - - - - @(context.As().Email) - - - - - @(context.As().PhoneNumber) - - - - + +
@@ -80,7 +39,7 @@
@L["NewUser"] - + @@ -96,7 +55,7 @@ @L["DisplayName:UserName"] - + @@ -106,7 +65,7 @@ @L["DisplayName:Name"] - + @@ -116,7 +75,7 @@ @L["DisplayName:Surname"] - + @@ -126,7 +85,7 @@ @L["DisplayName:Password"] - + @@ -136,7 +95,7 @@ @L["DisplayName:Email"] - + @@ -146,7 +105,7 @@ @L["DisplayName:PhoneNumber"] - + @@ -154,6 +113,7 @@ @L["DisplayName:LockoutEnabled"] + @if ( NewUserRoles != null ) @@ -161,7 +121,7 @@ @foreach ( var role in NewUserRoles ) { - + @role.Name } @@ -173,7 +133,7 @@ - +
@@ -188,11 +148,11 @@
@L["Edit"] - + - + @@ -206,7 +166,7 @@ @L["DisplayName:UserName"] - + @@ -216,7 +176,7 @@ @L["DisplayName:Name"] - + @@ -226,7 +186,7 @@ @L["DisplayName:Surname"] - + @@ -236,7 +196,7 @@ @L["DisplayName:Password"] - + @@ -246,7 +206,7 @@ @L["DisplayName:Email"] - + @@ -256,7 +216,7 @@ @L["DisplayName:PhoneNumber"] - + @@ -264,6 +224,7 @@ @L["DisplayName:LockoutEnabled"] + @if ( EditUserRoles != null ) @@ -271,7 +232,7 @@ @foreach ( var role in EditUserRoles ) { - + @role.Name } @@ -283,7 +244,7 @@ - +
@@ -292,5 +253,5 @@ @if ( HasManagePermissionsPermission ) { - + } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor.cs b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor.cs index 08a214c17e..c9084bd14d 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor.cs +++ b/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 UserManagementTableColumns => TableColumns.Get(); + 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() + .AddRange(new EntityAction[] + { + new EntityAction + { + Text = L["Edit"], + Visible = (data) => HasUpdatePermission, + Clicked = async (data) => await OpenEditModalAsync(data.As()) + }, + new EntityAction + { + Text = L["Permissions"], + Visible = (data) => HasManagePermissionsPermission, + Clicked = async (data) => + { + await PermissionManagementModal.OpenAsync(PermissionProviderName, + data.As().Id.ToString()); + } + }, + new EntityAction + { + Text = L["Delete"], + Visible = (data) => HasDeletePermission, + Clicked = async (data) => await DeleteEntityAsync(data.As()), + ConfirmationMessage = (data) => GetDeleteConfirmationMessage(data.As()) + } + }); + + return base.SetEntityActionsAsync(); + } + + protected override ValueTask SetTableColumnsAsync() + { + UserManagementTableColumns + .AddRange(new TableColumn[] + { + new TableColumn + { + Title = L["Actions"], + Actions = EntityActions.Get() + }, + 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; } } -} +} \ No newline at end of file diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/AbpTenantManagementBlazorModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/AbpTenantManagementBlazorModule.cs index d4f75668ce..e1f6a22608 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/AbpTenantManagementBlazorModule.cs +++ b/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(); @@ -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) } + ); + }); + } } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor index c1c1ff15f0..65e6c3d87f 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor +++ b/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 LH @inherits AbpCrudPageBase @@ -11,55 +13,22 @@ @* ************************* PAGE HEADER ************************* *@ - - - @L["Tenants"] - - - @if ( HasCreatePermission ) - { - - } - - + + @* ************************* DATA GRID ************************* *@ - - - - - - - - - - - - - - @(context.Name) - - - - + + @@ -71,7 +40,7 @@
@L["NewTenant"] - + @@ -80,7 +49,7 @@ @L["TenantName"] - + @@ -90,7 +59,7 @@ @L["DisplayName:AdminEmailAddress"] - + @@ -100,16 +69,17 @@ @L["DisplayName:AdminPassword"] - + + - +
@@ -124,7 +94,7 @@
@L["Edit"] - + @@ -133,16 +103,17 @@ @L["TenantName"] - + + - +
@@ -151,5 +122,5 @@ @if (HasManageFeaturesPermission) { - -} + +} \ No newline at end of file diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs index 0cf34e6618..cb5ecc3413 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs +++ b/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 TenantManagementTableColumns => TableColumns.Get(); + 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() + .AddRange(new EntityAction[] + { + new EntityAction + { + Text = L["Edit"], + Visible = (data) => HasUpdatePermission, + Clicked = async (data) => { await OpenEditModalAsync(data.As()); } + }, + new EntityAction + { + Text = L["Features"], + Visible = (data) => HasManageFeaturesPermission, + Clicked = async (data) => + { + var tenant = data.As(); + await FeatureManagementModal.OpenAsync(FeatureProviderName, tenant.Id.ToString()); + } + }, + new EntityAction + { + Text = L["Delete"], + Visible = (data) => HasDeletePermission, + Clicked = async (data) => await DeleteEntityAsync(data.As()), + ConfirmationMessage = (data) => GetDeleteConfirmationMessage(data.As()) + } + }); + + return base.SetEntityActionsAsync(); + } + + protected override ValueTask SetTableColumnsAsync() + { + TenantManagementTableColumns + .AddRange(new TableColumn[] + { + new TableColumn + { + Title = L["Actions"], + Actions = EntityActions.Get() + }, + new TableColumn + { + Title = L["TenantName"], + Data = nameof(TenantDto.Name), + }, + }); + + TenantManagementTableColumns.AddRange(GetExtensionTableColumns( + TenantManagementModuleExtensionConsts.ModuleName, + TenantManagementModuleExtensionConsts.EntityNames.Tenant)); + + return base.SetTableColumnsAsync(); + } } -} +} \ No newline at end of file diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBundleContributor.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBundleContributor.cs index e7a231c2fc..684426ede0 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBundleContributor.cs +++ b/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) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyProjectNameModuleExtensionConfigurator.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyProjectNameModuleExtensionConfigurator.cs index 61795eb4e5..53a4ab0879 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyProjectNameModuleExtensionConfigurator.cs +++ b/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 */ } }