diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/BreadcrumbItem.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/BreadcrumbItem.cs new file mode 100644 index 0000000000..f2c8075707 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/BreadcrumbItem.cs @@ -0,0 +1,18 @@ +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Layout +{ + public class BreadcrumbItem + { + public string Text { get; set; } + + public object Icon { get; set; } + + public string Url { get; set; } + + public BreadcrumbItem(string text, string url = null, object icon = null) + { + Text = text; + Url = url; + Icon = icon; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/PageHeader.razor b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/PageHeader.razor new file mode 100644 index 0000000000..df8f009290 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/PageHeader.razor @@ -0,0 +1,42 @@ +@using Blazorise +@using BlazoriseUI + + +

@Title

+
+ @if (BreadcrumbItems.Any()) + { + + + @if (BreadcrumbShowHome) + { + + + + + + } + @foreach (var item in BreadcrumbItems) + { + + + @if (item.Icon != null) + { + + } + @item.Text + + + } + + + } + + + @foreach (var toolbarItemRender in ToolbarItemRenders) + { + @toolbarItemRender + } + + +
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/PageHeader.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/PageHeader.razor.cs new file mode 100644 index 0000000000..60d8d51b42 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Layout/PageHeader.razor.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Components; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.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 string PageName { get; set; } + + + public PageHeader(IPageToolbarManager pageToolbarManager) + { + BreadcrumbItems = new List(); + ToolbarItemRenders = new List(); + PageToolbarManager = pageToolbarManager; + } + + protected override async Task OnInitializedAsync() + { + if (!PageName.IsNullOrEmpty()) + { + var toolbarItems = await PageToolbarManager.GetItemsAsync(PageName); + + 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(); + }); + } + } + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/AbpPageToolbarOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/AbpPageToolbarOptions.cs new file mode 100644 index 0000000000..7bfcf5acaf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/AbpPageToolbarOptions.cs @@ -0,0 +1,30 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public class AbpPageToolbarOptions + { + public PageToolbarDictionary Toolbars { get; } + + public AbpPageToolbarOptions() + { + Toolbars = new PageToolbarDictionary(); + } + + public void Configure([NotNull] Action configureAction) + { + Configure(typeof(TPage).FullName, configureAction); + } + + public void Configure([NotNull] string pageName, [NotNull] Action configureAction) + { + Check.NotNullOrWhiteSpace(pageName, nameof(pageName)); + Check.NotNull(configureAction, nameof(configureAction)); + + var toolbar = Toolbars.GetOrAdd(pageName, () => new PageToolbar(pageName)); + configureAction(toolbar); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/IPageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/IPageToolbarContributor.cs new file mode 100644 index 0000000000..b90fdfd768 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/IPageToolbarContributor.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public interface IPageToolbarContributor + { + Task ContributeAsync(PageToolbarContributionContext context); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/IPageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/IPageToolbarManager.cs new file mode 100644 index 0000000000..9344afe91f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/IPageToolbarManager.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public interface IPageToolbarManager + { + Task GetItemsAsync(string pageName); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbar.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbar.cs new file mode 100644 index 0000000000..8f7e5a393c --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbar.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public class PageToolbar + { + public string PageName { get; } + + public PageToolbarContributorList Contributors { get; set; } + + public PageToolbar([NotNull] string pageName) + { + PageName = Check.NotNullOrEmpty(pageName, nameof(pageName)); + Contributors = new PageToolbarContributorList(); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributionContext.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributionContext.cs new file mode 100644 index 0000000000..3cae80199b --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributionContext.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using System; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public class PageToolbarContributionContext + { + [NotNull] + public string PageName { get; } + + [NotNull] + public IServiceProvider ServiceProvider { get; } + + [NotNull] + public PageToolbarItemList Items { get; } + + public PageToolbarContributionContext( + [NotNull] string pageName, + [NotNull] IServiceProvider serviceProvider) + { + PageName = Check.NotNull(pageName, nameof(pageName)); + ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider)); + + Items = new PageToolbarItemList(); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributor.cs new file mode 100644 index 0000000000..ee452407ce --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributor.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public abstract class PageToolbarContributor : IPageToolbarContributor + { + public abstract Task ContributeAsync(PageToolbarContributionContext context); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributorList.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributorList.cs new file mode 100644 index 0000000000..b3c2157b3b --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarContributorList.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public class PageToolbarContributorList : List + { + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarDictionary.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarDictionary.cs new file mode 100644 index 0000000000..c239bc52f4 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarDictionary.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public class PageToolbarDictionary : Dictionary + { + + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarExtensions.cs new file mode 100644 index 0000000000..71ff4b3530 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.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.WebAssembly.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.WebAssembly.Theming/PageToolbars/PageToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarItem.cs new file mode 100644 index 0000000000..dd940fc84f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarItem.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.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.WebAssembly.Theming/PageToolbars/PageToolbarItemList.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarItemList.cs new file mode 100644 index 0000000000..e427b62df2 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarItemList.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.PageToolbars +{ + public class PageToolbarItemList : List + { + + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarManager.cs new file mode 100644 index 0000000000..f8eb784ebf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/PageToolbarManager.cs @@ -0,0 +1,44 @@ +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.WebAssembly.Theming.PageToolbars +{ + public class PageToolbarManager : IPageToolbarManager, ITransientDependency + { + protected AbpPageToolbarOptions Options { get; } + protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + + public PageToolbarManager( + IOptions options, + IHybridServiceScopeFactory serviceScopeFactory) + { + Options = options.Value; + ServiceScopeFactory = serviceScopeFactory; + } + + public virtual async Task GetItemsAsync(string pageName) + { + var toolbar = Options.Toolbars.GetOrDefault(pageName); + if (toolbar == null || !toolbar.Contributors.Any()) + { + return Array.Empty(); + } + + using (var scope = ServiceScopeFactory.CreateScope()) + { + var context = new PageToolbarContributionContext(pageName, 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.WebAssembly.Theming/PageToolbars/SimplePageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/PageToolbars/SimplePageToolbarContributor.cs new file mode 100644 index 0000000000..e138faaae1 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.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.WebAssembly.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.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index 04aecf1f5f..59070f32b0 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.AspNetCore.Components; @@ -206,6 +207,7 @@ namespace Volo.Abp.BlazoriseUI protected override async Task OnInitializedAsync() { + await SetToolbarItemsAsync(); await SetEntityActionsAsync(); await SetTableColumnsAsync(); await SetBreadcrumbItemsAsync(); @@ -462,5 +464,10 @@ namespace Volo.Abp.BlazoriseUI { return ValueTask.CompletedTask; } + + protected virtual ValueTask SetToolbarItemsAsync() + { + return ValueTask.CompletedTask; + } } } 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; } + } +}